From b1b28f82d6f46a1a102573a692d014b6f5c9eeef Mon Sep 17 00:00:00 2001 From: cewing Date: Thu, 17 Jan 2013 17:38:23 -0800 Subject: [PATCH 001/487] * update week03 with link to presentation. --- source/main/outline.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/main/outline.rst b/source/main/outline.rst index 6b51e5c1..cbccd589 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -185,8 +185,10 @@ at the data they provide. In our class lab sessions we will practice scraping a website and using a documented web service API. -For our class assignment, students will choose two sources of information -online and combine them in a mashup. +For our class assignment, students will choose two (or more) sources of +information online and combine them in a mashup. + +`Week 3 Presentation `_ Reading ******* @@ -257,7 +259,7 @@ Bonus Assignment ********** -To Be Decided +On the way soon. Week 4 - CGI and WSGI --------------------- From 05a33b339ea9b6b81e3379bb3ef1d011be2d20b3 Mon Sep 17 00:00:00 2001 From: cewing Date: Thu, 17 Jan 2013 17:39:42 -0800 Subject: [PATCH 002/487] add feedback from homework, and placeholder for GIT presentation by Dan. --- source/presentations/week02.rst | 121 ++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/source/presentations/week02.rst b/source/presentations/week02.rst index 29eefe6b..155563b9 100644 --- a/source/presentations/week02.rst +++ b/source/presentations/week02.rst @@ -19,6 +19,120 @@ But First Review from the Assignment +Clean Up After Yourself +----------------------- + +very few of you closed your server socket before exiting the server script: + +.. class:: small + +:: + + server = socket.socket() + # set up + try: + while True + # do server stuff + except KeyboardInterrupt: + server.close() + sys.exit() + +Use Module Constants +-------------------- + +Constants are provided to help us 'do the right thing' without needing to +remember what the right thing is, exactly. So, instead of:: + + socket.socket(2,1,0) + +use:: + + socket.socket(socket.AF_INET, + socket.SOCK_STREAM, + socket.IPPROTO_IP) + +Interaction Can Be Good +----------------------- + +.. class:: tiny + +:: + + try: + # generate two numbers + while True: + try: + number_one = int(raw_input("Enter the first number in the sum: ")) + break + except ValueError: + print "Oops! That was no valid number. Try again..." + + while True: + try: + number_two = int(raw_input("Enter the second number in the sum: ")) + break + except ValueError: + print "Oops! That was no valid number. Try again..." + +A Tricksy Bug +------------- + +.. class:: small + +:: + + ... + while 1: + conn, addr = server_socket.accept() + print "Connection Established." + # Keep connection alive. + while 1: + data = conn.recv(4096) + listIn = literal_eval(data) + print 'Values: %s, Type: %s' % (listIn, type(listIn)) + conn.sendall('Sum: %s\n' % sum(listIn)) + + conn.close() + server_socket.close() + +The Result +---------- + +Client: prints correct value + +Server: prints ``Values: [0, 1, 2, 3], Type: `` + +Server: + +.. class:: tiny incremental + +:: + + Traceback (most recent call last): + File "training.python_web/assignments/week01/athome/number_server.py", line 34, in + listIn = literal_eval(data) + File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/ast.py", line 49, in literal_eval + node_or_string = parse(node_or_string, mode='eval') + File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/ast.py", line 37, in parse + return compile(expr, filename, mode, PyCF_ONLY_AST) + File "", line 0 + + ^ + SyntaxError: unexpected EOF while parsing + +Screen +------ + +For running scripts on a \*nix server and keeping them running, even after you +disconnect:: + + $ screen + $ start_process + + Screen Detached + $ screen -ls # lists your screens + $ screen -r connects to only running screen + And Second ---------- @@ -26,6 +140,13 @@ And Second Questions from the Reading? +And Third +--------- + +.. class:: big-centered + +Dan Explains Git!!! + And Now... ---------- From ee0ca1ea5187dba3a6ffceb6610a2c5b3b56ab24 Mon Sep 17 00:00:00 2001 From: cewing Date: Thu, 17 Jan 2013 17:40:34 -0800 Subject: [PATCH 003/487] update homework description for week03 --- source/presentations/week03.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/presentations/week03.rst b/source/presentations/week03.rst index 09f86da8..6b83c7e4 100644 --- a/source/presentations/week03.rst +++ b/source/presentations/week03.rst @@ -1394,17 +1394,17 @@ pull request: .. class:: small -A textual description of your mashup. +A textual description of your mashup (README.txt). What data sources did you scan, what tools did you use, what is the outcome you wanted to create? .. class:: small -Your source code. +Your source code (mashup.py). Give me an executable python script that I can run to get output. .. class:: small Any instructions I need. - If I need instructions beyond 'python myscript.py' to get the right + If I need instructions beyond 'python mashup.py' to get the right output, let me know. From db1c4ceeb18388a6309d745d71f7dd38c825fab9 Mon Sep 17 00:00:00 2001 From: cewing Date: Thu, 17 Jan 2013 17:41:26 -0800 Subject: [PATCH 004/487] start work on week 4 presentation --- source/presentations/week04.rst | 66 ++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/source/presentations/week04.rst b/source/presentations/week04.rst index 3464451e..02d94f4d 100644 --- a/source/presentations/week04.rst +++ b/source/presentations/week04.rst @@ -1,2 +1,64 @@ -This is Week 4 --------------- \ No newline at end of file +Internet Programming with Python +================================ + +.. image:: img/gateway.jpg + :align: left + :width: 50% + +Week 4: CGI, WSGI and Living Online + +.. class:: intro-blurb + +Wherein we discover the gateways to dynamic processes on a server. + +.. class:: image-credit + +image: The Wandering Angel http://www.flickr.com/photos/wandering_angel/1467802750/ - CC-BY + +But First +--------- + +.. class:: big-centered + +Review from the Assignment + +And Second +---------- + +.. class:: big-centered + +Questions from the Reading? + +And Now... +---------- + +.. class:: big-centered + +Gateways + +Think Back +---------- + +In week two, we wrote an HTTP server. + +We set up the server to be *dynamic* by returning the output of a python +script + + +scraps +------ + +What is CGI? + +Why is CGI? + +How does WSGI differ from CGI? + +What is WSGI? + +Is WSGI Python-specific? + +How to run locally + +How to run on a server + From b98d02577d56e309939e5996f3894c38e512bc05 Mon Sep 17 00:00:00 2001 From: cewing Date: Thu, 17 Jan 2013 17:42:00 -0800 Subject: [PATCH 005/487] add cover image for week 4 presentation --- source/img/gateway.jpg | Bin 0 -> 475556 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 source/img/gateway.jpg diff --git a/source/img/gateway.jpg b/source/img/gateway.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7c81c1372c312d16f0dad089a0658dc415e79de3 GIT binary patch literal 475556 zcmb5V2Ut_j);_xFy;lh!C6v%ar6Wj(gdTdYQCjE$mEM~mT?A2j??Qke9i)lUTj(It z5v3?tZv36^JLmlGeeQFgJIUVr-D}pY^-kH7*)x+r3xC!DT9^h@1Hi+>1GI1-;LmS> zQrX+v1EK5S>rVb>lSmM%s%mEd*VlmRsN>WCfQZ!r7mv>c0DexMzHm(yE^`Y@E|O`0 z1i;1q4GvCz-pU3BI{#pt?mxo+<8(3iFWqU;zqbC5sQ>R93SXQ<0Kg-~sWLwN7iRy9 z9sh;J|KdP@Z-1PQ+F$JC;^2(K<~S_kYYbP#;biz9=77Xbdn_a6y^ssj??>%jH5S`2)>9=LiS{zvog<^LrX>4C!K_n$z6J5wS& zO^k3?FfO035Ps@^u?WtUjJ^XK-Antg4zB$0?>uoa#+4z!hLhv4svZtAouAVsCa6l7K0Ym|B zoWu)w0J!2l9=PNGDfhr>KL9RpdR+f)MZ8*kLwxVwmbk>{#gD{i#S6tt#19aU^mPNi zyV?CGHqzJ5)#>B2FMz>69RB+IYxiH?xNs~S{$a)ir~(@}p8vZ0UoP(d#r;2gJ^szr z;NN-p7uTQvcdme6!1sr8|MB;i2_jDK;@=h=ajg6RcU(GGAOMFwaCZotzW@L5{O{8H zUsnHN@>l;a^M9A{2Y-xlYw&;k%@Vd*Pg4#B|G(tk`5#}Zz~;Ye=)ZI1^&dNc2ClCB zafj1?eEqlI|I++#3kaOw|E=YJmAWae?zw<}`SswsfwSiQKXrikC&z!=h0Fi=0{jt= z{Bi9FQ1$YD?Cbi_#h>erxcFVJf4V^~RWGDB${*p&1@&|i6XA03@ZkDK$B)Yw;fL@I zKsby2P5TFn3Gn|0LIMJO0wO{pA|gUULLy=kVj?0EVnRYV#2=M3td^$V=I=nvvz)c)SBBHx+Er3UWkE2LPKuAhJNCbdzafC#405Lr`3Bzq=QXWGGGR8YT zyb)A;Ja|g-pMa4z8mDKk*BPD5=QAa_$8hEqB4q#o777Brv(J3q)eS3_y@dc z?i;{4;J^d$a0LE~0s$UAjs!qLN`{LzqWi}`J_!k~w1|oD0UA62M}Urqp8K}4Au$7w zgHJ>n$(_PRoKwaPCSDb|qi^~tDf8XPqA3=zs!LQxq$|WX4xD<2Tb=f0h7B z0-O;#0y^M6kmA+#BlQokrATvIbziaVm#PoyL-p614_NbOk&U;8$yY8DS`jxtMN6+6 zvR`{o_XtmYyCT`@dh+|Uj|8*J!e;H#6t~6}c4Iqj#$Dd&<)xn$V8-pBb0XM)XWt}2;SXSqFGFF|IZ37YVD9Icno1?4 z$haL&{)C|Bs7vHY~^y*t9S@?N!D`mfIHfS(PfeHsJhP{W+1UCoxRwM zTU_5h@8PVLN#J`oP-zisqts34Jg}&$^&^4f$v2v-&3oZ1%y%~2fn>|){QJM(a3LFZ z*wr6tB)UiaIJ5mRLfU=a&RODq|5J*+4}>D7Mx;^FATw+6j`PB+nEoitU3bPI-OOFO zD&afIWOtmSCSEz#{yb%z${6IxQn}{#*}r46Fq&R{xdURqqouV-4~gJkYhqunBm-Az zUmSgp`{hj{xw6}Sj*(7+hwzL%=c0~|WBT2e%uB<>53!`4)127N4E$I~%=ZzsFOv2g`;;T+Q5Ak)5 zl>R+&^3%I;n`5GsFj7lRO#Ze!*&TBI;%GbVc;<^ccmnpOwT*$=6txIl1tZ;S zDYe8Jz4qo8M7CpQ`t!`mWnkNVf-0&B61S<*^kN>R)uB_;_JR0HEjjukMW2xDyQbM> zzu)lc|NI;*Gri)UW!gZX{_un1W&*u42v;#QTak-B=9vtU( zq@VP&+bL z!%WJ)GDoY*sn3Hje4Q(0Luag{GK_A7|}@-!ejPsl3{X%c|^Z|Ufun2 zlP)~66ooO5wtT1nLMP zXQbUNZYbAlBc^mlAeX{_)rl>Y)=Q0M&8_(|gGcygGJl>W$JshI>WkvBWw|n0=`Atd zdmsyg!w)M-{s3jd!I~)Ub;Cu=kN(wpwOW=VKPn-*-IwKITd{Kay%?UR2O0J?Pg-tk z!w6pxDL{8_o)1aoEM4lP8~TKj3b#N5ETdb83aHr?nzudSZ28ATZ`1DVHyN8$=@kC~ zp8f&q_|Qy*I@2eFj3y67r?RwD;mV*IoS4)B5Rh``KsqxGfgx%?`>!w*B1e&u$LL)> z(XOa~_=5cYL8P3mx(4HVezRa*!9dweX_;F1tu`^voP1q#q+^r~Y!#1@ zWZ7`)FoCW6vovdiSm^qqsbtOKoH^W?gjA>eWO`o)@)B!faFxp89W7I7-7OM#eE*$p z3jWCWCEQN8Y^f-`9ol9bck~CCq!u`j-X{-ta_vGgo33RbOBHF1P%n9x4-Qc8-*`xT z=SGf%*@G4F&MemGRyo=QYn=2dW@BIw=pC@v^oJVNbkz{@1}8Q)3iZiR_;;nZFNkbB zm;(k#bdZHY?!0)dQukkx-fJE)i4Qddqj06!3;8_nFN^glA|3l?4mbIj`dqndjA!9F zZ=LicUSqhtsWz)ck%22D)HwZkpgO1id{AWJG5_JBrO{mSD@oP+UW)BHwe*Ovb9HNn z*tFiV-49jnDT&Gm@=hg*VdHio#ll%o7`wx%ORE(nn>%}{-03H12-(|8!aS=}lizJ) za@V3k9E&Y6sXG%_>RoP7Totp6zdaS~%g>$~Cfv!l)Gg5>}WuKXd6Gab6Xy2Zve4=r zXLTX7@ey)?>(4${TPE7D&mze-8mbOoRn{Ls4_q7gM+`w$IbJ`%$X2w26C0L#Z@HrO zZgGH*-x>J?b}KBG9{=B75o+ z^?8}$d?Y*LJC<0r8xsj_FSNtvd!JUPm~)Pj_`ELHxPJ zvF>-J-tGl<|30@nh+xj*ZVC_3NH#4?dGqOYM-{GEh{n|!tl+U_?RT5^B5dD&3acaD zDMA~C;EyIA_GtasLti|$!ac6y?~J+)oe=p(Bdj9?U_kj503_woS{e zEjhR23?3%|MFg~$e(_b zbXoJDQa_yZ2 z9fzESCFds5?oFXTz(>+yv6p+uD&7}44;U+gw~O@u01DDKhZr2AOxP^*@Y5vOI+dq3 zjT8;q+kdLx{5IGk56l{O4$fn=yM8GVMoFp6JmGY#|9Pq?>qkUT?M=S(ql(36k7OpR zy8a-d%kPa|NPzN$rxwZD+V#HsG(u`a@|Mhej}U}MmwnQ2 z%M>>Ugqx%Mm%)KpQc&%v4S5?lJT=W{`Ap{Epz5=12REsv_R?ybk~HK)SFed+Q*(Lk zadlvSqBfxNKJ#_i_Uo|oKE#%@W?O!XYM$FV5ywdvc2j=Db7UO(Yes>Lpi=7Q5FKgP z@R8SpZI61$T4;XQTA2(Ly}6ZP(T6M`0Lp)PfR<@qWRs`!7nh;)Hgbqxyj3OUH)0vr z!hgA7dwq1Zp0ArynFiB{AlGRjT)HGg^{nWTA70FeAfEIE-rS39$+rICe_~D$R{?s; zsv%mH0+w#cLRIyos)YFTiMM|mGI7)^W%3}YRPZi+If3g%<+Xh@bOp_K3BF% z+Do$!CHPQ6uW%^9v)k~Vl;;v7t=eI}@Z=<3EW8-)RF+LT{(`hCi=z?W(zmo%P{3It zwjZIa`L!R9YZ2<*wuVS{;2?uV$P=JBiL37AVm@!zYf}r-+|RyF!_vHGxN0R%0!1qj zHfO$C@eC1{$4~o8SBx@yq0O1=g{7iR5%iK~xo2uxk`FcD0$s>_ekW6j6q~?*<~Rap zWUgL5V~x4Tb;wxA&FQK%s74!2a1^Ga8ghF@mx*{z#U{HcRo~9e8t7wzU2^nwKF?I| zZB+Pmd&Q3M`)a@n`(P#q;*1pOY4=l|Tk!GM$4$`9Bw| zEl| zOtgUH#1QE}z&(k4NnLPM-E)f{DHLUc(t9418q#`x7~^gYs5 zC3j?mMP)HpX{ArSd*urRl8m0Em-S7u-S0Q#8M1(Twf=CR;(M1AqlfnG#3X<-Pyv@{ znMv-Zii|;gtG#*u81t(qPwWU0vIHiJFM?hP_u1xEZ3z6>0BQRn#;XVygfqlz)k>Ca zf9HIjiYOAV63`>{qo);v`Tu_ObeCO99ibb0L4J8wO97$?bs}&Pa_PE2k7OF^+-u!P7N$82n!-PGUOk6PpFyRI<8Dk1hrv{Df|0=YXsX^vq$)qeqP`)7|=+skA7s)xPgz+H|w-o7pQPdeaqf zPsX54id^Fz%sObrDYYaM3;k`@N5xPQkb9gYM%K`j?j1bGRxw!oknnX)<9md<@cr|F zQO$+@f|)+{m6_1@lP?`UWpTqW5#0tpt^Ll#V=VD~nlAf^1tZqZ-#8507sAQ}v^gEw z7>U_2(X9n@c|s7Q=L&IULc%U9$gCJqn@h<1a+3&{vJfx&`v>D`J48iUWm|i9q#P3; z6`wGhrstZ68HNgpxThVW!a8W*tVC_SdY#|3a3eZj0VHM4?H1Af%4>dvuq8luL?29t|5+<@jsv7BFN8#i(W9x#J)h?V!q)O!>y%Ya8n zWPRQp*D=-v~-49zLL#SiQDSMz(0#j5BrILUAte+eoOsCobTz zppLOoT7I&z@pj_XLCOe}?08RT+S|(uEg()|U2sn(FEZVaeMXD_VlRPm+Jsrz0i!c+ zc_>mhzxw@Nz;@wC5ZFe2UdsR~y}ZV->B6V__#PdePL_?*k^9YH?T$wkomL-RJZkWe z$uoN2Q4yrNgcMxx?b>E~>hD3Ux13qpBC7Q7i%yYQqPtHAz88T6ePJH)WgmQs0CfGA zV;?crn7Sfkm};}~LiX0qSliE(n_Pf3VHylNzaR75c!|Y+<7Vjh=y%DZ;?#}zO=7_< z-!wC$8av;Chb4}cQp{|Z;k7Sd+&mX;=X;5*Z)}*N^$!;^d2^MxVTK&P#O3XbRjz>< zs&>~O@dY(uZW*m!;=Q~sVoF(8ZY>7iOdp>%e5-ElQq1u=%JZ|O#3GpGYMyxcluv9F zxa8;fTBwGIrOQWPsYJ=BdfwN=$jBB>mOVA(wHLsyopo;t8z)M_6~v>9C2Y`51s-@| zJQ_pPQ|lF5x7pvC+Anpa1z8Skw5~HOg*8{P$^Rg#zuH)q)O8v6K?G!`isVs8;krY9 zYvR?_Y9Xrzmd+vF&W6(aG5|G&5L}9dE1>aWh&hSx{UlQC4dG#3w7+5w=+Y*uAdj0e zJb&;C3uMJ!6}7zEg%Z|%F2_>ZgCHXF@OpjKwssEW?_Xcu7yG|x`f3ISN|WlgrW<;p zZCZwh@pn}IK(0sBnvK4~mz?FI}QeJzB78JSp2jR&pc@+JOKV$4DB|G zUCJhF-wo)uVal-n>aTHMrd66SdaYnD{#`0wm4Myi>;s)-A+~tVyycfvUru35DK5c} z)gfRI1#TiNv*-#UQW;>yP{i0yK0%X1=QMTEgQe}vcz?-0q5s0Lwf!hTBcF1lc4GL1 zekYy!Ri5MRXWGS@5QWUpvG5Y>@^byldD_)J^4!I!0A>vP*a(G?W!an^eun9;N z7F_Z%T6Q=<49%t2f|aw=cjip#W){r%pYhD3ZY6Nrgj_pP>}kQdD!TIc2#i34%aM9K zIk3!;nm`qu*J1-+=poA6l^hSU)xF*_=OMeT?4P<2@83p^M{+&q)1@t*Kz3aW>~6Tu z4bwaZfm`$nrs7@zufjLqy~;df(p6Vx%Um;t-<(I-a9w#NQ{8k9H_<7VnH{;wPoHs? z9+bA1l;!vEulH zMz^3wr&j`gAWN}qT+H|DTbRB&Ibv*X(7jdY?bvYABP z&1#N0JvHMe?p+5m?JNZxL`Hr!swmng1Recu%LH@Th)Yn_Rhe^3lQ@KacS+@#Vnxl= zo1>v$tJh|n!rOI3$Ck{sI6SDyCqs;+rSS}?%htlKHm=IzvXi`x8-H_jY@l`Ie9WRV zuQ)D9rr96!BuVuh3<{vk{nw^Bx)SQp2R%!lvvD813N?;%NOH?b*_ z_SML#%8P0aC0}w=8rj*veG{zmvtPC9mTB@wr^dB9Fi_0gQr=QUxTi$8x($Rh@-@C9 zy`%V3BNA?Gxi140C@)JX%43pL15OV{f+MkW<|I7wd_n_63*U>Vk5^vy{d z^1Ca)Nvsj9q$Wz+=8)b9L&xj2=LQ62-;;NbB zn!75)ls^dfNLqMue)%ptb7%IUo3&Nx1O_zDH(04L)NuB*AuCx5;5Srwu6K{@vVod5 zD&$%4Lm{rML7PFim-}vJ{HtVu$f|wNubA6X-JCeWk%`Xlvph$`alLjK#+?yKT?dfO z+tXm_O3Kx__{LmsI~wbuY_q|IJa{^PqHlOPEel6Ud`I&Wlug)^618Wyejrt`zZSc z+_RKJV-jLGfL=?Kc5L!;tPdIgBHc%4q0p@1VM;v@@75ukh$!NHAUIOBfKf8Vzw*I& zXX4XUql_!S>Bw$t(tZSw?D1n8Ds|Wv%;bu*jqItX;S1jS!b!uCfl?(b!J z{iPOAvDvd+M5YB!*Zfx`HRw?t-s#0yOv$GLWXL$9-F`Ts$qG+5>Q?43GMm6!I zBOf1+N1WL-?_@8k$!a$bEWIAj_r|~7yIwDQ04pvVM9XP0`jjWoXsuLx{{a?2M0$?z{W*4mr%x|CV zNF?D8;1Y31E<&1Gz&mWH&=b@F}|^b5y~n!30F!dIQA zpu?uv5F(*FtUOaw*y2Wx-~VIl4TW3Qk&o|q(cGN$HLj80MfN?S zUXDr2tOPSO2($)EDKX^go~bZSLNI#YQx=KN;Ymqw}$R(870l4M{ey@c>vMJ*5G?`dm_iM zTzaC6`HG7_KtNx3^rnY$XV#t))&RhEvGn=}$JsBmdQ*uFqX;8fZNNVUKz|1&u9omGxUyqxo9Wdi_)1 zT@h318&$MRGyb@d1KE4_^c$ozh4*IZnzEIT_98H%9&7N8jqqBX*Kq`D`b!9N)TDXzDmCz#oZN= zfN#AIQokYOW{?_NG80eg`s{KjG{2CSeKXAejwJL` zbh%B9ho=vxrM;v^VnJJ)fAKSO9~%CB{q{kpJxi1+WsSEKM4!G17AM=su=J~u=q%2@ ze8{MGL~GolRZ2B-ZFA7C;;8E7QiCSKx_ol(axLT}djG>9Q^pFTF~?U3{`ylb`&oQV zYBCbZTW%yKJqN)yJyy>V+D4!{juE^7IY!3fN|N(l!e~Z-DCrraGGC`Kw>*W_QIZyi zk8dGNa*|%`hE+892k~`EF|&#Rer?EY4C^$TMjrkXx~cCJ+axA@Y1pQeVxx5WQo()R z(7ez`wb_O9ZE&Y(psAg#iC#0)s^I1rfpawDSEB1l)x)xFZiU+pppg|~^Iuytf$ z?+db>$j=c?6a`kkL|=kj5jQ??FJ(PbHc8kG+?%HE=Iikj?v-i;o$xQSN=z9 zzKmQ?(atPcr4TuF3|`E5m8X$AZT+X~1Li%?woN#|QD93j)q{8S(uYN^eES}3q*R(` z1B$*-P-wtc-A<5X(mzArma_jbM5wNU;+e?aI^s z8)b#glU1Vz>hFGu&&wo7ZYs0YI5`F~E9N|A(UBtlWT+a%zw%^_8i=TJP1#PWPEY1m zTM-sGlc7U>h~S9r8+@pdN+zw?dfv~8&1cA6pA6bJ_2)PVs<1lr7T}TG=5#xkGrkoX zRmQe3{q$|(094C@Tj|NhqLP$S@Yc$5!KW@n0_<7gKt$O{-HjH$$2yDlD9-OXmzuftb-fq`2IcKWsTv(#GUm_ryGT}93LA7ARL8FS&U9j z7`RlaL~4XLvXP_?QerP4Zc6vI8LyWng}hF8_@LV<{-h}l1eGfu4cgPPWbCv$YSmG$ zOu7m;W&D<$pql*^A4O5Y4ce&&i(B+zkCQ33gm7lQq`?(4!ktxfy z<6Ydg89v4M4NL(Shtls5k~O+~^6U{$f7PuIhH|jk9|1i{9!W24cUPE*_@q1I+Iylr z>6F{r7Af6IOO`>%12pS}x4L`JXMcsN#M#hnf|H1Bs>vLEq8uopr;^MK*Qt?>rTrS~ zWa)3Vt2y=#T?wcK8y3vImYLBSaibPT*=~`FSGQBx7?JCGwECoWO*yjf%0V>|6rui1 zldM}E^u#_HHLb0xab5KJg?v;AZUO=sLR=wAk}HzBAR{RJ5}V?ZXarDMC9PgNI>YJg z3-ueT};Xz0J)}!dE~LMbkS$+ZOwkHEo6Xi@;2!< zFy29{hm6Nd=g#`C7WkfI(j-)u{@UKmy37W;Sz)c#(h*Wx`apGY$l#Y9tn<)9lJHby zb@cL45Ib&F)rNN5d!imj&q!bU(SzR)$uOVlf^B@@fL3ct znDVsqXQ|Kd+E1>;L-mEdSS~>?PVz5NB~;B9@}ZByK!pT7jC@pCOIxPAvWvQX_so3T z1*hN=he64;(eI%cSGk31)3mBxbo%{!oYHx2a4pjL$YwNAX3%>4gSmDSNK-(|A0S&+ za!Ml7vkoSLuOxrgb<+{0GT|a^7M%`Uu1%A&C2;eh$qRXUmeb~gMeF=kpY9>D$Sw)3 zzV&5#W6g!r)9<6yP-~=m@%p@QW*cU?nS7U6^#+6fSLq& z`YrV9V9EEc+H*b>axCsY^s1kn_t-IIgwG9H#{e)`T(IP%t9Sde#zs|8Ft>niLaSbO zj~$DoAdCQsQkOGEJr3{oT;NI|no4mie3I49l{}7duY5OTb?UJzIBS3wo`s(T3DsY{1Z6lsDaz$!|cYf__zjeQ}hBk7P zZ6<~wWHwmcpDX&oa3Fzt+TB&vUS$|8Xkk5)IJ=B&mFoCuUd=sGlt|U(t{(oOLY1@0 z$Idq1HdJ|bG@qVe{*@!TD56%5NHMo9e{vL&#s6W?@O;oYbLUFHh{lr^kXX=(eVxhfr~BI~Y1t20$hp&k|g z#W}}qAuTPpID*`enGj~O;FxMh>V?YmYQd(~MEr05p##celLfzy5CHoe`{e~ai* zxItQ_G7X&J59)zh&CXGCeD+h?>=tJW7tM*9u#8%r!j43h3E9m@v?#flzZJPqLV@(L}w% zis-Z$S3RzdRTCJ)q}CdT6Goe$^un0e5A(Ne$yg4P}Qx8#z&(j@AS3G?y<+&2oST|5N>IGC2iyu#X8)!wxa zM0OU3T>iY?P_1Furbf*fPcSp_ek3O8x(`~!?p%au`LX(9_) zS`xakb!^0~`r{$97ywK`@p>Z;f$=h5Ij+jAI{nE;%nveqj3xuG@gM^ADuh zLp<6SAvI~09zu}Im)&E!H%fR6D0~SA46VNgny@T~a^L*OZb=_`%Ts9OP-Fech9!d> zHs9pPx~k{ovLC@_LsxPf_f=&|NpH0)C;DbxqLoHA9QX_4t5o*xTUB(T21WA=_Jz{jNlmZK8CSx{PT?LP`^6=lZa&hBv z1^)a3aXrU?C7r|!0xWcr$%Pub>#f$2W#fZPQ+D<>zLs;!Gb9B94snV0#Fft~g-L@@ zHfnZ+`~DMPdiN!j#Z+{_nxE$a#oikMw9!ot`gFzv^Fsi=P?`JEXT^HR(64NGhYv&)LEG8vJrqg+Zc9hG3`Oxa8-HhJRN z(jcCki9dB~f0zbMqM3<1D#1iDBLoT$X~nHBMJHE25-`TsRbu}5LRe~zB;~ag;gAVI zq1JwM_DmM4``h5)Jwgr><8wCV=v?D`@})V@@3vOPqNS=ArGEb87dv?Yvq9<9tXF!_ z*b zM40hcd}HFC%Xe;=2dm>kzhm*Y0xcjWlv3nKN4bc^&FgCErr|mx?Uo+tYZR;Cz0Ai% zZ9J{ayG@bFzc7wE9_F6|OfI@@+v;<;!TnJD=1r1gfXQvXyeYQ?znxFsA_2J zHI{~Ir;S4-LiWhr%FDw?*SmAlZ-hm<^Icy*%|osn>j1%)FQmB1zwThhyNOQ8Z9FZ7 zw&9`XVpat*m<#pvMMGv5{evjYLe;Et|C~HJvqsacVEtHSWTq@H%L(-PModMzcYAhngMwI4VQ6=sl>S!vU6_6?+{1nV}sz zq9@1%wozSUHV~&R)Y@E?;|a{4BQ-ooP_RK8Xh+pLCLUF3%Y~b5a#>%lF;pIT7wK8z zF=OJU=w-i#OMk=d4XINo(%4sjo;9GSOWwe3byMm)BGURp+YZxmhZXYU7uNOdCW>Tb z3w*pw-mkbB0&_6WwQwJqGMN<1uK1+;aybjV$ja;nCo-MrdgB=Nz2X|#{>=hD*Eh$r zRwp|M3JcQbv$f4=>HPydXXhA~9Vck6SJ9oKHx}KM>gTB2MWzxw*lj8#Fqbl9>H78M zF1n(Jh2z$4Z1aaw%h9ugcwa4ic?WPzzM&SmRu`7WniqktJT7Bd9ki|Z0A_IX6r*Zb zZ7ikj+rV_*K8u8DopXFC)6Qp5lT~hOYLMQUf|CDc=|2idwdzWe76GNA!d|gL)rqg` zA=OrmtwvE&x{^A#@jaORB}>x9n5OZ9+A3*>G7IrCLif(345nkP(yzZPk$KwxbK3VM>iHai>Fgz5ad(Zx&(xJbIw<{uoCuB;#7G zIx=wg2@1{FOa;@%XBw1WFn={f0B}qzGh5($M4WS*a-7c1vM9!wK$bytYYwrQX?aoQ zMZ@%XQsgA{zaME{mP;JiGwo`;+cVVvHslFkmT(hA85aObtwYm2|tl z>!2rvz1qkxj&@0w&(P{WIp24BFc*3|IWf(6TKJ37w(pcw9we6(4Jr56%IVY#3*C838*An&h~G6Z4k zI49b-tbQ6~Z;MJ#U*YOtS6LsS{ccOmzGwFs z9%DgqVw2R2h+D^g8#$VFXPa3#_b$g_L>TUk>rEF;{;MVMFA*=u+*j!j?|O?;lKHunD6EE8_z78D>(lpS6iaOwkYi0Q*gR zEy87a4yCmBR<{tEFSKA0T(=e+%)fb7`QXX{Ps`a|y{&2wynvq-uvSKQI~MC! z`)PsT8hsMSbB@HN>ct8i+aOUkTml819Vj&Y$l#VJ)~l*CIh>5w%Qi>b8zMFTZL^L5mSLZ+ zyesb%=VIYKHNV!&iatsY?znz}Tb?>J{&u&vV)8K=(mr1f9>9DQ&6Ug|gI=s@6zu>D z(sW+izYmm<$`^ZsZi!Bo?q0>sMbmaBdOwG>{Yp)3Qg2Rut-YzJ5mlrZ+^;*UBt=F% zvikeG0Rzw-$(S-i1h!lW7;u%J$w^?7NFs{qbNk>z3|<1yqndc1wFuC-UUTQZWCMMETIkrCPz^?XeXj==dzA`}#2 z(oBPnLb!izVd7tpn5G=DkN>f}7FEY3m&aaBD!F^NQKy1>I>aYG+MaSGcouU z*YX!_8P8HvJhdb*5BP^Zrfs-&fbLYH+_Oycuz5PpS;qHp zNsI%=)D{?D2dkw11umno9JyDeV+gl&(UuX`by{npvlV-TebI})te$84${hDM)~Km=az&)npMmV0 zsw<^?*|3FCooVjb%d4M%I4TJ^$NWshznY5jR!IC|zkq`1?|q~#;URV$BT6}G4w zm0zn8NX-;svUUU6C$~*_M1LXcoRqJ?gMIb%`mw&Dp4RHim#(6o7>SH}_W>pny*gYu zbe87S>J;`Vfd@EZ^!-8|kJcVGU;TU%rB3HLeCIuKoDWe0=yeF7e<_?Q@*mh2z>c~3 zY%)sHjRQ}T9&Hi|y;&!E z?6d!DcJMLw=FbL?M!qK9<}B2H*hkW>)l|xra;jjHD`0y0DlIlL&_?tPg>bu7xpVSm z{~MRA3m+D?n!=(&=hfAfFH^r=Z@k;kAnM`T`i;%1B z;)2rg9Ie;zrqxayKU+v-E>KY>=@Ke^8KcOmvCe(`4%vL1e-+Y5*7QKWlBkvttA+>l z+>WR|`JMA>A^;Qrb=^}^U92Q4qu8N!4a-7nPLX9JpI?a{-InU)A8G5_3Ua9DvOOrG zM%%~m+_x&jp2-lDY#SH6ORKPm;^u`Jg;8hG+LOoV_F;sl;<=&~Hdf zw&2-~K~{%;iNA=MLh!=tK4mW8L$A;Kj$iG#H2EHDF)Q{{v3bH9TGQWx@j~a%4r0?` zL4i^fJ@ojkyFm_vm_@Fj+CY&~@D;v-cto}oYz1Wk^Rg!;p$HXDlCMWSQbF(GCIB{7 zK%5%cwh*ahn&~pRJ$5mVI??25N2aOoTh8CgHk?UY;tVhQZN>#dVj^pkhvib{4%&yP zr1bp<%opuS1PU7N_j3eg@_eOg6DgGot-gu-u`pD<^P_r7v^9Ip-3kzy1t}z_rYnNC9ia;+!qg)1 zbZ!5_Z2W899f<;bk=jOL(~LoLX(YY`3=6>n<24+_tI(&g6YtOOaF^sUo*ztm(98J- zDpypE6_9rNO_ZdPM|6Fc7fku2i85$8an`6+n8~;;w3M&}-HyL$Fl&D+ zbYyUbr`Pl&M5?h({Uh)MKaT-h#;?(jiM_PbE{Flli3D)l4A_zWWFUl#*Mwb5Z44hE zwPB{IlAgEGZn`@Y{n)9adF@ zblA#+y%aAVL($Sv+{*lfRk@CEZ7vd!Ww0(K4ZmSMg^L|V= zBo&Pcr~UphDV^^IjUz=wZ!=>&1c21AF)IAsdO+&Kcad=Ol8B%q&;D;c zU%%GRB2AaO_aB*_-FZ@wF2%VY*xI?nne(KGz06rMQ~C<`GNZ~EI15TJL9 zxs@r4MXEFWOn%+-A>X7-{v6z>RLOr=_o5H=r2O-nK#L_QGIB1wpW-BU(?y)01(_s| zahO6ne^D>+;ydkt7hD=*$9v={{QJ?$yxQ$Hh4^#dP7Y$k1k?q8E}g z;?<>&}<_+^ex zc$VsIK9(rm*m8Zfu_&SDAPXhE4K-}n0_^I@jt`^U_qX|Cvp2(uG*+Z=Lr5Kbvt~Er z3ia{W%AR7wiAfqo4eY|p2g21akB2QSVN%qyQ?q-8sq`^V%r6G-+Q0WSnclC#N|Lx0 zb8Ekec2huN$-kSEAc)?`OMYZjXl2}tP#F!v(tdJrN5L&W%N(b?0K%0{d_ouMQdcbB z0VXJ}l|TY4npW0ttE*Q1Lo-w8=K|Kd*7$fNxuo%9Bte-}&kB0iWOzHN8r+hdBx;pP zXpoJRZ5B6@AIb5R$|*+22re954%+CP`Q{7e1*Niz0z2Hgh*-+En*+1Erh|Ou$)0Pgr$DCAfdBkZfl7mF+Jiz3TKq=<8^VO3cccCzWg`aI3;id_ztj zGLkq}t%;s(C#h9yIaS^pxV&V26Du}Bj%oZ<)KjK@5fQSU4(tdYO26C1d=Tarv&5Sr zaRL>y4 zmgRPq_)Nt6 z&1RX?l&xLyegpCd@ZqgsC3gzFDu+xNm(U8fT)n*X)arkNJ8YSX7R_{)c^d31P%OGWL9MfS=Suw9PzqsxO`Z9`=#MhtRq#(#xT#QzRS) zYd!M(o($eTE|JCTM-z+Tw-8|eFNV%Np6UOK<8!}7?#d9E+(H*NkwWhG+g#^PUzcs> zE=%tBh`Cgx+^@OD%rtjNBDrmB?)STjDbnw^zxUYw`t0*Q?{l87=h=_F`u^sd>*G#N zCGKSvV90|iBE2H(9|L5(ZpMH!L{@0K2`kn2tFrd)euJ0UE(1ylO%)9czm#bC&HO*g zO)Wv8HtN99O3A%~IB3WY71seqr*hh6P zdWj$7>(awckJp08t&nhn`1)r>C@LmVUVX1&{eTYm2Gup(K0$=C zn&&|n+Rbo}qP~CN@Me@h_La0y_x!-u;{O`)vXyqso9<6GaJvv?Gf_D9qu37mp+BCP zcz*3&moIp&2}5Z_H&KM%zX%OzVJwWVknInjRU@9}J<*9VU}r!U-Ae4aegaC&llf(z ze!fT-+@P4kOfmY{%1ms!qKC^H-p;sg!A$zSs_==&?pILur z8#SewVV1pHKgZU<1`K9c2OUgiLg+R4-5SQZ&!ta`W17^hI9*4(v7kXCqj&`$QnC3| z{`M5t{B2KB0R0!ny!FrGQ66i&>WBZ%JoK&j!={VUKD8gZgOS5NPi!T{1WBKtVIUCYAH zA6jJ3gsyh8DGs^ZgtsxU(<`gB{)riR_a3iWh+kVx7NysE8S64h!oU$p*`pdQz^J@l zQT9fE+Q7$XX(gg|OB}=0{`UxfeZ6U_k)OxC;{espbXTjxhBMAk7_f`>Osuc9xQi~A zOFH3ZmFyB0L8eg3Nr^7DOZ$Im`G_(?v49OWV7qGp=c^{&>aE5Ufh1~#@2I;gd55mo+@DsUa8zMbM)(L9?29JIMkB<$1X3)`7Dc3&&B&!S&qXMo|Ns5hbJ zyc}U6F5jb%E`AUty}yN?$PXg`mm$&SOM#y?A*uKdg$wm}{y=v&Y|SA$GuF#E>Wd~L zRpa8;9i$@P+%Ax}k?zq~#rpTRVoPr3a3dicVi?^Nh&1{wPP}c>anmOZ`u$?wKr~v( zp2q;{C84p{Ph`I2>;aHsSBkck=Fi2(?UX}^T7~}$ z0o~lW&0@)?!B^H!zd+>1sO*x5lZ?Zo`lI!|a=RECfQ5L#eypHxZ9bU?RjndGuN?hW zM3YY0Krhxyi#D#PyA&M77kfX%;UtSG^@LG`^%LKR*rCuhLNmm&i>mQsEV%=6!r~Tc zfBD%Lv6)`LEGx`^(Bt}mtexz+`}r1+Qef0{A>~B687tVg6}ixhHr%Ehcf$iW_zZyp z5k5ChKxc36YQ!lA#;tl}EZr_~_gKp4qIEnQD>T#zzhc(_?*x9*?JKlscqHxs zW?b}N{h+w>`O)efR^80CC94PIvQGzq3b;i=i8_fY8V$2CQA7&7hcg6acs9(zAsQDb z-YK7vh>A;gtvOE1&h`b`G7h$`YQ}+3c|RQm>P5zbBq7ODzTiQZE;xu$HK?7J2=Ik`a> zhytqz6$*}N$Hjgc{cHBDHXWpd#$~N^kSFx2t^e@q6EFH(q{zRAzby zqw!8^)qPw3?0`x1inp>YL{35Hua;plED&^K;9SJHxukEW_JDayPOwZi;~O>gUqn+? z0*t%FT-u8qLN?U=lghk3Bceh0Q4;;JdX+^6-*kNm#`q28bJ}KXinD{!#}EIkrbm=)2p&2x_(>Zua)ccwVR*{awxFMViX5%< zN$!Rw3ciH2&sWtK7GfgZ@1hL)^eSBP&tR&oyNQyqk9aT52-zhK&rwOPa0zjrS6)OJ z{1@)h;u3r$(7i!TT4y)n{b!uH^QY6UApn~0{#4fH+^HVt`>NXRWYg|UaYHk(wPZoB z3s)URX_8Q%u!Cc?R(&8t>u$&JXPLXF}cYheZ;uaR<5RKGU>RKQ@d0||6dkFHMjtcfmn(i^_Adu&a12MST!6v3CmiE_b z5C#tNZz=uInyx-&?HtvwQ$+TNZcRWn)ZWaN#YS%^W1E zkNV<{Zm(*DgajiJy3D@CIgLJZ4_ht;dNy^vbl^^3yvR;K5ot;IAn3BN0l4XyfjzHY z>}0xEJ?QkoOh1~aroJ<6F^7ewT>rG$pz7pBnGxMp)s(iF*KagEVu1nq?cZ>Hgf6$_ zpb!0B$y{7rpP&1R{rFv*>q0bOXue`AW{BAdb>S?e@L|Q0gy&7CL*mDMArGGhC*|w- z53BhIJn;-dmQnlSa$7!;>smSM(G>F2U?UzZ(MCq_`kIJ3!rEmzLQ~l6-@;=46)hS- z*A(c0DN1P~P!~v*G;3k@7rslr%A9K4rdd$@AaB_w-&w_p!n#NJsA zJ*G|S4$7UCHO3eLHC5SL@OZz|F&{GT1Pf{mp z_A=2m6JuIaKW=;hpBK6^dI>HiozRl)x1V8myYAIDO)Gpmu451I2OXf6OD&F6=p3z|b;d5T z^NHro$pz^ix+h=d8lDp*)e3$V^Dv6cLEPpE-+HpqtbZWG4vd@4{kKIyVekueWWjv?_?&6p)j$*>4 zn|ppVxyZKVRr?VLf&I?B+|1qhM#UM61=_`K%onDcRAN(%xsMg=XXr}h`~z=Te>cxa zo(k!Y6~6AbuU)MrG&kJt3cIe?y3xJaYo{M{Qz?N-R%3?Np)|03FteYzlvk__t84vt zGVy>E5QkD+*ug93raS1k3u~Et)+@2VvY=(&naBj$QT(`eCgRL?WZO64GGKL3=)N1& zh;E|jVhAhp>KraG$Ue71?H5jw1l##uGoK20R&%pZyavB4^Dp;2`%vBhNZ~bG5+$<4guytz}R;f0CtYvNv#4()o8zV|1grIGhTvE(slR&~@ zNEy_0=oM1U-o2i|!iw)dIXZM!VJP8fqdnFPHCha9lJ3eu#&Z(mkWgRk7~qY?5su2? z83~$=D9r#5r-9SumjK+{q@Ejdu@LHjV@8;6g{R)udQwPCX?-Wh@!m{uMMIqn$)QsgRrli4K}}H zTOK}dS+OumB&d7vm!ahiM5FpFbfA-NH}zegLd_OV)b1fO9raqvv&vEu%`=FIFIPtl zO#haj^rRzgGT_a*J2*>1Ctos&GtNJ?+ox{sXOTFky>(vJ|yq6_im8TU?MPUZ4opFBlKnjTd#C75XBb40jCwspgpr zw5^od7zCg!A5|N5j#NXIlZ(JX!uF$B2YSd>?tv1m zPtD>1Hp_zTG_KQ^A@;kmA|esxoL}J$M)!LV=#X|8SgRt(p6M7UKM`YqH`3Zh7A}k2 zRF+-xtxP+5F%JQRYcLBVN=y)+5+Ab(GC8xD-1-zDdo}hV->X7=hy3e*fM+BQl37X# zbxML&ip5crVdkP)^k`$e^!7o3&o!HS9PEtg2l`}z57yqZ_CppTH=$!y7A;14SNYx} zEmc~YvHKgc>>5f>1;gV)3`P>XCc}hW1~N%8zdTE`19M^XmTSiv;biu~Z_`YK(djzq zx!b;=u((=a%cY(B15Y?Fq5?flelFKC*<{Qzeh*?5diV^7_mQZL{f0QE$fy5@0H%Kcgbuo%K0R zVwxi76qLL`idfW1D0;CObgERbpPUh@%^*AN!d#EZL7txsd1EVN(3xLqOxsOApDuEW zSA|x&LANq>dw*SqF-^w6)7&S9yt6Hji(&hd3|>UAv*exGGH)GhR-Jux_j())(9cSh zV~%RK1ptwFBXbhQ48gid-+wy!7Lr$;-g1ix%0ZyUX+rtk4=Sqz;WJP7Hfl73@Q5ERzeT3AUa=G3Of=}%mC zM;vvunE>pat@9Q0Po! z(~|WqRZ8dtO3316P_St*{N_g>gFj!lIb69@_v@l}&Py~Ch&<&Ulk53RBBB^3Ko2E} zpt^ch$O~T*yOx}$u6122j58@4wgJU9bsS@_AO`vG{M%`h1#HVMBFiepmWSei3TOvA z)5Kf_IG8vq|Au)PDg)s0h;+TUJvLRT(gPt%aSN;#Mo}er46rEP0o$`y9?-@=D z$)?s$7u@o*J5*M>n#K#Vk4H2pj>p)l-}Gy-;-{r`84C11W(cgynNnGv6)$%*AX6SC z3p~!FlvCchyh34@m06gaT+yzG!=yl%B2!$$yXsogg%HayzN!VfY8}Bm~wws0VZsrC<+yNne$*G!#>MzW? z;Wnl`gdV#~+1Pzx3F`yr`e*-0DOA#|`Q5O9XsExB916qYyq_7|Y8vBAY*F#4{b!|o zf)g5W;7rUt+7HnWbddq5KiFUpQD|@ims(*##9jol} z8gN^)jVIAt)y9GKZlPwggAk6~B`iBkj>E_Ue&}NS5XHa{(Tm%6(0R5n|8vuLD>?2$9H>4Ti8f;Rp`a83+i(jTGMdrvh8sP; zqM9y~If!Us^lyM++Bn`3j$D^}Iex#M_qxDW*fa5wFR4CRd9!CmW%3rN*K&zEoTOLw zuC8zNorgl1*s_NtB#?dDomgk2nlNV?t9Nyt1<+)wPNhfq#sO~FoZs@_&Xw;YPTYdUc~jcD07FI^6{#IUREBv29i7sp0F8b^cgtM$ax08H8Ek$#_3>@Ao^L5@M-=Q z@qPwhe|)NxH`{bn45YhDgfqvu5NB7>na-_#DKHE#U05_@5eL_thXT(&z7( zFa2RgJlz5JkJ%)SwZ+;o0%>sG8Y*!xxE#Qg$61E1?62v0%Z?7Ejqh&sZ85YrT%j{! zz0u3z!*e2<{ByuBDa^E0&+`rY9c=)kd_FAopFq7?}t6R!9<1VAyF_ZD}=q)76)KIV$wTbyx5PANt}5JZvenqJNidd zEBLrW=WQUBOSuaRML&AmO>)yu<+knqb|a2Xl`Gq*q?-kbigZGtOSdWlS%RS2Q8qS8 zfw8!sW?upAOxdg!U_j<63lits&ihu(po!zUg$E7Sp#ek`=d zd3G41T6R7sj~Tx~wK&npy!X@Iuj4&Y%XQD+`0;Yh4QvyNV-7Fp7qMO$Ka;jRIOG>34TYHqq!Gp&i+?ph$Nk^zPhOtc` zqT6@>qT=r2-NN$Ov1G4B|K&%Q`Sm_u=7iFR6q4%PaaY_RlU|7(X`R|}c$bCb2HvF# zH;E_W^afJ~)cr)s0uz%5~gY86gZ^|^i~t!_GflYSHv8nTF0h3F8%@bG$80`>te@DYnsopBT^(<9>32g}M$ zMetfWn&%6>q(j$o8#BWM%gxw}MGg@~mflPtLXlZFix~H}C!o=jy<=72XRp==c>|qw{Slzu2ni zv}uvAv>Z?!Jfm(wFKyG#-X_4ey?8uWD65+nGVx1`V^`YBu9}a=TRZWY{h}0=U1H5K6DPF)xv zrI$ShTGUOUWaQLt`nwN{{qyTHv}6)C-%S`9ez3M<%T!}4G*ukw{)nCr9%BC@%Fyo5 zbGDxB(%gQ}+*(ZIJl-Z+enq|z0W1GtiE5UWyS_$xv7G5Sc%Y3uqmRoyE98wlReeSO zLOuqpo*3)v(9E!SL1q-@wE55J8LJIgNh&To2xe}1a9i}-hs3Gg%U(3b(8!1Faydmt z!S*5${^`x2jo}SFx1H5*qW1AdfG!D6dl~D{b>Kvk z=pDbAFdgmm zV;thhnI;mAg!t{AKOG1Ni*c|T?&`@w1F2+omz!_4M&8qz3vu9B29S!Kl4n=-+&`Nv z7J{89DNFwYggdZU5io4$o^+E+zQ6TY++C&Kg!${vZxJ9RF2jLv-y}yc^T5NJjh?sr z!#}@E1~+Jpil}`(xnEVdtz@~IEl}}kN*mK!xERWLTsYyBWMM!`R%FQSy1)C-mHolwroq#pNF07}z;KFUVh zXPl!wS`3nw%`>e+vBQDuSUKN))7F@6G}M3Qu`h#F z6K>WX+In%AdK*8e8|>&5*reI&RPmzn_pAP(Vw3TCO?$!lDVkmAFx>~-4E;H`Hfvve zQ!%p;_!d_r61G|zx2?rwX<#61@oZt0#hutew?^lQ@6N|qLH))0oBA*bfRQFUAM-+k z#hNRysx&)8_hLK_3k|AcpbbLTet!3_i({TKkR&%S|3GDNs|0M;e$J;FGJlbDLtXkb zR|3sm95i;dNl5s`HXJZKr>n4zFVVuc3vExb_$Py|0xN4{ zOIg*l4akgl((OxFGY+Qr*}J3RlHROE&Y87qfSWl{-z<~)qO^CF!{9Aa-Bl>XaN0P$ zu_C7c(K74-Xsdt9ROXcHVK8eUj%1y>Jx~Ra6_i`aqMKr4_|@kilTj9>{i!t%mQY?u z_MGIsqJV!Pj{9zBgwX^roKoETTX{R9puH6``v(EEDGbx-V|*PZ#wgapbnMe_|H5H; z(NS+>G)d+Rh=|D^yrOQ*1TFn%8HK0zwUQ_m*_AWCHtTyfbRGSNy?TrbyS-A{XGrq^ z6ZwL7GeEh7!rbaTGxb1JE;mG8!bm#+$4HA0^)xnAC*2BV9~GsI1)}rWK}!~wt`pVd ze8rLU;n;pAAEAwcy;(a<9$w@i{KaUoS3W4bq?S-i ziP_@Ey3q6GUX?@exRNi~(|wzG!PQl39SWwpe_@CPe_le~l`xpT2ik?+B^4&b#~z8dHF;ZnSHrh1Y{>m?-VP{Hp{2ddM0mV zw5Ndmt*Lv}CEf*4NwQ^&XR-V#AR^6dGY zE%!0Pr!Q~nr*4*NporY`7I#IJZF6hXd3i{eRO$RHe>BNmumj$y>?a{D3nrMR(+tH! zC(KP$ffAjzlsr=j@xpCsj{yH=#obfsTQTIgk5=pklYffp6OlDAvmR$V(}u_sRrhIe zWTES*lc!fgW|2a&=!waswh$)KHOj6V7AQ+quQM_b2e1O;6PI2&*QeDMUeo%;w@=(p zU`Sg5sMjV$If<(BK&;{;>b|HuUEG>kObfGWFocNb@iLQuuiZml5y{+O5xGxd*Lp|JG$@7_C3jr7pk%u z`Dd34xKrf>@r?__f$#~=zHE_E;kb`p7_L*n-2{ZfH_*SfHQtH1m$q8JxFJo)WZua9 zO!g~pay*&^ctW3O-uNx!W{N&gmvBNCoq|GDtpIGQB&8=Gu|KKgNf84nl}z!uGx_%G zYvq@*YQ3uJXINWq-jWUI;WL6pb04h(77%5J3IAEWxcKzeogE8I-_lM4XkoPhm_Mut zV+$&AOjD#gzT)pT9S(ygU^xF>C?w}gxBW?McrP7f^Kd)SKlG7Qyj7E{9a@eg>&wcx zXaTSD4w=&0on-Ucn>n!Kym1~&?COWB^z5W9EHbscV|#YFyCUSXh|x;L)t7hP3^MzM z5Mwt?7}N3PFm6_`>FL6fX!FnRwr~E{L#q8vHFpHxP9{Hiw9{2cHQvKQ`U3B3i!Wa& zNUmu8zJ7R>W?-cVWu0=XBE%lMEra6tZ42w?wDZn0>4Hc8?R-O|5`L6Y?e-&Vvy(j< z=%We_E+704AT(-DE!oq`j9Hl%br<(2T^go@n z2vhaX-r`;;zfdd6F7pviOeyUf1{I#Y#TlG-%+jLTJkMnAWL>WBq^vwO!zMD@E^6BH z&Sx&oox5J#`j1}-+Yc>}`PVE8vA92waTa>gqx2txSAA50Bd@Kt`Pa`l&@PmqR40T{ zehl8ISqV*?xfN5))V?1}ipOgjA7j(+I5quTm}%AsNEUJm+0-9?yk3N5vvb7?!}#-Wb4Jd;%YGTH3-VWJTA{bUvV&a3TMk(tM@0sN%+GuKPmgEYgbYMCnka2^|6 zGnVJiq>DYG(h*)iWE&|ZD+D^fq*qhxWpc-4X(nSB%rNNSj`P;F*)Okr-lgxupgVlT z5Zc-Wc&ZYN^oaQsx@r@j8+1nRdXbQL?QMR#%QpoG&tZG+e3%9w@!H*x(~IJzlmZwZ z_ChcC;04{#T36dv!1+CJUPk>kLz{3);r{^3om-30W|D*2yS(exK^N?aVukw8$?)FC z42B2=mGUA9p=Rl?MyYaEu^rM+pGIfc*-Vf5$-!Jsk#^s0ELv`)yc(a0xd{dYiR4`S z)J5mb1-62fPm7NUL>O9?PI-VYRdZN$vg=qPKBfA`#%P-;!tADNBpA@c4 zfyOB|oUcxLqE_r)eT>`9s#o9%1x9A?CrV*kG>JkmxPZ+(^??Ob;?dDKi^?~~yro&j zxi2`{iQTaFrvE<&^7}2btdgM1WVrV0gd+ax3dEi^cVXqG8+iYpea19wxArXvTgVh7 zunr;7Mk>d1TZLz%0XT<_SVIf5)k*qL3E_&&(z67S;xY#!>TO_)uSL9 zx5}L%51C%P+~_JI^pKf+n@pY{+o7xv{OxlN<6vU6w>4DLY-8rLs#to3p$Qr zE-rLM;Fp;WOGA?ee4u@+Q3ssIwEDiHblWK~$X1g#vV>uRbj_|ZHJCz5d=?kr6&qC_ zbu`b{6M7(E>{SkQxiGkb^jdEG_>s>W&i99Qy5culuZ2dG?}*-vhDkbAR%?yTo!UvY z@s?VzcL)DPWrB4*!xd+pib=>w4*SsFD-pBo1}TtZ=z2{!C`-+ebeoQ@{l=Kwf`cRq zfo4dCIR|>@?Z7ieJmwYkVc^r1wB6Wh7dAZm8w1lU2uXk=-NarH1z~4V<~@_B=FG;bd(XtW!zwvuT`xG;Wct z@U@XJSFfF+pfr?rW{Fz75#g#`nx8&?7nrp5+#V*NDOPzA^<(g3oUQt~@vy&9vawTl zgDQSi=aYS>?!Iseljdq0+ZqbrX>J|#fP~!cGi6?h|Ewd z$7}TIStBC{5&+pJb1mUMkx73ALiX_i&v3p!%p!;u4Qy)f=`1c#WSAfA(vw@u|35&) zjn$u5G((zTqH~>TrQ;Ylt60n>dG^h%aE?Ld9(hk>S(n=1oP(wNQ1e`l>cV3(L)%#D zs5^tzdl@o{K56kS+cUO?0I>&Y1@!M#xC3x~LJoo6#~g!ANIFYZt*FTqM#r6=bXbhu z`C)RWGxwFy4)UP2=~x*$yZZuFI%7cU*;n!r(y)n)O`7e!@4p~`50m@F_bi?rVg%Qn z?q!KeH9fy1p*D{K#6ga1IDz)`8Z3=8VpMw`4srR82G;%~xd}@XX3aWl`H#gpY4_Tt zLLx7mE4jnd*xUAJ;VHQPZA4|vc+d~KEKNpUW=5Xp$#I(Hs`@?jjG8*y4qF~^1 zxpT1A3IsY)ti}F|rmtknb>QrQAczfR(RG$vw<@rDLi4cl7_E-BrkUJLlHaN~0x!Cs zta`&`R_IKxKQeS>a_pST+x}tW_hT?E+-)}c}*0?p7Q+eJ4K$CFhB3z9!(e^|< z8y!GmNW?pdvO*aJ80y2s;yHs1=7XxWq&%n^H`SMW9PUbl?h&TaU1<0o@MVD}+o8?A zf1HxPXT06*K`Wxg!Gqri!qRv%Z|5kTaIxa(n_R=a8)rqdnsman9+5eZqNd;QV~%yS zrah*WzaxWPXYb#iW;e@mE6=2D4T>8I9mVX^ja*Y2nHg%rs;y8>m@*f2uHUyS|2P$~ z|M2>wbYmai^1S-N>X_ULao!4EI4>QjkS^w%{1uJ`IExtTk59$}CLm1M<`Q;f*|?`4 zK9*kidsjE>Kjm@_4h4KkMbphkIUx%>g!jWuW*EEbS;_T>zW?S5{!XbHx6Xds>>E9A ztc@x_U%9DJKlqBH-5=8ayYrl2yR_Z3otv1FpOQb8C&k)q6uzg>wCx{)ePELh|MuZT zey4gn0seKK1@!)o?+NQfN$1a&<&Sd(*<#xC3OYUB(BtxW6VpB1MALab_9BeGv| z0lC|ZS0Kyn+F$R=UHuSy!utAg>9%!kiIG*8<+SL&==_M?ULFj+x)6DJpIRGRUpYXY z8Bpf>*F;-a)Aq~7d2-SH_v8DU(1~}GQ$@%BoL)eb(d9oBCOdq;JvjQNel*c8skr&R z*?t77H|;^e+GM)@`)Lzq71gVH_N}bwR)4dP&M|LtCYTbD(f7Nv^4aKZI6eGTu2hCP zEgkz;Nk~j@s6*mjq>UC{e^JOPOJ&|m(r2`^G9yz@;CXc5=3(~P4 zmwc&nr+{d{nbuccxkM_DI;uZ3#dDSOW@(C_KEUOEa?s7|$q8)faiZ84bzU+;&dAVx zRmy*u&3tQUECM5^u}20i>=O`V%B-d37T-|_Taq);4JGnKz)Jc)w?9L z^yXl!Ds6PctSDBJEE?3&5!Mo@8qoiAcwq0Fki7S+{SE~m>%;q-d9UE&eu10NSvJ$* zLlQDDZ#&v(8|4SFoi3!?F&A&wVBXTTeF&4OK}&|K?tTAyaWAj?A)6RbHMsxEC8%s_ zs^!;o7V z_`XM4iUO5nMXR#s!b#B~zN6-j2|lvron~Psk3INFCCojbw`q&$(}!@k!)&~~+)HqH z*nu@dF30p)Fl$z2rM`i&DHCHgDADhiloL--_`)JwGh~o_q#MPdr6^9RT3#Ng!0|v5 z?1pNb`t-g3zVfmHXcfE*5w;R$SD~g?7o*VB^UY@#6_xnu%gQ@V19I?F{V(*l@+dD` z>yW=Kdh+$(GP&?t2UgQXjj8FysTlK&pbG_ptl#rBL)4cu1kLZ>>sfbU-9hJ2_M&eZ zH(63y?vy%$839omP1;B7nsmZ@jchE4!(i%=m~X|XPs>MeB%e0}xsqEek8NQfbUKBB`! zM&``5!v^}bh+(FPRwS#%jfGc2qPZA4A;NS;8|Nc8js1>+-zV(&$ISTU2vAWjn0fPZ ziwT9j*0O_1qj5i}qn+(*ApIJRnb}gjb%!j))j>>az-Y>`Eh2FyFTbO*n5l8p^gmYC z?T-=^Hi`DT1teBlOwwX1WxeZVfP{fs_XMX)O+?*1v|liqRq3qG|7B$iLiVc z8>@vO;V?Lpc@AX;%C4S{kfQB-n@$dU%02&zTd8GuWDlsltP!t zorLf5MK#d%*b_z?)F}&?hVe8*dluo44xZ6Tw7jxCrCP@RT9=5(J#kJI;o5D}aiwnO zF@e63f|b?A%S>T$nzl1LbY#|>Z_kU6_2XJljFLNCG2ehqx*OB|a-CGv>0VIEtBS04 zYF>07KkPp0Yb_7NCfem&Y1g;6dnS%XO;E@!A1&ZYiyW29oDJZX$~Zc~_Vs`ER$7!w zmBoC!pwV1jq#4;WbtAVB79|v~BPu=m$DQMMLdJjegfBusne^k6Ay@?ymd;LJ7Z7mT zr+j2|iY3wv7+UI1^`Gwb7i=wru^%`XHmipD@8PK$6+Qvc(VLmUIZonT9|eYy{UMaF z{{b$OISF4h&w*PXd75P@{{!4kY-ea$3Z1lSP{3dS5|1uU`U4QwtBPuJf(@85>>^y; zT&i>4`sK_D`GD>)nI#*KI4rhfwCC2k;uPPapDt=v8_QVuBt|2=KPcV5R_k@&Obbqm z{+|_i=k|bl=xhvFey|Pjv}PAeT)f1^SlW5}RFhVi4g5(V{~CHM)UrXC>9A#M2jBK>OxhypS@dfb+^d)kYAql)9lvn)mdtYXPTIqR zw(2Jg9(dMusjZNuC>WzQ0}V|&7hJG;sXj+UE!oWgdKmkoCCneZJ7<=IY{#yO0BiMC zRsEWOew(7#-1a~1KcJh|s9f2dVFVT)V!1OyOi_Yutu7OEj2Lr7^8o*+PUBi1QG+?M zX9gAKJWwlDuakFU@ter1*H%$ss8w!J;zV&cwVze}NDsuRT4w}@2<|^s{^04@R$ri-Rql#Wb>yg zc*Q3GSe-I&F`arqLX*iFORq(l1t9$$JoM!Iy^ffcYOS+eOwIvnbN1og_aFIiX93iH zD+*%J4pl1Px!r9dF6@)bt1LG!tCpU^yznYeBu#sXo|?r9Kt?C=uFJzX8&qs88PGDc z%@Q{%B#S5wAQ(I{^td1KwIcL*-r3uJvHIMJb-7xPkwmEz@SimT_s55|um#$d)0Qf9 zZ(>y`@Hai8hw>>85QdC2WQ$3ab1;vfx3Lzv9A*l(&6O$IQ@=PWuiy-B_4{EU8W$-d z9ci4j(|~yC;wX%0_fl(PEMYa2Llpu5qJ~>6PuU%WKfT0}I44PBr?GMq!V3V|MJ)b&($x`f2CA>ekeaD+OrEE3=0E6cj zG$?WB^0VO|e2zYoogI62lDQ=3j}A9%hkWk6O&7afGLS_Ql|4U^7Q1|VqGylr zGtK>#>kG!Vvgt`HL^%M4p@yCSJ@W_#&92}W7IjnYl7KJBC_=MHH&p5?WSYh5CL5u#+l1#iXsZl}J=J;xcbR*y z@MmS_hP_-(IU@xgpUY7-Uev63=9d6t?^2iCxS}@Lp9=2A^<@~yzg=R9yb)FMi^jR4 z9jUZe>W%xf>ndH?JoIKY6};Q-9*Zjla?Y3n517tl)Z77P3w2Wn% z*0z&-qA3^htcKkxEtP6s`9PFr*;dRNc1U@ak^Cp{MJlDSOC#R>w)-pV8xgHJB12n( zV@}`xSS2#EU#Xs~*`qL4ROB@DTvp89dYJV4&q?#`c-;fOl>>~^N6ZuP4>)qp+9&fb zwuJ>HsES*OH$jor38c`Iu8Z52G)Y#5fz@`c*r`LktaWa%F;r5P3IdZJ8OZ=;?z2NT z%yK5k_UUf?A0880Z3VdY9OmYofBBA2`bAUI$QIUKfHJh>IUgxI!K;BKv}-l-8*T;T(W(g??3uR z{ZD;JP`y`nw<&dKO8hOyM%Q|Z$~cILt4Mt*kz(Y-^0-mZ3i(bJM{y4>nuJfNxEO2N z$LNkW5qYg&=Z3{~$V@l=ZOjyp$ui)Ib^QV;j{)=}LN>*WVw*_<9AczLfu%m<>kf~M zC?uyp?hXjd$9Fx1617Hz{$V@-9=8%McVN%PE{R68TPJn{@>Zy!dBa|XbWso9CbLy; z-{rlzZZ%7B3h+$y#wiA3%bg>{v%r#A{<-a%Q1aJ5 zRbQlgh*M#ZgL1rw0#))UE4JS&!DYZt;Io#?8KN22FEYlOJ8__0CHK!w`$fg!Q!)9t zL<=Vrl+s)cFg)pg%DV|2_4(Sko=`iGK(4&nHSAQQzey*o70sL6HI-AOpt~ zO)rTErSZ9GGOv&0w{;|Ga9{61V0cNEd_~qiNxB6C% z<3-@@(<_fXtZv2EQqyzVa!&i`0lI|0LLKhf%W~?+eL{ugxYa9m{Boysn#Y9tOx#Lt zOAiyWFosq7@6krraFTckO&t^Ee9p1-nxeO5MpwBe-?|5u?k0<{fC|V6fm9S&>Ho0kbyu*UQE)lU^2o_C!BhJ@Fv|?4po+KnI|n^v8ZzIpfxB=`eNHP(+iC`HapXtppdtx{qP7Wah_m&DR20!kng;-K zI~=9v^YWhBtVJuU^o}ahgYSd#R=5l20V_@{0j?(uOB1ekqNlQ-Q2#a)rDQmlTZYPy zLH5xis@xXy5_a5$eE#7SYJbq|1KOr@(;LGeV00HLuEpP%+I)UGJE3m{`|8g`#86T#o_T71kOdPKM|hf5u# zDC$x^R_+-BV)qlIB-R9IJ8u?$u71?k);o0>um4+qc9_tHX(P%d%8Aq8ycOdg0@+f8 zDj;rLM0$S2;NGF*O3d991Bcf)y`66?&8?FEcs5pUJB~aj+ExfMAO@+sv|k02L!)T8 zngMu@qn5A) zZY$Njm2`d8mA|OrA2G!)a!15oUUkm#r`70n3ImcJemgKFN)E0v8zm_!Qc@D3b(LRh z+V&e`;x@twE(LvMC0xS5w{A;t94zAIS*~TuQ=hluOQ^|lxhP815cHPHdmtZf-qr@h z;GbnZKpVYbwAc z&CxBhHg}T63Sw#X6-HZahnAZMRQpS)HgL?u=1G(>k!y_Iu1L~PkQ20(qx4?`3>F|l1 zAXRy*h8|pUfLn1$0IXbse5Bs{e-B(EtW~5HmjI4E>KFLY%26|?2DAJ&*(;k(ZMy7h zrutUd0n2+9)T{ph$~`f!_FavfI~k*6u!2DV z-1N6ke13_s!NTEwV#!QlaR4j|NjBM6{cvE*=!Ybt;FJ+)AfBI=B}6jlqE7pQLJp*j zwGvOhCo{QJNWe9A>k6Cw?e0DBeilsx-$hmtc`?Psxrn#_01(62bqI3a#G=R0er7-< zr&EjQI&XKU8XenA7dw{Z`vAT#^a&b+v#yArjK^GA1*7+ zdU=G3tRiS+;?t*pcbez<#*~#5tr`_`r~&kz*`xbq%Ql4R2w#fu(x%9pfyQOw(Xst?8G;O5&5xySbWQ_y* zmHe<3+$Y%K7&OrcJZ7+00Fh(4zp3klBSie-_bUEf^#TarucjQ^jY8v;os|-R6aqo9 z>IuWm_@U=MOCdlc5;q5ay)b|uB>(;PT?xLzQb{bhVoBo7t}9kN-bbVuS`4=QWLF} z+5(2c=hR^fjqIJ-+lr_IaBc@~xI?~(PJM=@c%yp}U=H1IpmAK|!$p3AkeiDiwi+$L zKR-3?2`5&q`d_{r;y~_Aup;+fQay$G+X;K|Ov*vJ@JK2u=m&3HAqRqRk+;+<^!3yf z5zt@064qQ?4y9E;yKnr?658sX`9@m;yizPq_a_|Yo9MeZvAU>01lZhr;il=q&El>I z-qs{v(+#oRJ+gzcxTK4a1-t(M=Z*xCqHazu3e_UR_c#7Ha~pK7c^g{F;MgL=uWT{E zgveW_nk&?WC>tikjex?o*Rpf(y0<~Pyt+rGACPlQbKEo>7DAMb)o*MtGk{Mrk~0m0bx@r}4SwMMH>+gj(O40{%piPQLPkcNL5MC{+@NUA^w)^37**76P z6*LQyoq<2Y4lg#*Ff=QJSGXtx3^IXYm9gB}SCpiuPwVZ4E(cV-S!$s{D%cP^dyGYR zEwKt)97xM$PG8bR$oqA~mP!j$H${}_t}P24J@>=gEz`QOuvc>J-s8}oqY0k-q!6lv z17JnEVL`UZ^A z2(VX#j>f>8cLcyJdn$nnQMuAbUHjp{fShv`QrQ;zeZbod2a0P)D=G$+YmiR&7ykew zhc()zZ+iBd+d=#H!dU+RP))dY#Z#5n$@<~hyVBcB*<2DYZ9TBk-t?>oh+Zw5f=X@Q z)cvsB>Bm)GSphu>I9$mzBSmR!je!dn>)#!lTNT+&yDFun8yghi0RXP*iQKPf-)$;B zfcCv;ZNC2iz~h|I4ya_4va}-BQ9f?AH{TC)u56Kl`>S;QM1>td zSYx<&ByqX5{;KkU*bD831FCsow#v-__Ew&so)o&lH>(PYK_mo)D2rPh!^eV02W$ed zNIJ+TRrUmp@b-Y3{WVr8I)8HM#{dqOPHo1dFD*B)QdMGq-{p>OnX)q5md z{kq`^&8bS(8>Xtrmbpg;}dzWSxUa>0ZG0AR5wpNrI8+GgU!h(>u zny!L3vVQ&W(ni53ByOlsEHCMXjdWdMxeCw%NU%xu?}f7CEr1K$ph`ebPkw_5ZfSDd z=&7Wt;B~`|xh^E|-CR?Btz~!L{IJZnHw%a)YN4+l-l)5qo?XHJ8veeO>H2jlaX3^3ihb@5wY?8t8KKl*yErCBCwsondHJlonFA zG@uooiMbc{82QQ7qbGXy$5FgbXI|F}W%(wJp7?VEBq52JmSrN5DK0KJ2`xBE30A9a zt=39adw?{NU@=Afb1Say3s3&+7ewx;YIWb~vUM}h8#twz7^AyH>TaT! z6k8$kkPDHD0)oP~aG_dkPMhtz)YWy-=3qp^=}k1*COVEggZ3y^NXQ&Ysjfql{{U<= zLUn0Mm(S!EN-bv1fGR;Z{54%W?mOb9m6F_C*eyMKS!1z3FAY}1_*0o=P?&Qr)niCX zqXnt5br6Ox<+6^}7v9}1(-)A|Fm_&b3XSv<#_OKx)azD=!z}IyQO`r#F6^Us8{_y_*JQh>G7mM(Da4lZ-$fHoLS9g4Q>s9?YFK5=V+8@LEQ^! zlc;qES7Ckd$83xk4!5$}$A`ZGc_WJ)63ZM#%oUvH12I%pC1_$4mP0COE)=$OskJB) z5~6oKwix+G+Ap@uPY=ZUG8K-Hao7-M1?4E>s3c@Nds(QM@^DKilkFW!W1uQZr zgXkPPq)MVuo2tuN-EsYLc4;3J=xJDWke>u!OYr=P zEQu~rS4l9Qy$yGm| z;7!AAX+cj@aec3Y$AV=yB{lfFEEv&n5!8+t(&lMp_ZJ;V8!5AJeLSRF26hC~t?YyR zUAOmE6!5B*$U_39IwN6MJcOiQZ*gL8zT*;N!VZ8H5?n?zYmbV8J}TwI$xt)4Ux!wa z3PW_p&GgiE@FEZbGLj z#H8xItTz7uJaISGBec;_w30W!VlC4Pn1$0=v<=lmLdNJM{jlcmx_n~8WmL3mO}d-k z)3y@hWIV(TG*wGPtIhuamK||z7Xfpws{H^34J2>3d~n@yk0|6-LquIfZ}+*v-}+Mn z4YO{p2o@F?QVMwQ8>_iy;EjRna534mvS9!VZQ!oZk`=MHaB=aa z>2G6lujSu;fxh<`Mw7DX8ZWw_K>9_k>C*Ul1HmA5wpS&;L;?Q$;g2VpbaHF5s#_Ky ziy!BPkZzH>8xXG2k#WEI;n`0VnYe7K8ra-_YeFF)YSngw zai|e)rwf!2m`%0{-7By=BzMOK4VM==WC=TxEThmIaRE5pQ zHc|skt`~|z?|uD-91XMyue*Y|DNxh8ho|~s3x$_8gcae`Ch1Q90GPu(Q;q%ImHI7V zbALm&8eRsxlZ0nus_;duHaFXRc77?jNZ_x~LXT_Tt{hF%+S?sfOJtL^)H~Q)2y|Uy z3i4U=8;cA(J;G~RNjFz1ut+~oZPV8r*AOh8;MXq(zz6TYz8d3wQjJE+r55S19k9?s z>+)8X@3pt+aoMb%=3QPI++S<-`{AYc**THry~?wf`?mcsx6;KhG&txL<)dJJk=qPt z7f&RGXl$nT7YEbR9PmI)jkdk_UgeWx)APO%6!zZh+H9p*sE+r(7)k&&A(=f!y`H%Ri1#`sn~+7g{3Pdk;DmQ{U~Z$fQ}Md~<@iTSGAP$~59g|WTU zP56aCg$r08%wZk6R-Ki3XHXWut%f){`=^p`qR5u)cGLy?bikd=r!Z=)35Cb;4#yU9Fm^Tk~`(BVoQ3uF*IGPP?l@cCpcM+W2wNKQ)JIbzKTJu^{%s z+$I+0)UO7ImcZY>7){q%yRUNZeTfA6bi?$ulk%Qx8iwZGeSJs!IP2+hgzn0xlTp>T zOg8sRmgjvH;l02rN|Jp@!i|%S`CU;+w#RSJ4QO2F0o<)98vu8;@arBau7536x&lZ_ zih_^ljvHMon|%tQK?)}1ZTX-2VRW)b=xudxF4{l=L+y?axz%xD8>>*-fFP)U*9!Lo zvTJhyK~yP7HnBU~2yVE!ycKj0-6F%b5IaQRbpRi-w6;a)q<-1-669dWow;124V724;q?S_{N>bof# zg+(>Jg@OM7f36jd161d=#9HdjCfi$KYu?|MIoqM+KhmnC6?sU*LAIehxSa~ONmas) zkD%?2b%J38n>%&lfS#d1VW#Chzyhhu0^0=}@9&NdDGPPK6++P)lWZmIiLT{%w4>Es zyJ4Z%**hrO+p1|*m2J+}^uYpVz~$9=plo+h_s0NvCV~eY)vEG^6qBTz6KqbX zTS9KG2s_vTZsyo)t+_^FHnOy%atKj3?}fgX39M?Rw;rABFo4-OgKJvKns0sfxADhk zTpPryl-z<;lj(+w?vmG5lwV=_Twe>SR=8bUlmT(D-*Q00Uy9*%O*;*eq3z!Y<9(8r zSZ=+eU@kqd+{2cs`2lZbT9licSl`rj!a2!|W%UI_E;!O_Z*dNl29AX#btp|CDnfTi zN{Uy%{t@54K12TiXdE&}R>vy_jvKG3{fE~^C?3PRUGrO0_;LI{_)nbj-fZI5XR2ow z^PMuPX^lmv&0&b8r7+vXtqwBbDk@p?Ty(X)eqh9KQw~`Jjn4ahSJHhS#o1RhkWRs7 z+Q#G^yNcXud^%(qRMk_L9;S6Z(k`ScDUnjp~1t}?k4=*3T1e7eZ0)~5yKF~r zdSji2GS}DD5tysC?D@C%R--S=jVWdoE|m@$I-JqWQ>q|XBXUKrW4Jy2aT&O6oqJe! z6!+H>EYdIG`>Yw?CbOI}Mq$cw;kwNxr4@0csypSmD`vo(EkQvf=sS^XV$%+l^iwjX z4P4W4eMQGL7E&i;splgp1Rfe60-%}j55q-G)bz~Gnsvzm6)jFH%W?kzb8e@$J#nAy z1JYdCTqC#me|64jyq&J7lV0nu>ikpyXzQ?+0B77Ph6N z0HeO-0gte~p5xQvSX6bh*geBrXcx#H)p{{YgyRpQqX(-NBIfqLdTGjkbX?mTz)JGI zumV~ZBG@2+Nj-0C;q5)i8FDmOi+@Sg?e@dRfwoYKy%cg${(G&jwqu&P@3^dpO04woaaA^kT&A+ib z6JdMrkIm0$4ll;)b-!${)NYJ`+$NQ$OGe+4k!~y}SZY!cAPbU3&9AXG-1Np*BCs+v z?6E1prJy$^H}oT}ILUN^KJ}4EVcRKNdyDOY2MvnnHrlI; z4LFgnd-UG~4Y1Q>7g()vanmDGb9Wc&rlCzUsSmLli&8_kDOyBA>q*i5%SdqCe((o! zFNrku(o;Q>!ffW7td&L^9b=`6VRk%N`Yk%~ONTWc9A?U;4oW1wPfN=AIW8c9A)*44 zy?`pxp?i0}KR|t)bm|Oph&`lrtsSsFeg%9d)Bc0ag4Py16C1CTo;}_vv{Pf#N_{$S zk4FTrJ`Uk+6$4~i$J=p*&&?re0{33!k^SX%`(Z|_gRi2uls32D^23CPZ|*9kzRF1{ z_Er_HNOKad5+LZTL3k8>#VQ`Y8-+s94+%`dLM~d)3Hr(yhb-@OSp{3fYrLt|@UwfP* z?Zqy;U3)+#z?=U7EG_I4udan%YYS-uYh#A1u5Pd8fS%{_>4Xlsx^QV5YP=gH6Kx~E z+X->7OW-W4%eB3K-%N9ym94oKR~ClX>H6cE?g1o>*R&OMl6KT?Z;rjRNNnSxzd*Pm z_w>UvDF)V5&@~NPj<&uXoS_B_g;IhD@?ZS0n%LN_J(Y5Qbdp8;^}_@2c9dY=A!Ox{5=aE^&~(7$ zcp4%$JAhoMrtCl#ALoNMKmq}STdb*Wz=C><_re(l=*(q?p;%FSTEO42$2r@T*)Bzu zQi~}@$I|||gCzFROOBjc{F!=AN`A) z{xZgV9N?8vJRSIxl`)!s{2$EFB|6!0u`$@uwWJUUyN-^R8+G3lkM`5i_BQ_jsJQNH z&;I~|r!&}QKc6IwjfDRIYF1m|T$fS)AD$^5j@*%vXlQJWR&y}H1q0vlHtCG@NBco^ zd^>pv<|F%%v~d3bv&JwR*`5G@{G*S=F$jU+Gmi4>V=l;lhBT_?ok@o$GBwUv@{6Si zN{WTnfppw%H^H0!(D)x#T*gT2a%dLyaudJV>b=tl<*S8+?eClTS+_>Bz8)SV;f|WtbxIcsY?nU~BpZb$;P%DT-rxE-#^#OhfB0B_H?pFS{hu+X zIEmj3V1H^uuZC8ijgx}!!>h!qN8!@)B%}eTsTqZf5B@6?)6*1Z{iHAeZstlqxQho~DOD#OkWP(uQ)o_%8Tms~a0BlLH>OjQi z{{XZXN1bfuM&F5N*q@Sy{{Z%M#qyWMJOn0|wpjlF{3kU05;k{+ZxA%~ zsSN01KFZ{3P2| z@+NZ2&pyq6C}xTyt)Ik9x@*jq$N04*Tl2=Aho!h(SiLn%AAU{;_gP#=+15EjA!TJF z*hlwI(&OTi>PSk$O3|;d)Gz-4TxbB}Wsfc2FtxumS8`QgQ>y(9leQ3oH6b!Fao9Ih zEhuR=I(==vJ2F`!BGyzb^tds5+Kmv%7PwXf9nHx*{=a-UxF(X_ zuBxP2Bn1(K%sD3(lWsu=Qf_qsq1$|RWR8$p;44Zy5IS}P9Ck}fL*jTD^!2am}0DhR_bg~$C1EQvqEG=Vy zz7#J0@Kn;P^ic1AOdv=YI0f!nO7_@V`wVt#1Y)e^i*~)NMY>^0D0+da_KOR2#{iI9 zV6Ib1B--SQSmC9_B>}rD3PA^QMY?`?P)*ktG?Evz4xhscO6LG<7BYaF=_L2UH&d!< z*FZfL0!r)#-o$jmp2~0+I&Q2|Kneoa``Zc*x~4qtK~&}M<=gGo4bN>8G6HTFw0V8L z_-)P63%C_-goKrDJKqnv&7$t8SyPsJ_O{l?UhA@QE5#za9~^_Zqcf z1CxjWUCO=gZVvwdY!5di^4p6QZj

dUwOO)e9|#QL?6s+>Jy0zdSfP$)%Un1??qP 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%0DbU|wX9Kco=a$4 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⁡y?(N@#(b*?Dl%=A{r)efr_?)t2ZrL6VuSxw6KXX-Nd5 zYg}J^Jk_}93SgxT7qYxDYXArq`{Dh0;!+66*4i&7Iza^Y_U(tdazbE)gW{@K?oti+ zw@tqI=1<2KHBmLWe+4z89|pMcrPyD)JHvZ>1w^ zj3J)l!*$Jzi?&v{!auwD+YgR&WRHvm;T<n8C_qq8bLsZMN#=&l!C^)dAfdLKT2plcy1L&H+WT=*`vFW`s19`w_^>8!cve(Cs7+44bSC)0Cp() z0<0(0kOyCUFpw8DgcXHK-(mu{Aa}%Bj@dk+r|e71GFe1zN^Wx)Ds7VIg)^f$VN^RWruqsg2Ch zqAHOv7Rk4i4uh^BNDY+eh&&PlGu6T(KNYr?wXGx|1HJ8gj8|1vI5#L8sgP1PK4r(( z#KvTE#LVLrR{4`vWl14d-7Tyr9`_otfGt3H!D)Z@f1xakN%hLVu!LaY#yo1WX>81}&BjS>JZvdM>U zFPByBuKWG)$)mRE?0Dy@PR)g^E6P=EyrS0pyY$3KW4e&pbkr1$n*f&qwT|N8bi@-0 z;EdCtCqkmXAG|wcem3RlG;GmLX;OeCiA|&jW2@CF^!C7?**V&5M7;!;5Sw3{w< z{6+Xw&3q!PJrbtF^Ju<>N;aVhGXTf$o>8cZ48ml!sz$pp(R2S@ZBxE zh4cj~KfF5}ZlIa37YI&j6-BPqGW_@zYAr%lDyB zWQ~$WV|chc7XJV|Dfqw1J}Ppnd3gNFs0B1#uo{iu%~Be?w!uDYph;ronv_u<#Y2NNQlPtBYxt2q_8&rD;Qn9nxp zQ%-6C=yYmQLhM3;(m*;$b`8=XZ4~>CDx(*{ORrN)<_@c}4AJo;;nh>aCk6P|N~la~ z1ye9UhdoL_SIR$U6zpdca#W<2RHBrNmdk3gb=X-~MAJ~x({SY{4aZBU9hh0o-A}Fx zaW^Vw`eW_Uq{nf#TS0k+XZS&3aTE?*9z|i#Y5e2Y*J?+@Ut!O z?~1Xd<>)Z!X>qBP)G-_s1{qt5DJ_eHq=J+uWZuXdkZpm`Q-H%CawaMoDjPB9^IDy$ zWvZ70zA4;FYLM+kss?PR(`3wbmx@9omLteG91Cz2+-cM9PAfVhaz1KTY#dJA z$|tltK5BZVZdwP$Zi6=E+^57$u@5e0b;mS0aheSC$KtgichIJkK9_*$*H~cG8TwLJpVc|t(s8uj#(B%a?PN+64+{VG* zYm$YhV5A+v_OZv?odNcRPmMu#_GNFp-d*FEKLzpMv_EH3VAAJfv(vctTs}_ZN1;sl zXkT=jYDJ5%D;Yo~BHmlt z_)_}>j3lfsGi_D?ALMW_>*!OTlxbz6uZV3bp&yPpGL=tBap_ZBlL?}2cN7EVdcSla zDb3A>{cmi14ee(QbR8m-F2_~&pR-!=H%FO%9iO&~4+m-)k2hwgWVI49=_;fp`7@e) zDFl)VKu=vt`oB+Hc`In#;^1@(&|Ov<*ud7>DPcpRy+?-h%Bq`0c2<{@tbg63=p>5| zs^pJE;bNs^4eK18EkmSuV{{%0Jmy%ns?~dm`L%T$WtU*HM5o3G(x#m%CCNq3yP-ik zKo)>H_X3JS2eU#qcVaD_5lr}NYaM-19vI5a*_S$HulRjNsn)Yxiihcvxf?!P2{2lN&$-IwHFE-T68M=%vneW4;~h(CMgR zs;2!lzb>VJs%5@r-5c54Aw;wCOPbzy78sx1jT8cJGz&Z&+hc`)0#jky_ zrlzcCRt&nd@e3g?1yJej6KwYSAHR~E^{Q75c$A2B%z+ZCLv|yrxfD41l_n&F+fXhb z4=Etqu&_OG)fGaTK>B0Z?^k)LYbpAPW3#yZ2>rbiF~qJIRy;%TQK-3*_%wO+*li-S zR&~Un%4n4(mr~iVQ|cE+-d#y5HopB0JW~@;288N6)@K`J(S}jD-orw9a$6|jCQhPo z$1hQGZ3>ebm6s`~4Zvw=1P0Wiv#CU1QBhKfB$7!Y_$;#DvV0Oy(RD4m4}H>)jky@{ zYlb=7C(@GS8jBIWaw1w}ITW8}X+aeO{XS>&aVSBqlOjS)fhGE*FhFghwIsTvfS{4N zAg8B$Rr80+ogsxlGK~sx-E&rql^&! zUGnfzkB>Ds_-v{is$EHkprHY}l`Y3s`z|)nE(hI?l@cSRU;^Q?HL0+A+ZGU3J*>Il zs3&7xHHE%*JkJ5D8&X#mL(5@~NpyrD z##W@F=|OQFh`?d%YbPv;rtKe|YQqw*hYq8N&hPlHAaN$%7SrIKejagWgnW3S%g&rK z&wM}6@L~k2XY8tja#a<=ZVK7Dl$CZG^xTW@y`3Xxr+8%Ggh*$mmNPXu2k51bhD`4r zjPo{{^T7yqn=VR+GWJST$Vevk16W7{U_G%ulQX8|JP~^KHkreIDjfLu;9hX!zZ>$c zM<};SW;*h!)+R_ooMporXwu%vvfLtPlx#EtNd*cgNh|Kq&~CiJ)CIMVsX7Y-Zhopx zQ#g|gB=~!$8f#OilxP%a?8SZADsUl4Z6LID`JGT#m#(93mfI33BWrBaxK?=XB3%)1 z&>fUT;4c(2M;G(+nW_zYFVkb0tvu|CnKIi`O}LQbC~PgVk)bQn<-$XOE)cLcuBfWd zAt=!vl_FJ%|aR(`8%%>I1uU3OriBvhIxYqt(*J0JQh#D??sU93_ldCr3tL~12QpHhh2xbACh zxkaV2uv4rFG1p}SVW!*K!^}ghH@D44r!A5)<6;Y~>HDCyo)l%e?tI}DamM1qr)5T@ zzQsMV62yYrC}Jlwx{(;E)wT`76mBhJis^0!KsPFEFf`0+U$_K%@%_^W#I6x!t{M1v z;$0$)#N{(GsQzei>B|d!`mC90bxx|*^J-Gsu-lf4Z*50$?9O?a(g>xD>f>YJy#D~& zq*U$b%jw)K)>w{rz5RE()(r97-x^T|DlyS}s+t5rb4$RWg#Dxt#N1`N>NE01$p0 z+2MDGc{3^X36eN~!da-+7a2iKyfs`!2_yuezF1Iqs9n{)lAL^p((azrVzV2Zu#a`U z+|PMmThVkDmj>gB(_L}& z2OJMfs>>v(kV(4SChAho$+=RFGW4{wRm+*j#H(1tS_M2KUHgZ5TlLKUt*e;CQyp5N(BmkB%7zq>dDhgG$u=sv3ELZLd^N0(t7xzur^oEB=Q$C7NSa)v$=6cuiX3p0Ox}Nly=qLgF&)W@1eLR}gs7PK#B}L1}&!45&L2 zl1AxU=cBR*r_h7_;w~{Ywf$|{-*@7FWlvj*pLR2^KeF5vI+m83P3$eyp11!1JV0sS zG*l#ADw=IArs*XkVfNn&*vq@pmT7QohNfF=v9Ig&w{z)(hVVO}mj??Yrjp@HTF_Fp zf#nA0rXJkd**iA2Mn%*>Tu4Y|>ZNv4`B5RpPPb$^ZIYDw4(c{aM&yButQ!cPs!+(q z$yFG>F$@g5+y#@NmN-1IRAVw{xzVe&7Q$VPPHn&HaF?+PI<8-FJ&6GWs7W?B`h%i= z&10kjTAMlCxCQgiNd2L@qVZDbIq@lPoT+cjrcF#{B*`glZYZP7ZEM{ASH_>D4apG; zJ%c&MOu%S7*D3!172X$4nVmc?=S-!Qs&zVqxbrDB2icBPK4DdIBOsLTsa)3p?0OEk z`Ie%kjh;xJYOq zmSi%rER?8N0(~&X$OfdQIhl@u3gv_il0tnw@YcMY%5;naV6qzvjU_hewjS9EYnlMm zEQzqV({%darT5g7$1r8tP+H$jy>{t?wdVJ}syo^ji6LJ|Qcp}t4!BGqTg)U8rvCjc zhqNXZ6=@`X?YF)N9D?_7w#w4x-`*X&;o+$Ru5Ha@Q-ma?yXx)S3=yF2P|SdKMeeAT zd9Bj^yI%y%69aTr)S=~4ZQj^;JZ_laZ)+;+DZTWKyZ-=|5DV-V5J0(JB$aLn+wX#h zn^`cObzTYr-v0od{{TE74oclMS93Nt0{v}lE>0FmB;>2jQMSnkz53&v){RPY9P4SK z#-*rqN^j~fg2wGGgl=7+y7j>%o2Rvp`r!<`08g>wp;(sUl02y$cfWD|xE1a~=5|HU zbt_%Ufg`o?A%uVs^4{d2MMmodC`lI^o}<^>4U$5135{vuf~{Mmlz>LSk<$ol03kFJ zsJ4p`bPMb)xclIloOenZ2L({!Rnl$u^cWbG!*uZ0ofT1F2)OhEp~1ySDnC#dNCjkd zpz~@#Do{O&zuwprDn{tdgu7v?E@qlZNmrNwdtzT)+irm9i@PfMvB-=m@-+)U=b+xxt#DN!){}WPnbjZF`Z1lvvxP!oasuNds8FTMn2R+f~{$ zSfFZuNjsE;n}ciE;uL_DE;pN8A{n&@9aF331vsT#k}MD9>x#*nVPL1lAbHnxn~^-9 zE$qIA_umyV2Nf_mw(V$$pQ*T&Cg(}q@BHywD-HXVgEZHIDte%`>It*13)v&7IEOT3 zjTFYqn?Q@zQBt)wgqIWr$OM6i?1zForvTk2s%cD)YTr66Ej{})sRrDF<*n1p#C2ztO zhYK)xx{U&RExjD&imHh#(4-wL0Hhwefl#%-me{hRrxQP`cE}#kYYY?t+=M-?%=w3)!!F zok>(!w%pRT^&$1iE{6O&e0)fL??QXkS;7c{> z6}l6={Y=1mOKi0BPHl9RrG%t7Ndn|-P1Re4Vu8d*QK4?i1|x>uuAY<&KXKkTuDm`O zJ|=iO#2l@V;^h3=Dm6h8WO?vpDG}twZH1w-B!ZxoCrZN5<7pR2H@UexF%grs8Ms;O zD!4>Ma|<{gKQMM7ZId}>dQ)6u%ao&1Wx1=6!-;Jo{KS^IstT~!5EZ!J6x6Z1u64LA z&M#2cM!|jTv?=i&@jsV18SxJlrz#IM0ya;|xvAM9A#Fa%{h>~j+DeUx0xWxjVin(} zD(E9Dsge8%7xYoOOPTc0I2}d)8tN3nqjCOE5co$&&KU}$Udb>c*5)BE)G4J)Q|W1f z+p7etQ%XyOgrt>cYM3l^@ zAxdJIEiI>8th}%Sm94UsBH)5ccGw(R;rPV3Y|X5sIbO|eea8{r3S==yTLY--#&}<$ z`}YvF<(@K4S0ZL9bQ-frQ9&wY^lsdyu0mXF{{VE@`}GGOYxF;*&|?%$s)Xyray*yE zeL3iixHW63-K!6}coFyJk;Ncffw#HFuKd;{4kcqK^AqMH@BVmD?GwvvLEy2J0xT|5 z)20_U6oKt_yV(aRb66o)Mfb-zf)h!$i&Xyr5DI)2^X5Pil9~CEp-(A|8rLaSry0K6 z`G8K{%1%B*_V+@@;xWwAtD9mx*VG=yD&PDzNS*Gq-5GHI058&VjUpTvV^i*wMq1K= zXBI3LvHly24`Gi2sFV^TV)j@m%URaHbZf;)ZVF2j_{&I+rxVNpJFEe+e?76C$K*B) zYSLh#t?j>b)Ku5K*Ae58hO#5U4o2PXknu({BnN4f z$0HlI=b1xSnILQhzcY!=h=F6pLu}gV!Aq|PIf{wET;G>-!QnQlc!pE92@gv@dq zQXAF+mfeDqP@ojrw--SGllKJ5k%OuZ;;!(VM45{Z%T(O>*v%0t95STlC=4!4x@}#T z*-*Jgq_0AXh&KpOSw`UX8(d<7a7|27Y%aFaNF7ByJDYG%Uk`YVlQRxkZhb1J1V(X& z(6&_A3odL`sVWx-%621vsCUKut+6>yoEA$7t!ZOJ#hf=ztrW8))8wHJT}bGFqNJm( z)=02BdX(G?p7@H^UH2thnObA)jwz4vYBKCxqeQDtT|Jtr<(Nr$r72PwD?*)ZE_MY> zqf&Z#Me$o-3tKB(-YWVDbJ9JsaNEUbZ^i!r#b3kk3u^A=OupuA%(<2uyt)4XAx}yo zvf@EWNpaPqTF%2z8hUPVE|a6rp6|E~DuS=1t*4AbVqQNy(x>770P!-)yncnoc+qHW zWmvf@E;*ShkJZTytsgL$@!DzhETwL^>!?6#!$`T*M%ZRKf*NXWuy(DXXc}4EXP&JEVCx1C1?f2Lrj$^3P5y%rdfH#FH>NIETo+z zi{hRM-q?d=*k~``!s|#X4MkhUIXdb<+f6PxA^Z^HeMXsFL>FpIyYll8ih|v}oI=Kw zSO7|m?QlAE+ZQmmt!;=|ikY7brsu!OPJG>TO-9%|n+TV$+IB zwE*iuKq)pV3BAC%HosemFYh;F!pk#5GhEXX?i|Co{M0E;!@2WhL~^cH~acpp#<3qKT!oFTYrb~Dz=lL zUufa1l3)O^0BT6T;ZwsWWh~^*Ma^|{PeLR9$B?8l+UzBiG*2yy3jn0|C;O@Gd@_iF z@COxZic-EBC%w+M5ICj}!{-|loghnL=vAo=ND-tu{HaWRdMrb1fRzTW0Zz(LzLI)e z)l%g-M*jc>3ko7gMf`WUDcSJ@l%dbc`D;Hh&yej6^=ebVY58^NDg{Zll?681z&mWM z?oK01Oy|X>;Yz5GK~l->rphSi&M?EvnLenf(&I3OnR-l@9C0Y+w1&#o=G~HzO~@zL z6tPm5yS+}uaVEtXaXJC7;9O{Uh4_N!N@s|UBJuK)*AVJF6wHwzC4sWVneP<9F%Ei@sj9lAqgVoYg(=l46G*zG=;|Z z2g_9=YJ)TS$)me~AQDc4mb^U@v%n7;v&L5AreDugV$D*DB<- z<_asR`4uhpj^;E-{7Nbo@e{ZtHAjL9H-xDIQ~CNrG6+!l&70w zN-li`Z3Qcw>%1*~Gc`Rd9b6>nIPvn?HhvcPx0<-!<3ajG61x0;59JKMQ;}C@JBtyd zKO`a|TtFn7UBoN`q7mmH3u4BrE!zt>C-zy40ne3_*GPLUZHFtJeu^)66!?Khtx)_x z@gp(2M5AOXWp1Iw8q~?fYMEWkm8ztS=y;Y2ld`r_h$+>%QU3rO zvo$J0q$C8JscG_R8z^%V*7&NDFkTu>j_0^7d#giYbJ{M@Lq)Z@+vcOMiVh?N@VhBw z+M7($bH!PRb$XR3l$Ytz$y z(X$R|?VA@4R$B8YzLD1-VS>I(m6zF5mQ+pl>^-sBfKSP$p?IUY2iqK6n&`;_88FPej>P~~jY(IcpIHT~+WiG3m zRFv@=WPW&xwWn1YB89*xCwU4@mZaF}M%x`ke7Eg8rp~W%q^5WBT7S%b%j>UY{SA)_ z0!g)~aMzAe$anMfPnR1gY2s#A&3RP0R*yD(d32^+iW13M!xjocwQP=Jhf{lQH#WzP z7nTiIrq|Q;%^(AFe}dJ|hRAUE6ISBXTA6vOoT$-Kx0fAB`DX^bKq%}rYCzJla&CKX z#g>pf@>MjIE@dmD*puA00m2>}Wy-_(dpXxK)jAb-_IyOekfze9agqpkmK`5b3X~WB z05y$)#7Db0x!G!P>QNi6Pis#U@A2|geuA#U%f?^;R< zHZiySKc586xdbnirkYY-TC9eM*o*Z(*p?>KQ|6{yTLk)Ww}jc7KjsJ-XDrg4t>y_! zvJl!Xmc_4iAKgIp##0r=n#SLUE@;7;YHSxm{ti45Wp59Wq-Ki9ioayEI(*j1DbO2fu#x5LN$u^3xk)-I zX8<=!W|5__s@C)!vDUX_rxxj8Q1m3Ip(z@jUf^`O{{T!8ts_&iUHd57JQf*CZ%F03 z@wJjqL+yzT2a0Q-uVn;ksa4Dsv}GP2)1u})-loH@mmUqqrboV>bcZeFP4)l{OFJZE zUD3XZRALi|;%)v*FVZfN!$%2xhQNGOxyU>?gOOl345#Z^h4g_ssPY0=B=hE|-uYehaPV$mVwo*Y-_QD3M$ z%hBZrnssS01bW$#%xzZykQzH5s`l=2^0qYJ{QQRY`7ft%iNE@MOy5mW4}wpNPlY}g z@Ir~hJ}_rYw~})W3PaHwZPip=TG(<^?^)o~6{Qjr&C;|bZZ-(GaaY?-g5uNANasNw zeA?B&jmO;M@}2X3|zHXi2)J)qT-s~i4d_d|EG_wi%> z0v#XY4e<4l&~iTz^Diq<02&2UtdCF=1dro}o}N^b?l=6wb3L57o3-A9?yQmVjre^> z=B>Qzn<^2)NlKccR1iV*QB*q)``_}xBk9Fe$7R01x{B_A*z12*{m@vy8Lx*l;1JIe zGenud4N+O8%Tt%XKm=R=01f(LS?R@2-B|TY{{V*aTKQZ@k{vJO3-JAf(~iHH__o7n z2U69PDnTjQ_P@&RY&vajxIxpppl#KI=7s+NhVCP0d_L$ae;GfASz9P`i8;MG#fG{Z z#2sDIQe*6Q?td&4`#_v+5FTrfviEVg@(9iU0E^ed{iwe<=6uc(q6KI&U!l)K0QR$j zAq4weW1{wvC^|+z%n(2Dz>{m6`F+tD_{jV_$eqgKtzuiO+wfSVOm*dYS+vJ0_8)9X z{{X~??qdG{s3(8nEY{rr0GIbgbgzv^!-}Zuhq#?qSwucgL+Y!I~MFx8cRq~1SWiQ4#!H?@gKzf^r&^(sq!j=X8Fn_c!tH1CM7go?vydX1hO zug4)}4#0~gWl5oA*(q_CqNIH`c`tsd)GB=}(CoTTf={ zr#PS`wkfiCiAsg_s40ZQ6KDvW{~3V`cK(hj~*NZdE(0~ z=SgjB66AVhm8EJX)=il6ZaaD$1bb3z{{ZyO{{Y0_x_iBq%ERvg^O}9?Y z>v%So6x)>d*-=R(1LtIQu^(}XQTteEAMn5GY8m!VF(&W-0Hmx>c-Y{CXH^oR2RqW= z06C%f52aQ+gJRC$jqWzz4}Z0L>(&1N)Ze-v{uI0m7m?u93P+8u4Hz;foV&#F5w`iI z#8Brv-iw{e+l-{AVS6ZpfkW+d1KN-Nw*AxJ?3vq#pYoKFk>mdWfRUeeB&uH$AWBL( zsOM$6phKv=u96|&_*H!u1KIu2e20x=NCU z$e`5P<}Ci|b;2HRYv1(2zwvZ&kN%*VJ&shJ0l$~-l5Tuu{42pjf>k4lt+<40QdLE$ zognnOgewmCYdx?-?uhUI05g8*$Jljg8JunZ059%{T=?L4U2SCu%6vwWHd0iWa{^Y6 zRNfWO^7r2p+wD#x{{W;%{J}zZvAWiudj2E#LaCn|p9hl=T$K|(Q(8|&E}u0)U3;b( z^f+Xm)LPx4{{X3~NcKHe<81zbAF6gJzZw4k0JQ`o=D3Akr8=SHO6YYp6(3EZ-}oFt zceQ{whi~tfZq^5@q{_~OBj44ZPbD6Dq_NOJX@T4dWR^@!rzLo3V4xJtE#-byTdH04m+}5 zs!v^JX;?rzA(+&qTwDZ|DQQYc+~L(e)7yO_7eC)>41UEbzyP_{?qUA`xks9p#{U3< z%q76iM$DBLTe(YYxZvh(&=s(r{0og|Pxi8f#@Y{s_%2 z&l-e=np;T8)rB}#o9Rv10FB3Tk@@3C(eeKPndhNdKWexB7A$SsZ`F1Li0N_*ktL!z zLef&`DJn~#_BZYK+Z&mp4sD#idTX*c7TkHHO;0XJrYDM2s|eqBB)o{rN|co+t?X^n+kUu%BUF~w1QVp>(_13zxwt#yTNg381WmoKbBi+TDH#1-?TnH3tF$SBAo7p=~54w zDjTK2*n^KkX=}oe$CjIfA}ocp;$$d=r%+J=T2JJzppRbIVQ&GVk?(>It9c#`JYd1% z4H^dk`1v&zh|}9KsFj&kys`zk4->GEoreDa+6#9eoQ^Mphl3JP^ZwPd8t)KTnFXN#*~tKYzCvaAO&1l;+mGWT^V~g zA=ly1$kQlo+E+^74gNBCgz-nl`fm_r)#-IQY+5tS)E%nHLr%t88cPfS(k``)B#VKj z_61wm>>!QCH_G9AkBZLI%3U;Yhicw@k-v@)4Lm~49B|;58nO){m7Q~)4xL)dQz>tR zpw(2>S&7McZm1L?E%T-es1vN91giT$qo@(Qc62+fHaAA;smwv$wwsSlmc#SzR%eG^ z7c&nSU*XiM##CxT^NOg`nlav#hfUT%5 z%9*L2SS1v-yitI16s8)YGydTv&Pn*``nPCBat)cHmA zZ8owdm|GDy(&16y_3koBCS0QSBZbqKz#Ns9`18Ts_e-tELUT(Qs;s!Ra@rFmPr9_N zp(R?0Xe-V`D*9VfcCgcl{SWCaRto6qsY%QIP1erW=A+{HH7+das4GR=dxvS6x@bq{ zsvYKRuT#pEx{U_09L1={bxkcjt_{4tp!UbzJss%`7?mR`>5baq_zL*XrJWb3!mC|J zP&FGKW13GXumHJLv3MPInJgB))uz`^-)rGWHe4JI%FaP?XhIUAwGaUJJAa-Kk_F0h zTbQjD@%pGUw~H#Cay1&FA<`kc5*QAC2PKs$roaaNa!Q;c+ZA6QpWfB_PU^f~c`tUe zvOJgCy#eUxr@~=^)^oc>JJ~j{gAN1lI_lJP7RlJyD1{qi%wc&1JBeH8jWXM0pv+FW zRdzIV0iZc^ZOzSq{{TPJ5bDoZ@YO02m8R*n;v71x_7P3XS`AIK1_RczVt{V9EPJFK zhjU?rx-w(~fJ({Q*tO!6@$&F$bpnMY)valaz<*J?kZp5w{q48+IGpAKP#DvqtN^wg z@@|}2^(9wov6^#Bl;%PjX$cxa5Q~AZ@7MJ>(nC?!$_D_b=77f*o2|fj7NpWLTiMQg zRk|#gHD}iY6p-+b;=e9uHlolg8H_ucBQo=@Mp9C>M<;Y8Y68e`f<}$a zx3S+At$SYF?IBds))?dw$$Ju;ABlex@}#V#4~DQSacOzZuH&&ItV~DQ>v0_r}WFoVvF})_{1}-W;eXCbOZYD1uK;LN-0PI{_Zae|Jkwf{9=IxK z`IxZcYmU-WOL^CuYzLSn#3?~PF14k?+l~MfsQn>i(#8w}-T11?AN;*mX_|5oU~Q-) zeYvg4_-gosaN{WF*?tCc4QnT7YJPOf6{_VzyG)YVMK)w8hQBEh0{qQ>Q_7 zDus|Xy3}S= zqDz1h63cCcY8wzP07{A4+M1!VjH80a%p`_j?ei_d`KxP9P5b8d~MHlbZIR)T5$;4*GgQ{FZm}QX?rlD{XP!^ zPZ57r@!z(((Kb0SxU+0N39giYCCnQi#a`c;$Dz5}uORB$8ZHt)I@PB`q$ZCQ(1vFy ze8NIOE+GUEn~`ue5O%fgzCL~S;Z!=9;~SE_*VxS=bER?HMX=ui+zhL|Nv&p#-Ak1Z zEX^#Xh;mrvuBD)rCEfQ^1f7P#L|3c7%-O>#*ARmrnp_vqFQ5R2Q_Do%ya|c$36xr-x27=KQOd zUyL&RY3_wF4X-Fl$xupEpD;^kC?EnXpjB&}MZ{z+lFb?&Rv)9!lENTOnr))nPF3PO zdaWvj0*y3Lz@Mp5Q0)~YZ5n%%5k5pXyT}A zDnV~h<97aO&2iPo4g)yObyi-iKUd2wA+b$%H9nlJQl4$a4r28ycNC&Q7CkN4V?$3V zV{A87musKa0e=D#S1R}?%-QavC}cdROp+XMnUW<%QdJ$lq>`1V$S<)L7AFYoL=Sk} z_bJgwD~4y;tQ^YRpMowG_+PAerr~FY9Iu&jc6;#~HkA8wnxubThnIvJYmU1vr0P@< z$UiEC7MmtZg+j?snL?hq(+Km*GPIik#Q7~Q5g%M+{UEq&a~Bb2jv8?~^7CDX_*>x9 z{4UCn9?tWq`G<&-Hkmb;;Wh~;mm63K4kf#Qk0>P}BF4iI>BnoeqP-3gQwBEW$KE_i zQl_v`AQZ7J^tMr8lqi&~1P$$L+;z3bYxTwKR~p-8pK~q?Tz5?67liq5C{?6Z=2WXy zda{~QU6W9BS`>111|y*%DQzU$>hmo`?yaqXzcbx;e!)5>LrTILJWcgI-QEE;98zN` zag|kW70Q!Q47(L;ecE|bPQZ_H-{8EYl(y}Pt=#T=j7l?gL;<>?nvu2cA>&RbZz1+d z-wJ*WI7#6)m0XLIsyU}I%ghEdRZ4|nO^04#1zK5c4Iv?gkxZ%l z)KFcwmBp!`08Pr&Q*pKNHxzh=V%Wvp>klP^=w=xuZXO*mEQy-mn}x$b?^EL`WzIaO zz&D4Si7Sa_FfYmXgDb9gO8&spDrej|AC#_19(JXfjbh_tmydckp31?L%% z%V2DllH|8q2~U>ni(jri57{m!P|SI--p#d$8*TZj^UrE{T|0U+`iovyzcD9!-rD?h zNl!9w`=j35jU4 zSS@0wM}RB__oKp;qUnJO|pJPaN0(01Tve z_{jeN$A*cQ=THe|J0EQ0_?|AZ0E?=O|m6@uQ3an;g)Y78ckJ|qLGM3hK zC>z|{Q5XIsU1eCDJ=0yFlmf-wT^4sQ?#|*?iWPTvcXuo9?q1y8-4`qF#p$=t`~A(M1H zNQ0zkxggM2QG`o@qKiLCJcpB&g@xoGf|}MIEK2i)tUP@F=ZF_I35iIx@AOc#?K{(I z=onocBt;OBim0XbNj%XW7cp`V=U5ylD?~8S4P4>DX1&H94oo8zU-=MS*q#t5{K@Bc zEB2%AdUesLdLk+m*UOYYyxQ1lhUDb&_O4*DF)RL<)y|@77S~H>XZ#g?0yCN~Dceez zcimllf$t8ON`GmjSk;))dr3p5OL|9``b@j4cJr6X3GG2;e7D#deqt5=hRzp>aH3_H zjJG9olIS;yY{iNtI^O>7OQZd4ZG)F>CuCv`{Ya6IVjP(U_|Jn;SuV|wE2^p;kaRP% zBvP2*ZFQN&IT6-^GCp*+CTH*;pr@OLjUg|oqur<4KDP$N z-i*sZle2H!LooGFu@Y#kdqAv9`+kh=`6+gw{33dpKI+SGx7gh^d3_!?`#qF%`Cj3` zXVqO|t)EDId}cp!{MAl_$~)tjcBH>0as!al$5MH(*yJj^zauh7fJ;;oGFiO6)rL#^ zNGU38y8Ksv;}z2FD<)wl z(d`=9N#cPv$Wm#2=mZ(+NSgp4P>wAt3`6q$-mmcf$(x)O(1S7M-4p8^2q8G<7*Pb+ zE0Ts6a|w)S^Fw<nF3F0uY!;V-2^xjFJ5zQHj6q)a~lG1}gI z?qPXiZTKRK{2ii{K+Kj^pR7Hz9bdOlN3fu#zL7lMi5h&^J1_aL6Gsko73sn3Si1DUYePjUUafZ zi)hD?y1~86SXD(K9;rR7a86v2GN0}5jQh+D`}F|cTsX(hQW(Q<2&B|(hNjb8RKfXl z427&xvGGT_EFA=kMW>tSc2ND;qPpk-YP(LV_>B-AKRM=IP$bGAJ4N4n-s&ECGho^C*mO-|O4erDTnC9WT}J-{JX5UkA1wB}tL7*_^V7fBFq*?(B3f!A zbj=v(?)CInAm6^hokzUDSRo=ll2p&Cy@@*#ME}X^%S>LPq7l|NM3A}DClirTKj(ks z-*Ae>rEg_k=@WNFKPD3M!D{FxTO(VXenv){Ddf3PPaYf{NpjZG1##Ek0bKv^{U}6m zw+VvqfvY(M{C@2#LYbBp%SHW;J619g!W^s}aDv=~cUgYYpxV__xRiO+$yHp5k|L z7MZq5rI?RDS4B?EqZ=Q7E@pPa$IvTcjseU8YXPgV!1)3?hcMc5OJ!9Hcz78c$>o-j z609eTxQ~)79%iH0asCHeX7NwEAKXDaVb)%eA(nF&)n@kvz zBto&Kuk&a@_eMV`qtL|w`&|eFzjHm|PFPoz?wuSLooN1bp$;V1L!sCBj}Rz(w7YkE zqxp%l=36<(+Z9ObIm0^-WBT~K?k5SJ0LCO;@T&mNbjEiv1;IHM%3*zobb`OWPAYo5 ziiu?%?M6ASmOb~dLeZ1&Ni2G5>}U@}0lJys@QTnIIS(km=uVT)K1i$sN}j0*Uk2Hj zmNRsq7TT-NT6~+v6NF>$g$4=0%ZDqD{It?Nu7yMb(duqi_Wn{ymTDE*i}5aeR}qf- zx)Ql&Q5TPyZMc|xN@Xdi>WFp{-r#Jc`L)Ch$hx!`lrdMAi?U`^=6<$ovi3FQx=@I3 zxVQtnqNfbfn|JQ|<`3Cs2m!FS)?yA_SK603JlUBg@o@|OOTTI$ndAX_BC}x&!i!A9S_3B6 zz2`A|Z;#7)80dpdz&n55NExibuCI|ir={yu5pYbIFGG6fG7nBHY#z5p{tG{3_u75T zcjfYyvYPk9(CV`RD5|mtd-E(EFA2GFfUs60#Dpq%GQPRGAQ4_!2RnwZx(yoqN^i9r z*Q?`7i?)}!HQf{c_EfYa1kN5DcYbymR{y1`mxPA7_WN|*AVMWPTTDFtve&7U)b&D22#Th!<*_&+U{QXH=BvxxxD6>1sm10R#bjm96FZA{K_3K;MmT36 z7v)ZF@J{p7d*c=sx{88PXVOX6KI+P6+>_v)lIU>&lCb>M?&OU|APd#r;C@>hmwBl! z4+qqCZI{a>OraL{?6lMkPUvWlMmyW6Eg@ByD-rlL;=3C=GCA{P;_Z8~Q~aiOr_ZE0 z`72GZ;EFzJGC?`AvQ#n2^+Pl5sIJTZYWWyT=u*zsOYE)ivPwvwjHq&_E#dV|ITC{S zbQ1W9>yY1>nxbF|YY8GJr}yqJNP74j@cE=WkNM2YFf7mhe4cT)h#N1R;O0h%gDLKY zWfVj2tJx*&k?aPowUp`UcSFncyy0w0o()#W`)o(qNtsM{^_@qC4+;v~0%qb-827^6 z-q?nT(oS)Kw8HP4MjB_K1#53$mPg`LIL{|{tw^1Cnk&tg`ET%EB_*A7cE-fGK ziM!0rP6Jww&yXF^7TgGUE+t?h>>Xas7=q@E{poCgQSK-qpugRO$d!km5~ z-`HDl7H$h%V?2D#@4aOroRy-_ZP5C5<2UvodC;i0JA#dc<`|bCN*~Tslr4o_g_@*7%04I=L%kY!m$y)QA1Zs0ly?ny=^r!f$dKQ7A>{JM84&M~>bI*L=2tLR?3c|C_$F$a&Z-WQ0O zcTRoAHZ5u?(DlW@&44+B+V78p=&&jN@kNS;6LM|2GC!&<5p*F60wbUzh-}H@18-7*U60MMY$Cb}eDr4$XQ16noz-Ce|aYMGqNDOYD!-qHnDh5+GyJ;@&2x z?njbQaKsI&tA;~7Y)w+4F=AH8C*lK0vfm4gv0j9uGiaOmfN!s z)_5ddbW~xoZVJKxf%!tn%yl57-1VyuuRm98pcGi2?XauYpBBWQ`9z(2n$g6Mhxcare(OT+L=t0KMc zHqvip@qI~9K(C^JwAst|HeiB8B@TMN`p@AB+0e}ctzz?2=gRy~UnSXtTUm3UTHd$i z2>*5@yn%&~uNv0uf@jbnPr%+>fpG!fRD$j1&s=4&4q0&r}eoFc>3bSDEF`$q! z&8J~_UP^o-g#2Oq^Omxby|R7NMwQR>GgIda1?iMAbSO z^6ErTb+AJb5-$)F9dFR#kiK6k=%3Psvg$GOj;AyvU%W(v?$^a_1v#d^ohN`9j6?PL*wpoGh-TNrG00 zogPqzM~I#b2iwdYHdm;NOL8Vn%SUHeihyLM;;n_L#Ykfy4_AOqlmLR{R9O1Kj*I&I zmxIFLHF~aZIry=Np53H8-v}ZSD%F2gVbSx5C7w;PC1*`W7MBH+`a|Idj;nSAP~@q! z#I40C83d_6U=Z}))jlf0>}FpOV^hLn?(uyerNp5OE4YrJ4Sq7_w z@J)p*@#RKlfIlNs^jamoMqW2rcWk345kX`Hi~azTN7V?8gOWuvn4T?F4Ec zuIMpr0cUSyn3%n|K0|&@_QgU7>e`i8;!VacmUn%LetlEIq_0wEhxrF+Vq1cb_fHN^ z?%4OYu#s!Y%O>5VIqi^X_1feTqdIaO5UyPN!j9k?d)q3Ld7G+P#+pLCY|%{euF0Vg zELO{v+<`6%>efk`l#t;w{J>P}g`{LuRKb1Ee(gdU0^rM5U}%QbsH@u<{4 zvC&oahCWR@GlJv19-(dBOmLE_nu)DBm!eV{5V&U@oRwq+@H8SO`PoxN(^xTR+{DJY zrHn%wM~?;f!A7Vwr6)Fd@v{cy_{CS|Jw;DK6f$s+#<~uGyEDa$o%B>L@X7Xi}kBCiQcm!$U}IXsKsGx zY;z=iP6Gc5*-;bATpfQ|ZURfPZMGfCX%1gh6_{cPfi`pP7-E`KmhIOk5RhT3zRuracDVf$lZ_cpp4TeCDzL2*l?ShIZ zadB`+-3dXbtm6J z@CGCeXjZNzag6xXAv-lqF6z#mr_24Jc`UHz5|L3pn2NA6yVBex@n-c1|aTwTUN-n z=c>~D2Fr+=B2K0?Lu#JQ{sC%ua$faShVg|PBo`abtJZSe9a0K@Yq=J(vh-irXDjAm z`HE=1)!#9<+V4>^b!XO=y!+3yxpm_>;auyZ+uue>jN-{=q?O0eePe@xk6n*#$eaHh zuUYAQ<=YAEaCcqmhV{VdOTJ<7Lx@v>$qTF|-`@(HwE~u?;wNuP5bM+`dzi^mG<(6q z<}wa%Fr5O>NmOZL+C|<|EvgfXcdvZHgzlxcKR?-(%sSN=f~Rd+8UjBxD80q_G@1#;+CoEbS|P&MmYT?zkRbZ06g=;wQfafQh5ukvaxf zAMhpEBqS+igPOpV(y1##M|}cmy6`p&{UMDL5g@j2k0TX$L;EyvE3x<(oJdage_^ES9eVQYE=XII_fZ`@NkqhUDF{z z^~z|?yP%2;y){oq$r%h8zVLtziQ*+%_|Ar;HWT(p!hb7+FEGNM!(um$YD|F*=<|ot zWjxJP1$o#W61&*SYbroG$%bq)(OqyyYmr?f!?`)E-8BOrU52==m98%rVk=3=PCuJl zz;{~3Db5i`MlVL;{7yI~4ccI`j`89Xg!r;k!eJTXbOgP{%B}}y7o&jUyHUz-HQa9p z%`5^7BlJ|*9_QY{RfdYB1NO_gN{{wMF}V>pxKc}guQc1QyGSXO$4c3U0p8;z1;nhuAy2Dn#(*Q zOiQi=u#xI#hDc!}o!rG|talB585c6Uw!Qgvl?5jk095xDtEoaIiepTK{B|A3PT_m4)KRV1*>+|Wzj9P~9I1ar z>6g3VR^x3!f(t|M_WOGnHB4(%WY|tKztgeeAk(JaOq}iTuv7pml3#3yv&x(Q4aX$UH zjnApTy}L5^VZwDGvzB_U+34)@G-yfyI>nb);CoCMxNMb5tGM?Jl`ohmXj$Ok z*0K0ARh}cw8srxW4c}p7@<1eIge)kW>h|rDax;5ntzlG5;+_!BF-rT$4U6I!`|R0O z15|3FC{{Ht--57tY=s~KZ#UU=DU}?EARcWd^#Kw8Q@ZOFv-h z>nMTy_1w)@P7R?kF;Jn|Cxlo$Zok^=Yif#e$S-RE$IPI%0m0dxVFv$Wb@yv#W3hRf`8_G7xN1?4AYvX+5P5F7t z{p)LOJxxqbxJvUz$(@dr1XBM5KU(7ScwxFKJs4--)B$OPdbrY!jjJ$!PC`w%PgJSP z;92zbafwT>uR_cmY{%OdON1>1HWnhXqSbX9)&eZHzeZ4*RA7mzf9`)aONwvv0;-)d zaHG9bO?r1JEM#dwvM$6QnpEXNvTk39O>KVo(B!?tCZYd=-r%tHU|^Qx)5jvzbm$?Q z`Kt>zs`qU|KyU)Jp+%*HJWa*~>x6#sAWUiTZkmKWw(MPwKPRvkAlTk-Z%#{wD$D>k zg3~D!Za+sFNs$QA@tKOC>?kGfY8sQ71NadTuiu9Ln9<=!u--dz|krZK@&Gl ztKXJKYtuPfO$~NKpcI?NrvD0BR@*!Oy?$Bi-oSukKcU^gNSM?*2s&}!13S8jkq!_- zCCZtc_=QZ&=nI8$TnRydGLL>;!_FS!f!Td7HXMBg?Vyy5Kj)I9U0v_j$?dwyGQ0{;Mi{xetB z$E^|fd_IIo$Zg9cuJ1ddgs{9Kg1rX0lz4NJg$4A{dtvO8u_y2UcO3i=@R)|qzbNxz z<}(}jB-GD|SQ)HGN=fh!@KUP4^$&24Yw+lW(jCwKmd|4R6w_4Z_niGGiq`Lo*-{K7 z1n#lHZ=Q@N&q2x~SZ@54+dZn(pJo0hMw0&qCpZzxsx{}^ z4#~@7bpKJ+7Nf0Wm{uH9N&G^}Egl~8?rLop_LVr=lH3mB9IUI&+KZD{5X+PuDUMYh zV;%gCKXEW!;hZDOF`7}Qziw68KDe~c?FTYDVc313{T2UU)Nn@cgiO6re0)s@nzG=t z+Bgg9t9R+3r+|jopO4diT_}sc>chmFOvzsLO@8C3*%4~l2X4=CThP212!yy-t`_z5>qRlfuFcJKcI4qZR*yobTRVMqPH1xyF9 zEB^tu{_DyR0_FWJs0?p_!sDC=5AivAd!aW)o?U05SIGXL_Z`!X)^teOfmlkbhUoe_ z(Qj`C>D+UNQT4^|fsnM(-*({#KD(bID}Ck;^ZS&)hxlKsD{zX`cFK0?WkYmj%2kW{xK1a@8k#F) zz1{8mfuHBNA$unH=t569vi#o;+8?e_kU5#)2{HTzp@4kSi_Cv zYP{R`43s~fZa}uZ{>$^w!UOW6< zvYm&T+>8w^%xrHlRVV+gnzrSubK=>x2&+hOrE zGwh4(?moJ}lQz70k?ih}n4xX1P*w~D%4r@z(~*@+B>9$UL8n;;?cF=zor>Yl zO%+~LH1q=<=+;8M(RxAPI<7}9v+gw(0{U;ZP9s>Ewb%au{Tz6|amUtE@D;5xhzc{P zn~hz>MO`=*WVR<@$6y*V`Hhdir@yM9!yw}!>daiEM&&};2)IGi#e~*)N}bGxsGQ?A zS$GbJsUO|^>u&TmIKdckU#An;xbdGl@nw_26XBB!fn(g1DR8zj-xMB)zapNxeLsF< z%UnL)_#-&3;4PDSC^pQEZYt19CFdKKa?r6KTy5J{)hefxT1>Q9Ae*e_Mw#eFgW({h zVS~X1eG%E|yTmTQxX^>TsMR7%?vnv&l8rRyJCOE`EwGyUZeepi~Z1=6o6 zZ+*MD(K+&EpCi^~Le?Eyjk8m^*dbW{&7)_D8A{|VYu%Yimn?H%j&_EHpaUL#PEW+s zX;wYZBX%;bzb#cJQ6{lQkPi4fV36x5TjAPO#AEKJkLhl?e+V4&!52dV_b0|!&(h~G(D1$*?uE}jm*_cN@ zUhbvLCQU9@|HC(`iWvz~K=5I^heXe{M2~5akx@2QI*>t_gtffw06fm;(ot(jfkiE- ztQ1}{a-eSDYHXYljSF0oA!Ea6$+zYX65yZEW)D><;}y+7&yf6r`7~85A}zudZ`9C%w&bF)Va4bRPsWy!d*$%$EUTO7u*u$dcnRHyaeaz$m_2fruW1X>Cd`B{ zxeZ!j=}=deFJcjD$y=(IPTmzxq@m~}n_XY|geMR=s$hM{Q6E$#Ub1GI0;Q$6e;&`;(=)lg}gXi3wEsd7_WX*%0Z@4+HOC{-;)rZ8EZTQ}@t zSSD*;BJd?FD)K#DctC5(Q@SGb+G#*BSBe!0S?;*tW66Pg74*hQ@KXQlLuAT3SdRax z3df#gk@qQ<4yKxmjMU)S_+d=jwDGDKUxVOk+=L=G@8MI>HnOqJBnb43OTJmOW z$v$tgp}?l)sIqKu=srhCao0=Y?YLjSNnBW0J-E7jL~r^lz@xUdD}4^%8n4LwIOjbn zg*fuUF;`Pp5mSl|iA;plg8U%ioGHsERv=Ytup@_lA>Tf>*IxK`+Mv*6voeLPn%bn? zInr7D#OGKIymeX(w52U-|Ff-C8#=fLm|B{q2S%GS;@zua(kZ+ZZ*# z2kS~Gv~l&&^~$i1M|>P56kPTCVY<)^IftTuad@^2lm8=>`n@b!;nrexx904(_Za+( zVV8)8>3S#38DAe8lSgDMwgvNitQH;0SFB=dh_)yNaTW1Xa51UT>E}i!t$QeK5xK?H z-})m?Q_`D{nYe|fvW2xgVdCzm4*dX)BCYI@*uwfcp&UBPzmy?$`S#Gge^jydMxqxL z85Y>95WI(fb|D)_+`@8_BBE#8pfY%O(jwBL+O#15k=sSLzf^0&&CyvAv(sOgNp<%~ zG_P;JAID-MG^1(<`Lq;L2q&r$GOr0IUYv{et-tD`o`##a+9m!jwD4ZbZRdM@UqK}1 zc_KC{&$% z@O?aOe}oV-z}>g3nX~)w>8kD>bgMSCQ;5<D5a+!TL?)lY7_~U|)cd=0>02ON}Hn2ci zrw3~U#ig^f0KZK$cGg8JWArn zC3s%~L5jPt*3MLEgv^dUDPB-|nuko1EEi*V-DzIDj=*wHmhb)4h(VtSt)4ykEjpfY z#Uh`EoST-b_P|&~rZd(cDy>D~^n;5(*J{82y?M6&er{CB9P1vXu1arSLl(@$R<1di zi?xW*^1ZZCw0xFKDY+OZ4FqNRV|nqNCKmysDiuN=`O6GQIA*lw);bjLvIiJO1TF6!299R4gkV83y5z$eX`Lj8{SlEC_06$>pll>W| zNHx1swnF@aphnqv!X3vmA7)XWwm4rJo{a3pA#$57QjG^0HMvch*7&N{=`v3?aL<#FqxU4{cSy0jlUU76B6cma22)I=SwaiS+8GW8qQ12q2n}57>6Wc zA^i!ndMR`^&7h-q866UkVn{HF6s+O58&U;vj8Wv=a_$*FAC=^W+2YOv3B{v0`a(At z1Vd*}lio97BkEfAZM#cWD=Wv30g{zcVLWx{9EjC9B*){T?i2|oJ*vf{YSvvypg4Z9 z1W+*7s%n7o4}lybn;!j^&VmwN5rprY;T!}za!4S>u))?waq}kl=q}mVvmt4h!;bh{ zm!f=|&;?Vi?AW?QVN$IurAb@{Zn_-qjL|a=m?>g2Uou>^ssV)PGmM7c=62ru^|`j7 zT~hXr`SGUedw?vjIrPYcgK-G22=vQK+0qj1oIujr+n$Y@*tJv2pI-`-%@!GHj1JJn zzbr7eoc=C8jYmNfni1X>mu5N6lKB9O|LN0mNWK& zqRO5RT6ESdYzFVQ+Eax4>+YdzRN~!N6yyx*YNoa{?38jjQA1ga2vr2@gh|y@(>nMq zy5@N`lt?wsYEI;ab_q!>FheGoc^@RdO~uBV@SQ?~VeZ;dLG zcdF`6l+%-QWN9aBe5&$P$6q6)WjAbfBjY!|HvLV8)ZTNe8X~a9(q`(pI7wW9E9vU- zGb3Qg+Ki_`H(PB)2PdyZtzmId3&9fMKd_xG#XM!`nQ)SCmmABfElFfSaC6)JtX$o|LZrr! zxWwm?jTWpI&(SD7y%m^IOYXX-(*nnk+7`hGt44FpKt4teSa)jhe(7=SnJ^cyfV}}^ zDo_iW#(LtQv#@B*)gl~GFGfQ2S1WcUnOrqWE7B(mLMnC<-{f%;2%NoFEm#0ISC>Qy zyV3X`zf##nU*hxjd$;yyJ|Y@TRv+{E$h26JDUyq-6EU%!MT-6WBmL==dQ59MF@>n_ z>55>uf)$Ulyu!8Au-A>bI7?s!N^lwtYL{!EvAEY30Y#zgoi(?FHDZbQ)+2*-tG zp2$TBShD1Zo?9{2)%4iCnpeVT-u0l<+Scas!<@I=E5$tCQrjhz$dWxeQ5r#@*RAWS zjX&w{2plxHhTyY#*qqqqw}Wy{U&iaXqm6hfP9>m;kEqD=O<(;hpXXjj>d#?yqRb{gQ;69 ztm6%o#Z$*k)foY)lol1QauWhFc!IKomZxDQ%9O_Vtu}WbRNB3F0d0Jy{TuoeKTJZm zDFH_?MteacpSKD7bR2dj&Xby}Oe>8tm+m+KxOCq>%Y+e=4NE{4S84b1_~fYbiv}5u zqieutMhJPYPm)^ad1T;g&}~N(dQMHQycW6+lbeQ;dyixMZ<;+OGq9pn!NFUpbcRZ` zoDbutmcXKhoKy7qV9%$# z^#A6=qM?OI#f_uA8e1C9gbsTd@0k#|%B{xLeKb8s%r{hPf?KgDyBGSFHbe?A} z`@1}c>@pO^=Nq=4grR0Sb9Z#sbuDeL48Tj&)xjOrsi|A4>t$I!ONI1ash_cWId zW0)He2$J^Lot5AQWcZ3YOGdxO@ z$IO_HAwMw{b)%7B{LU8L`$j)768W8U-Z5DgQItu3inAS24nzh^MO!4}I4-c@B=si#6Y{ z;gCjXxV#vqTude+I)w0f&r%Z@`xn*t-Lc@2zak|S&1@)9Og zN0~Gi+(ZaXBtbfJ#iL>K*p+SiZqBkrLw6tl)rB`jR$Caxw-YV;O zh+{ zuIwvYz#E3J3j^-wzY$s&toDW|)H@_%AaQEeJ_`JKTg}dkiUA_$nop}iF1j%7G8-#j z?E1b{!TqSFsKMT&$W-r=JiXno37vYb{S@1}v4AwwTg*Jw@DR~83NJK*Se(XL@JQtz zn|l(X=%xOpzQGz971JLX)^qT_?Hd=50p@E=>}h|z@cZQx*gYSWXpMf|)6SZcDM;ey zU{)OCt8s0C)UW>2$julbaSb*-sYZOsz-J-LW(_~ zIB<*rIGrQ zK}2*$hLD|thL{8$h^{p4Vb83Fsb-Q@h>-jD*r7jX8=l5hz=-Aljx*IA%?# z{Rlx7Eb?#m@OnH6-A_v8XZg6AGqX3tUKpMmn*IkkIM{tdA}{~W{&O6~F_Fzw56$5z zRZq2a#q00=a9jcS;fEVm(%%{|OZ^AeyXFt{$lzeI<^C#o+1eweO}F)p{aJcDAJOM+ zI4LXW0Jd2Rgt#2M%ztE7J)t(V4gxL2sLnXr}8eTbA( zOapv0^naewHOk|96KUNv=w{qLYZ!@M4))!|BiLg>RFQf7c7zxhW-mJT3O9T8?3 zOe}f#sK1A0p4d5=-;Fh>IJ!u9y-xBva<5V51c>{q33GC_@yFH1O^H?&n^ZHp&%W{Z z{}~9=o*{n%?=~Eh^K)#I4@k%Hk;mjlaMsuLD2r?%UUEGQ!=UE*Fce6?Z!ICwPug+Z zWqaHqS_vTwMR2kQwv*TI=?-F!HEoW3=C_z=kk{0ckPY;`O`%~Lt*%*-=o+YrUJLN0W7FQsW3Fxfa1!Xx|% zZY6LMREp~7VLT|&7GIKc^@Krcf}=>>msMhw*B*)7!jaWzYLOV#%8P{%1LB*~E!Qcm zd@+L1?H(8me#g?dU1AEz$%w!@PtmnIBI`l3awr?;Pd^3y?vuIjE7N+}I7cxfp3NU5 zHDwrH2pD+@WAQb1xkG7UHgjCSF;d&-_;hA>LK8sP`B#3STX$osdHS1n(T4hg`06Sn z{!`=(M|3Wj`5TCQMsGdyOtn~`F2{_ju3CfuDI64OYYp3_C?wQXJYwzXTDPPAH%^4J zpWG>=hD+(YPUXkU#3F8EuGj)mG%*sRj-JE9k$xEHbN(A^DEq;j^%}B0p{SAuJ$g3? zLV`8iZA>fc39anf+|nwqsm||uLubn2%KbtvABQY9{ws9RSN$uEUJ9yi8-I~!ygeTs zNXxE+(d0dE_7^urD_Vm|=)e^p1zU@46&UHs$G(cRr6z38xNamg2f z5{E(%J-9&@E1!JCAx4r&)9T8&U<#~O&`UJj$$0ly?B8L%(T@mP~ewozTjm2I9-W z>qy^0!>_;Ecx@VUaw?h~(tuht8KU?h#3a;ydsB*@u-rnLF*0k3rLqppWI$mwLSc;q zL_J!d<;fw!>Z&e|1Ik+-BE6(sJ^6myoRFT{je_==x{S6|s0vU$@{O~}N^wRwedDV& zs2>#p0UO`?9zE_g>Ubgh)F#)0?bVhw%AlN))K|KF<@sio5WUzl;*G40 z2cDqF)&^dzu6}*LE)s37*jRm}xeQxZF%E?d=I)oB9*c!U3aD5-AUYsCL z#euFBFB9xcbGw=N(+=bIb)w|3+{G>-^$hmu97)6xH6C7BzbTQM(vkqCIppStwE66x z%A<1h9+k4)^lgr%UD@&5io>!6lG5K1;T?&DVm;D2>SZL`GHv{U)?D>w+WF>?=m+&Y zx64FaoGq8UZ`l+oTT6)mn1abTOva)mv=y_Y*&}to*b0=&XoF2)fJR{GrmsBuc7@d3 zBgB-)4O4z?<cG_AS89{$!I^y znN`|ngk9hvm?c!R)2EN_eHQ-nG3K<-wp@z_YxAY8hHcA5E{~7?3^5{)$e=)5Nd?IK ziz}0rhLEvNo6T@rBkWY4$vP;>B^CpfzMGMrN;!rceR2~lV1U9hR9gL<9#In+#((9io{k)O0S&2Pl zoD=UB##Bc_O#|`S^9(0Felkru-^rtd2nACihIzYN4MG?wN~%V(E!ty$8WjuYNwTIV zpEdZJh82yu-9#vHTBwrMB^9lipgSmm^y#Y3TmNj4+B)nnJ`Pqsb7*jOUEO@F0$54Wb?2rfUU z{J1T11n;Z#9kKOGq#G}qGJ~qCO*rF$w$P^>DhWsfa(~wio^~~vouFL>JLPzaF>*)& zKXeNC;I?L7M$GY-Pp?mj7J7&%QlA8<{JIowoB5ImBw0aM76C)#&uHB-7?j{bf0WG! zdFS?DR{K2Y=kUgLQVYsRF1N^dC;P@tdp6Rzd6@HFU(2%R$EU5Sg|_3NYfB1qK}iX^ zk-AZ~o`9s<;Nt^HD;=R5t)@8nSWEZ=@Fgg`HSq^3_<-RYOx2ZGefWWs5x`hq^=U{& z+-R@N3R13?xB!9Hz%rUZ-pJv)&`B7Q4z+_qG%4@kw-5yOD*1l0>rtjcPcU5hUua!F zQmwtvcRg>l?SaW1rph>}6jj}2F?-IfTGaToai+1sj}6%?jk#sK%L1(4V|J3$kyILS zl|IA84lEK$1LZ=kx!7B9F=rXHQaFD~#Po&EWUx3JXVZS=&L0qX)5K07p*&pi0iUYb zvac2i5f@c;C`BSM8rA>_LPLunEyoDds{*2Jd|~TxDQZh&8*l+mijq2VUg38g&(LyQ z!}!DTfmh?sc6E%eG3Ig=EyapT0n^N0=`&WJ{ow^cpntPZp4yeRuMWc-O&y=_9sb@N z)`t(n+~d|rH9R>EUOfF22Qb0BMDr4X=5a*arvCuC2d_+9b>G%il*@D@Nr?Q2-6P8=cQ#icCuuWNalzYj3Xrx_R(@;YN?ZEUoi3G&4}* z4Caz*62fjH3lG3(`UCYV_m8j`#78rp<0PDR9F+zoU)CP3GiHT4V!^RN2_e1gN!t=G zTs2fyzJ(ki32V-D>Ai)IQ-}7p3!2~#s9FG0ZnTh)J$|FrM{c_i9SY~{{XyQhd`n= z{T1lM*p)zzF{d8|nduKmA)|%QCvTr1wkN}08s&}^iR$dKS%nv9kI z0BI&mmKxq!+@62{lz^0hkFl@}1`Ix&LjdtS%K38{#bvFVt(57&a0$RlN2<3y&iKD7 zmoB+NuAS~edi5B3XH|2k3gQP)t^Ek;j2(cY+@yAP^;fc%~cPHq+#^_8R{UR4M^8MF1zByQg*N6(! zwD!YMAEr}ZLIAKpRAikXT-x0_k?3%2BmV%mX->x1F^<2h_?`2)K9k7?xCmj>C+FmI;5G*j498nqxJeLQ*9f(Si@kHV*aiEzr9H@k97YZt( z#Yp?^G4kiM2+#3(d+qWI?H^?|BmLft{{Uw)ohrTJR+H4zS$4E@A z?oqYTrc{Bp#ba)r@o3$Z_15HgyryON@8az})J`qV;k6DTmd&o!^34{-N3sb{gKhlS zujxs&Za?8vSU>y-&-af10OE3ez6V?z%#gf8aXUXtR9N)N6(U6xv_aP6^0^C2)7T_7 z%C1j!jA?omRM~3UM-YB%7wvjK{D5b8K9~EhrsgtGH6W~%i=+Tet`B3>TOOrY!@F0` z)Y1&S=qqeA*bXtwLz=EqJjvC+LEEMO07HuSMv7>G)nD-KyjO##pim4fnBL&C?%bdb@3~l|gZTIsJ&loO|U^(vg?zcED zF_eg;DKVk9*+Sbbt)&e}Qb{`zwmjCZpQ{>$xr$)s-KO_NFGc_zM5^HR?TUBXf}b1m zolVBY=Y!pGc-+lcsC$+X9=#3Z$QK|T-+s6J4 z<*qE`>ZV$+L__U7+2t&3rWe_0BXp=68{kf6OF6nZPNJ(ZxIB6;S^PwBQ#){1In*-V zYh~$03R=56v(-IYZI^N_L+ z@Wz4R-_nU0WxGmFcxmw&nD`IGN?voOy!@!cM0&I|tN#F+aRKXYoaV;qC#c)j@M|dB zBQhP2z^Y774HGuw-Wz?q3g|OE)2KXZ$~i;C2MlJSOz8ZYnjeawmk^}x9YN|3P)B83 z-xw&QeGN!ARN^+)KjB=O(F##2ppMGBL~ls_VwDw`eF!;&0n zuuF+Tyy3oCLdBD$5~Ko3NXEjiElydYJ(ii;07 zI3jFmD`~P&`)Em92}1eHD%E8s#@QssyUZF~wlnD`@TP_5UK`Bw(9^-9~ z+aGS=c%v%m8BoLT3;ox|eI~*U4Rh&;(Wg%FxGR+p5;=E0&+)s)?jKX89I=_}6}eMY zRDF{9jZaK~<4QwYT`O&4P4-ry)B-W^r%x$lj~tvzKdSyK>>i5MLhKrvMrtzU^W*52 zUMVASa<4_oTtMK|=Hg~-l9`jz#DxVvC9X$=%J^nlt#^LWPJT`MRQRkvkQ5A>P9dXprLys^PuvSl)S!n=RX|cH^>_*VW z9Os{O9TjYK67_6}*UiW8`MOzDb44alF#W1w1zd!Ej_dO!EQ6e&k9+U;m1z5=DhBn7ei8I8{dyK%2GI)R*y40X4YR^TGdW6j-rKY zb=7JFovo-|;DgiyfwBgc7Vt)s5_{@IvU|a5BQ(;Pr||--6-iWi>MD^Sl!XkL!5hhMT(c*)K#(Kt;nw1Re0m2v&wqTZ(vu|ca^-E3C6 zj%!oB_x_cve-E4v&fIR|yj;?%OSHVB5UuAWzLcpZK(>^jy+EvskVVbz5f7V;V?4@g(mpn^yP%VdlFAvfuKPN|d^ zWgHObDa%`PsVTJMrx;@7oUvU@8L4``jlM({9+E(aa(B)$vm| zVs%n6>}om+NorlYMvF>mlH`h$Pr9<>%Xled^(3n2A9v8e*qGSH!oV-jtX{SC6FzsH zTuDA_G?IR9P&WS6efRo~CB53Jc-V4)Q%A)bYm*HNLS9;&TB9T&U-1bAAbXwv08D)8 z?Z$=0vD6=QTrYn1Eb%1Iq#p6HT>*G!;q4cN{4>i`$duz6LL(!b>y4!@%ao+u*H>a} zO0Q(!WPm$k=Q>y#JA6v}0TSIrOR|(qLm@N}do&Fu&=Y9*5zYsEN ze177r_HxBYD=kARWpx)4t2&)mQUTnnb8CL5t_u_(Hr!POIVHwdZQ-d)yqlET$?_Ye zL}?3o=#PgQVIUCdP?4!=Kf9$?zxRc$Y(}h%*jY}3s66E6wnO04gY_ydVu4hN1v2F@ z)3pgjNj3=y@~2SUCsL7OEoBjGQPk5kw^g*m9Ol0>1=`W7=zoEkPcCK-9`Ro&)hL|I zqgboTG9btULq9Vav`J+kZbvaIDNrDbr?|zA99+ShlADNAvU+C5@!2=|{S)iLz8Pe0 z5oJi(Pa@G+q-E&AO6$yV_l<#dYdft<(r!YCk}(O@)9{{Rsw zRM;7s25tSHNkru^sP4{N4K}n#3JTGzdDPye5L>!;An$BiWYAn}va-lxd9koN{sj_v z$;Qe2IEPYmF6HWOXsbH3J25WLW+H+Ur%SH{>Toq-tY~dYU4R1XClVuIz10nNBIX=| z*5iM$Q9~~LO`%Sz!Htt+(DO||zKE|l=9H}{PLK)^Q(`T+zTI}WM|vi~ zj6U~|M)4$mc_-f^{8jiX#$OTKBk;GwQ11|A<_FN-TDr?6xU|%!JI*Nz4jZjO#+z(} zf{+T-R4fujh&ho%d-l%`S6A2-Z}AGF8wI0az0VtWc&(Y|3H3a`m}1o=IMeh44d>Gw zm1|svnJPCR5R{wgy}jNrp5&vM(uWv@!#OQciPSj zDljJElj!^Qf5CfO&vgxm+uyOr*SB9Qvopj zG%7t}M0u51@SU9%1(1Q~b;f~CkPj`oaGK$0)a^d&=ap~dGCpJkiE}smMagdj+nnYv^@K})}X#2J~C)N zCLN`4$0NxTcte(|$*Q|CB_=&Wq|cE4RHDpbCBG}%_9%G+t1yaclD3hY^t%GOf&g0pB1#Iagy3>q}$WJB#5uzvt3~tBZRh; z1f&85`T^Gk4a=ZP*#nJ`hFe13-9Uuw1-AT-31UXOpvLQx00`fZG+Y3*-rIB-R*nf; z4a!bts{E=W5NP>+l>TGRbvJ}MO*S~x~0ZcuaK7WHGKC{a8xrbSPQPBH2&&O{^69KQ)n9mf_kju>`sMr zVVHF*SVwH`zFp~8NF7}{EIom@-_1U@DZTo4zBcS5g2_DP*?20+J9}?}mZp~m?7W>8 z`ia8WrZPs`ebshMsw5TOWK2kdM)IG2w5kLo9 zYOqvDMJA-8t1FVb*!A1KD{GvrA+TY->zqFlKO+AC9C+0p1gMTpm6KG{dMF@ zs5Vk=Kmh$V*bbPH(eM7zp=;o6q>z7j{S!Ztytz(FweR~)Bqa3N30Ld3G?1RksKqsy zcoi)34I)*3tHX6uV#}8FtoH$k$Uql$Pe}y{w{mq`@))yxM7e}>A4QPEDss9=t^E%8 z1@vmHTlUp%#A*52AO8S#So+$W{{Sp_FN-9wkc0$W9=$Mopt{$xt&RF0&$bsgG?_rz zUB3HR;R~*cTcXIF`s2J4KpdBVJNEByOmc0nqNoRZ6K}Q@-u4L^HL|!1C#UCxz4Tld zPRq$819AK@#XM-P1EC{tz7sJi3oJHOKDNF%8pJ@o)m15w~Dny z{{Wxc3v`5ERX}^#;Sz@tpjP$jcD?r)LU@JFZOJ6BT!J-jJ$*2{C)kCIfOLayxJ!|! zU6+F47wbTGFi#(sEO)u(?nWnNGvj$j8k+Jsk`UU~hdVNk4;#ynZPiQv06a}@%Sbj`REfr1 zr^G)PTtwo&OifO&msgQ#5o4|Rg{7h9DU_HlscoB(ko0#`dw`$;*eevhDyd^>-2VUp z@KxAm9O5H^+vYzqR`C7|IeMR6;+KgA=E|DOF$ z#m#UR(cd+f_R~z!3~`+<0^OBz3gcC#MrAi>ETJGO+C})Rsat4Pq$J+TY=8yM_at149r|At%x%rD^HMAZr5K^Im3c~ntTd}@C|H|Yx2L`) z2#6XeqEJb;fGZ=#4YHA<=nfK&fTrY|-sInZ<8HuVBd5#3cVBaB=(2K?vO<)%QZL&{ zJ&nKe$4d>xf_!p-H6J7u$mn!9hZ;(?AcY}96qy2 z%5^({q~-apei7{v@BQ8X0JyHHKbAbxq*x(s-qE7o;JBe8(r$sOI#%C9udS_r&O1+9wHajKSeH@(6lkirxbx&UZ>dN9GmE*7=`pH5mAbb zO0ra>+=F9*NG>%>*XyCZlqB(A;nIP|%#$u0nrwG#QPQ^|x<{R-3J3)!^XcEGd^QQ) z3&YrKt}y!7HQMaCVB!Wt%v?9kHC&~c;i?@{E1DE7WVoN*T76QXxc>mAJxdS7BdLf< zANn3kRM!Up;l(3cTH0D%ZAA-7xFe`Innm;}%W0nv{{R(_aDy?!$=Rl3E8&%DPsZ_*%u8pqzj){3K1*;9Xz<_1JcZ&T zE2g~WQcK#Te$12_d4>o)#34%ZA%1IWI~3mc>52>rs6i=?LaMQff7Mfm#qSFr^s?=n z;qh6n*E}N8Gu1;jQgc)a%w^SL%ZP%O(1j;RXtbmz%SM8g4I<=Tz?)-LjKEmH*MF)P zLh3|?^0f2u1aM1_2|gP*O~VZJ;scB{YDlYb6Efymtxl_#l_Kplw4p7V}GOA2qFi6M2_9)n!D=SyH?pwwdNVJuNEjH26lT6P03{ z22iuPPymFDlyEn_?mizSQBjeRkkh(#^DhKmuJ9Kq@j8UmrB{hMU^HpG@w6g zldUJ}9fF0n81_GAJv=mXHj1bI3-&+RKVrPcrX2(rtqZDP{{ZeIx&HtV8;>4Kp5GO# z;o>;cR?d}bRW>btn+7Ei&G~Sbq^Yo{G?k~!u%DPMf_fwrr>VAM+g>Wkael5LV$otp z6W)*Prwf`aFc}H$5sQ_*xPx5bB-&3Cpi~4pWAr+-AsyA(PDoi{Og!37=38e5S(J2W%R!JFLlmJ#bjyS zDha-jMTzTdS9L+M^@>!oJE{?bsZSnCshagltz4W#3T?GIf>m_3m0TqK$Omjl!n1ay zx*j0bi$>J<@Xsw)bG1?)U&?d|^{V{IDUAvwM!Al??3;AAQln&na!3OB-Qkdzx3V=^ zTt;lJ8NE5Ki~JyXUaRmT9C=xoQ7UzbR+TeAQoc>%n^}dB0ze*8qkVST!owEqa~XDg zREk_CP(<$1{1nOJ)V!w~hWWu6x~9c1Ey{-UCtr01Ko^jtB`HclQq^;C5(%&;wka`a zT4F6HQoSbzs3Kt?8V%PUwf-j0%hgKt9aQ=3Oy({FZ~UsmJhU4rZK$VxfKUf=Hul9; zGhXHk?p8k)V`Hj&nl9Vv=8f{UcdX3IEgIV5p@x=S(uQ;?BmfCgj{ATOuVKCqQ&S@b zx+=&T3yWE?QBq|!S?`Ies#Bpj{8LIsH29V8Moowhr5#A;de0Pc&33ya6W zZEwPkLwQbdTZjfRaTN9<(qpfXTn)IrYk5gRNN>5#*3IMlN02-ef7zLU_4fTAsK_QVWIEi(=puS39{ znWe5C@Uku7jW(G>%e4A6CY*?L#u+WNlpqZyCdU4x*qikyt}LK-c50|0r|Km!w@?ZV z#sN&G)pF)xd8%Vl*>P?2-i(!~1tbe4%_O9rmIr)9U;<3a_Y!e^CR^-5NU2%wn+lIH zW@A*f`BBOZ9%YW!(mdB7+sZDh^|lGsx5W6Wh-);>wupj*!1#5XgT=;c@uM+a%q+Pr zrqN{2WY^~c?GGIg=GL9qajHSm5nMCw|JY5xGQNc2MFsC?Y3C;(kuyMFP+$qJ>7 zg2~t5oC$dWPr27+(D)zYeh7jh-xgZ7X{=?{t zv6jr;qXezAxx`v!J?ONkavG5(PH8);${Mr+3PJ7;{p@?%{{SY-W`H>_tC?D5lFdbV zq3L<1EJ}M2*@)zaTxkmCx)Qf6Y^5!*g{36^@=lZc*0>lG$Y{*cnCcf)NEqQ@Qdfup zIV&WN73Hd`kzJn^4pr()kOQs6AfO;ESF)Ybqz=h#1Z}GL8!Zb=r{6mw;<5^xP{wT= zEt|iP^W)sL?Z-YA%Fj6`{tVLUZ&F~-(z#V=F}1r%VYMW=sRGHl39w32ax9=Nwkn$` z2R`m771S-92#K_9)Z38YwHunaSC%++POCjbrN0WA!|P%Mca^0`0YxEB8(nT6sFT!^ zZEIUe0JCnfGMoFlavZ;O)Nq?AH9Ing)lhOpRrw(9>fQ!iw^-0oU> zBd=6p!b^x;iOXq-oE(;?4xZs{T8G+o&7QK z3!Nimei-J=zgOZ5Zz*mwTyAYmG-iraN6n$7HnlL|Q9we93#D!XfD)x(Z<&F-P5bTi zRaBU4wGy11HzZ!)x}4k(_(SlKIZ`|i5p~9R!BeWXgwKUbf~>tuM0KR4Ooo_RWD%im zH>t-7N)nKbAt}UWb-w#-JBGg!w%@^MnnZ2|{L7A>Kq-ge&*7usyTUeYlf-TUaPFs< zGat&BD3MXjGHPZNWi2XLj${&`r3S)E)TI!eNdy8;2_+zXff}dBR?0}6=*^mU=V8Ei zb6UOPzlaVw_~-FG!>qaCjojh?0Hd}=uC*&UuAUx<^+||JROir!^dy8o@(708OR}CW zETjaIaJBDbR-<9F+;u(6A%Pm2$xbr%-U!-DLE=Yu9d;a(fx-OE;#b8Z94N>HDXhnxg09JIC+pl|0_azM}5)xE8A;1)N_eqH`6O@ZNJ zqDbSbaV!n%NZ{g5-UHOB>*A9;WelB_=^h{QJ2dKPfQYJ@3MxZw)8c?jEtZ9>R-|eK z^$1zql5y-l#ri5;Rw|r3EEn@$N$t<2!e;)7r*p4$wgE!CuS8a5uhQuM05cvFG9N>3 zKI+40VI@EkRCXO~JxK!}Nc4*xj}D}DOorCmysrl6<^udiv9#?L2Xnv4`h}l0k=6Y;ZfG0Q;W^#{HZw0aZw#*33Y9AIjCtN z0Ju4-wx;!JDJOlmy~ZA1<1Rq0u-Vx9Q6brA_v3GwGIufulT5Ltkz1qQZ=dkhOxu@~*;s^c# z@STjYkpockMD=`=59|?7LQ{1-zfzDzfW6eD`{Ol*Q8r0#{l04WL~0+^yWQ^P$#V|5 zzcD^#MfapiTaKxG$5d3~>n7!DCvv3{Nx!Z)k~EQ(Y$?EK(@P}<7Ko~WTd(UbDBjl| zZ*R8Pud1rZEE60_b(Y~i9$pd05i8L+v7e~1SHrqPp)}ZTwomPff>m(h!P!hT*2H<2 zq;yHfR=&He85!n#xp?zc)w6Xy?mq?4WN5(&0EHX%KKQGOJL*TxQboVma%`J^rF9n;<6%Y+qLO5Wn<5owN7xQS9> zOhKl)ZmhXYSp+hpdwk1)B~B6aB!lu&J@0Sx!CIRmwcSx7!1=u1_~WWTG$DBa4{LgN!;7^*H)+(X z^>qXS2c|i}J=fx`H|V3Uxc0{c!Z=-3AgL)Qr`vpXWLVhTx}fzv2Ae!9N)yYmC!oIH zpIlVdKWnQPS)nVOPCl|K{vmTLxXh_+yOz+Turz)cT-t+*B)D{H32OK0sDZt)@i$DN z5@Hg{H0_bMa{H5^(mFgU2(AsIvK13gWq~ zJXPaC+o|_BZOBh77FK`&{`UQkTsXZmClyikZ)ApE2+T2&QBHM$1Q-mcW zS}%1%ZZ4s|IjLF>%f#DjSbFXuK6+dk?p+I^0v5Tvv{pn}hk`Zn$q?se4!{ z78dP<2VDw&Vl*nnSPPV$&+0GR38m1oYjV770RwY(SP|S{2`G^X>~c(T$7dLJceHj3w;vh z#z09;^oP``mGf&nIkl2=cTm~wXjwcMv{~O z=uLndE3J>~k3GJ(E7e0lfq-`^W!d!_g+_oDl`0Dr1Zh>Qo`Ouz;BrTYH)Vm%ub+(gbC4()FVv;%%0&ios`{O0j zrVr3KIPv(Ym^3Bz47u9p;8#!I1V`pS$Bz?5w8LhY?IoFozF{t1YKoK<1JGHcx3_Ng zUdY@-#BStI{Yw$;#t7X_9P#k8d{+1KCR>>%vha+Ax`#-*iLe(t-}w9E=(23v@?R#@ zK;td>qI!-}c8>tgc5r#nwD}0~pmf;%y>SvLj%_sxWRz_UCiWpEkjYYl^#nVr_ckQl zc0Z;kwla3nRz1KDYb%J*)}zhPn-Oh@>C^T1!3#N|wZw8OC`N?n2}<;-I}2Xcw)V$5 zJfg!@%yDrJ8Y~NG#hcirK%KAK+Y#SOrPQeENI9O8mD(IS%`Qbcdqq**vQ(b>#^9&W z_ZX(G!-T9Y=B+6!`nP6p)ko6?p_kRH+8w9^aNAmvA9WEzlLIUx*KdD7-+*^LT-lsjUppPGL@+ z3ElR_>OljjJ-rRRP9|Zvi>YM}9_iojz#RVU5N6UaVkj!jm3x~VhHSg zvFcGs94;1vP?R}FxfYL7Q*~(W&dajV^3?_rZA)a3bt3x*5I|Z__mVpkfz-lY-pR9u z$MfQYD@h%l*Fe4q_|%>vWg5?ho+#Crsn(&xZQ4amO4KV9*pnENfbd^tRDW6C!FIWFeNCEnAjC+*9gU zQVLNWM#rWpB8o|57WY%JTK0yPv|YhX`bUGzpTo?XNTrJ8>h)4zEy|4Pt^(wi!+~Xn zTiiDvQ6!DjN{L#ORfMdK%#cPkZ_Qa#(8u~yEB)ts4+S!4aaA8EuAZ38%4ux4gs@ZO zS{LOgBc_{deTE-c;u)eY3fzvwI-FIHnlTH2Of zSy6&YR8olzyh9~cBq2yCzc37A4mnXRQ{bvMe&NSV!|ph(4R=T5F*d4}&1LN2{gcG_ z9t%V~U(5VS@fE;s73Q?nqYULTp(>*)lKkMCN0zc#N)oH7DQygmEp;giAd`Gvwu`Em z7YpgX=ipQ{mC-Y=Gp<=h2Rct-$u%fZlzA+u zEVh6Oyw)HR5~~!0z3vVxr>1K`4A$shtIZ};vrU2K6YWFJlTC7`&H zRF9#i#k&9sulB>>q5+|n(~50HS#!&Wfbd&#@I~TJgnSXqnJsnaDKXVnX~{Ke%B8x5 z(_1MVrX5OBJc&12fF|WhCuEFm@aZFCdZ2CJ-m>#Z@ZnKw>$i6`&_r$^$EveVlTWP3 zswzVYl^f<(P?fMjI`3^uNCh?^T_IcTz5^(A%Pp$e)7P=h4{5MF4j<^D2a4V_GMdI; z;jKQaCCYsw3)5%E3l0Y+%1xU_tyU^SB-r*YDA*BUL5bBntPR`&V6CE^kwf0|bKsg9 zmjhwujtOQ65#ec_I+Y=a>gAx7DJ_+yN?F{FZiBaC4{SuMn$7H@;L$bC)La#$YR+Jh zMah*40u`a;AVSn*xY{02xmsJk=U{(PiBmMapzv8kOeyDk0MuWPdW(J^qvou|#0mB2 zwLHwuT5fSlA)mu(ZUty579B2-Z*zXQvZthtwsGB5Vl^*w%SPN+S>6D0yb7-fIJK9m zbh8Re)kxJusla5z1}6eo)F ztJMlyZe`k3)rLzf5TBU}QZ%Vb8mtmjR*-B+9+$vq4w>D-O2z5F^Br47+qwMNY_h6a ze=XHgTr7ghfN=wM&8`%i`gQNq53Os9G~H@&X8`fZGTb=K=rihY=P9mxZWXCbf>NSL zB!h4T@Am15RFYkm;;Aa`%93{nibe76yIzS7BB<2Ys?(WMj;KW(#WvmTa^0@yp+G4o zR>~bjDWq_IgJo+|+JxBevPE!zhqJhX_FB*R`YmdZh)%9VOuMpK5=WEfA6dHJ7QTcz zaGl8Y#Fw-*W;>sP&C@mWo~`;cA6tHGrHx){Xzj|-h8DM(S{g-wEBrNC3AXq5?QB=F z<<=`;#)f5h*e-13PD8baMBKugo;?Kcm?p6OzPVFN~1G(bGY}VT(to% zP4uhrRkyaIi}!D$^X8Dy5{oW)gQ$3VTb0UoUV&Q`HMdW7Z@i}dT^hC7B|X=s*Y?MR z`)-xZrH$lV0=?tdwQ*$fz}sEGc-V4J=Loo**Anv+l?P(br)D~m%hBn=TINrtTW(wF zNGU@gC={qF=Te3G+vYhYF72ONYf(;`ZCOsZ4Op;DY_ zolg=q0N?kNl=%(29j(_C@iEUg;;!oIBagC4EgJs-s?m3g-YwCqd6H^q3Q40gEnz`6 zN=ae^xmrjZVvGWHQr{?X4pwl??fk^4awklhm2$UnYXI3d^{^+~(-n@K zmujR^usrFy+zWH3WgZi7@J@|4<&y>Z@AA}9$_tR<)Sy%}tb_!e7aFX4fs6b--^(Oz zbtfNxS2J4S?zAYwk$9D!II+dJFerI;vr|tnSTxr&P`D^BuGVRU+ggfMWgRIO)w?Cc z0Ck4n6%z)-=AFgu;l1<&$LySc6`md|97D}n1uv^{%9AQ%A2C-1 zB|4Opgx{BC{umltx!EGbf+|}8U8(%hUOK6ack;(&z5Dn6Y?%!0;@^pp_={i43}yB* zrcGe9r!zC@VG!Ghv?)ngJo2Qiz!RXjfR!D(%9r$C1o*dz$S(bHQG*&-uRiCU?#F;P3SCJ@7 z%0g^}1uDT>lyw`Z+**c6^Gnyb_KMQdNZ4t`6eIay-@je_Q{5LJWfwo86?$b7JvrJ8 zdYl?M8A4Eq(d3;DX+XG0P-zCh?031q<%||ty93D(L;=n@Tg!*ZYcq?!9do@WG~v?Mig$Q6wOh8*0b3dn4&{X{x`6NC0cbhrjH; ze)gBp$v;HwMTEJ*=T1yI50Ak}-wr$+rBO0{PIhdkGcLJXf?IkVmO_##?s<7z>=vW87J0iR z<~oG+Qj)k-=NVE|!%x1IejB8!+LOu&SaCf{y4)LJYh7a7=(HUhpDW)R_14z!=VbEn zABFi}k992Tm-vlMMC_U-1w&yUgrK%`EW92Bl zw*LT}7dzZX@es!Xo0E`#X=g0C3ZF6RqGQk|A}f^#8d`_SKBbL8qO>3+B&9=i?iII8 z_C(`zYw;VbODiUG8rF=(yAB>}QywAwKuU<$5`0K;zP8!S6IA6&dXSP*%57%YVFRd0 z(Ap9=B=;&O8To2oTTnFa1M}jnAf@UfEoQHIx$h-%x8jqJS*wimoTXRfMny>y7b$O*x#S$4oV`^X@9k4 z#fpTjF_L?IM0Y>siy0^C!ExNHi5v#XY^97qlLLB_8ah{Z z6b{~VbbvibxW-o!t1++^p3|@Y?{JbiZr+;HEwats>;x#1p^0=HBS=^mHCL{`}{SCBJZ3gDJe zJX+4KXS%diyO479u3QFQXy~d{P(cnR`z@vp=W7>qr+o_;_J3wQ5H%Biu5s9I-Q{^# zPWnzM<1oT|ZukX12KPFx>Pg?h|k}*&%r*z$%5300&oloFM@*vN#I_9(&qpbB@4h-s1SLtZmA*rg$tO`>uL?LPM1g zjhUA=MT<{Fx?Wjqp@41_<7=!ow50h?pp_|N+g)1|rr7wCr)A8kkPQiW`Y*Wsp0%!_ zfRp_zoqrJ22>F_m!YbOO>jNn;yR=iS!K-VJOLRM4!~wPqgXW4Xq;Xd>RuZjm!}-0>CdOn``Q( z1q+86=Zlrt9)c!1SyB1IO75y#|&HTcSOH(+^M5VdO94Jy5eAX!pWy0NWn zO}nqK)ns5X(9a~b4h>-*@!P}2eHg1X2Pzd>o9@egY855rHnps-=_^qL6WD`%eS1kC zR~tpGpkEbLG`a30T}mwq>aDMRh9%~@gKm4Qq0kDfKqICRz~03?SPSu0O7##gYj(oe zCWCcymNflB{@7NOt~XWII-4uf=cYQ`lUxYY>bw`zbd!ZnwX8r@3P`cCPkx;-#N8uW zPO7);00+MK>*$lK8I^Sqb^_mf+Xxpp6SDTAH2_FGyW0zJl2c|YT_C>e!NYT@U#=5jqI0fIiuSt#K|huhk;OH_+be>}CiWz4jw!$bz0B#i<#Ucs zCgW1A=6a|AJ6jAOBpMx8weEKp>Mw;OifP|PXjo5i{&~J5R z{{VPe=YF_AdF;C_jqi2k6ZIhTa-;6?$yhkGK0uL&+&sHWI@~Q72~0?gbJC$H;}NZnx{@^?1WsrpLnP&@KH& zCeY2S2NIoLJNP`}R}6SpOX8(pEisfbv^uN^Y_>~^ea9bCl05FKS^6$)l%)D#l#Hp( z);)wYjn1ALD*Q8~RMX7rc04)OCq=E|G|rm8mqWoTQ6ThBn%CPFztXkb0J@TX7jnG( z;o=t~WvX0fWUfo;3T=kVflZ|aS0E5{-6$r;{{ViN&*Qc(bZ3y^_e&AeT|^4u8~EJKHF5r;ZV| zf#kRR?xd1HN*vX-)xWmb`X%gX=2y$1nDq;Q%V&Tz2h6mF66s}?BTITw$6gC~ZSakNqvtt)o_dJoV{EE&HwF{+VmM^d$Shsu@HkS(^ zxuLzQdMX4dZde7N^aj@7+;qa0Sn0ZNS}(5464IijC=;-_J&)Va;9sY{rAu^zzydAa zfk|zmrpQ~Q*r=r{*bj5-h!Vm#3RF{HR}|Ritfn&+B?dK`t;JtH6NN`-I%rY;;)cia zJ+Yj}FtIdtBT%m}tVF{g*Fu??@_uq4ea6BP*1M^P$U#>qvSl$S6`sxG5sr;4iV$ihFm>s^(|M=Z01AkBBmJZeC^7 zWV*|yK_x$j5>33x*lZQK7w>;jjdwV*kcgg3pJdSfxHfX9KcyaPHvm5%CH& zT{|Ab9Gf43;8#L)>dsQ}X~61!af<AdCp;5RFT4-us@hM&JH_5&IXgUfIL&p&n_L)dOrX8zXi1Ez0k=5`Z8uTZ^3E-_ z9n|>*D^A+zYySXQP8#ocETdpJbzyUFl1u5xu8X`DcxlVID>m^Ph|WRhW;yRN%S(`z z7ho{bR8WMvvZX0X4i!0LVxR%OorO(!*h_h}zF0|3K7Jinec8hzCH&o#OgE=4iA zk_4AlQh}?>^$-W;(%0#?t}5SW&$`rCNMeLvWHx71T$h4du%KT zRmlJVaVkb;yIsKspZReK0Qa^~SH;JMDo>5C3%o+$j9Qck979}LFXYO@;ItyvgGxz5 zD!-MrwmC-EBT5u^P4Sw>C}e#n$%{o*OlV~;x{}&yjp|mVFT0Ael&b=E zPhpD@g_yxF((1ClOqBT@rTB9{MX^l9#!QpJ+>-WZ%vpvxsB@cUBPw71(D`*17Dy#Y zN-jXPj>O_Kp)Pm~7w-C~n0-919l$07{y#*oX1aw=r#-kvR+oz2Do9Lwl9eoxUPbSW_!r0bN&vg1GQp!^0R3otLq^;&86bFOp1u94&gq*&hV6Z9g$^a<5;gOQzAChZ*MFil>vzTWzI45YE;}BW|YT17W@a zTpZZC#_9^t^lqW9n8NJ~R+}@{UZn=P`q112Jt9&P;t2r+00}m@P}F|dzJz}%r;u4X z^2gN3Td^q<;hQ2+;O9KGl9+LbuqVw!OO+wQQr4nB5UB5{n*sS^Z9b$PN}8}};xxHk zRrq|$w3u~D=2>bw8l^~}I)pYtQnJaA(Hz8$we{>ax2^?CA(^s++_qHlHkxQ0!=}D_ zDH3w69s{)GImvsL7TSZhHx>jCM{rUNjr-utFS?&KENvcWb#AC2<#|YP)*AvokE=pT zjfM97y?uraR(lpH*m27JHVal9Hq9Jg%zSXobljgzoi>^CMYjZ`ks2b=WRYHyZ-<%1Y=ux-E0>*LiB+NHf0+H{g>gCiOPusybG%U?eQ%y~Nrov*8%V|c)7dIgzb7B1Ldkia!w>zb# za}Ba+(4wClc;v=cYNK7JNr@tRNqL4EblpU)qS`coZf&hfx!T}$#kWJSSuqOc(=cdv zJc6(3uSg-Gqjc_fySI5-eQG-{&Sh$Ea_UJI@2ekh(?ZzT)(wS%_$w5xbwsjG{oG0Q zM)F;}xnL&8n6tP1#}ec^+?81qv>JYSrjLy@HRf!ECYah?eZ@?UQrlpaER__1E#B$_ z9!2enl*xp+jvB95_DD;yh}aE_v|Fg~f8pCKcy;08jY1k-&Git8)wzL{sJ$yr%_T=< zHrP4<{pD&=z47vFG?yTs^j~aLRWh0$ram7N%`f=lp4p;svpMFeZ>9^3#C6EUNLVR$ z!7Y-L^(?7E#B6(7*szT1c?FHfCoQMUPiXA4t-`)EQR`XMWvETpD%DudqDhwBl+yt_ zd9@{5kUXa2q3w+Pv*&Rqik*YID=xvKcQ-(MR``riqrBxE+4*@Y3y!rnp_RHVyL$p# zHyVw)g>~#?Fo?%zQmJt|$4v4DfUP9K;P!drhHr;YT$i9^pzktM%(|pGQgEHp6R_oi zK_{xM&~?JFhPN>HkSQs1Sq#osvV{w$ z%t}IcO_E5s-w|Z9g0*~3Hg^;9Q{#f10(&J^BS@;W%&glXrqa^dH!zmtV1!)k76Q@< z>`z^>96$)V(BbsvDLSxwM{>4L#?BAtEc)hL$oWR1{JK9XG&zk((1^%oi(SxcRjjEZ z#^&i409+G(@?)nBZltQo@bg(-Nzs7b{v4E@;V%d>#|Sc$bgEG*sJp!RYE7J$yKix8 zgbs;EPr13oYAQUvqq@@8)Um7)N25o_zr`SPS_WXR%YzC-(i0VWUP~^6p+zIg;zpFW z(&tK)2~SIsF?Qg6%h_VfOoh+2$HVsWTItT-DRM4G%=x)FpXIoFnCQ`*`PntfJjT92 ztRXG48Ev$*Om%5UAuRJX**CBkGNb{d2OHbd&1YF(qq68un`?eSDKei5GZz?!R?JzF z4ra@gxhTe%s2UbR*HiLahbh) zY;?HdK5J_&)$(TvGF?Wgn`)Hoqm<}$rzXs*)LaQ-6lTyC^4B1M5}PMdl%u%=R`$nH zQHd>-T$Oi?V$jpE&XnbAe0A>p;+UhyP8(*aJTqas*`l+WqsW~{eZi&as7qzW(w1+i z6}GUnIbsSzzq&w<`!u-j0kzd*8eH(l3plqmxcoNJ1Xmw2zC_MG8F&>@&5&N=Mss>^ z?53PQiBwD$oN{%PJg8E1>pFnd=Sl*vwOrSZBJ;5}R+RM}eM>3YH4Myr28ZHOKg73+ zoRz{+Sje@O7_8PRY%LBjRs(TjJ*~91Mees8El5yEHwk5G{m>1~B^$&hvBxMIb3E2s zs~cpKj5UqSPrb+ku<`jRK@w~@uqic3ETyNHPe?7H0H_{clof1Mu~7h!1^uxCnjGzE zTFg=AIUX-^v=!sGhJGPyd~%}kH-`CtIJ;V}&|$LZ{%lpI-NjO$?pXj`Jf(o)n%SmT%eC69+adxF_#3gg$Zj!MfEZY0$sRWtf&t-Dd2 zr;xv#a3u+K#A!BCg0Fo)P&eEv<&@oHV+LKy(bP>FUzROx`EaEyD*9@yQmRoVf}sd} z#B@1u!fX^&6hPZj?QO-6QQ45T1AULO3Vp?Y9c)6OQ zh;O#P!ozmd!Qc8&)q~EZ`cSveKo?~g)1&zRf>P+$t$s@x0E?oX3o-5>W2Z(L( zmm$;=a?W0r{c+aFD3w!9_TOTN_rL!DMgIVh99m%*b6}6Ge&l>Vb*RE9`sa1-8gTI9 zeD?71TCtdgw8|;%tgXfQ-BpeK?t7DeRbz?Zg&m3#pEAm}+uH=av`Lw}Blh4nmQk!IIlb3@{{ZQNHpLE50Y)$*wH&D+ z3n=Qch3s$Fe*Hg8J0T_gMx=mZ+B*?Jqm}F z4W#vTXzhG!`X$lXYpNRvZCRZK5J}Y6_Pc2b$URt4LEV%&FXf();!-mLR z)P~dj<$m(XB}!LSDN0vUkFfB}Ix1Kj1X?sNm@yneTA7_Ro0Ommu(%2yIFEDF4$#>5f_xADhj z(R559`FB=NLnfOun3wDky^bsDoKDKhAk3!YZ$+R_6;%isV?FUhG(Ox_#W`+0E>lum zB`JN^Doalx8-S-2@>G-^DctnA$HTtRCVOk#Eoj3ql$0~ z`4@!I(CZAj7c4f>5Vl zIH58F(pf3Vbv7K(ZFZfP0jCmul$Df`-uB0#U@?c!W3`ISdrEk28++Td->P2tG|bhU zvGHi|{Jfo4s^zxlaW;)dmLk5UzG@7KEj1!LnopURP^G0vI}oA{4T66o5{yDfv%u5E zB(O50qi3%H-^(XnU>hGL^aMfjAzHWVagVIQ8U^t?z~1_y301n<{{YVl;eFAz(Ogw^ zC~wztF!933JV+}lRbqDr!dBVfnBfC-JfT+tlN;Uy5+oMN)5KET4YZYe^SK zMa9>GhW7*M*ea-`k^!+Dy>Ql^XqmOqS`-K*o18w$xrY2# zw;Nn<*4SoXxw;iXq><$#9Ku1>bJ_x^Sn52BRj&NST`o(-|uX3wbGC;a1{%wAdN%U3f0+w3cA2Z8m>wFurPS1xx5#O!RoF4 z_&{uK0_>$!D5CrK+i&y3UhC|g8$i`srI0{7etmHEyEer&&C_41@L$tqepqRBuXW9^ zb%9mZ0UIArz8i8y)A!)5QpvDR#|;CCTzNM|&By(uI;6;44e;#L2jxO}Rr;mfX~Nym zrlTcDB_t9JlX1}4cLN?n?PT64yidt{zp&bNIdP-_sawjA7LII?~a91zYVS5TE#i;bXfuI)2DM#p-)4_)3JsXi0h8 z??V?S(K1#3Lk#Ie&FX_j_g4PNV?V?kPxc-3T$;-SPnrq24mrQQ&M|D*FQ*yqg|`3o=`#t#Y$VQD2>XLqu+Xdm|2wM05=M| z2XT|DFS*s<3$B2^49?b^&t4$v8G>46O+Pl#b+*D#vIQSW_E8S2e&IMTvJlt2bz@6A z{{WKA`)s>dz~iNbui&@3?^TyHv2@t0uKxgG({A|s5x{IUUoo_~rsqTn^rA~EWlLU_ zTodW*hB`Ytv=iAa?_!e8Wol|0aV08IS4)r2%jj@XAsjSO`i5$MsHW}ID^i+B)HM{1 zjsE~Yd)sVTk9T{jNd{Ni%Pfd;W1+WJ!DuWHFZSwfj%|ss8mDz{Z)lAW2NsR2k~-Y< zx3I(PEw-pVqI5wNmkNd3MafmHcKt>G>U-**XCNR?G^E@(P*QqaY;g{zGBg2ArIb0> zanUfGMWUjVwdR;Cs34Sy=t6c^k8F9jN$_mLtY}_=(Y#|Q>fPj!QWl3B zY1Y&f*#Su-x8EL1Sx#8%S$btW;Iud*DF_5Obl8p0xc0?NjkgU{(POet%xDxiND98d zTc_U;BxS{v$Yce#1JNerwRZGd&1-MABDh#t6Ra1%6&8F+@LrR~P8?=Dp-^Q4L+q>N z-qCW~ok1U%2lT+%A#22pI)!V7))-%!_XToypE5;XA?BL?RIWr^N~8%2j`~V^fPAhC zbqW?go;^m2v`ZLxn#A>pZdZgwDW;FvW=6OhgTV)$J0=g5k!8Wp6l8{yDtSENIKC*`)Fdc@i z{{Rm!ExawsW^qbx&syJkoA z3~~!RAA$YT`{IX>lzfk#;8G*D?D;5{5fc)WwW1?qNh?`d0VIGdPTft#jxx~@Cogu_ zTdZxtus1KgWg;?$X|HDJ6&&)I2Ah)2KGe1i%ksk2Zfk={2ug?0l#)j3wXKPAj>DYs zsoTK{fmmD0>hP*8p#h@>u+(U%alL+N1q5jGI*KddtNg99m~o!yo)Uj!q2&B>b!bGacgOD zE&kI$eNC{gau&dJDM4s)3R$>t+Oq_am~4;D8Ob5IBU>Gaw*Yt3j_c5;ua35vq3-^4 zBF5uV-Nw6;-dwg^^YFvq(eY*Bc5RPZf#9o(dA2jr6vJ{d?Am=%oe$j&z08j#No}?0 zP!6bsl#)TV_|(?pG_Gll&&qFYLHjISTmq^fW7Kct64!}82M>)e5o577M}Y1&$>uub zc3Ww1Trdj;>PcxbE`mr;oj?Ux1m4(-4OJX&4|DIQBlbkY=`D7&8+Y7q;=PqV1fLk5 zD(41TPlJ5>M?|=cHva(a%KbhhB{teZ2~(W=gp~rTX}Bu3B+}xPuWh4v=dlOkhfzpj zYgv@sUe*^Yc02|D0JH1yI-qeghA=q&#SadgD&ZtL35r!3t0OYYk0mXnC!X6Z#~yVg z-Nd+1ogpNfgNK!+l*A7aWrv-F$*N9r~ySxqWrnmL)QXh?94X!MBK+V)ONa8kG z;`=o?%BqJctw~|zG?#;GyAEpQi|&vXzbHK|idV?Y#uD9aebH+$N5>0lqJCzRU@dMQ zDZrsXsqoI9Mu{3LUnO0sND+#dTP-P3l%kDgdYldrNh$hlZVtd=t|69D3DldEgnuQ| z*xNvS)RCa^Su{QiXV+zZ&Wo8Ppu~?5xKw0nQi{q|U~S|#9YxYlQHu;t#t|Ko;MG}b zUn9=JHTgp<4F3R^8f}-?E=i6PrIwYgPH8@yp0>5RVDm`W;>g}gww2D3VovwsqyA6J zm1;I`L8!!=PLl>!k{lWo3SF@(O}wVSE2Z}sN_oYbBJ4(u?R%ml=(;xWr^Lpqvoj8G ztVnIBFzJlKTFN}7Z#bJBh4)Nxx1qizQ--!Ty8iK2lr>J4SlPlbZ}LfwDEObKP&3?W zY(?IOCG|orpng1ORzPjS(vm`w4x6@iT2yRqFgh9R`#X-x&mXJ}0nwWQzj#t2xtnKH zDR3z2To)uu04Gri<}E4IK=o2U{s(L=RORorwo6AjWErn~$?f5mU1psD5}py)A>?xw z5{)5Ox0=^G+PKK0~g)~SvHvuHr6MxXy?~2*` zB$cGAb>R&g-8Wf5`j7M?tTRNqgvXm-_#hZ@GgA8F3 zxsKa^1i@zy40R02!hG$-2ISQ0x#e=xS&YKhWV1~}dRHB`#>9eox`@=G7uWzczRo&C zFuKwumTAZ6MViIv>1Lv~F;gYvB*JmXGjwIDcv6J&=jpa~|)+WXvM z6-`y#G98xUmj)5j+E#+&t;V`?3CXBrOuLp}kyVuiA1ejIlrZ<1dtEKGqkk^x0@k^) zJqG<7OU6>G4w+SXkB9=fG320ONu7M3vYWH1K!?)q3t$i?adCHfpFeCp!u^lMy4{w zDlEvX)XGAfNp+y&TLR=ED;t#&pjaI@Cu{g(=xplJTBapC>6S`PU$xQ zUS&Lvd_7qP*4vMoTAVCFRLOG-mkZl#o<(fNMH*E{CdO#VLv9AppzwUQpq)BRtlh6< zpahUFYwdd(bfxk6t2|Yi->%p5OKhUUaN*Xd=Tewp>C}_AFG$$h9&dic*3JjR#RrZlY_A8)OVKpRmIO~4b<>h ztX17vY?iPau6HTkKfFwF3Z0(v4Iebgp-_`oauapo%641ScEa04ODHKQUDU9rQ|9uw zW3jzF__3!s8>_q1BY@OE9P?(K$39x}@LHPqi}DxQSJ2YtD!|785{i;0hj)0R`}$;k)d6tl#%Bn5vM!u-%61JzZAj0!8jt>?6kk zAtWt3br=*awx?B`016To2_pg&`{h zn}KjaC)*vBb7Ti?`_YR~=QxEt+-FqZTaEt!h3|$sb^~kbo?(ByLZDQ3TTF+_E1BL6=lWbxUsc0{7VBP+{wsbMTy!O{t}aj)aol|KTkYR$O2dWmMghKY^H!0(4vje9Xx;KF=s?5h zTP>{w?g2O3wm!7#$hFtR8OGqN)hVBh%U6$`ro z^y9MYbkc5Yc2zDVMESk?dtq*zKqEq{&L9m$56c`HI43xe0;e%3PneXX;Y)d--r7A? zE?8So!yG}~J0WVjnn@#7{dVt$hPK-$w>GvaoXuMW5N+v)?V?Q!v|i>C4Tj%rIIeRI zwN{rCVznqBTfa;uqfOFA0XHg~#4II9DK{N&*9tT?E1u3RS91@S%x{DsUqmv)z^nO} zw&aj8$hP7)R1aGAHoo{lei0@m4km_^mT8smK| zg3{pZ#abLa4gS}{_ow97QmL$xEOmQ&VQvPiwRaWZyX|p&G{1^?Am}t+QRp@wY&6Ni zHRF=zfBw>hwX?z>42<2rL$%tmQc8TqNp3Og>0{F#J?&}dtBHi^bMjvM>>anNncv;| zqEChM+I%x*1f4-ihS)bg=NQZm{{W`ZP;~vE;?m!mLVR4DTD&!7hL%s_XR0s*xAtKS#PY6BEKsSc2Ec-DkS+(Q^u}}AAtIRN-tGAz^hYQSbG8}&Wp9_@xYcd0 zBKVz)E*%^g$XHX!BF?P-%u2alzu6#;`yM<~S^&4re5BU8{iGB)Uet|fHu9Torv30YL>p&wPi&y} zMU@CPP+pN_ok|w~dUosIY&0|tkC9F;a2oPNEz@B&Ait$0``D>p<@(~lxcMs50N3JC zHfU(7Dijf=Nm<)%zdqv+h+9%n>Kx|+2I&K(u;41!s@`CF9=!+VF+4^KtgCv)2Hfbe zxUD)?G@%JMH|>O$D_EvA!!5x4@IfRUYfX)`?{GR?_rzL&9c!Y}z0D+)LsW{&*m<|x zOp>5eq}T)=^qbIsCg;oj`Ocac|CswO@A0HXm_oepvB- zkzsvXiC(pUVp-Y)HAQc>q#a6Dq}bZ{!Bh;V#cY@nOQ5L=H${c91;8CFq+AU`B#{_` zwQ5hG?}!pK4hmc)r&O7#K}*P3Rg?(nZif-v%Ny9EG`N#*_MQg`i-N@Iam ziF?D`*w$N_HU&k+IhSgU2$S1MAxv38O~^;1jVuME{{YNCc;Xf#N@Z=^qnoJvcpZ}; z7}4Cn2=iSZctGN$PCoF8slv?fDYvslIltMH6tx0Ys~%L8`h}zee&+tTz~XebXpyTh z!}@xRgGQZ4hc4?WMew8J#XG@2j@bMj;w4&TCx%(A@Y8NOwV&CuTjmA;7t$D0ueOyc z-c-1i^g^+r=>2J^h{R63Jb8JlUX#)ad84jtbhr-i=DHG}!~QPu8{!GW+|y0Zbv(C_ z3-YH|*o>74Gg&~;+ij-B3qrRAO6Za07wGIRkck{$wYKl?Q+h>H*ET+uGYV*ULb~E|&jJb)G zwA^?R*m>rbEg~~TyMRT1%Tw)3UC{rkqqT)ziyD2I`$*0 zYKJ|hqFBiwU+ucv9$fJgGd1{L$ox#p)jC+ARC1ePme(n^6zidBX|l`f(p#`;ZIu(N zPzv(f5V6?HUvNF^5wd4Q>$6idoda$S`F+q{74f@>%r+?;LRB_qe$yZJr9Pce=QzMA zH+>7ZD{O}Dm5XZB2?$o8MFZ}_Y;@narkSN|fD^yF-V)897}7HL3$y1Fs?rq9WKVjF zm!nK=FUY99^35%UI6}}gg{l5w8ill3cUC9UG3AZ^)4l_}O@^y1?{m*$J^TBDkC~r} zxt@hpVzZkwoB4&gu}q{=(@sf?P?mwEaul%QL{{}(C_pO-QbIyED#nJM2;#d=q<&pf z*VoBCrPv-^eqO21sW?XVTq z@YxcYBoCRB6Wpd(Vck_ckhEM{u zfY%2)Al99?Q?LNnR60op`UMoY`w~qH#8(k0iiIWiWY1=NW#|bBVfIj_ zVy6s{b$waBg#Fe308AoxT-V=1(dsu_C-Co;Y7jU#GAb^`R-sc96qi6!f)I@@EF~%g zr*#qTqIv>xc{q1g#tp`*ivs{YM;$IK6&vuKTjM5hr{)H06Ebsgr76iGOInmf!TarvxZ_O$5IG{eGZ(ASK z;8kxuW^I;}4WJCB>dvKGmMf4~4T^+kP^5B7R9go^$u`)Fruv15zSqR&G`F>V3WF1a zjzT*??wLL&@m`-1bAp_vxZ)9|Np;kug@8@>I*q#60(}Pfi#TZn?u|87j$8Vs{{Vy2 zDtuImWYy@BC^L1U0Qo7gB5+V|;*(Z*kJR*SO+Qq3&6`QpV2K3U?{bf856G2&L= zWuOi0km<1d+SvPJpf#p!DxODba@*5I@t3vg20@Ng28#zA-lJ5&&Z#KOl!T25=Pa8Y zj^`eNW8HZKZU7B-N_?p~=`|?S7>+c=`k7QF9$SGew6zV2t`E2!^%U*}$oc;O+nrHm zJWLxBSHF7`r2RybHK$Sl;I_lytHVWOgn4?kR?PXveqhYi1*tB+wDQ#%jXdU~6h(4>{(zJejV3)Nkcm zTGZRRh%y$dj$(BS{jazl=NI%4k~LTiMy0uXK3{brxJjHcX9##~$||{z60;3Nij`Ek zCqs=iuOmpgAGn^V+>)bVVRL5{oZ|9zKSX+(_~VI`?AUL<=jNPz$;9eCD=Rsf5jibH zTwwD8Lq#q~TCNg++N`T8=>#gnxgZl`!uGh`L&T~d11BO5M<|Bk|b910GTR4 z`G~Z^9j3ljfT9wmG~T1;-|FdMYn$P(n=`kt`^G-Zyx;pOfNeF?edq z^=jP;mzXLr(IKiT(x+!B*2{v)NY+Zy?v)Uv*aEUU;%u{ZRxI4CEj(|ko$x>1Yqb~9 z@mpo!MpDZ82PtH38|A#Bh

zJ%^iZ543=X5|MV^SW-fjvecy;jYM4U=7wYJ*}I+j zt;b(?cCD48PDA|^X7L^4FT?9ux*rC!7IetmL*fM4DSC;PsgAQCMv#20F(zJ}Bb%)& z^7(-qc~x;LsywlR^OStnU-*kBkg`AKJZcEodGq7qoc{m>z95A|B27+UuTqOlS1L(! z_L^4I=UHjEjz|;!cO5SWKK{q&_I;fl)(PQ&c z8Bq7Ltd!i5pwizSD_vYpo0H%t!tQ3KXFR{c$aMZ7$1y%`vk8fj=uW*Qb74H&4yrVS zCDg~%2zAELun7S`B(;P(2{LWychyqUTlH`}n;m=mHa5Mv9wALX5V@_|2LPee=hgD` z8mlZKa`|doEIZ0~<`9sTEUCq*4J9Z+xl*lSMgxWhn9f@Z^82Y>A)h0dNz_}{!8tq@ z;%zgC84`@8&Whyr;Ik#frAtD7U2dp0_1qxEo5J@^z0V4geGNg-(sB{%KiQ|vw%|m}5RgA)X zH1TGsM&?JYNQmTmbAD9->W?ieNGAFM%1W%0UyYb#dd3lnqKbBsgSWS1*=l{~md7#xD+*TnA~YQ848 z&0Ws*84rpBWW}PzaM(wJgXHq|TK92YPz~$5Z*-nI!_^ zn?ntN0n*VMgX(SV{+N! zTV(L?Maxj-Ee)V0LiYz`p8kgq4Lj_aB%}r8C?Tb(9hXmr{;e84Znv&gUOWvVa}U*N8s5xd(bfsUY)^fKL5Izu);{ zY%LpESJcd1qRJ{{1f?r0>`B`N>NP=ZfunRTJzbPO(S4UBH+|BTbo}tg!0e{lCbnxh z2Le*G*Ap2iFygk#^qZ>JAbwpjTq&+><8@~0wzpP`FMiW?q$)xk30|FBYze^xE!xOm zsVx_}Ou18e#RRy8fB^u5{bgT6KA&HWFXIR zrbn`Bp#xU$7spAjwP3whDYT z+J7wT-jmg7?>NM^*64qtO^CJi4ac@P!T``&IL=RG8->f?kBE%V;=MW(vt^lz%Msm3 zb+nYZb;wsOE4H$9wg#0Fk*T{8=EuNZ((?Yf;iBg=zH9Vf*#q9nR=DkEkB224xPzM} zK_{Ys#0Ds-NKm41%MR(y2YLMG& zapfz>I-hRCwm!dbxL*$Db6uGXa%^Q-txc%)_reC1&5#`pl^UoOtR)Dr?n&*Ab2y}H zt+&w+5`nj2hGjfg2RQq?tbeo`Mz1x21sJ8pynNu4ky6jMP z>Mtu%LqRD6dz)d#G0ioB#P=a+so2?eLNBof_-T)dDU^ev&We)`sDS0vaE2l+WWjeH zWo8m?0T=csU@+3#ol}H>3vpL`;6T;P3AbC}Lp4v#T696bXtjFIdPB;wFm<0ZGyD4hZpat;rR~bad12kMM^@{0;8zy&^UJeaPZO1 zFu1hpg`rFfEJu=+9saBd-YLX{Vw##PI)QzG9dORCT@ehYFK1EjguKO zx4OuQy6#GdHob`HhL&2vJUzu^5{T))z8YD@b4{+f*5K zR+Oth#}cJ2DOK-aZHE9*3`*hkW07#91T|=Slig*Usc2fT=|?Fu^O5U!c?Uvub{^W(l&Ft5Y*JV zl$5A+xi{!>#g;}DAor@KLx>hzig0xo18>s}F@wPk&*DnB%Gi>3_v?eDC? zcNYFwX=Sw=r#0Z6S2Dl$lBx)ikUTKbR!~xkl}=!?Jl2I za{mCCTgUht7iwDiC0?d^}J3v>qBFOiz-xZMRVAcvc7>R1G+KwAFe z23b{{UP-b3xm5=*b&wfx4pV zm#iZD0y+!{?947yksx8p6FbDJ0_v3H&8Lt3X$+Uy2_I5H^P}G5r?|!|q*!o!3F5X` z9do021lT5ZxhSZ_ZbND$ECaXu>yHwyrN~Gjdi5nqb1uWGDtWCWs>0yye@sxz%~-X@ z$TX&`ooN>YTzAEMvA2Sh(m}D%B(&5h6R8&WBcc1?G7e=JOMR0=#9W;ZJmresTdFeK z(B-nGmA2?MxKKXFd*Uph?%h<%8iL2JPkce}(nkq1m1inUhU+Y*Q>%ofC;snQ1tj;j zaXRP7khlFu6%!xDN zBAAT1bx0{{RHs5i56C1Hk{n8ciV~utw1Pmry(bQvtaG&OyH7=f#p8V(aSYvtAA;-W zi=0rCUE$9WW4$gtI%Ik*=GsJwU?=8M!;4Z9<$zAjsUVO6IxGe6jGj308y@g=3)66H zLq0&@GU(nxO(+uL3jO}`&&QFH5DKj9>r16;~OwHm!q?qZUnlr6SW zwG}qBwDsg&3I!v|>AFp?K~~WBvoG|I*-VyaM91eI@%V1G9Z1aT@b}>!p-9c}DAOk8 zh$(uMnH;GNNS5qyA+z%KaIM6xq7)QLu8_YlR?=~~uGZ<=76@G#fH9BEdj{u{Z{+99 zvBO-cob#1sQ6H|)Ll4fER+5N+HriIw+$mDZ3rw<(MZ8(IO;dIdQJR9XJ*`u#;zDofg#Fe7G)HoTSXkk znPC%vdzPDmrKz^GsW%q|7AdjBNb5r!eu?43rCsX zBGxMTo<%ac!(T4lmw?MZbkVc!1$4>hsukHOkTL8doOL+;ee zM1NU)4Qp6RMf49UdTa-8UCt!QC}^Re(}0`D3PMIp~Xi-ZjY#gx&Hu6NPt{u zrDPYe;E|k0%pW3@@)}F1N))bQQdOW^a6mh4ze9n^9o=Va6xk%pA7^yhQ)D8((@^u2*Ev9geflJCc zZiSR-vz?m(mViU+MU17NGTm7Q!AnpE*4P_##k}AH#qcH?pKgU*=Q*5DMqPH&pbP3lGi$Nvjhgx6p%qmok~r|=zX!_{@d`wE*#p1 z?!)t5_v{A}BNzQMv=1L8&=z3g{{RoTFOiv>oO2vXS{rKZpxI8ovPnvG1F32wU^5378iN2UsvN8#7yio_O=0O*NIvBx8f&^6xw|p$dcTaLvrdaIE5k$3SO-vmZBT7 zQ()4@tC4$daTdC`y?{4{%8LiX-7P^f8x6_&Et}M~pgI0V-_xa^M|9i&?T?5i_JV=H;l*1gBS(s)WRJvNtMe17cCJRg?Ye zHI00h1!(a6Ik1CKChqrs{{Up+c$dr7%*|M(@b4=tm0glt`IlrNqSGw&Lx2!grKw&( z5%P#UR3FJpn z0EQE|2qfI!et<-$Y0sJZm8@kfQBxSBxCegnpihgB3!E^n_@Lp&eye2YbqvKNJn2)| zn=y$ke7&1(DM}q}f~6${6)7clNHRJKPm2;9%dSZc^v$6bk%CL;nDmh+WP* zc>My=pNGB$aT_{jiVum;5_Ih6mLOE6%C5NrKQ(%zjVfTZ85&p2yX~DNVM<7_(yLmb z(>`;UXf73;SZs6ysye#dwYmCyQu{jbi!|jrmVIhAewRk01}U`&uhP=vvEC?sq`GR% z&1J__&@qDBW=D~dwr;hgB`K8YEbhjtnjlL{U%mXi_SeT%zTbrm4kJk5EU0zbB_4fR zbVNBsobNKA;_2?CKPb5uUZThh`Y%KG1`gZ!)m7PcN@)9CsR8)(4Q#XgG1^r_UH^uIE1lTv3xYO#?dSr?P~p zkQ_@qkeN`LRF>O92BO-vGTMmLqLrJ2b8I&bXeUFbFBNIh!W&3kYrjWdoxeR+u>Kyt zEvfWe`NPT`X=sfXFar*sISx1+Z7w7@!WM-cAqr3e`w&(wxy3X?B$ktbQ*g@M?IDL( z3y+%G4rHxm3de~44Ck2DhJU0#EjusN=}QfVA7y1~ZAmW_=u%W&3SExFZ7LTxIDu)5 z5x6>dC|E<;`m#p3ns422&I$#5N4!naxP_SG@Eao4UwV&5oSB)C*wP4%Dnb!vBVTap z0JFqjZz4#(*pG`;ex44gp7Xv+rSclOp0oNH@jtTU58~nCNpxxrGl02fX#J~KZ|7@D zZC+-erB*{m$Nu$T-~1?7_plz0(VLl{;1#|fOxdb4?$&(&0B!vif+A}CCK6O7x~r%g zZSVHQ{JWPOg50wx7QU(E$vJH=12#h?QSGHVwz3ns`(LRz&sEeHI5DL}mRy5P*GT>V zcm}Q>@X98B%v944G}mJ#*zLJ)WGZny#=^Z8=^@n)w&f@HaYP1b3)VvzsQ~1?`K^Km z30SjaF4nN`iA~#5sF`9mOE^#(Lm>~K7mb(Gw*aF+T)(CnWKtV#P?f1x0Z9P^slNXJ z%LZd~L6TOG5n(S#oaBcb(-{qEX&~&i9mPo$__P0myc2LqXor2aH_^*_)tXcI{FPX=E zyb`riN|kGaao=y_i`ES^RI)zX>Z&EL`!#uy*7zu3-3mw8<+8JwbOk9_x!7M1YqhWm zh2&~V%G2RIy%$Lv*paxyoC&&MkP*ZqaXhU7i2B;St~C-=aRsor8@Wn#OI+NI7WG!H zL13sosl^1}N`SfB_+ZR#ZIHUl6LGJ40*9nN;t-uAsa^j7-q@1ttrtR%F(C0Oh*Gr_ ztt}CIZF6Ja2PDgWhB_}LgYOd6o$biDH@1I zl9e8y@4w%;#CXH_qs%z+@+iJz<<=ZRol;N~EP5T(FaCIJkyvs>j$5?mT-Ny7q^%wy zXh@kTa-E~n+(W2IOOTMYN>L)|Bg&K|L#_1mCg&fW{?H`<0O~V2{^)bQYxJktV=soV zL+{zUi|#yms7d0_+-#>VR00C8s4wUiOt zV{ej+h6g^rX&-xp<#=sVj!E$bhgg!!>~O^)<>~V3{j*6rMfXjB>D-@dpGEdj+cF>S zyXd^P+iO6kjo01n^U$c1;K>2sim!%L6zq7TL?c(H%%I;ExL5xGy<`6X82PJN4f-`F z{{WMB$gc9*QiBXAY_3{=dgrD-#nWZ*o!$tt$dxNm->4QC;uE^bHRQ4-#qI*Y2h+Y0 zE^~c$SM#1J(p)5a9CeW0ax7KAi&&Klb{OtAPiu+dgrP|USs?n{+YGlf_UW-#u1>`| zRcmy<8`YAE`hZ5F=s2>8xmAGZa6*{J5yfOfno3j#-7F3}PAQyLf0`tKpcFeFOeL%n z9_tR!R<1*YpD?i4AABGI8aoY^8?9>DTl6?}z#5?!+}TrfgMI%1JSaC#cXrB`(l}?U0+g!uxWli&t{~fWl`2-71*IOiVH)bWj~X-;nJR4rdCJGQ?}nSF zNbUrz!SI{eTY6zMDVMjJ%87{zN>zJwJM1vh-7bzE!0VNP$8Mz(rIEF)aQ3cqZO27G z=G&_3z4x}*QajKA(&b@O>spjT!B0W95OPZ!@2aM?TERx(SR8O1Qk_N0%-gF#*=Xt4 z2y9c~c?650Mr@S-0N-gxq1yh~7gF8<71b{rY^)VUCgfbG``-?AJKb4b3c0g&y%D=sSz$QK8T5*9z1bP@xFH$5=9M~Y*d zZ*}Cj;+17Mbb4P1KnS;Uj;BN^Gn4=xVv%kAa5EjsW8UC(R+^C^K`HzH0Of|5cogQi zw{W?P{{XaSS6rHRhPr7=gJ^D|`5=DraX=4C*%!xvdt-PN5VN@a*V8`0nh#$7It1hV zF-aaAvc{w#2jn9uDYn5SCfLsOX|DY-3m@$ikK(VlGMfJYj6hKEy^{zjN{)Y}r>}pO zm`Cu%M@SpkYnH#+Gso+mFZ~DR7c9@*Oq34CQvU$Y8G*9;NxLoD%#`d;iLPdPJa%Nf zGQM3xd7&i<{{ZE7nX6DxAcB;rTHQ#s@lEX=tm+;gwx1;O|h5 z_HXeIF~-XesfL?szy!JispDh$D`DGn+W`LnXV?gW&EbEGimm?uX{wOwh_eBFt@$n9 ziHZ*tl#5?Qk_tfU{&@PG@c`Sej>M!pP`%AUlc}UIdfX{LT7c-D_=romlBBpX$3Q;o z8szB;OAA6A)7Iw6_WN4+AYnSYZzLzY0hNbUiEnvRr7j>S6>7fUVTZN5?PMpnKma%L zK}3eii73*pi3L|8-OuaO2D`1HO)hQk!3J_om1KV>!)$q6I3Z45-9?D02RE zeeOZ~C}YR^RfS}6EncV5%w!gTO|7Ew0ZAwz5>Kzwk2R@fjmFD+2?Slp6O9F+wv)K? zU$!8d-(+@%fs~>-XhL;a2m<@x5nrGj)0o@o#U|#k3RFg-gSV#E#6!x;TUg?6b*G<+ z2LV5&S!r3ul~3o)Y?lL#r_9soPeMABxRIy+WP^$LJyEBeUt+X)WoD(P^SyKLDWcMl z=PV_arpf%j&mN5vt}V%E3Ky5F3!v5^RKrP<+iJ6{tLc5BEVLhGB&dFP>WD;)EId;l z+lwxSejnUer{)~BS>SGDnkvv^#ZSp8@=wlEUI&uB`jmoDuR;f=FgT?ic*$_rkB{b| zWoNxS;qBSl+mYfED4HdI!v~1O<@CjNT|KI^H3}Ss*|Oq7ii2Fl?tyYQ8~H&S?}y-+ zi47O`o4K6y;pN_?H-nl75xh%q@yzR; zYY^(WHV#=!wD>h>Es1Ql;@Mh1^=eWU<8EmP1w~3zE+A`KkfjX{F)$H6Y`4*6a0s0x zLuo_1Ae;W&*D5?f;#Z5VGUfVDhj}@gUUjWa&eCFKSa4nqB_>X6F-@vbis5vS_ z4adz@H(8UIGaJ%*gECK3fgx+RB z)C;-8egJR?hvKW0tM%x)Mz2N7GwbQ5L9DkbWN5`kGWEw=8&OChv7k7+n+=b0agv%Z z=H|Bp^InCDWpyW3-qnaU?y`bhILx))9%OuvliiB_F~JeH*%*VtO;u*AbAM`U)&v#kD5k(#@J`>5B&UM;x8uqhOtdb1R!bjOO! zb;xnmELjOkyt)F32FlfNN=L34B$swpsBf&x7h5KQNj?eWn$A|q&78_2ip+qQ-$MvW z10GN`St7s=hTo~hiL+Q5bx`n_WORmCi(g^MF`26*(rKCZF;^qULZwV8LQaykG>v6T zPO@$jeZc59u-|If)Es?9l*AbP1Ape>gr6-usxObCJTbPd2>j6 zTu&f4`2AG<;x7Sc91x9>A?0dHV$kL?%TweN%l)A>o0TbQI;^$o)GuHXl%ywX;>nb4 z5oflcNv){rt3*u}jOx+eKD<(|F=v_d%%4D=5tYPLS{+yb+kt2bxWHwa5UQI zZLNy2ARUl@s_N4ft9zR12++rGQnfc#&NcavAe53M5)STc9%r3@_RAsEj41W3=6p(_^Ag6Wjj)GmENN zfbdfB3d@4`Zc}E>DlD43s{F`IiK%oJoaF&@-ooe918d)X&wB|HygPBARdld*cYpO1 zwqa~jVG#P8Ooqj-(^aOg4*m->uaD0WnR~^b8K~zj z_;$+GQT-Ill{n?p=2uXB(#X`522$f;z*H`>hVC?28fwXnLF!}oM(1BZv^^Tb1t2xm zKKs4V$aA{gKZrgYWh&-Lr)3I%Fn0=}}iI!s$Ysbw7#b&_TIKxjtRgnQ_9{ z#htRR#;;Lss9D2uxT*1n!v6pfc@M-rMLDB3CZ$`uFrQ|(rll@jEutJ}`hX#JOJNB} z)U8(pD(VZst75n$>C3rRbaqSB2*|sxFW=%$>$J}cIV&>oW|0Ft@mDa%i(Z=8Raylm zAdOCgQJ4~xH3A}&&E+i%j(%J?;rWE8mI6UeD(Pb~Ii>aheg){$NXmA|*6W(%d+W!` zlGPu??R;a;RGuAYs-9e`)c9{njhU;9jZd0Y7Aa<3E+|(tG}}@_UQ5j;I?{*HrMFXX z()3!_yEJ8h?seC@^F@FLMo!6PZrYAQ=Gtw49t&@N6lzAZ!5$dWD)OP$WmTzh-zkiP z$$3&Wg#y-*rR^zRwC)g;n~*Pvm~}u54g*E9#VG{N{W#Q-uYum*TPSttuaSFDewWnVX z6*5lcweJL;9|skJ31g;}Q0sd>S;zxHjbY-8N=;goJwMkhOC z7d$>|qQxUZ1AC zMhi(z$kdf?FSxhc*AHnV>9S^1=22v|CBURwVu<>6tVi-lfcJ9$X=I3qwq z0_MY8b5@55Q7YS}9BdOF1@jeEtwlSX@coa972HOuz~Taucl^d4MuiN#UqFSecy5SPjtKefX=?`6#xXHy1u% z(+oE{BU<-2L1wIokEJ?oq$_)yZ-7oio2oo_wVSHv-{KG=&f?7gQ(bxbyL2e%uyAWg zK$euYbd$MSR6!%k5^Ox%{&;&(hzi-7Y%JsPEA+3}quglXcJ0d2cE6iWKh3}PUG!c?l6F^Ae~i1-r#oIrXDPi z+~^ii?!aAoPR8dPTAbc`tHY!F#{U3wY$pv5#5QfVu!hyPVC=Tba z#{w^O=JHhv0FmV>>5g%}yjL~kaalDa8+0f0!ZzhA+;ZCM#b5$QY;aBz8x=&Tbh#tG z*iv;|$BU3f)xl!czTI%%IxcI72HPs7YQIx^VGWaw&uPl3T2)|^YhK%bJaIhIiV5F1S<+w!-7`!jp8&*3n#6IuqXr z5*?LwqygUF!wJPZv%^xXx=0|T?l!`Q9tjIt4yxdw4aZKF>yA4nxZB-T3bIYpr+jfr zF6Qd1%?GGA+rAT2xrUYk>djjlZRjxX6f!M!;=Ap&@QAsrbW|>ZV{i}g!dWIzc&rXO z>Qape4w9e>b%gEfbGN6b`m#sZTnnXO1mz~hWBJyKkkiUBpC-W%Sp`SivX9uDI1#}# zoV}ZBvn6R-LXfR!CcvcL_;t!?Zf_-0u%brd{qURHh%sdv{`S!%wPuz8Uvx!}Sfd0@j!j#+&^z zCq>X@W#$#K48TfQ`ldFhS;j!)^O(*=ZPts<%HMiz|OHb@|;q}s+ zY{T;lmnmc!^GZdMTyTN<<0j35`dym^yX`cg@h0MHl~!DSJ9!$D$_OMByZs)epb%_q zMzTRYE$fPZY0Yt^n%j$fm2X7F-%dfW&g=MH%XJ?J<`{0d#`QF(zFDLth8tPFo$0DQ zu0Znvez)#zW&Z$YhdZg)at-}TqW=JD6B(&#Z@bw8(Qb{m5{D!QikfjmC^oTuC#Pe6gT>%Fhn-wtf!RnkNVvx+CIw8IqiA+&PVl@5fB{@w6`M>*Eux$IzV#_1ehwZIm! zy@+yMR!Y}Y(B~a zr2bgRy0ChvCIPk1alPN3O=_f7%=v#$kQu@;6)XR}qn!6wN^?HUVFjBE5q8BD{@kHAE8{{6Fzq-+#EoCxUbd(Yp5f zCZ9iLYG!fE)qK5FZ3}8c1+{H*m32yo*xLYb(_IvbdF=eba;@Tjg0)^3aU(F&(NA1@ zJFht+G7>J9m#77x9k#uQw`1*%rUQyK@dmrz8hLYD=;hAP@S>WMq$s68r9jw&+ZvF0 zC#hxOw~O<*b(%7^X=&ASs1K{2kZfd9URV#K-;}bKNBqk4#U>?A+}Hlro_sxa^i^1$ z8JaT2@3`?FaiZT}iVTwBM!kd)YYS!r zhXLf9(%~be>xd*5UnxJ-G`Zp6HraJY!umd6rPFCKA8wW?&|g8M#dQ}9ywe<}*4nzM zK?+xtf)W#`8{*PvgPI*Cq->?(L^RpDG}_~V@k;3YJ&3%QU#3+aky(zhK2n@~g117F zvQVpmacehi{J)+fRL5us_d>s+0rgKj9DNp({9sXORNg4kCPby81SzzpA7BDGM`Nid zu&@Jdy|F<eQ(*oO78GGFw|gvhOhoIzFRu zZ^K9z7wO*_*VA43#_e0`YP|9FZrR|D^{X78Hf~pwTah+Avh_VK6bDAhbtLWis0?3q zw~s~V?x*VN3~m|?*6=(nM3GG4o=!}%%4;(LpHbO)iSM`Gkc+HZe2j7LK;*~q{eAGHciMYB}*fr0FjAM*^M^+%9Pp==|ko6 z90%umkkV>FEG3p3X-+JqN+niG0kyC0eFtHGY)oP7*lec>GMk@xsK1`7RIl3=;I%*# z(1fXOa}tFm2`5qRK-2rmAZ=~0h=TbX;mr!I-_2_tcqUJQS#L4%8!^4aYQzU9*=_V% znNE=Fj;>Q-N+Md4zcWZ#K12deizuDI#B+8s=X1l7sxkHRZiqJjU_ir$a2XRxA!&lw#OSkW=(ssT6agearCySdS4r3!fOP+>ti~6zh$B3 zUvSKid!NNme{tU*aK;)ezdfbRW5-1pC3u(MVkEqy#F{4VD@Y8iXB?@FYl4{u{XxLi&Zn_ZgZ{cqz@Cz@^%n5u|GsR7iXVjf@UWC{a8JqNIC|_fB5D#E6 z@{S!xcV|E7zRszZI$D0BK0BT+{{T(_WAUZLYHM6Cs?lSmq*NH03PM+@Afznl1(O`_7_)#@~SyvtP>s(v_Vg=$-T zz>uwqK-H)eugs*B?wzr7Om0IrzUys6OV>0yVshoRyRMyvI8DRe6PI%p9+W4IpqtZRk01;WJ)N}1c+AyF_M1{%;WrUXs z)T?YXt7LWd79Vqo^0Y^>RkX}~Q-B-a^L4S_5OCfP3^Js8JAW*?qs#e;&$cv&pI1;1 zbd8b^-1ot0U_SG=T3U*RF`^j#*8ER2v#w8V#~O&y)PyTpP;$hmbQ^AM-rue*i!943 zH%cUvO@aw2P$Ib{s)Jm}Gf8&iy+G*fZHlL?1XB+C7R4xYr;(8W5R z8ghV2-EFAAsiiEY&ny=fprJpnE|Sk}wKg5ciPLpQQ$$}(T*H~Aqc@2Dk*&xIbofcj zOQGfLr0bbFvy#zDil|XxRE~$yB~}kFLC`{#Ygmo^q!XxOx|M(omO3p|5|Zw}Yl{KL zzx@`);#St^Won4&i0esgei*%!kVS`m_CA~9TRq@HJDy1`e-+Oc#a}VR%=~A`Sy+lo zu(I4o>KwKb6j+lc$v{ye_YEaS{{R>u3yem`<;hOihxKZ(kvlze8O~@zZGtCR+JDDRHJ(U zgn_x~r_=St1|vDX>ZV$wa2vYnN5j7g;c%md^ty3`)Joi@T9Y^>8cJNy0$Z@?5R-4Y zSFS4P<2Je6tY$M));_~w^HMgJ$#G^w`=KP1U;D%P;(G?Rx~+7UZQPF8k(Q80sp)Hz4UuqPma-7jK#lIDsUu;D)Rej83>%dW zy0NjdGmV0E_-VvG5%9+%WqgP;#92~l@pMd(Vn|7sHEL6`A3ulHZ#e3{#0-6x(TYf@ z=-C5Y(P6HmbH5ex$4N0cD(hc39g=j=?ZGYF@dv^Nh%e`=V>jFt$9xN3-FbHQ#)#EK zHO}8r_gU_t_On`iY*E`hT*&W6=QmNVt&*GTO$wk86aDRcjW+kaw;s3$@p?e)y=yQ2 zCjHUfhSfEf>fMxob>BN8C%i;(eTNG!XH+5E1E=Jq-=RGVV2@l(Z1L<~-}4W;fa4|Y zl%FH^SdWOV4m!SDdF}{bQUqxSxBmb`!D6Y8gMsr2kEW9Srjg`~BXO^X($f#+YW0a9 zFoNV@iWNm)G}!94z+&r8-%@Tp@Z(nv^>FXhZk*~_tzg1Dw;a%Sd_nM{Gmb-*n?6=c zYSOlyr^`apZG9yrph5QQhdM~kpo8X{kb!3pk_3+toFjclk(@)yu_n~{M#HiG%ceNU z!0lWInq%U7j)0#eZx4>VF_zo&Ay%eIjMxQgYMC)%yY;yZ8-9BW;ih(NoL|K+RO=qW zS2f389L!-4MXS~&w3EAxQ0KUj_bFtJtZ(Vx4s)76sCuPr4{!%6F?)=85=ueXqa&0I9w0 z+UH;Sm+5D*3%3R8h}5^}pqGtKMLRt~pvgn1nGU_1o^hjMq&ByyXaxJ~j_|Pl?)DbN z)pLoWZoGbqpQ211Y?j+ZyYQJFJQ_!eX$>^fNtMH(^LJf?iuuT-kOA2FFaH3M$Dw;8 zc`lS4!%xw9*SBW0Q^Ec={Zu*ddzdKsN8)|JyvJRrGftwx&v7KlkfbSLw$hSGAt6Nl zfH=Fr&;I~civIxHA2fVP$Nkonk^cau<=N~H68spNmgCd2u&KyO5=tRb=Ezb-wk0jH zPv?)XUn3i<$OF8A^DE)F;gF8QPmukRrS3B1c=X9tscz>86lN@6ohK?)*ow$K3g28% zgpJ1Jj5JlkPLFT-ntrRFODkJjXZbUOn{)V&x&VET zACK8sd{poe3L5y6N^jFtIb#0+{fi3IrvCsD_f4?9h`ICoEX{bN;4_0lc#}$1&Hn)Q zNn8H__AGUdZ`^&?7ID|p_E}Tni-9-LIE_q7t#SQUPUHUose9wKCsXksbn_!X%16Nc zke2*Q@JY~lS^6v1*yw>VR{PnUDYJDXdXKtmTs9!z!2OY&FAy9oo^4Ld6*`KB-_>X} zC(r2IbzvQp3zrLjiNAD=lE%Ov@}IIgUl+1lZWf(haBb9pwWQ@rz*0x4A1iV9I0I{8 z;Uj;{-@1?@myB-z04u)8<|h!SQ@KJMJo79qJjVH1O0d022G`mtw*I#MI1IRzGis=POv}9_G0G07dfnvyC*|&OG1D*%&TzMg`=Rx3 zy@N?U1qxRicy<@aHG0{1%j6k;rllM7*hf8ZBU2XPQhrU%;WvabqaRP()#! zpHLUFGL2;R?gUTwz8U)XH|ra3@ejIR(n>Vy-GA`A?1VMN46e1lmfFtFt+a)@hO(7q zYH23+Qqm$4l$#q9Vef#u7NiEA|;H+y4NFeb*WZ%X4*3xA;%lT@Q#fY3?PMbj~A8bzXF(td(3| zq3SIUd^Px`D@L+6)P2+2K~!}SKm4cchRV)R;XbI-C>&3U{+(R6GDUPO0yen$JK!wF z=*YO4zM&Z4wV~E@F8=^2O;-}Qrn+<-tn~(soMfd{sOp^Dytz|`m!Tjiyx3dulVYUm z8j*FP+JN%nEco3k*ycksbJ*Kax|@gL5;CEJsxsK_FK~9_vQo(LE5RDexqg$CGb}?b z4JnCJY7RKsY7PYwmxEE_s4;X{6aeR&p|&yDZZ(cV9r}nfj^f|C_MBUx-3*njbuKR( zU;U8B-_*1X6;Br6$fr3}r^Gcz66Y-~#(`LpA+zDI$VfS48Ca*$cK5ZlBJ}E6<;?70N?nh@cRVvwa$5Is9XVEG#`GeIuhdUFOHlmX)&F9H#HqEjZEvO%t>@!*FY@YLvEvN7|7f1 zJwk>ikKQLmY_2-+q8n~GGdabIgy}0&ux24BxVX72?Qy;x*0=jZ)P2xfQxMZOzG#Wx z6MP44WiD|~EhhagAM<^`4+<;s2KdgldSQ3bRI#?yjLj_b8M{72 zcr8q{Rjta(`bUyYfym~(p5vFb;6d?78mAe!QwpZIQ8O-Mah_TnOVe_dRu~FWwDPqn zg*LYV(g;G;eMz?W0&X9T$0#k5NW+II7~p%xxAG$D7A1g984iv)9Njc@ZfR}w0Ps5T z8Xyul+rubalQT4~o*h>$rAeh!7)#3E$k}o@3s%bVrsrd}#}mdSOkJ0)X(NValk-%r zpr~!0=$rxO*IQ2|fzCT{p_po^Ih^C7nwx5q`#NZ0Hy{m8mNX{hfB_>>J6|3ALYdAH zi5gsX8HN0X(zcdk8I(lqgFT`1@y!ou60X%3e*(kt@-gk5gts+11NwVL?ex zm;F)*|AdiiB3+&N>Y>iFrg^>1S?<$#}a*oksLve(13nrV*dcz0q>Gl$j^4egu~=wyQzfehhQ4SknVyoZFSAjES}Nt-ulq5%0aqJ$`{0bqJ1$Y=m^cTtAR{y7 z)UDN~txt7&K>)0dqzjKx&|vS7mfH3R4Vp0Q!&0%knW)XU+LKU-ZbFBdNkV-{7T<38 zEOG;TpStJCW0}8Ydo}8G;L2(0lKQW3mRfbitP^Y5DJIwT^}x)`Wy{4Dw$lP&O(}Irom34K>ppm3M8LGFNp7OdAn4>W;EZAJEV&9 zEfZ6BsYlSO+o-?W5#|G4OPMvT-hsPara0hj6I)uZV3egwH~Rs9TvSXOajuH$2j79Z zj}>TW%bDtIK^|0S6;zqg!sD&9m6AgAl>u?8{V&(s9zD{UCUu0zsP0~`(Ym*o!H`>r z6nGRA-H8_l#9OXB=6HZVb-RVxg~>&-K(dl{BHb|!;G=>8?nKg1vYRC;Ao_OO_+lKI z=!(ai_axM&611$8`Hja+05G`fQ3H!~A9btG9()glnsU(1F`^|?S~d=8Cquy}Nj}OK zN%slBB9O%(Agx9XTITjj=QA=>)laENX~Yz`m1$V?IP}~)eDQ*`vJN~@dIed`zgdY< zx53 zb0Q0gyDA|60EFp2>9#Q#%_(zkNBZ$u8G)v&yKV!u`>1Q;mxLLUggO4LMapxkbac#` z)kcpl8?H9-eIOt)01M;)Q1dk8zo$z@lbo3tuF`9(kzmgrCp>h8y*AUij6sHBn! zHkfTcS56~o+!Y@g#H6dL%=6fcfG^LvbqU4H&icQF@^K=_&|m zlEso7c&#NMxTgI2g0{FI?~KMfIF3Ay{5%%-qSQBjb_?s{;<@eNCyxIB4*nu|aGGkC zAn_9~Qkr_5J_5w45bNt$Teg@La1^AeBsvSP5=xddqV|wR@H)^)AP>T`)fKUIj;5Sl zgp;q1gmDXHz6>~r#Vq^8EQghvBI-xaNj&duDbu}R%4 z9LDn|$r0enr3sw*20Z1WRLA~hZZ;YvEjEoeK80NevD>M`DWVr~D>)pG60fs4H>bzNpgd(IyO=6Gx4bo6KS zWy<|O_GD=)NQzhsQ)y5msW-4Bi+0?0#oZj?!zUG>J6sqH%L3RNvQiXzt@1pff4j{Ilh`+PN_vr&l4 zk}Evqvl=UxY{>-Qb&G&gb8&6J1QUYD{;Z1&os<^_n2U+98r>`SJzCEB(g*aKs|8Rg z?zeOiWnXTHNjC!j0KL?Y(-I!y*o%s*pq=x|+?o%9LrbA6H%Ok`{IbLhqK6W*B4Y|K zR@8&5No@6C9nHt$5C+2cucdJe&miz0RcVPa&y~?LUT2qZPW=X}PcfxWb=r(bspcxr zpfZ<8>U0j>2k^vsP1sx!scaq@YXQY->&KUf+?Y>{+7@4$nJ!jpA3ZIoWza^3 zw6^M!r6%0Ns0(kgHaPcRVYoYAGppWg8KChymE<1Wx#`Ww(q=9X@UQZ{Hpz0qUE6E8a1xfl(o6x;|e;s-85|GImMJ5Ae4qOsr-q^;V#n2BR(3 zq&%mT;41+MK2<3?Y()(WibTI{Yx=bex%xa`r-`Wr3J; zXmqm?No=iaQ-oX~CdT@$Vml4?#Z*)TIFfW*BZ|I8G6);n8Y%mc@*P5(OpjL1PSa|< zM3;FJr7c|aQaxE@r^=N81>7JT^doFqQ$>_!Bfx!A>w^dKn(p^IndCc@-9m#(iy2i& z)b^Zx4c)bkI-Tu(fB>8I+xeUk?96pY$vUy4DmIu5QP=`<%^{{Zw&pNL-+ZskhddnZ%rlIt%ROvY=IrCOw| zY6=A0^8wV@NJ>SN6gpt?O4x0FDu!CO)ktGt)Q|_=Nd5}sh2-plCe>b@HoqlCRY}>1 zN?mp0ok~iQERYlQgxuH*->w@-=RBM7T1u!Rrid|{eEZf6#WC4StF9!~s#2DM<8C~y z4Yb-8;PNQkBx?YGEp1&k#gnajDhV7%YlZH7lxxl2BQkb&syC4G7G$PMei^-8O}S*i zS^!eVH&&5j*ehTK&B+1zgIkmOlu0TDOrgxtgO3Eada2B;z;;xnPo}|mrI#Q!972Lp zbdUi7MOPO=BrK~?xLCYf-$HJs3-y`y^s>|^#Gj7Od>TGw&&?J|^? zkoJTnz@@n3sat6zYXNpC08PVYd)(Or$6fnmd83v8xrH%gpIVm}vUw14~X%XT; zdSyCG&9JDhrL+=|@F~`yLPD>;yWE?b6Kq%?aJzC9JygMuV*t?D@=1O-@!pxjP88HQ zjaW@E#*GC}M~wWU(x$uxkit@cRHEX_8%a&RpiQiBlgrWV^CqoPks;Ee(ri>x3H{U|As~7rV>5_UI;Ly1Z?d6fFHseSr*q7b zxR2w<6e}EG;_hMM41kGkzbQ|flVE}XLrEvIZHC+Q)D}n8jd)~ighWoZTbu@z!oW|O zZ)sHb>b1Dq70N4EQ3=~ZZ`gs_#M|2up8l>YDfLF=gRj?~ld!;+8zvYRV z0cNaexYfwzanRC|#-pU%6pg}1-vn;RS>2l9XIfAYv=XbOBEsGMJuQZ{uDWS?DLpyW zDfXMbw!XF7p&!o^Ba9KQ=qv{|iv*b|M6@=$SR^Q@ZDIa>uttXEOC!#51(Z(X7JjTp z;$B##&>xt8qxvgreknHMmPMU z?7TtvjbIlwGGF{|KU7myIyx<9DW zb{0H>i8U)^7jZ5lO-<}MYODP!%mqn?+-S}_x`+%ZO4Ki~P+tE4sOyd|ZSVIfqJ@^Q zz5GYn07h%Ahc%`>J!&L_rZKutU9PfEOKpM@!bc?^^bFy9`2NcFv%Y6x*H)Nt(6yih zIwO=75_)XlH}M15m(&~h{>aKcb1A*ypOx>O27?Ukhn?Wc)EdBZU@!q^TN;V9J7(Htl9NDJIw4r@l_3nmza?RRP3P zU}e^xZKpEC$nCiLlHhf&b63!UKL~|4VxVqGJu$xaWZODJwuO0Dw*z?L?|9KeP7jCA zj$DW%w9J?P0Hmy`2wDP?qsu37Yz{AQlWayZKeRq-PC7v7tlU4A?~>?B6>l-ZMyOB6 zr7WQz`z!+5lX2NdAls)?Y<)gtXZ2Y5FVCE;X}Bl+#S5ET%+rZ}u<(-4RH03&Xl#?w z2vdp!?Q9fe%X4dZ1h&Vr^IF7SfeS1xfO0ga(24)$DEwz!^}&?77nC z09*nOiaSL5qiaxgq&Na>5Qf1`za@0UkyT-0?UHq_Ci;&xR;u+EQna@oEAfq$Zb%_s zz+bnnI99ZqHOa3J0Gpfm-CRPMLo=PB)0&R8DDxE+wFMNBs2dV=`I0O^2Ky7f8~Vt` zgo~t%&AUnUKpAqH!;U`QU85INvVRH_O`*N^00nHGz;@~BhR0ITvA^duvQ05@1;+mX zoH!#ECx}iz@>H}(U5XauaiBN|-8ztW9lL{vn&zK)sK89qVDqnfv8l*WEH^}K1O3Hp zuk-KI4`prLrIBWQ#9YXIR(B`FT0=^sIG`+466qRK{{SxE!yP4VL+=C_LO}&jsHmgZ+?#aUrWKWki?k^3nx*z8S9<>IF_{Gen!0682mmM&>h?Vi ztZjRC^v4>j4b)>4j&}F@EUi}CLoTx18oFcL6rfC47QM#7dt0r&u*X(3*cV+ru*w~q zF}H#n6EH|=Z9N?sft9S-DXNR%YA3zY<<1fAX&s}Yj`-anxpm6V7dh1F^WL2W{LL1j zYZ);rkFfbk>I;clRzdsy@F_aC46gyhzw*em!bqGP$Ci=E+u}7>O3yWU$qAc3JWmd8 z6C*H7cUPs-w~9|pL=n@q*_y_K+|l$3beNT7k(l2zi+L9~tA=l^2E$FKF|^S-w29;nH_<>HX=xeFyh^nhrmD@Gj;j9v%j(yq5WveMiOBMG~ z(Z#A+BHotV9)s4rIczfK-Sd<^rw1IFm zSy7&ID@bjktl9%-Kq`{001nqG{{SK}-DH00Z`ld7jBzI6XFNmAq}?uNz0sz^Vu1}(tO9u?b8lqbj=nFZM*>aA%302-#z?E`k}9J zGd)R(`!-c$IY_0Eq%x|b>R^k1aIZ-Fdtvz@4!%$iKixU4HquQz{#znOGi7zLsG_9W zZDig-)%ugu1!Uj@n#d-fTLb8XM9!Ixp8BW6Ife|SH=!=GQF#keN!%!*dxP9`z-E#& ztAHcH6_nz}$5b(S`!_x2aoon^pz6A(xU+lQ?{ZID;EXW?X4rWl{+i>oek&Stwq--< zlGL2f9ql>;t~FP{@0zIE6r}+sZ}`= zU1)!SPc20wZNN4?$4dd`7M%dsxFd*((7fs1@14TP>!b@oi`y zx~BDMSGq_zb7q8%K=cVs4V)&;uRELi-6*n05_5J|s0hE(jyBV>i_w=JOf0#YABOr6 zpP1H>Yys6Ba+t#~bQjm54Y z^BXvKXiqe*y)n2 zR727@n&Ay&I;U_tWj+ocBVw#;It7|DQH9I;h(@N@4{!L`O~t>oE<4jY_HE7Dl-grd zTxg4xCiW)RxwlYpq5VWdQOCdcSl3~oTsdQrm}|sqa+y+j!Y!qG!iVR7&wLs4v^O&7 zsMrO8)46IF;-fwKjXQ&p<}&L@L8_^}TD23)K{mfZaeR26wJDnVi1M9n^Ta4Gzxfrt?*fqIQXb<=Xm(qyKU`XZ!opOfHq12*#qYTrceifO_D)1b&F}e@hxX+2 zG%OA_&@GDP*^^cpebqhBQPdJus=$M7i1UBtkD;G9aJUQQh@f}%9XwK|Ek>ctN*_zk zEiIKLK^n)Uj@LbR`{9OG*bDj>`|PSed4#?6_Ep0UWCUZ*-zv=^gDag`g{DH_m1l#RM~ z!5$+gTP8+BEJeZbvMG^Vt9;>cKREJ2N*3CdbdI~8wgiBEP8}T00>}@D7iK2s=iaC) zm1iY1*EFf+DE=6}=egML_O=>oT09V&OiP9LM=nz{MPijEq}>jn`wCGjnBggHk~X(J z%Okfb@L@6m+9dhkQpX`WHUaK_mTU7~h-$^P$nsrD}Be+l??Y0F_SU|W&iLM8; zrp>~{3VL!>mVdo;4x^iHwy%aP}PX?IMh zHBgSkww9M#bs=KMsmG93MUliWYNVGlK_=*2h7#tbsM`Bj1AowBrbcpBk-v&0aRe15 z3O<9jAiqr$fs9%*H_6WkGv+aw23u}-lEZIq|*Z^kK{C*!V4skt#x=<^;F zxwlcbDaCmS?d5Yx{LUj+Q-?-X7C%kaKwLL&zkhwB|6PI zB#AKtqCs`UsSUWGf9B-q1Poh`2QZm&W{Q`$<+L%lJO4dLK|r} zDb_ECERLb=l5ckRw>y4aZ_XtxJB=&?&H}{pzURk)S_knp@V-}r4~Sk-&Kx$VOv&5? z&-Di9QJ|({qEu%PRHxxeUCI=)@k)XaR)nR{LXZGSvBN9h*E*5IP1<>mULgmi)Bw=O zSk1>}*BXP&TT2kSTJWN*vBA8%o218`Ns*YP)KMm~>2xjBU9PgGRy;Y_)O30pE1+S}n{Q0L3g1kM>+*p@X%~Wb?V?cQTu3N;Rxlh{aLRW7x zw>R5s;^nkiBC~j`ymfA%gt?9g}gO^mNL`1T5=*tW}wrJ)U4l;;^TT2n;+Z> zR**jDz9q>UB#6UpE&i(G4TbPZCvojx{T8A)Z9}V3__+@xhFg0v(en|65a1-PFj-2) zhUUQ}{jpPrO6#$}cON93E2L{GWo7IfL!0NWi*mVHrl3v?mh`&qopoEDVz;^9zShNr z9j6wJl!Mp}bG_n%acZ#whn4FS>JK5ff;x-3ucbqZc`5T1 zEWm){4901g&5JW_Hq&oG&~@7kGiPZI7Fv2bR>nY&WX?mWzgU{vZNCZ6FFl0?sS3Co zf-igRweNpXagLH8)?9047FvSoh&vPUQ5(ch7b=w=CFD*8Whk>I$&~vO>&s!SKPwei z({~8~17m)NdvAPF03R+>qesn5#ws04M|SHhngQL!sGae5;D%zP@Gl^7OBC*qo=PBQ~+X=O+Yqx4aXgd@}FpZ z5Pm1o`6Q-sWkemm%bW|EJ>j7n4M&3Jecm)@cPB<%jKjo7(%Xqz7VTbEq#OM}sdv8Q zZM})d(X{53zT+4N_*?c1;#nP9;df5*cd>i^q}fFe{#K){Ns%6gwUzC7sY;KU_t`cU z!(7OkZuC|~Ar@&(rNGvm%=wRYeP7uvU_m!clI*%5f&=Yo^`t=YG>= zhxlpFskpasUc>BSo_1o6k&ZUXLFKN?q23l|E+gj3M0|si&1PyQykj)jE%RSi%2tOG zkfvHr>QO3C0{81-^D(M(&tZLKONU82L_lfs9LfCTwwuCl3cNSTd0EEueF}}8vs9#B zblFVn<==4BU0b$*e|u#t?t3IkrKUHzSJkxi%!jLB^WslF;oPErcFWm!!uEEl@eoj| zwdgC5(-g9YRDWcZrDV3_mrlfL2`2i}s1OaWVN}}y?SNR?Dz{RXGS_pCg!1HNDZMenK2blKPhFRKTTe)}11kNTX4h}MRVt-38^#H;Ze zjXCvEBRWy@)`XTLl9u0P3MZJPsE`G`$|At&7r6r!Rn?9sD|jf_9u(?_UEFm&-Ro?e zJ>mU7A?3KRU3C+u2EcXQz&7lZl5`|`4bARvz9dn^ZF04B<&9xucKp>u49DTVlRLyP z<3)0%7EK-$Xz8X=z|xl`peZIpq>TycFUAoWskz)G}6g2H!j<| zP4(m8rEJ37e60dAs`)tUWiPs=p+tjyl2o3zvPQt4$l$b~YE_;t`&pcV(MQBj#yw+( zbPUnKtgjBG3p!O}7M`hw)DsdC*L`f0Ybjb3omT}Qk=)`$^R^-!HCQT%B&i>!ZN|F# z=seLM!`H#?bm5l{b7zRIHbPY``kXcwmno7YDNnT+lIo?p*2!tdE|n!B>d|7LE-hC^ z*G(>Cx6NwnsKpHl4g;+`2Ms=HKfwMxW~|$kxS5x;0yB1Et3av9T|xbXC=}@P9a1+Z zTPU+_l%W?<8iIEM_70lzmhHh%Lht;PZ#vsjPv@XocH{3BD!ggWz9jO))EKo&3@o{r ztF>xVP+VrAS7i)0_>RQpKdr`!kmE{pwvsKW#_Uj$Ry@7UjxGM5Wdfd`Jv@`hbRIjC z$Z=X9;GR>Bo^k{9ddSVy9v>q#QmO4cU{$!MVlqpBExCq#WE0rpwoqE(Q~=d zrClJMwP^&4++N1d<&ni?vAHtJ)3Did)#C%i5aQl&p>WcP5@bBHme#pd2NsmJ)k31L zD@tu7sa&?urxoTS&f@F}KqiK^qRi@Bx!=K5=Mzk3IyIUP9w+T}%@4*ekHaSLs-41m zG{rYv%+GRUB@42X0kRb7+orX0(e_fXPLI;(kjU+trs41jss;9DzI;CGof%M6?0RAt zbxoJh6jVQSTYb8Eo8n{=_S{{;Z;h>?;Gb?4We=a56=-2rbMR0uIe{asy~;p9_f{)w zs*m**RV1J~&MT{54BR0cEa84!%T7f@b(c}|)ewY)gg&r83vSJ%Hqie7l%Dvjr)e6V zD;0>iJ=X^I?^0m2$N?xwKuGD<-rvg-vVf{h?U<|#C0f)%R1;ze2V?JV=YqKMDTS?K z!!AN?Wqu-Uc>XFT#;;uZ>;aAD51M_3ERvqzy4SusSP@xkL-YG z-JlB#75XDZ#sF?dEoCYqGk^tL@AREtp5B+h#dsR%eNfv*@u43Tj%89dlotMC>$0?l z))Wn`u+w{V_r$KhH)uHl^kgcrUZOc7OD>hUBgzw{g@JR_5>wN*{rh2Jsk5y8N|gE+ zxEpQpLF7-Q5DJ=-RxB*TMPOR{lcd}EVbfFq(nwKRM0u>xs`SQ$)wlDq5>PCaG_nD= zRD`5@VhgH;^wjcBZXD+VN*0X4M@)vCL}W+a;3*1iM!;@03mh_%m? z_}hPc6i&k2&D40OKM#9%(Pp1rqZeLcWGT^Py%&~;&ofHZaC^1_MYN9B>JMx{mZ|5m z(5AACUgbxR7t`r#;-3TRXp~-qCWA_+A-+&|nBrQN+bJp9+q)~yEi9 zM-bz0U3c&c^e3Q(N=V|1W_rnc^-BK$4^W$DE$0VSr&OGYR&OC=cLgFi0NA`l7i!i&R z5`+H$w&l@WYV{{uboc&oMI+2Ym1Nip?_vkve0zbdkQ}DLd@L}>9fqCuM&`SgBCSXZ zeGeUoQ-x#gbvJL&;DVqH9rGwI!r#CJR;!fPR)X%? zdm_!;ZHVr~CK_e8kzM>FD7Yg}&S=FMmXga3wF+foGb^xhT-```19XKAAR8NzeXs9@ zWmC&-C66r*hzAXGPHTiy9=nvMIK6chzWD2=LP}MCP#Wv`o$<`7CrtJsNs|w8*lXat znUvPw48}yalb|U)#Gd=?qSzPrziccOuDA>!j{=b4jt0&{{&JYvA=tBmzMxY$ASY|w z4nf=6{{WsO)YeMP?2;N6=F;AXE0d^l!%j0gyxP*DK||>~{kcQb`r(4OI>F?8QGY<| zYzLwcr)jRVq%kh89B#_LISMD-!x0} z6t~c&wx4Js8*lY4v zH3%*>*^tD98FAAO_G=qwx~;VsOyg6665L7Vx;*%zhVFb9Th{G zGVt?6Yyqa=YOMX20hJ|aQ));TD^drid)oyvjF)YY9ME(jd*oqD-5{mgkVtIW_UtdX z?}+~Zsc;trTq2kmn`M>Q@uD}lxdT#=loNl-*gxv*Eaw87)H9OD_$nvy!q7ab7AH;m zZ*7hv97&*VJ}Fy8nD$$u9Mo2d(V^!Sp}I&ybdSCF?S{Uz>6F}e1n=SP{-&X!Ji>-b z5y?YudvL{6M!tQb&a_oj&L~(py_-T9DIvkC_VusC!u?9{A}i-?}mTF^4y-bufs4m`rZ-!M9@3vEasg#@J7{{W%)#CfM9 zW2bii02KJ50pteyp++jXZLMpPsM>c+tyrh-Zhuj?PMCbPQdkjxPl^xdS-Y$X9Y~Qj zkx+wNqg5)@I>a?B#Gg-;xU!*@Cdw?n*-MR*lVVb#aBOzl5#|BinE)+3_ViO|p89vT zXq;H#v1zd$g%N(wsZzpSiy~fOfJfmZsXs8-8+jI@1D&>63LoD)3`zY%YyoJn;y8GZ zvQrahkh%WxWJc45v_*{3w&%rxqc2V<_L+B%RjhEFx zDJM~_lDaV=i>w#*3T)T}jEqkBk5)~y0j2zP)oAD9{^M+;flEr;kfkQ9l63-9EXcjV zKK93-^uM(`PGEH0cNO$^umHgv>}|jqeyV?X6MYZxHzuToB}k;h7b4|fhC6-fn9a@J$Xi{y6{UdNOw2#deo7j^Gt(~X)A5gi( ze1*%Bphb$7f1Wa}*?lxNTXW$NasL1sTuNGb%c-|Orm)hNa5a3CHrAC39-wV-N0e-K z#2%3g#y~%oSh`6E=^}9AUGpVw>*4DIZE9hKjcG~NrKDzOK5?uCE%sEb{L|HaNjWkGYY`uNZcMDaz+pynnvBF*d58lV`U(4se~ z=ypWKxTwlnl1pU{bYAyOhf7=63}nO$B7T@X+Km%p`Hu{CEaaUL~0u`ML%x(m5MI1Z%mSW7Hx~Cm}8>J~y_A6}e z2_1!wJjWWR4Ry-)j1r@)ZNhfGNx~9!CggPL3C2oig5tFCw6ya@k5hCWV~Ym=0K*X8 zbA?ht|awX?Vl}1HUcy&o}F`ZtU zr7KE8R6h+09dw21z3u`}69uD;Y>$J|Ja?sM8e}nWDtDTPgsa<5PFG{Z1>fD4Jf(z4uyLSBBF_U&6$C ztw8vRuSm{WmnLRO3QU=Dn3ElDXtwECQcy*#K)JWy5b0@~3y*rG#xY0KMl*0W0c?Z9 zHfp2PcxRWg?G0;&-8IFsrWBG?)vQ#q6iM8vM)&S|Um95^4{KfyfGP|ah8M&~Xq7Z_ z-A%cUyz^@hqvl>|L>rdKU5L_pbid_@^yHsAtyIJZ5O`TNEpS6G(fG%lc*0Q2^CqDs zrV`)&%;7-iI2C==wF7Oo1ot=;H-)db+~2_)6s2ucu*griE#t1AWV@q(Sgx}!ISXf$ zwJPMKr`u0{zT4tn8r{l=iMTz@18|hJn2~D@E-bVu_?i^j&_|WT_Xpc+bg}7z&mHwD zNR*Dq-8VB#Ith*=w$wPH$U<8IDM0L5$V4 zbbvrAP)^n)*n0156ESRL@lvVY32RRku58E0sBuApaF=Ev@nr_)sjq*XH8vR`qW(;j1C zN>Z3E6eV{*NebK@&i#++jZ~GeI_0mwcF2&$BL``VVgCRQ_NnzgA?Aowfe~{Yr8L8T z*2AO)%4`6l2`Lu%HNB(q%Va*eHJ+fRk=1Le*SWT+3a zr>j|=_~1QIc@{jg=H;@Rc@R$La#dhS*a6`*bfVWQ>WYxsc6BlNo+tM1Pt|ibL#MoG z%t?f*!Ecy`Iir{n>J#aGy6=A0#kgg)R1?-`agCagnY{JGidPezW-U@GWFcruU2bB^ z+i5zkrJ*4{Rgc{S*b{sAz$cK}#Yc|`WU^*Eap&Zn?2C}Hj|_728G9*Hzh*>g>m^Dn zb@i*N+*#d9I}7#z0bnrdctF)$RZZCpZh&d|-ifo0Tc&3i=%v)-J5h(t9Ols4mX~eO z2IK_*cd-PG&JQz&QmFp`MA>8o!uD41{{Vv-3x^V9)bi~NMX0`=F23Wdb!k94w1Tp9 zf^1HnwjP+TZ76ettgk76r(unn1G;c(wGL22C^vOh*c$?o-|dTLv;ZutYGozXQKN|2 z@{5!zDVJN8rfKAEohR{DR1t2LBh7nXbGLkS&g`mYRW*|KlUY~sBb2jD_vm?2dpVl6 z!=fB$tb!HJCr{FMNe9Y6P0*vgy5S;`t#5J^)lZ&6BNuVgyTugc9|N2>%^XLj@tchF z#c>0OEr#U8hc)H7Or|&$sSXIr0WLU!r6XRX4L1oSm0}$4bjI%6lD5Mzh$!4-8p*}q zWhnE4sTG!uB08Cy6)q6&tJtV_w!u~;8x!1g#Q35N7Ah5Ff_L{WWxQSZBk{J5HD_9f zhYa_WGG_`iEp$(L+JwtH9ruD%<12^Dv&c~nl(?0sqzfr2vdC>?fbBNm_bi!;V;kL*uPFBlRr#nHM-WnKLYBoQ~XyNkhpoSY<#rDb%Y`N>-&M zD{jOBzcfhnlJ6SZ!pioZk&@Azqp(TWpON{fFY!F^>y`XG_&d+TgpK8TEc~rDlbV&6 zU5vUlCR~NK@)DX{sLx&5(GbZ{VPH64az)F^z7J1G*S*gmi~0JhYRu6-CI?-uHY90l z^4t-?-)&C?Ha-X*EHW1qI5Cm(eM)svjKrwwn4u=7^p_I%IJWC5Do{|;RDh9jV4$7A zO{!=n9c!3)U3w&8rJ;;FTHWh%zB%d>sQwsulU1g^$(c-z`%M=>lC&*@%}TVXUSoF0 zTakN&pQPwvacFSn7Eh&a{!>WY70Ue`>bxoqM!%Y+rcHKI-JdbiEP0N3wD0}f>Fd5R zPXxHQsQs2i8*6i1Zus!yTKMteUpLnx%3SQdPjOUwU<&f3mQxn;vi+j34uiP|onW&JsWe0UbS1wz)u8=1p zG-$1|+kCAEI=hv9{r>>h1&%8fikRj%Nmm_Oi>eA!eo%bAm$2Ih(49(SqyeA>dI)8; zD1)g+!AG$F06Y*kfI@N8T~SPukewtIld?b`N%g;cNsMV=moc@rMbbb+W-D(6F@HAy z08qEDZrG9ryC#=kLR5V50hpB&AxNN8WELxR#}i77r1=YIUhgjB>Co1)J@k(Fu)?UF zJi&mfyjr+J1D8I^(%~^C|0O zGCM+pM`18|j^0d#uIW&IVIzL&)|Fqb{(}amr-{2e;)3TFjebiD6#*H=mg%jjfo&xV zaZ5?Hj;jEWpL-koV8nt(Q>Pnm^g(+aZqe7BkhiMpu#%`Op(++{marFO?|)@_3`!-T zx(oQBvJzc#>wb42@Tz>ct_bkqf|V5lxk_D)j`k`C-vW+Ub6KEy@Lc**0CSD}kZX)ZX%l&ks#Mgt0aBFNTC5Td{YKqD z0Cnqw^^9q=o-T&y8VVqOzabLKO|A=ZKsV<;q>V#=qT|=l^}t_J!fY&j*L6Ha^-3sH zt8J;xZMMo%v<2LqD^0F^x9QM>ewW0JNYD#&P3l8WYjh@|E$HtyUuGd~XHg9TjgO~7 z2L89c5Q5RTw}NX}(Cq;iRbq3p8)!8R#zI2PiV##%O{^41Jw^S0&6(Iunl0mGLrs@b zLd_-N9fGONQ{hT*i!xrilA+x0qMO+M?%vzs{g#Zz*Gw@r+bT0HreM0tgHn`8NlG0z zbX;^c?0e!X+g%=ZNK z60Jvbxx}h+B*I$$@O}ui1FOX6iJJ`))57Yf2e`EwS{7JuBTeLLS+YW&C0l*KKK=2( z_IooVk=EYDc^|gOiy(-dF5sfq1Kj@r^V{L#%WSD%w;DQJNK#MWE3xV^qoZ}J8hg=k zHjnpmP&FAGx*4RmHlo80Hq;r4LI#vaY@}Y^fkwnzwmq(vM@Tz1E8=OQ$U$}WMs7rW zAqktxXi8ByObqZk4PK8fcA^A-3BLNs$P2n z9lyE$DR6f=|njjWyx4{N&_|7R!xanXh+W!D8%Sx^GQjbga>w)HR)#AWa!;bm4U{;bL@2I}Lqm-?y8*G>k+vf; zctO+?>-JIKcAalxjaw1Ocq*M8({sNxAt&#s+>f>;GDzKbG;8J(gTU?i$rQ+bGa*`` zGa0*BsV<-c`rLmUMv_s!O?*?LiNFv}ir5ojpdiYdOm(n!)Pu}W_psA%wh2mf*HD~e zHoHds>oc+`YHYY4Y%!#iAxJmXwTReli7#-sWuPT78)`ieI1(C|g-CKF1feMfKZ~=+ zy_82@n;b-BfxzZq{O?93_OJ%aBC8a39FCV)1{ffX1Sq+FzEX>xm;3r*Ow6$C4Loo1 zOl(iwe2|4pq{@t`DMaKjr4j&Wl^=T>ll(Ady{~R!!|J)wxE!HiQmJJ@*IaerZfv-# zK}OpEY%WjV94VMR)}2$@%`_VK6fwCJ)S*AtUXI#9v3d%$qKhwP;F7a4%MxXyAS1gEAn+iN=#pm~0m(}@uQY}rMZ zMHX>uYvQn`u^Gu}FI5;@!sIAju(58p?_-8Nv4>`Gx$e4aqjOEIr?16Y?AeWlCHkW! zp|+OUx~dN$;gfNc~8}vm`9Nn`6i*jfLjg6mC%3nnlqd6q}LB zNJ_riR8Q+{JODG#pID4K0hQqY#3SdJ;wKdhc!U&b~m~7GB-w z?7OMHtq3aBOPbmh9p;}&BxzEC7wcdMKg$4dW40bwx+7t6(EXRG)kU=Gl3z?<$B=6U zJl(IiVn5xm=p0S#+gtOBHHfex>m;i6CALG-Dp6_rl!nR_m7A$c2uMoE2{%%bkT*9V zSlh1b^KnyP-*`BvOuy(UXq{;ohzEc)+Ze^G75IyX2Bt{$n* zr`F@(l-Wy(`Qsu=s7T6Hc<|}91R^zJpDG&@X_eLzHfDS$0cJ~L-d$j+9a~#!0YW`( zBWeY$rws<41Z=Ia%IbomHQFU(8 z;2XD(yM0H2zlxn+2T&N`u2X8-ZBB@t$JO{r-xe4%hgQ7Prwt#jfB1@ze;0Q_;7UGyP}X5}Nl~(hD`Ew~P$UuMx7%zxpt9OchTKPaSWjvY6HLqU`>md3;ZXTFb0awC zFG`qqNgs%`>bV}D^7RAP9???vIk_?bd5f=|DIjxBYv1IRux3EDJnh2z>T-Vobb>= z)4d6?XEqx54Sovg)Cp9oWQi3F!AyfwLKaa^X=V3|y;6miiEW+jaJA|i`43D7^(}j? z7`W&Ds$s(%!FRk4?a!b(d6dt}k6Ea=xe_Eg846J4$04D64T{H_{{U?x?TaAxFlZG? zYo7brdAOt{lqHq736yzMrIm!--02GXNh5tdNxAEY?{iJdhN>Awamr3mLJOj^L!IZM8#z*BFwB(} zV{1>D)QhCJ2VT1odmnRwgJYKH&5Svq*jXY42~IY-PfcvIx;3;g5OP z6#k%+FS19&RHmF?HTE4+PQy*Fzx(}h7NOS~=%zspj$7)B(D|ok$Q2|hpd_Tnd?7Xp zBXsKgu0JedG1@@kb?AK>t9A0bf_B<>%|Z>KaKLhdYFRr=|_ zQHXBP+^KE7wM6n1mA7RZD!^OQ0(Fk*Sm$3rlQX$UQ)GZP{eAEUYHksnU2Bxf@sBA) z&$$aQ(2Fd&B}}R4+S7YFozg!&#l7(sb{kwPEHlxJ$v>Q>D!53ypchF&A?cPQ2_?Ej1*zl_`c>WGc!_VdpO3aUh*e5ZD1Yw~8*W zve9h66%JUF}53fqy125W_cIrKAgI}0? zr5erQ{U?f)MiZXCZN@%jPsVC9{IbCMe99NOBK>_n_G*EaovqJNAJ z47olB4RZEm;oe(*pHZR821;3R$4l|tNl9ALNh(lSMabUD7=c;{k+NSyq53INVX-=n zNNw60gT~{3f(7AHhc}0LcDk(Kx@A7SHcC}y-uy`Igr#Xg?hTIi*bt$8?TM7JHIQTn zRg$A?y7N4nSxYRvS$aJBtZ9)@%WHE}OGC+8UrK@V3twyh06x25l+Ene=&q_N4_lmS zExN_UtlLn^*(}2At7gjMaiX=OW@zr+NCijE8S#px zSIpG~$b~J4jX8Eu>w?N9Hc)L>vaNKIEn$1@d|FV-(H+)8rgxdZ^HOrJn;=suKeeio z%qn?W80PEp>rt=@Deb?0_UYFhBY+@Zb$1cW(*9bWVJ5Q;Vv5}@*_AoXveFw45}lQ9 zqQlpvhf{z^+dDDfp2^!JWM4z_MtLtU)umYa}P% z1AsO-M>D^IiHXxXYWW^^Wvn@prR8@v(YQ~PCDyYG)XF^yJZ93DTwa^H5_JRWNeRF2kWw@2F>d@&+ zW*e?4NU^_|I*^m!p!LI@OE7hWgUeI#3c->@2fB9Ur@?K@;SEB}`SZqBLgD!pZt64a${!*(o2EJYp7DcQ0?naYi=ocf3xCl*n0` zjv&crGb#+`9&t(^h~1X!M1qth3KzHvW!KXD7JBtz7iym#N@Kj?(h5i7FWEN)U;M9$?EnQ+Jf-qw z8*Zr8QawEhdR%bcgla;H#k390$?f*X7Tnk){-Lppof1}e7xK$=IaTH#l`fhILKKD+ zqT{!)LO|b9I|TPQd~N{Wl8IMc*af=ZWDh9JtY+4~Y)oy)iF5*nuW-=*={tf)u_FD* z0|Rv7$4wDwsa#uk?o=4~l`Ah~{tQ>Mg?^}eLB%mV;L}1bsp4SlX6s3vat%DQe1Vqy{Mwe3u9=~!rS`)0HW6CkA|4f zFf(6+SlJRTZ_K=2jH53w7b3jX4Zy_IY57IyRCOtAGTNPvmn?@Cm6W{m0FtU<0R2Rq zbh60T)4HnobVIlA=F`)->FM6NqwvMT4mA8d{Ceds0al_^>bWi?h97;(b7^z-bfI}QdBo669cLI{JOg6-YjL6(8?_KXf^!MuB3cx_?4cX4>7~4 zg&0#a_G0GK=R{k`yf}@h2OM#m9YJXT197El7u*mo9a+`JTt^KRPB|#3kVM12uI{%B zE?s^je0xU$yf|kW@MV0yW}eBWQ!IB(m#&aUu92yK_%U0Bz$KZWjW;NLPhTrxJWjp? zQ}$eN)56{lG^W<`>LeF0xCgK2*Bbhl07I{$^eEVJ=oFseeE~3F{MutF$xf{)VFYYc zNJ>-h=1~1Hl&-2SaqduRZsTU`y29`=!6;lD;B6jz?MiPkR~v4nEpDent+rEUn<*n> zVx^Jl>GZ`#Fwc1wTNtR?F~LdsvevNT`Hiag>PfKl+omjH0BWIv~fH9MGil~#dFd6h?^MiCov z#>&tnICZYwuca-5M?h`g9)Zw|JUPyA13}4o?@g+YR@U=8(?;D=qaEizYE|XLHdiEu zTWZGsV4D%QO~~(TdJJulI97^paueL21 z!U3@d#C`=^B{?0Pyb&atvohm{rBtSf$v$;3pF5YZ^MVN*@3&7(2dF1^kE&MF*oxDnuAGf-q;0j0hhx*G_%t-qXzaHh z7DF*Gc0ttltDVeMn5kN1J4Io~1(34KNO8+tTK59h0Q4tfa48I-_aqMx7k-j3+ZNpw zJ(=oFu$c*!4YpPbV^io#2)9y7PLK`Gpl^=ruFhVcWx|kV7aOA*CTFfPo@4cRPo>Z; z$a%MbNa^KDQ>i^V+;4|b)V-SATgazXVfQ;7JBn60n(E=yL}i2_Nq1VFA-3+D0xpuR zLi=tzZHot0G&aC_{uK<+_VYOr&de2;-IChjH1#>O0PBFXtlQcEGAq`EKLN^X*F1^Wy~imBJW$Cj2vbRgIzHCHq{ zR;IYAbZF4YP*u{kE0?#Tht>8e>(KPXi5Vl>F3VfVbX3+Q!(Svx7O5&kDUU&=uoi~P zt~jL~T5b|-g?G98Z|iJDEH*kD`64nmYFu>gO)raV$eM;@;Hy;SlydUBZmvRrNn5*gk4c5B6LAOzD z-V{_)+wW5%#+ecMDs5U4>z^&5E;-N@29A(_xUWoTaG1oHJ3#n&Ea0E3#_Ai!{{RhB zqv6Q`rExl-hRe!(EKQ0mf&vf*tNwS!%h{Wq*1f&Od55=mH>iro`htgiDJ32RX$dWl+CIoLa+lk?SvJkrb?NJ|g1v(N^i#Y1gTm^U8cUr&->*zfO_+Vt0%toF60P2Y? zG*$t+E2ieU>XO==p3OZdPLin+Lv5_@VhC9P6Snr-2AWfp3jjITga*;ad$e4jiOiLy z##51{(x*vSAuL4xO?t;b4RTaFEC74gSePPC<6$ZTB)zDZEOP-?v z4SUX4un>E`%2=h1p6Ru_{^<1a0T2|3^D|CUM3vm~`H54F>`j$%WSa}>@6y>AXS}tx#d+%0%{7qJo!Pfc{d=8$qk{q!-A3v>- zpM|x(sR0P`O=_X@G9*7!b)~p929e4Qvt)o9YR1SGNITl)SGgpTK}hBsx!)V2Nef;* z+x!xKK4+|#mePnyXDIVlS->Dw>BYMVY!+v@L@CXKyA}&V# z_C&^hcuI`u75b9FPNLL!5mvocxEdW*lh)lfzW9pqROjZ6+8#iBiBla<3s?bfsXs6h zsdd@whKHxjFsBd_U3NN9qjPc=lnplfVncx<&T+r^eyDNNMh)`%6bV&Ir^*RYsuZaL z>TSS>-bYdNq$L;Cu-k6O)^^Szg?Eij4{MPO1dB;7~3;mpMY)i!6{6 z+Sdlx-w|1cNc%mmusjp9M%(59+rNLxf*k6^S7kbfDz!9~-ES$Bl8|lW4kg6&-0qWrzBe%6DR(`-i-b}C z08_2VSqcE0Kx4l~W15w?kh(h%iB`UBu3MxLz0^l;w;!e?Fvjn64SUmFN*Znfzk&$W zYMBvls-G@RMqyUrHN+&`oxxI)Z*If%wi?#J(seiGo9>(2;G-kS#x4v3|J(!Im%GA?f z6KmNvQ3t5=0zn;x@dc7pIF~Xrm-CI&-%S7krP}%ZlEqn$wM>NZojFZO(1RSf>nTG9 z`}4w)Yg?fT7T>NWxz&-j`VSj@P{lkCHrL4lV>nBFrksAQNSQEPr4Z_js5(Eqkd$8A zTHD*#5&r;JEv`k+bAmCWjkdSMB8j<@y;mkIS60L%3xz4=7d3YZ2m??(I{ui6Q!KIz zL=UPnDdJ|Y+qfetT|!hzEija=Xtk8Kp9;15*$W?SuZfskQ#XMho#+z99&5Kz;Ez*P zksZ!c$&g=H)ayl{N=KmcEAscnkzfub`|}nr%BK%aYtc z-l6~+m!j$a03*2rd{@pRZx;^`N6S=b;Us_>Jc`dzsy|DAfC;U40=zTEeRWa=Z$Zg^GvRSalM&b)W{{WaDmDTdfqFLyH`#uqZ(?x{ zSi?vJ>$d0UK8Vr6YSfqnMI1Eu){&B{1; z{a3&H6=qnf2YY_2XMPD>4DgpNpdf{+pABN?a5+GKk;5>Hbyi+?(`II^c<( zt;g1@qR%SBab;NVwT1ES=QW8VfL}M}yR12-j$ahmawWMgB}S>LLV{UC{{Sq9cJk_Q z0HGZyo*$(vht<&2!u|_^g$T<63buA(DzM5%G5^@V~3HrQY6q z9d4g@RI{+Q0?Jsg+tu98zpzD;x?!VxEj+aKJD)U%mo^d@LK%em+eCL;R*70dT_?)m zNa<^hx^05J&dx?_0Hd*yXyDtVZAz6_dILa*RT(P_K?^#ZLXPUN>MddR^}?B%du~vL zGs7>zVy08ufLE#;t&{zuX?*UYcQ(=hA4vzP_P}JC{g4qOr(t$tLado=mk|ka>M)R- zCFaWXg;<3Pk>0?LyJ9=ve|V{GiLJOCPzg-NeH96<$XXCJItW@^ur?ywT=ng2J&ry| zZjFP-#S$u^DJ$l^t;vW$NG>f-6oNZklWm9F1#?3+w(34$d)8qk4YbS8IW?szNhLzV zLAg4TPfo+80(Y=Q0^>IxNTO{{6D-Jdy*f+l1xaqjYAFY;#=vcWJ=P%=nFuZ^pr2n= zG5124emLe3RH3K?>3uf8+X9i|`Xj^!;SR5PwzuAOI$mJ5*dBD7*zPv=_c*M? zU}M;F>aK9wuC7o@cPNz?Di9#dO4NCc0!P1H@#YnAfa7)Q*mXtP2tyX*n)HH6J8j<- z^D&@k6}t&=7DX>8B}#2e@{w|$zLBj>2jsiaft z4LJRY^Ds`A2H)T+#HphXX=zlrtsh@b==kvQ8im&;Xl)!!;KTE%5`n0>2@x#>Cu?d-52cN}W=wOtzTgsEB@QcaLTL!c=xB}ppY`bty+NWR1|Mwm?FLKRjGO!iD^ZLv*EuN@gX#cqDc zd1r&Q=~>o?MxP(%W7DawI}V!-r%UNXnU+c#RE5WBw4+f{o8~MHC>p4+Sf!SswK5Gm z_;L#88=bL0>NcFW_3uBr>K}sn!bWDw%FdOz@o8)XB@0V0g`qDC^AJyaDMcWik8Sa; zuXtc5nwQby>8#Q%mvnTc=8WkIt5t}WX|R+WW)htwhZIG%i*-Uzf8MdS);OSce1*qy zwQQ6=Y_0b~)8%Tr#X1)i65W62>YPMsai+H&T6tRUVh)=QUAMUX+gr9EQpop615NL` zrpK6LaT07cw;SxYX_2Rom#5R;n9Iv)mhM|cl2>7HoB6GN$I}{F91D&3CeW8QHU}Sh z8CPpAKDSH~`JtRfg-)I#Qq3oaRhbK=GgOBfDxFLPfZ2HowZ^L*$5Hm%d@XdEtzH*P zc9!!|uY@nT#ai?%#Odcz>A>iY>vk-uRCUv~UX3xfK1yq(t5eEt zM_Y>pK1*FG?{##OPXJ)+oxcv?s4DB-S^of+kNz0kjwg}sQjf)V45<87@UO?N9M&6X z!=IFD1-mCmZT1;2vbzgdrEDU^TM^8LGuJnEkbMf*U~#a>*sa-jWcVEy&W+mjaVb=F z$BRe+=_*@}v86Y%KyyI7`i_Hcryo$$K36a}Gyp*S-F!KXQAJHzEj@|I=MH-tT&U%F zZzZ+-^>yY#l#-z#wu+N}mexrwE6PVF|G#1*VM0a_AyfEW}aW}fOPM= z>H4FZr1-ARS$0I&-?N~>lBC9Lmt8WGs2i4slq9GmT#Kn9;`{I7Gu4N;s~ay}qM$QW z{-NVuTdkU9Y@bTYR5a6`MLIK%wi{D{q%&X#m82yp8bIti-0gktuz(G~S}NAvg_{%c zQSUAB?VPV!;vP}WRRlR#rcF|tN?RdjH!TIV6_fkdR>XtoI|2&{ZmDUpT-266^GO9b zJSfeRIEx|N#_|K&i4j>-iEy%#1^kG*K(RaA+uL!6iNSWeDY$hzi#pBRc=B0z=~$bV zVZw(dRESb1xTvt?HWCt-3Qqc!bT*(aeA^p!+Y=mY!tP3k5HITlJY9Pz2f&E=*EI1u z3<|Vr#L6uV=c8(PDGajtQnZB|ps4=jtAus58xnDd4VZ zT6wWxumfp26>xP6i(+{Nt*|?+Y}9eoP8{~!H1Xy>$^d*pI472JZcgF<03GNwhp1J` z6;dPyoP>T^u@TjBxn&8mZiAymfFK(S1Avw_(7CM}D(q>}Qq{7dr1rEY^NQEU4l_p+ zJWFwslHEExmAaHxnU5-@Tf6PHm8ngo_3VNWtz;oKD$+`?Y*a@(ooj_MijC6BWg8wV zb-5cZMd7Av$+<#KVw=vMQo;kIl)oV)sQJL$>F6)G*xuNmJ0xs*mEIX6KT*|RL8@*3 zBAK1~Cx&i6=7{z7=#-(7YBAYFsGROvL{|wdvf8!$!qiffD(gdM&7*P+l^xBptba>q z{!__1I@bNW`_xz9ca9Dp@Xx@X3G>}jT?##B4o{Bju%U#r9-B~HKf+}z2vB$z7Q&Vi z2})G8C;$i<`T{{D?RBf^9w(8F>i5b3J@(tdGk*_CEkljj%ZffJGcIh0#5qCaW$Jx7 zN|xk?-EB^;T$C->-HmsaGhWOb2cOc@E;Q-EEn$fu>=MLGA7ry|H(iv>{Ic}RR}X?9+s zRDi4D?`fKq%mTzHHF>D(*;%`Gxf_G_J7}PWbK?bLj#-87BG<&$ol6EIYJI|P+7_Zp z5%ji&D3t`K+T`M}PUo;@;D%xik<#&UNJ1aGf4&Dj;g8-Jy6|J zRTCRbhl=WsQlP+sh_FLUwAur0G)0n@(kzfI(0~8~2aSYSECo#0If6hYpek4b@O7-uohU{fDfnX zi48hxls3lY1C;6%;+bq&S}sZMZ)<;_<$^}uX|K@ek$KLy6D?)h=3!7mT7e1Iz*(|Y zp#=2zBEd9>Ufi31+v z(dsc3D_YTGzMHQV$E(EEPH5O@76<5Gw4)+t^oRCaM7W-6B8906)3EPiIs!M`j9WUK zyS1GE0F_lTuTs+6`J&`yX^~5iAy?g)m1al_zm@p+Mf=yKQe! zaCsj0YSw~(I4F@8gJR=uNCR+Up~u+FQz%Pi#DJqNn*}X{f8J8AP)N4qeZ6rGS2eB; zn~yLo5#l6*==gV(E~A#BL1H9`CYb8oP(yA;lv2`kn{1Y@0!7j`+pgG`B_vF4VQ(#v z&11{8B?0A%iBxKnvE7u-teEYUl&FK}88OqapW; zd760%Qc&umzoE5uD@D&vn*y!+j7H6szyo{p2k53WHO)5`w<49Rt4q+(nI2SIB?(HN z=M*U?u9ORDy~yoj*xwdib8JCvt>a}ECfe?W%8^om9e}*WLX90?Q-88taY|0Bq$u3m zVX+_$g@*UQdg~n7fF2i4F*FPPY=p$4RUc-c@S5bNU25($y;|E=p|*nFomMspx!C=V z6h_AaST!Cgf=gH(j}*uFjHELMIq*@+tBlT&?p=mlN~9z$wY&RK(v|eL_N@_PYj+_d z9}0Bkqb$u~*D>M!<@$5%#;Wd#q+A98{{TqyMI18Vbw7?!ICH`b!wQ{6pl5LCi&&`4 zoXke2z=$L^7!evtoD70gK*0$yaB4bHctm3b(d+Y&!C)p~_sBt8L(;l1ADp=#FCOwNv z^51EAu&t(z<5CV7x`rvDw8CCilh!lVe?uF z@PFOuGVhVgc+%XW(y7UFEyb%$a5j`V5veI}mXrJGE55DB+sog6*!O8_;)}Hd3Glbo ze1{ZrJN_X7Vxfk;2vWC0Av@w zXzh><5@NeU%eitgTANjNqUyAzl*D*TUG3W-Q+ zLX}gKE^W4HxB11ij+-TS{E67#aof7K!F<bpt{5W2ciN|l`~x>@7gjc^maqq z)Le@5NfFG|5Y4St;WX0a@``rqu(dpF)MYgIg)m{yxT3c>OLuUF? zLuye3cem@`51y5ej@Qh4^+SQ>kIid%e!*j;#Fkt{T9soa7E+X-{e|dh0CxkLNjKHC zukD6X^=!0ndk2+~CX|v(LG{1I9nD1&ITC;MT(_2_qU=R01opX5=sx(9ID{UsSok5g ztRpE0^TA@5IucUbjm^r;I#GMMO(DeGo0RTJ8xH=PU=FWg&}H*(sDc91p+34HjIxl| z%tcmRn##ZndARF98~H)#n~%@<;PJFL2Q)O_k_56FkVy*~DiWacd2lJPrmyOCAuiu; zsY+Ipxb5sPVN~{923Vdyw&}S;z`M5L`>$1-r#Rzs9ETyv&7+uyORlzcTE@soAtTt6 z(*voR7Y#+qa~Ug5!SYv8>9rKMt*T2EQWIuFvYtm?z@10$Vb>9Cceg{;f(h8zk~a0d@aZR!(cWN49pENLSRZESN&vRv)zcYqVWIQ` z%v5mWTGTE*7F0biVSh|h$txwXW{u^i-s*E+=!w4k(z-1!m{lE7^2GL5k`hwN>=F&` zE|c4Bk9=6tb$f<8)CC$@UOndzpV17RP^Um;#uZMM-O@I8LP{2Um0TUVT}InteNB83 zv;rJ2-Vj?9j?j_lv8l;5cG2?DR?9X?=Arcm2mH3R@3!_obAdLbNC9JX@zpp3we{~+ zhfby`PP~c>R$ICqD>{_=lhH(E8{KXq;{vZyo+g(T4_E#^<|4X8b87&}sR7 zE-eT;idtHfow^%>N9EHJBss0svu@=bj>Ji zJqIwP38MqF??RMO8i?>^6-YGZUP#nX;u4^OeL{dY^&jbrSmq9}nWFr^WemuFrs&mh zDNQ`eS)@g6om!CCDY3BJrofMG*dri}Jl%rcNv@JW%}%PvU{XBIwMq>~Rg|VNfSmp4eNXT0>7H`f1#Bao4>86xO3OvmPwEgI`KoGE$}V`ff-CSNmWNYjWmb zE*-~YhEiW+r;@EMn-VmnzZQow45c8c*3!u4DMzlQ0C)T1EOEtt(;PgJUo*=84*jl;_S01GD&K-7=VHDk=y)p*7vXWMNf zQdFNUwmY^`mEQuX5{)uk_-X07H9OdK4zWb(q}L~fnyh+2h*VI@BPsBt4uCkDk*IXI zwg$>skG$4_zzhA?30r*$zZ=;JO)8ZI5tfBWiVD9JG*aRgvD7I#Zaw!O=YpI%Hh|}X zIr2>F^&>)!wXhmfuhi<4+Ak?YJLOL+YuOEz5>x6eZ$dCBoWL_?%HDc>uXJEs>i{l% z57}x%;%z29LVpHku~uTQ6;LXuZT8TR6cVPbasV2Q`Wum9zT+Na(^{5EGdj0s0573E zjYdQ>+*sYeRke=>g#(0nK?!uJYNo^1Yz2=X97e(Pjd`z3<3Fo$9M8>1-;00Co(FJ= zh^@G}O3w``N4fr_{=>hf1C6{EG%aVb_`_=FfA>DCokrvswG}=Rc5vJcjj!9#<2`GI z^gG#^wp%LrdC7>+7xdut93bd8qa-BC97CT!7%F(Nih)$a^vs?B> zFI4Be+m1BzQXJ^ChP5pM;CYlyjqSOx>xj}dgxcCC$1|JRHo7i|UTCw-dNXfo1;)w< z)GzFIJ#Ia_;GpYfw?KsUf&nho6FkH@HzqvQzo@0v1q--2l0T)7K5Yd9g?0Y%hDHfIUXX0g=vafYnKBOZ!`X za!t&4ALX5K6ohrPlDSI;x!gvr8(otU45wsU#AW3;zJ9 z{ITbF?LJrBFHGqDQ7y44#!B@AWTX-gPX7RxY-FSt)Gc!*Hn2qNLQ+-~n{H2BS2>#M zj@JX+fx6h{Ac9A0d-uXv17eQp2lZVOOk@yKVXPg8Y;d;aGDx$G@NnW?cIaivg~P(KWwERH2`5|x&!GDEdmI9(y&Rdb~Pa@2n4Qa?kC zUOh}2{KJaFIuiw3*wLZXcpu$4*}H-KY2wS-tHWmlB*ceP%u@p7NtYxu8U;DaE;5JH!XV zsx>L?2H%q!Q|W2MEo&(p#;lb#rw*?vb3(KvCmOn<23Vrf%D)MsC61}9?LFTv7Vujz z;XNVz%!(#aD3117rM01GW6AT*B!H(0YyrvCm1y<3JMDR+OWw9aDEZ{glY3 zW!Z4teRAJwQ%OP*9fTk@h{zYR01ES4ZT9Kugk$tK-Id6l}56K_{ihLy66*8Z>H3&z6WTU9j0px;$#5k)Wbf z2I=7-1tU;Zh#T+gd+&m|pqmwEP1Y7(+Wu~%XBYe(WF8|)sa4=r>$zIJC49%0&=OjC zXR6fOgb<@)x>N_YATpFke4|39S3=p_+xNMpPXu^PmH1mnYL7r#r`4HRYIQ-zl82-^ zl2dC7gdlVX+;uyWP9?B{Mp0m?pu8e%;ww`%`5T?>{2S9m1ucoq&GyQ(`e9HMwGK1poE}a`+5z@{P3+g1%it$BV6+P zYsDVTha#&1Q9{Ia+yy0R9$|6Y*VJLpg6*@Bsp?20D7s}b22`VP`k3Vkkm;6^>#n-D z7J~E66ZNP9E_w}zKsFY_0eFKr1qskLI+sdMXq53%9pzJ)XLejGJE(LWdiU*#7X$z{ zT?CdccNMPQH+W0T99QEUJlfV_e=YFsA-C#G!&oya52at&3#Us=tZ6D;^;+Oq?kgWo z8gn~q=sxLjpz55hjM#yx?(XmJQ}-xkid_Po0+j|8J|uRULu|7dl(d8Z1%OIM!*5f9 zok0#dpwd&eHnofv3O{(p<91r$uZ8|M=Gxs#GcrbAn@py(%7JoZ=`EHTX{6rjSuPWA zM4!GJMNaCe8%+=;&Nf#RvqwoQs%i*qarTKjXuf(?MwJFyBR@l_p{L{kMNQ>0r&LYC zK|%<)J+}wcW9kTCdosr6oje!Cc;#>EXO^TNc$24j@l8BjtyglXCC{6x#Zg+hZAeLq zgevFg3PrcK-*dh+!j?{mI9Z`%VW>S8ZFkV^LtWD`dA%+NbV+!tk@3b-u(OvrTn*ISh1(rQem zOn98XEM%(MO0GVlEz`;cyWbuoMNM~H?7o>0idY0^SD%8L)5B~w7V!<6gVx1ApROmm zGEK(H1cVLNnY>2iip0+nl}I^tBBpDt!;=y+7L&?+ptQ5Lz#dk=vWeIn3cZdwUBE1E z6-?*VNdVZJ`5o5QxG$05WDKE5qD0i}<{3kBU3lHs4ZnM9j^HNb3v6wNQ$=mppvd;v zF`nvJXMCwh&Qxb9Rj4s$G0a1(>u&tFQf`Hd^iV#Xi5&^WhHVJosVb=&`yc8Wgc?mU zH4c)}fDQ7<1si#kdXw&djyN{$T~_Rl1SB?M;;R{Eg~?(KYHe-#Ou}KfjU{gDe!&i; zETuY930j8a0ec;R=rYDLos@dY%)zj?bEk)Yg3ppEjW-S}X_ATHm91(mfV8ZyNhE`1 zD2+s`sV3gI26sH%?o`@n0~i`L1BzxmUhuw88Te0|xJe3pNHSe&E37*5O3@xePbK!2 zqBlY{vf5Umb!j^T(Av|0!LJpM=^ZQT`vCi-d=qow7s72L!=DW(Sxo_|ooQ}~l_{&b z)lhv#<;9f^KmbY*l0K2X>Nux@ETomFYXc)}cF+Xfc!kUqoRi0X80M;k^tDWkHPkHH z)TW4Ek;J7JE}!iaVw?2=*c@-(J z@|>5WQlqZQN*`?NT(-dpNg*mmuBaCPBx*R36#9nWb(h87NqoD2M}p(qCh_{e#oYT; zp=Ug+nWb=vx->WfEj5OviW@0QVW(C$D?*%UN<&PIPOC~(NFd^tXdK&yk(<3}>EdQg z?{$ef9epkSi?ROzgwAAZha4oNOR76u |a(#$IOrp2bnl*7V9jFnT6pTlv-WHZej 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

AQ|ep)0AjXJ3NjOuBslw=bC(}V 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

lHgO!Bi;|pi<^i+Cz)g^AVKV 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 literal 0 HcmV?d00001 From 6c62b028b8d911a106d1ab289e5ece043721dee6 Mon Sep 17 00:00:00 2001 From: cewing Date: Thu, 17 Jan 2013 17:44:39 -0800 Subject: [PATCH 006/487] update --- source/presentations/week04.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source/presentations/week04.rst b/source/presentations/week04.rst index 02d94f4d..52d0a5b9 100644 --- a/source/presentations/week04.rst +++ b/source/presentations/week04.rst @@ -44,6 +44,18 @@ In week two, we wrote an HTTP server. We set up the server to be *dynamic* by returning the output of a python script +.. class:: incremental + +But what if we want to pass arguments to that script? + +.. class:: incremental + +How do we let the script have access to information about the HTTP request +itself? + + + + scraps ------ From e94a5516fbbce229df10f987f28019eac85a556e Mon Sep 17 00:00:00 2001 From: cewing Date: Thu, 17 Jan 2013 17:58:04 -0800 Subject: [PATCH 007/487] add answers for week 2 assignments --- .../teachers/week02/answers/http_serve1.py | 30 +++ .../teachers/week02/answers/http_serve2.py | 51 +++++ .../teachers/week02/answers/http_serve3.py | 86 ++++++++ .../teachers/week02/answers/http_serve4.py | 129 ++++++++++++ .../teachers/week02/answers/http_serve5.py | 143 +++++++++++++ .../teachers/week02/answers/http_serve6.py | 162 ++++++++++++++ .../teachers/week02/answers/http_serve7.py | 170 +++++++++++++++ .../teachers/week02/answers/http_serve8.py | 199 ++++++++++++++++++ 8 files changed, 970 insertions(+) create mode 100644 assignments/teachers/week02/answers/http_serve1.py create mode 100644 assignments/teachers/week02/answers/http_serve2.py create mode 100644 assignments/teachers/week02/answers/http_serve3.py create mode 100644 assignments/teachers/week02/answers/http_serve4.py create mode 100644 assignments/teachers/week02/answers/http_serve5.py create mode 100644 assignments/teachers/week02/answers/http_serve6.py create mode 100644 assignments/teachers/week02/answers/http_serve7.py create mode 100644 assignments/teachers/week02/answers/http_serve8.py diff --git a/assignments/teachers/week02/answers/http_serve1.py b/assignments/teachers/week02/answers/http_serve1.py new file mode 100644 index 00000000..05f45505 --- /dev/null +++ b/assignments/teachers/week02/answers/http_serve1.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +import socket + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +print "point your browser to http://localhost:%i"%port + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +html = open("tiny_html.html").read() + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received:", request + client.send(html) + client.close() + diff --git a/assignments/teachers/week02/answers/http_serve2.py b/assignments/teachers/week02/answers/http_serve2.py new file mode 100644 index 00000000..37b591e6 --- /dev/null +++ b/assignments/teachers/week02/answers/http_serve2.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python + +import socket + +import httpdate + + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +print "point your browser to http://localhost:%i"%port + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +html = open("tiny_html.html").read() + +def OK_response(entity): + """ + returns an HTTP response: header and entity in a string + """ + resp = [] + resp.append('HTTP/1.1 200 OK') + resp.append(httpdate.httpdate_now()) + resp.append('Content-Type: text/html') + resp.append('Content-Length: %i'%len(entity)) + resp.append('') + resp.append(entity) + + return "\r\n".join(resp) + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received:" + print request + response = OK_response(html) + print "sending:" + print response[:120] + client.send(response) + client.close() + diff --git a/assignments/teachers/week02/answers/http_serve3.py b/assignments/teachers/week02/answers/http_serve3.py new file mode 100644 index 00000000..2ee28fd8 --- /dev/null +++ b/assignments/teachers/week02/answers/http_serve3.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python + +import socket + +import httpdate + + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +print "point your browser to http://localhost:%i"%port + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +html = open("tiny_html.html").read() + +def OK_response(entity): + """ + returns an HTTP response: header and entity in a string + """ + resp = [] + resp.append('HTTP/1.1 200 OK') + resp.append(httpdate.httpdate_now()) + resp.append('Content-Type: text/html') + resp.append('Content-Length: %i'%len(entity)) + resp.append('') + resp.append(entity) + + return "\r\n".join(resp) + +def parse_request(request): + """ + parse an HTTP request + + returns the URI asked for + + note: minimal parsing -- only supprt GET + + example: + GET / HTTP/1.1 + Host: localhost:50000 + User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20100101 Firefox/12.0 + Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + Accept-Language: en-us,en;q=0.5 + Accept-Encoding: gzip, deflate + Connection: keep-alive + Cache-Control: max-age=0 + """ + # first line should be the method line: + lines = request.split("\r\n") + print lines + + method, URI, protocol = lines[0].split() + print method + print URI + print protocol + # a bit of checking: + if method.strip() != "GET": + raise ValueError("I can only process a GET request") + if protocol.split('/')[0] != "HTTP": + raise ValueError("I can only process an HTTP request") + + return URI + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received:", request + URI = parse_request(request) + print "URI requested is:", URI + response = OK_response(html) + print "sending:" + print response[:120] + client.send(response) + client.close() + diff --git a/assignments/teachers/week02/answers/http_serve4.py b/assignments/teachers/week02/answers/http_serve4.py new file mode 100644 index 00000000..792f76ec --- /dev/null +++ b/assignments/teachers/week02/answers/http_serve4.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python + +import socket +import os + +import httpdate + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +print "point your browser to http://localhost:%i"%port + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +def OK_response(entity): + """ + returns an HTTP response: header and entity in a string + """ + resp = [] + resp.append('HTTP/1.1 200 OK') + resp.append(httpdate.httpdate_now()) + resp.append( 'Content-Type: text/plain' ) + resp.append('Content-Length: %i'%len(entity)) + resp.append('') + resp.append(entity) + + return "\r\n".join(resp) + +def Error_response(URI): + """ + returns an HTTP 404 Not Found Error response: + + URI is the name of the entity not found + """ + resp = [] + resp.append('HTTP/1.1 404 Not Found') + resp.append(httpdate.httpdate_now()) + resp.append('Content-Type: text/plain') + + msg = "404 Error:\n %s \n not found"%( URI ) + + resp.append('Content-Length: %i'%( len(msg) ) ) + resp.append('') + resp.append(msg) + + return "\r\n".join(resp) + + +def parse_request(request): + """ + parse an HTTP request + + returns the URI asked for + + note: minimal parsing -- only supprt GET + + example: + GET / HTTP/1.1 + Host: localhost:50000 + User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20100101 Firefox/12.0 + Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + Accept-Language: en-us,en;q=0.5 + Accept-Encoding: gzip, deflate + Connection: keep-alive + Cache-Control: max-age=0 + """ + # first line should be the method line: + lines = request.split("\r\n") + print lines + + method, URI, protocol = lines[0].split() + print method + print URI + print protocol + # a bit of checking: + if method.strip() != "GET": + raise ValueError("I can only process a GET request") + if protocol.split('/')[0] != "HTTP": + raise ValueError("I can only process an HTTP request") + + return URI + +def format_dir_list(dir_list): + msg = ["Directory Listing:"] + for d in dir_list: + msg.append(d) + return "\n".join(msg) + +def get_file(URI): + root_dir = 'web' # must be run from code dir... + URI = URI.lstrip('/') # os.path.join does not like a leading slash + filename = os.path.join( root_dir, URI) + print "path to file:", filename + if os.path.isfile(filename): + print "it's a file" + raise NotImplementedError("I can't handle a file yet") + elif os.path.isdir(filename): + print "it's a dir" + return format_dir_list(os.listdir(filename)), 'txt' + else: + raise ValueError("there is nothing by that name") + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received:", request + URI = parse_request(request) + print "URI requested is:", URI + try: + file_data, ext = get_file(URI) + response = OK_response(file_data) + except ValueError as err: + print err + response = Error_response(URI) + print "sending:" + print response[:200] + client.send(response) + client.close() + diff --git a/assignments/teachers/week02/answers/http_serve5.py b/assignments/teachers/week02/answers/http_serve5.py new file mode 100644 index 00000000..6ce40fd0 --- /dev/null +++ b/assignments/teachers/week02/answers/http_serve5.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python + +import socket +import os + +import httpdate + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +print "point your browser to http://localhost:%i"%port + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +html = open("tiny_html.html").read() + +mime_types={} +mime_types['html'] = "text/html" +mime_types['htm'] = "text/html" +mime_types['txt'] = "text/plain" +mime_types['py'] = "text/plain" +mime_types['png'] = "image/png" +mime_types['jpeg'] = "image/jpg" +mime_types['jpg'] = "image/jpg" + +def OK_response(entity, extension='html'): + """ + returns an HTTP response: header and entity in a string + """ + resp = [] + resp.append('HTTP/1.1 200 OK') + resp.append(httpdate.httpdate_now()) + type = mime_types.get(extension, 'text/plain') + resp.append( 'Content-Type: %s'%type ) + resp.append('Content-Length: %i'%len(entity)) + resp.append('') + resp.append(entity) + + return "\r\n".join(resp) + +def Error_response(URI): + """ + returns an HTTP 404 Not Found Error response: + + URI is the name of the entity not found + """ + resp = [] + resp.append('HTTP/1.1 404 Not Found') + resp.append(httpdate.httpdate_now()) + resp.append('Content-Type: text/plain') + + msg = "404 Error:\n %s \n not found"%( URI ) + + resp.append('Content-Length: %i'%( len(msg) ) ) + resp.append('') + resp.append(msg) + + return "\r\n".join(resp) + + +def parse_request(request): + """ + parse an HTTP request + + returns the URI asked for + + note: minimal parsing -- only supprt GET + + example: + GET / HTTP/1.1 + Host: localhost:50000 + User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20100101 Firefox/12.0 + Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + Accept-Language: en-us,en;q=0.5 + Accept-Encoding: gzip, deflate + Connection: keep-alive + Cache-Control: max-age=0 + """ + # first line should be the method line: + lines = request.split("\r\n") + print lines + + method, URI, protocol = lines[0].split() + print method + print URI + print protocol + # a bit of checking: + if method.strip() != "GET": + raise ValueError("I can only process a GET request") + if protocol.split('/')[0] != "HTTP": + raise ValueError("I can only process an HTTP request") + + return URI + +def format_dir_list(dir_list): + """ + format a directory listing as simple text + """ + msg = ["Directory Listing:"] + for d in dir_list: + msg.append(d) + return "\n".join(msg) + +def get_file(URI): + root_dir = 'web' # must be run from code dir... + URI = URI.lstrip('/') #weird-- os.path.join does not like a leading slash + filename = os.path.join( root_dir, URI) + print "path to file:", filename + if os.path.isfile(filename): + print "it's a file" + contents = open(filename, 'rb').read() + ext = os.path.splitext(filename)[1].strip('.') + return contents, ext + elif os.path.isdir(filename): + print "it's a dir" + return format_dir_list(os.listdir(filename)), 'txt' + else: + raise ValueError("there is nothing by that name") + + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received:", request + URI = parse_request(request) + print "URI requested is:", URI + file_data, ext = get_file(URI) + response = OK_response(file_data, ext) + print "sending:" + print response[:200] + client.send(response) + client.close() + diff --git a/assignments/teachers/week02/answers/http_serve6.py b/assignments/teachers/week02/answers/http_serve6.py new file mode 100644 index 00000000..c11bb695 --- /dev/null +++ b/assignments/teachers/week02/answers/http_serve6.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python + +import socket +import os + +import httpdate + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +print "point your browser to http://localhost:%i"%port + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +html = open("tiny_html.html").read() + +mime_types={} +mime_types['html'] = "text/html" +mime_types['htm'] = "text/html" +mime_types['txt'] = "text/plain" +mime_types['png'] = "image/png" +mime_types['jpeg'] = "image/jpg" +mime_types['jpg'] = "image/jpg" + +def OK_response(entity, extension='html'): + """ + returns an HTTP response: header and entity in a string + """ + resp = [] + resp.append('HTTP/1.1 200 OK') + resp.append(httpdate.httpdate_now()) + type = mime_types.get(extension, 'text/plain') + resp.append( 'Content-Type: %s'%type ) + resp.append('Content-Length: %i'%len(entity)) + resp.append('') + resp.append(entity) + + return "\r\n".join(resp) + +def Error_response(URI): + """ + returns an HTTP 404 Not Found Error response: + + URI is the name of the entity not found + """ + resp = [] + resp.append('HTTP/1.1 404 Not Found') + resp.append(httpdate.httpdate_now()) + resp.append('Content-Type: text/plain') + + msg = "404 Error:\n %s \n not found"%( URI ) + + resp.append('Content-Length: %i'%( len(msg) ) ) + resp.append('') + resp.append(msg) + + return "\r\n".join(resp) + + +def parse_request(request): + """ + parse an HTTP request + + returns the URI asked for + + note: minimal parsing -- only supprt GET + + example: + GET / HTTP/1.1 + Host: localhost:50000 + User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20100101 Firefox/12.0 + Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + Accept-Language: en-us,en;q=0.5 + Accept-Encoding: gzip, deflate + Connection: keep-alive + Cache-Control: max-age=0 + """ + # first line should be the method line: + lines = request.split("\r\n") + print lines + + method, URI, protocol = lines[0].split() + print method + print URI + print protocol + # a bit of checking: + if method.strip() != "GET": + raise ValueError("I can only process a GET request") + if protocol.split('/')[0] != "HTTP": + raise ValueError("I can only process an HTTP request") + + return URI + +def format_dir_list(dir_list): + """ + format the dir list as HTML + """ + html = [" "] + html.append("

Directory Listing

") + + for d in dir_list: + html.append( "

%s

"%d ) + html.append( " " ) + + return "\n".join(html) + +def get_time_page(): + """ + returns and html page with the current time in it + """ + time = httpdate.httpdate_now() + html = "

%s

"%time + return html + +def get_file(URI): + + root_dir = 'web' # must be run from code dir... + URI = URI.strip('/') #weird-- os.path.join does not like a leading slash + # check if this is the time server option + if URI.lower() == "get_time": + return get_time_page(), 'html' + else: + filename = os.path.join( root_dir, URI) + print "path to file:", filename + if os.path.isfile(filename): + print "it's a file" + contents = open(filename, 'rb').read() + ext = os.path.splitext(filename)[1].strip('.') + return contents, ext + elif os.path.isdir(filename): + print "it's a dir" + return format_dir_list(os.listdir(filename)), 'htm' + else: + raise ValueError("there is nothing by that name") + + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received:", request + URI = parse_request(request) + print "URI requested is:", URI + try: + file_data, ext = get_file(URI) + response = OK_response(file_data, ext) + except ValueError: + response = Error_response(URI) + print "sending:" + print response[:200] + client.send(response) + client.close() + diff --git a/assignments/teachers/week02/answers/http_serve7.py b/assignments/teachers/week02/answers/http_serve7.py new file mode 100644 index 00000000..ae889efc --- /dev/null +++ b/assignments/teachers/week02/answers/http_serve7.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python + +import socket +import os + +import httpdate + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +root_dir = 'web' # must be run from code dir... + +print "point your browser to http://localhost:%i"%port + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +html = open("tiny_html.html").read() + +mime_types={} +mime_types['html'] = "text/html" +mime_types['htm'] = "text/html" +mime_types['txt'] = "text/plain" +mime_types['png'] = "image/png" +mime_types['jpeg'] = "image/jpg" +mime_types['jpg'] = "image/jpg" + +def OK_response(entity, extension='html'): + """ + returns an HTTP response: header and entity in a string + """ + resp = [] + resp.append('HTTP/1.1 200 OK') + resp.append(httpdate.httpdate_now()) + type = mime_types.get(extension, 'text/plain') + resp.append( 'Content-Type: %s'%type ) + resp.append('Content-Length: %i'%len(entity)) + resp.append('') + resp.append(entity) + + return "\r\n".join(resp) + +def Error_response(URI): + """ + returns an HTTP 404 Not Found Error response: + + URI is the name of the entity not found + """ + resp = [] + resp.append('HTTP/1.1 404 Not Found') + resp.append(httpdate.httpdate_now()) + resp.append('Content-Type: text/plain') + + msg = "404 Error:\n %s \n not found"%( URI ) + + resp.append('Content-Length: %i'%( len(msg) ) ) + resp.append('') + resp.append(msg) + + return "\r\n".join(resp) + + +def parse_request(request): + """ + parse an HTTP request + + returns the URI asked for + + note: minimal parsing -- only supprt GET + + example: + GET / HTTP/1.1 + Host: localhost:50000 + User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20100101 Firefox/12.0 + Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + Accept-Language: en-us,en;q=0.5 + Accept-Encoding: gzip, deflate + Connection: keep-alive + Cache-Control: max-age=0 + """ + # first line should be the method line: + lines = request.split("\r\n") + + method, URI, protocol = lines[0].split() + + # a bit of checking: + if method.strip() != "GET": + raise ValueError("I can only process a GET request") + if protocol.split('/')[0] != "HTTP": + raise ValueError("I can only process an HTTP request") + + return URI + +def format_dir_list(URI): + """ + format the contests of dir as HTML with links + """ + dir = os.path.join(root_dir, URI) + names = os.listdir(dir) + + dirs = [d for d in names if os.path.isdir(os.path.join(dir,d))] + files = [d for d in names if os.path.isfile(os.path.join(dir,d))] + + html =[] + html.append(" ") + html.append("

%s

"%URI) + print "URI:", URI + if URI: # don't need the parent dir at the root + html.append('
Parent' ) + html.append("

Directories:

") + html.append("
    ") + for d in dirs: + html.append('
  • %s
  • '%(os.path.join(URI,d), d)) + html.append("
") + html.append("

Files:

") + html.append("
    ") + for f in files: + html.append('
  • %s
  • '%(os.path.join(URI,f), f) ) + html.append("
") + html.append(" ") + return "\n".join(html) + +def get_time_page(): + """ + returns and html page with the current time in it + """ + time = httpdate.httpdate_now() + html = "

%s

"%time + return html + +def get_file(URI): + + URI = URI.strip('/') #weird-- os.path.join does not like a leading slash + # check if this is the time server option + if URI.lower() == "get_time": + return get_time_page(), 'html' + else: + filename = os.path.join( root_dir, URI) + if os.path.isfile(filename): + contents = open(filename, 'rb').read() + ext = os.path.splitext(filename)[1].strip('.') + return contents, ext + elif os.path.isdir(filename): + return format_dir_list(URI), 'htm' + else: + raise ValueError("there is nothing by that name") + + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received:", request + URI = parse_request(request) + try: + file_data, ext = get_file(URI) + response = OK_response(file_data, ext) + except ValueError: + response = Error_response(URI) + client.send(response) + client.close() + diff --git a/assignments/teachers/week02/answers/http_serve8.py b/assignments/teachers/week02/answers/http_serve8.py new file mode 100644 index 00000000..53eb5ecf --- /dev/null +++ b/assignments/teachers/week02/answers/http_serve8.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python + +import socket +import os + +import httpdate + +import subprocess + +host = '' # listen on all connections (WiFi, etc) +port = 50000 +backlog = 5 # how many connections can we stack up +size = 1024 # number of bytes to receive at once + +root_dir = 'web' # must be run from code dir... + +print "point your browser to http://localhost:%i/make_time.py"%port + +## create the socket +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# set an option to tell the OS to re-use the socket +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + +# the bind makes it a server +s.bind( (host,port) ) +s.listen(backlog) + +html = open("tiny_html.html").read() + +mime_types={} +mime_types['html'] = "text/html" +mime_types['htm'] = "text/html" +mime_types['txt'] = "text/plain" +mime_types['png'] = "image/png" +mime_types['jpeg'] = "image/jpg" +mime_types['jpg'] = "image/jpg" + +def OK_response(entity, extension='html'): + """ + returns an HTTP response: header and entity in a string + """ + resp = [] + resp.append('HTTP/1.1 200 OK') + resp.append(httpdate.httpdate_now()) + type = mime_types.get(extension, 'text/plain') + resp.append( 'Content-Type: %s'%type ) + resp.append('Content-Length: %i'%len(entity)) + resp.append('') + resp.append(entity) + + return "\r\n".join(resp) + +def Error_response(URI, error_code=404): + """ + returns an HTTP 404 Not Found Error response: + + URI is the name of the entity not found + """ + errors = {500: "Server Error", + 404: "Not Found", + 301: "Moved Permanently", + 302: "Moved Temporarily", + 303: "See Other" + } + + resp = [] + resp.append('HTTP/1.1 %i %s'%(error_code, errors[error_code])) + resp.append(httpdate.httpdate_now()) + resp.append('Content-Type: text/plain') + + msg = "%i Error:\n %s \n %s"%( error_code, URI, errors[error_code] ) + + resp.append('Content-Length: %i'%( len(msg) ) ) + resp.append('') + resp.append(msg) + + return "\r\n".join(resp) + + +def parse_request(request): + """ + parse an HTTP request + + returns the URI asked for + + note: minimal parsing -- only supprt GET + + example: + GET / HTTP/1.1 + Host: localhost:50000 + User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20100101 Firefox/12.0 + Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + Accept-Language: en-us,en;q=0.5 + Accept-Encoding: gzip, deflate + Connection: keep-alive + Cache-Control: max-age=0 + """ + # first line should be the method line: + lines = request.split("\r\n") + + method, URI, protocol = lines[0].split() + + # a bit of checking: + if method.strip() != "GET": + raise ValueError("I can only process a GET request") + if protocol.split('/')[0] != "HTTP": + raise ValueError("I can only process an HTTP request") + + return URI + +def format_dir_list(URI): + """ + format the contests of dir as HTML with links + """ + dir = os.path.join(root_dir, URI) + names = os.listdir(dir) + + dirs = [d for d in names if os.path.isdir(os.path.join(dir,d))] + files = [d for d in names if os.path.isfile(os.path.join(dir,d))] + + html =[] + html.append(" ") + html.append("

%s

"%URI) + print "URI:", URI + if URI: # don't need the parent dir at the root + html.append('Parent' ) + html.append("

Directories:

") + html.append("
    ") + for d in dirs: + html.append('
  • %s
  • '%(os.path.join(URI,d), d)) + html.append("
") + html.append("

Files:

") + html.append("
    ") + for f in files: + html.append('
  • %s
  • '%(os.path.join(URI,f), f) ) + html.append("
") + html.append("
") + return "\n".join(html) + +def get_time_page(): + """ + returns and html page with the current time in it + """ + time = httpdate.httpdate_now() + html = "

%s

"%time + return html + +def run_python_script(URI): + """ + runs the python script in the URI + + returns std out from running the script + + raises a subprocess.CalledProcessError if something goes wrong + """ + script = os.path.join(root_dir, URI) + result = subprocess.check_output(["python", script]) + return result + + +def get_file(URI): + """ + returns the contents of the file in the URI -- and a file extension for the mime type. + """ + URI = URI.strip('/') #os.path.join does not like a leading slash + # check if this is the time server option + if URI.lower() == "get_time": + return get_time_page(), 'html' + # check if it's a python file + if os.path.splitext(URI)[1] == ".py": + return run_python_script(URI), 'html' + else: + filename = os.path.join( root_dir, URI) + if os.path.isfile(filename): + contents = open(filename, 'rb').read() + ext = os.path.splitext(filename)[1].strip('.') + return contents, ext + elif os.path.isdir(filename): + return format_dir_list(URI), 'htm' + else: + raise ValueError("there is nothing by that name") + + +while True: # keep looking for new connections forever + client, address = s.accept() # look for a connection + request = client.recv(size) + if request: # if the connection was closed there would be no data + print "received:", request + URI = parse_request(request) + try: + file_data, ext = get_file(URI) + response = OK_response(file_data, ext) + except ValueError: # file not found + response = Error_response(URI) + except subprocess.CalledProcessError: # somethign wrong with the python script + response = Error_response(URI, 500) + client.send(response) + client.close() + From 7cd16a39615814d54894b062943fd591a4e1f6f1 Mon Sep 17 00:00:00 2001 From: cewing Date: Thu, 17 Jan 2013 23:33:18 -0800 Subject: [PATCH 008/487] first CGI lab started --- source/presentations/week04.rst | 262 +++++++++++++++++++++++++++++++- 1 file changed, 259 insertions(+), 3 deletions(-) diff --git a/source/presentations/week04.rst b/source/presentations/week04.rst index 52d0a5b9..86235db0 100644 --- a/source/presentations/week04.rst +++ b/source/presentations/week04.rst @@ -46,23 +46,279 @@ script .. class:: incremental -But what if we want to pass arguments to that script? +But what if we want to pass information to that script? .. class:: incremental How do we let the script have access to information about the HTTP request itself? +Stepping Away +------------- +Let's think about this same problem in another realm, the command line. + +.. class:: incremental + +In a ``bash`` shell we can do this: + +.. class:: incremental + +:: + + $ export VARIABLE='some_value' + $ echo this is the value: $VARIABLE + this is the value: some_value + +Environment +----------- + +This new variable is now part of our shell **environment**, and we can see that: + +.. class:: incremental + +:: + + $ printenv + VARIABLE=some_value + TERM_PROGRAM=iTerm.app + TERM=xterm + SHELL=/bin/bash + ... + +Environment in Python +--------------------- + +We can see this *environment* in Python, too:: + + $ python + ... + >>> import os + >>> print os.environ['VARIABLE'] + some_value + >>> print os.environ.keys() + ['VERSIONER_PYTHON_PREFER_32_BIT', 'VARIABLE', + 'LOGNAME', 'USER', 'PATH', ...] + +Altering the Environment +------------------------ + +You can alter os environment values while in Python:: + + >>> os.environ['VARIABLE'] = 'new_value' + >>> print os.environ['VARIABLE'] + new_value + +.. class:: incremental + +But that doesn't change the original value, *outside* Python: + +.. class:: incremental + +:: + + >>> ^D + $ echo this is the value: $VARIABLE + this is the value: some_value + +Lessons Learned +--------------- + +.. class:: incremental + +* Subprocesses inherit their environment from their Parent +* Parents do not see changes to environment in subprocesses +* In Python, you can actually set the environment for a subprocess explicitly + +.. class:: incremental small + +:: + + subprocess.Popen(args, bufsize=0, executable=None, + stdin=None, stdout=None, stderr=None, + preexec_fn=None, close_fds=False, + shell=False, cwd=None, env=None, # <------- + universal_newlines=False, startupinfo=None, + creationflags=0) + +Web Environment +--------------- + +.. class:: big-centered + +CGI is little more than a set of standard environmental variables + +RFC 3875 +-------- + +First discussed in 1993, formalized in 1997, the current version (1.1) has +been in place since 2004. + +From the preamble: + +.. class:: center + +*This memo provides information for the Internet community. It does not specify +an Internet standard of any kind.* + +.. class:: image-credit + +RFC 3875 - CGI Version 1.1: http://tools.ietf.org/html/rfc3875 + +Meta-Variables +-------------- + +.. class:: small + +:: + + 4. The CGI Request . . . . . . . . . . . . . . . . . . . . . . . 10 + 4.1. Request Meta-Variables . . . . . . . . . . . . . . . . . 10 + 4.1.1. AUTH_TYPE. . . . . . . . . . . . . . . . . . . . 11 + 4.1.2. CONTENT_LENGTH . . . . . . . . . . . . . . . . . 12 + 4.1.3. CONTENT_TYPE . . . . . . . . . . . . . . . . . . 12 + 4.1.4. GATEWAY_INTERFACE. . . . . . . . . . . . . . . . 13 + 4.1.5. PATH_INFO. . . . . . . . . . . . . . . . . . . . 13 + 4.1.6. PATH_TRANSLATED. . . . . . . . . . . . . . . . . 14 + 4.1.7. QUERY_STRING . . . . . . . . . . . . . . . . . . 15 + 4.1.8. REMOTE_ADDR. . . . . . . . . . . . . . . . . . . 15 + 4.1.9. REMOTE_HOST. . . . . . . . . . . . . . . . . . . 16 + 4.1.10. REMOTE_IDENT . . . . . . . . . . . . . . . . . . 16 + 4.1.11. REMOTE_USER. . . . . . . . . . . . . . . . . . . 16 + 4.1.12. REQUEST_METHOD . . . . . . . . . . . . . . . . . 17 + 4.1.13. SCRIPT_NAME. . . . . . . . . . . . . . . . . . . 17 + 4.1.14. SERVER_NAME. . . . . . . . . . . . . . . . . . . 17 + 4.1.15. SERVER_PORT. . . . . . . . . . . . . . . . . . . 18 + 4.1.16. SERVER_PROTOCOL. . . . . . . . . . . . . . . . . 18 + 4.1.17. SERVER_SOFTWARE. . . . . . . . . . . . . . . . . 19 + +Running CGI +----------- + +You have a couple of options: + +.. class:: incremental + +* Python Standard Library CGIHTTPServer +* Apache +* Some other HTTP server that implements CGI (lighttpd, ...?) + +.. class:: incremental + +Let's start locally by using the Python module + +Running CGI - First Test +------------------------ + +Make sure you have the latest source of the class documentation, then: + +.. class:: incremental + +* Open *two* terminal windows and in both, ``cd`` to the + ``assignments/week04/lab`` directory +* In the first terminal, run ``python -m CGIHTTPServer`` +* Open a web browser and load ``http://localhost:8000/`` +* Click on *CGI Test 1* + +Did that work? +-------------- + +* If nothing at all happens, check your terminal window +* Look for this: ``OSError: [Errno 13] Permission denied`` +* If you see something like that, check permissions for ``cgi-bin`` *and* + ``cgi_1.py`` +* The file must be executable, the directory needs to be readable *and* + executable. + +Break It +-------- + +Once that's working correctly, let's play with breaking it. Start by making +the file not exectuable: + +.. class:: incremental small + +:: + + $ ls -l cgi-bin/cgi_1.py + -rwxr-xr-x 1 cewing staff 42 Jan 17 22:30 cgi-bin/cgi_1.py + $ chmod 444 cgi-bin/cgi_1.py + $ ls -l cgi-bin/cgi_1.py + -r--r--r-- 1 cewing staff 42 Jan 17 22:35 cgi-bin/cgi_1.py + +.. class:: incremental + +Reload your web browser and see what happens. + +.. class:: incremental + +Put the permissions back to how they were before. + +Break It Differently +-------------------- + +Okay, so problems with permissions can lead to failure. How about errors in +the script? What happens there? + +.. class:: incremental + +* Open ``assignments/week04/lab/cgi-bin/cgi_1.py`` in an editor +* Before where it says ``cgi.test()``, add a single line: + +.. class:: incremental + +:: + + 1 / 0 + +.. class:: incremental + +Reload your browser, what happens now? + +Errors in CGI +------------- + +CGI is famously difficult to debug. There are reasons for this: + +.. class:: incremental + +* CGI is designed to provide access to runnable processes to *the internet* +* The internet is a wretched hive of scum and villainy +* Revealing error conditions can expose data that could be exploited + +Viewing Errors in Python CGI +---------------------------- + +Back in your editor, add the following lines, just below ``import cgi``: + +.. class:: incremental + +:: + + import cgitb + cgitb.enable() + +.. class:: incremental + +Now, reload again. + +cgitb Output +------------ + +.. image:: img/cgitb_output.png + :align: center + :width: 100% scraps ------ -What is CGI? +How to run CGI scripts + +- locally -Why is CGI? +- on a server How does WSGI differ from CGI? From f7ec1fcae4ce2a2ef1c26ddc21590af6461c21f2 Mon Sep 17 00:00:00 2001 From: cewing Date: Thu, 17 Jan 2013 23:33:46 -0800 Subject: [PATCH 009/487] add image for cgitb output --- source/img/cgitb_output.png | Bin 0 -> 48545 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 source/img/cgitb_output.png diff --git a/source/img/cgitb_output.png b/source/img/cgitb_output.png new file mode 100644 index 0000000000000000000000000000000000000000..0dc6d78ed2ccf7cad4014bed721c74c04c334850 GIT binary patch literal 48545 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≠Ihr&<=Jn?+B`-vrM1r|B=@%q> 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 literal 0 HcmV?d00001 From 94e3f92d2953a0d69ad255b450add4dc4719658a Mon Sep 17 00:00:00 2001 From: cewing Date: Thu, 17 Jan 2013 23:34:08 -0800 Subject: [PATCH 010/487] * start adding support files for week 4 labs --- assignments/week04/lab/cgi-bin/cgi_1.py | 5 +++++ assignments/week04/lab/index.html | 15 +++++++++++++++ 2 files changed, 20 insertions(+) create mode 100755 assignments/week04/lab/cgi-bin/cgi_1.py create mode 100644 assignments/week04/lab/index.html diff --git a/assignments/week04/lab/cgi-bin/cgi_1.py b/assignments/week04/lab/cgi-bin/cgi_1.py new file mode 100755 index 00000000..b969de64 --- /dev/null +++ b/assignments/week04/lab/cgi-bin/cgi_1.py @@ -0,0 +1,5 @@ +#!/usr/bin/python +import cgi + + +cgi.test() diff --git a/assignments/week04/lab/index.html b/assignments/week04/lab/index.html new file mode 100644 index 00000000..a5c1d715 --- /dev/null +++ b/assignments/week04/lab/index.html @@ -0,0 +1,15 @@ + + + + IPIP: Week 4 Lab Examples + + +

Internet Programming In Python

+

Week 4: CGI, WSGI and Living Online

+

CGI Examples

+
    +
  1. CGI Test 1
  2. +
+

WSGI Examples

+ + \ No newline at end of file From 9d1a064747116c78d3e4a057d98eedfd87b1de60 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 18 Jan 2013 13:05:16 -0800 Subject: [PATCH 011/487] * install pygments into the virtualenv so that we can colorize code in slides --- buildout.cfg | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/buildout.cfg b/buildout.cfg index 2e57c3fd..f4b725cc 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -5,6 +5,7 @@ parts = sphinx venv + pip build_s5 executable @@ -36,6 +37,12 @@ venv_options = --no-site-packages --distribute distutils_urls = http://pypi.python.org/packages/source/d/docutils/docutils-0.9.1.tar.gz +[pip] +recipe = gp.recipe.pip +virtualenv = ${buildout:directory} +install = Pygments + + [build_s5] recipe = collective.recipe.template[genshi]:genshi input = ${buildout:script-in} From e4d183944a6edbfda6c1c2524fd8ce0623cbca32 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 18 Jan 2013 13:05:50 -0800 Subject: [PATCH 012/487] colorize week 3 code examples --- source/presentations/week03.rst | 122 +++++++++++++++++--------------- 1 file changed, 65 insertions(+), 57 deletions(-) diff --git a/source/presentations/week03.rst b/source/presentations/week03.rst index 6b83c7e4..2bb2d43d 100644 --- a/source/presentations/week03.rst +++ b/source/presentations/week03.rst @@ -128,7 +128,9 @@ First Steps - Get Source ------------------------ Let's start by grabbing the page we want. We use the Python Standard Library -``urllib2`` to handle this task (note that we've shortened the URL):: +``urllib2`` to handle this task (note that we've shortened the URL): + +.. code-block:: python >>> import urllib2 >>> page = urllib2.urlopen('http://tinyurl.com/osfeeds') @@ -145,7 +147,9 @@ First Steps - Read Source ------------------------- We can take the page we just opened, and read it. The object is file-like, so -it supports standard file read operations:: +it supports standard file read operations: + +.. code-block:: python >>> html = page.read() >>> len(page) @@ -207,7 +211,9 @@ Step Back for a Moment ---------------------- This is going to take some preparation, so let's set aside our html page in a -way that will allow us to come back to it:: +way that will allow us to come back to it: + +.. code-block:: python >>> fh = open('bloglist.html', 'w') >>> fh.write(html) @@ -345,7 +351,9 @@ Parsing HTML ------------ Okay, we're all set here. Let's load up our HTML page and get ready to scrape -it:: +it: + +.. code-block:: python (soupenv)$ python >>> fh = open('bloglist.html', 'r') @@ -404,7 +412,9 @@ Searching by CSS Class ---------------------- The items we are looking for are ``div`` tags which have the CSS class -``feedEntry``:: +``feedEntry``: + +.. code-block:: python >>> entries = parsed.find_all('div', class_='feedEntry') >>> len(entries) @@ -433,7 +443,7 @@ What bits of an entry have the details we need to meet our goals? Testing it out -------------- -:: +.. code-block:: python >>> for e in entries: ... anchor = e.find('a') @@ -582,9 +592,8 @@ XML-RPC Example - Server xmlrpc_server.py: -.. class:: small - -:: +.. code-block:: python + :class: small from SimpleXMLRPCServer import SimpleXMLRPCServer @@ -610,9 +619,8 @@ xmlrpc_server.py script: Then, open another terminal and start up python: -.. class:: small - -:: +.. code-block:: python + :class: small >>> import xmlrpclib >>> proxy = xmlrpclib.ServerProxy('http://localhost:50000/', verbose=True) @@ -680,11 +688,10 @@ Register an entire Python class as a service, exposing class methods:: server.register_instance(MyClass()) -Keep an instance method private: - -.. class:: tiny +Keep an instance method private : -:: +.. code-block:: python + :class: tiny class MyServiceClass(object): ... @@ -702,9 +709,8 @@ XML-RPC Introspection First, implement required methods on your service class: -.. class:: tiny - -:: +.. code-block:: python + :class: tiny from SimpleXMLRPCServer import list_public_methods @@ -729,18 +735,16 @@ XML-RPC Instrospection Then enable introspection via the server instance: -.. class:: small - -:: +.. code-block:: python + :class: small server.register_introspection_functions() After this, a client proxy can call pre-defined methods to learn about what -your service offers - -.. class:: small +your service offers: -:: +.. code-block:: python + :class: small >>> for name in proxy.system.listMethods(): ... help = proxy.system.methodHelp(name) @@ -814,9 +818,8 @@ Suds allows us to create a SOAP client object. SOAP uses WSDL to define a service. All we need to do to set this up in python is load the URL of the WSDL for the service we want to use: -.. class:: small - -:: +.. code-block:: python + :class: small (soupenv)$ python >>> from suds.client import Client @@ -830,9 +833,8 @@ Peeking at the Service Suds allows us to visually scan the service. Simply print the client object to see what the service has to offer: -.. class:: small - -:: +.. code-block:: python + :class: small >>> print geo_client @@ -853,7 +855,9 @@ Debugging Suds Suds uses python logging to deal with debug information, so if you want to see what's going on under the hood, you configure it via the Python logging -module:: +module: + +.. code-block:: python >>> import logging >>> logging.basicConfig(level=logging.INFO) @@ -870,13 +874,17 @@ SOAP Servers can provide more than one *service* and each *service* might have more than one *port*. Suds provides two ways to configure which *service* and *port* you wish to use. -Via subscription:: +Via subscription: + +.. code-block:: python client.service[''][''].method(args) -Or the way we will do it, via configuration:: +Or the way we will do it, via configuration: + +.. code-block:: python - geo_client.set_options(service='GeocoderService_V03_01', ↩ + geo_client.set_options(service='GeocoderService_V03_01', port='GeocoderService_V03_01Soap') Providing Arguments @@ -885,9 +893,8 @@ Providing Arguments Arguments to a method are set up as a dictionary. Although some may not be required according to api documentation, it is safest to provide them all: -.. class:: small - -:: +.. code-block:: python + :class: small >>> apiKey = '' >>> args = {'apiKey': apiKey, } @@ -907,9 +914,8 @@ Making the Call Finally, once we've got the arguments all ready we can go ahead and make a call to the server: -.. class:: small - -:: +.. code-block:: python + :class: small >>> res = geo_client.service.GeocodeAddressNonParsed(**args) DEBUG:suds.client:sending to @@ -980,7 +986,9 @@ And What of Our Result? The WSDL we started with should provide type definitions for both data we send and results we receive. The ``res`` symbol we bound to our result earlier should now be an instance of a *GeocodeAddressNonParsedResult*. Lets see what -that looks like:: +that looks like: + +.. code-block:: python >>> type(res) @@ -1008,11 +1016,10 @@ A Word on Debugging .. class:: incremental -Try this - -.. class:: small incremental +Try this: -:: +.. code-block:: python + :class: small incremental >>> geo_client.last_sent().str().replace(" ","")[:573] '...\n' @@ -1089,9 +1096,8 @@ Dates in JSON Option 1 - Unix Epoch Time (number): -.. class:: incremental small - -:: +.. code-block:: python + :class: small incremental >>> import time >>> time.time() @@ -1099,9 +1105,10 @@ Option 1 - Unix Epoch Time (number): .. class:: incremental -Option 2 - ISO 8661 (string) +Option 2 - ISO 8661 (string): -.. class:: incremental small +.. code-block:: python + :class: small incremental >>> import datetime >>> datetime.datetime.now().isoformat() @@ -1112,9 +1119,8 @@ JSON in Python You can encode python to json, and decode json back to python: -.. class:: small - -:: +.. code-block:: python + :class: small >>> import json >>> array = [1,2,3] @@ -1326,7 +1332,8 @@ Geocoding with Google APIs https://developers.google.com/maps/documentation/geocoding -.. class:: small incremental +.. code-block:: python + :class: small incremental >>> import urllib >>> import urllib2 @@ -1344,7 +1351,8 @@ RESTful Job Listings https://github.com/mattnull/techsavvyapi -.. class:: small incremental +.. code-block:: python + :class: small incremental >>> base = 'http://api.techsavvy.io/jobs' >>> search = 'python+web' From b89c1ed036fb335f52ff536781c5d9361e533f36 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 18 Jan 2013 13:06:13 -0800 Subject: [PATCH 013/487] add colorization styles from pygments into the pretty.css file, augment to cover incremental/current stuff. --- source/ui/uw_pce_theme/pretty.css | 70 ++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/source/ui/uw_pce_theme/pretty.css b/source/ui/uw_pce_theme/pretty.css index fcfabdf5..3a6191ec 100644 --- a/source/ui/uw_pce_theme/pretty.css +++ b/source/ui/uw_pce_theme/pretty.css @@ -67,11 +67,13 @@ ul.urls {list-style: none; display: inline; margin: 0;} html>body .external {border-bottom: none;} .external:after {content: " \274F"; font-size: smaller; color: #77B;} -.incremental, .incremental *, .incremental *:after {visibility: visible; - color: white; border: 0;} +/*.incremental, .incremental *, .incremental *:after {visibility: visible; + color: white; border: 0;}*/ img.incremental {visibility: hidden;} .slide .current {color: green;} + + .slide-display {display: inline ! important;} .huge {font-family: sans-serif; font-weight: bold; font-size: 150%;} @@ -166,3 +168,67 @@ p.image-credit { margin: 1em 0em 0em 0em; z-index: 10; } + +/* Pygments 'colorful' colorization */ +.code { background-color: #ffffcc} +.current .c, .c { color: #888888 } /* Comment */ +.current .err, .err { color: #FF0000; background-color: #FFAAAA } /* Error */ +.current .k, .k { color: #008800; font-weight: bold } /* Keyword */ +.current .o, .o { color: #333333 } /* Operator */ +.current .cm, .cm { color: #888888 } /* Comment.Multiline */ +.current .cp, .cp { color: #557799 } /* Comment.Preproc */ +.current .c1, .c1 { color: #888888 } /* Comment.Single */ +.current .cs, .cs { color: #cc0000; font-weight: bold } /* Comment.Special */ +.current .gd, .gd { color: #A00000 } /* Generic.Deleted */ +.current .ge, .ge { font-style: italic } /* Generic.Emph */ +.current .gr, .gr { color: #FF0000 } /* Generic.Error */ +.current .gh, .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.current .gi, .gi { color: #00A000 } /* Generic.Inserted */ +.current .go, .go { color: #888888 } /* Generic.Output */ +.current .gp, .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.current .gs, .gs { font-weight: bold } /* Generic.Strong */ +.current .gu, .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.current .gt, .gt { color: #0044DD } /* Generic.Traceback */ +.current .kc, .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ +.current .kd, .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ +.current .kn, .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ +.current .kp, .kp { color: #003388; font-weight: bold } /* Keyword.Pseudo */ +.current .kr, .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ +.current .kt, .kt { color: #333399; font-weight: bold } /* Keyword.Type */ +.current .m, .m { color: #6600EE; font-weight: bold } /* Literal.Number */ +.current .s, .s { background-color: #fff0f0 } /* Literal.String */ +.current .na, .na { color: #0000CC } /* Name.Attribute */ +.current .nb, .nb { color: #007020 } /* Name.Builtin */ +.current .nc, .nc { color: #BB0066; font-weight: bold } /* Name.Class */ +.current .no, .no { color: #003366; font-weight: bold } /* Name.Constant */ +.current .nd, .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.current .ni, .ni { color: #880000; font-weight: bold } /* Name.Entity */ +.current .ne, .ne { color: #FF0000; font-weight: bold } /* Name.Exception */ +.current .nf, .nf { color: #0066BB; font-weight: bold } /* Name.Function */ +.current .nl, .nl { color: #997700; font-weight: bold } /* Name.Label */ +.current .nn, .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.current .nt, .nt { color: #007700 } /* Name.Tag */ +.current .nv, .nv { color: #996633 } /* Name.Variable */ +.current .ow, .ow { color: #000000; font-weight: bold } /* Operator.Word */ +.current .w, .w { color: #bbbbbb } /* Text.Whitespace */ +.current .mf, .mf { color: #6600EE; font-weight: bold } /* Literal.Number.Float */ +.current .mh, .mh { color: #005588; font-weight: bold } /* Literal.Number.Hex */ +.current .mi, .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ +.current .mo, .mo { color: #4400EE; font-weight: bold } /* Literal.Number.Oct */ +.current .sb, .sb { background-color: #fff0f0 } /* Literal.String.Backtick */ +.current .sc, .sc { color: #0044DD } /* Literal.String.Char */ +.current .sd, .sd { color: #DD4422 } /* Literal.String.Doc */ +.current .s2, .s2 { background-color: #fff0f0 } /* Literal.String.Double */ +.current .se, .se { color: #666666; font-weight: bold; background-color: #fff0f0 } /* Literal.String.Escape */ +.current .sh, .sh { background-color: #fff0f0 } /* Literal.String.Heredoc */ +.current .si, .si { background-color: #eeeeee } /* Literal.String.Interpol */ +.current .sx, .sx { color: #DD2200; background-color: #fff0f0 } /* Literal.String.Other */ +.current .sr, .sr { color: #000000; background-color: #fff0ff } /* Literal.String.Regex */ +.current .s1, .s1 { background-color: #fff0f0 } /* Literal.String.Single */ +.current .ss, .ss { color: #AA6600 } /* Literal.String.Symbol */ +.current .bp, .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.current .vc, .vc { color: #336699 } /* Name.Variable.Class */ +.current .vg, .vg { color: #dd7700; font-weight: bold } /* Name.Variable.Global */ +.current .vi, .vi { color: #3333BB } /* Name.Variable.Instance */ +.current .il, .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ +.current .n, .n, .current .o, .o, .current .p, .p {color: black} \ No newline at end of file From 850b437f61cf8cd858b3b6b774f78063f9d23b29 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 18 Jan 2013 13:08:16 -0800 Subject: [PATCH 014/487] update week 4 slides with colorization --- source/presentations/week04.rst | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/source/presentations/week04.rst b/source/presentations/week04.rst index 86235db0..d571b489 100644 --- a/source/presentations/week04.rst +++ b/source/presentations/week04.rst @@ -92,7 +92,9 @@ Environment in Python We can see this *environment* in Python, too:: $ python - ... + +.. code-block:: python + >>> import os >>> print os.environ['VARIABLE'] some_value @@ -103,7 +105,9 @@ We can see this *environment* in Python, too:: Altering the Environment ------------------------ -You can alter os environment values while in Python:: +You can alter os environment values while in Python: + +.. code-block:: python >>> os.environ['VARIABLE'] = 'new_value' >>> print os.environ['VARIABLE'] @@ -265,9 +269,8 @@ the script? What happens there? * Open ``assignments/week04/lab/cgi-bin/cgi_1.py`` in an editor * Before where it says ``cgi.test()``, add a single line: -.. class:: incremental - -:: +.. code-block:: python + :class: incremental 1 / 0 @@ -291,9 +294,8 @@ Viewing Errors in Python CGI Back in your editor, add the following lines, just below ``import cgi``: -.. class:: incremental - -:: +.. code-block:: python + :class: incremental import cgitb cgitb.enable() From f8d0d347a4f77a05db74ddd10d2f97e3d30f2549 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 18 Jan 2013 14:16:34 -0800 Subject: [PATCH 015/487] fix more code samples with colorization --- source/presentations/week03.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/presentations/week03.rst b/source/presentations/week03.rst index 2bb2d43d..c12813a0 100644 --- a/source/presentations/week03.rst +++ b/source/presentations/week03.rst @@ -1125,12 +1125,12 @@ You can encode python to json, and decode json back to python: >>> import json >>> array = [1,2,3] >>> json.dumps(array) - >>> dict_ = {'foo': [1,2,3], 'bar': u'my resumé', 'baz': True} - >>> json.dumps(dict_) + >>> orig = {'foo': [1,2,3], 'bar': u'my resumé', 'baz': True} + >>> encoded = json.dumps(dict_) + >>> encoded '{"baz": true, "foo": [1, 2, 3], "bar": "my resum\\u00e9"}' - >>> incoming = _ - >>> new = json.loads(incoming) - >>> new == dict_ + >>> decoded = json.loads(encoded) + >>> decoded == orig True .. class:: incremental From 77c6ea21f0bde14ba30cb05ed18aa841e4dc9698 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 19 Jan 2013 17:55:32 -0800 Subject: [PATCH 016/487] * complete cgi lab * push forward into getting cgi online --- source/presentations/week04.rst | 380 +++++++++++++++++++++++++++++++- 1 file changed, 379 insertions(+), 1 deletion(-) diff --git a/source/presentations/week04.rst b/source/presentations/week04.rst index d571b489..2c3455af 100644 --- a/source/presentations/week04.rst +++ b/source/presentations/week04.rst @@ -311,9 +311,387 @@ cgitb Output :align: center :width: 100% +Another Way to Break It +----------------------- +Let's fix the error from our traceback. Edit your ``cgi_1.py`` file to match: -scraps +.. code-block:: python + :class: small + + #!/usr/bin/python + import cgi + import cgitb + + cgitb.enable() + + cgi.test() + +.. class:: incremental + +Notice the first line of that script: ``#!/usr/bin/python``. This is called +the *shebang* (short for hash-bang) and it tells the system what executable +program to use when running the script. + +CGI Process Execution +--------------------- + +When a web server like ``CGIHTTPServer`` or ``Apache`` runs a CGI script, it +simply attempts to run the script as if it were a normal system user. This is +just like you calling:: + + $ ./path/to/cgi_1.py + +.. class:: incremental + +In fact try that now (use the real path), what do you get? What is missing? + +CGI Process Execution +--------------------- + +There are a couple of important facts that are related to the way CGI +processes are run: + +.. class:: incremental + +* The script **must** include a *shebang* so that the system knows how to run + it. +* The script **must** be executable. +* The *executable* named in the *shebang* will be called as the *nobody* user. +* This is a security feature to prevent CGI scripts from running as a user + with any privileges. +* This means that the *executable* from the script *shebang* must be one that + *anyone* can run. + +More Permission Fun +------------------- + +Let's interfere with this:: + + $ ls -l /usr/bin/python + -rwxr-xr-x 2 root wheel ... /usr/bin/python + $ sudo chmod 750 /usr/bin/python + Password: + $ ls -l /usr/bin/python + -rwxr-x--- 2 root wheel ... /usr/bin/python + +.. class:: incremental + +Now, reload your web browser. Did you get anything? Check your debugging +tools. + +Enough of That +-------------- + +Okay, put the permissions back on your system python:: + + $ sudo chmod 755 /usr/bin/python + Password: + $ ls -l /usr/bin/python + -rwxr-xr-x 2 root wheel ... /usr/bin/python + +The CGI Environment +------------------- + +CGI is largely a set of agreed-upon environmental variables. + +.. class:: incremental + +We've seen how environmental variables are found in python in ``os.environ`` + +.. class:: incremental + +We've also seen that at least some of the variables in CGI are **not** in the +standard set of environment variables. + +.. class:: incremental + +Where do they come from? + +CGI Servers +----------- + +Let's find 'em. In a terminal fire up python: + +.. code-block:: + + >>> import CGIHTTPServer + >>> CGIHTTPServer.__file__ + '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/CGIHTTPServer.py' + +.. class:: incremental + +Copy this path and open the file it points to in your text editor + +Environmental Set Up +-------------------- + +From CGIHTTPServer.py, in the CGIHTTPServer.run_cgi method: + +.. code-block:: python + :class: tiny + + # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html + # XXX Much of the following could be prepared ahead of time! + env = {} + env['SERVER_SOFTWARE'] = self.version_string() + env['SERVER_NAME'] = self.server.server_name + env['GATEWAY_INTERFACE'] = 'CGI/1.1' + env['SERVER_PROTOCOL'] = self.protocol_version + env['SERVER_PORT'] = str(self.server.server_port) + env['REQUEST_METHOD'] = self.command + ... + ua = self.headers.getheader('user-agent') + if ua: + env['HTTP_USER_AGENT'] = ua + ... + os.environ.update(env) + ... + +CGI Scripts +----------- + +And that's it, the big secret. The server takes care of setting up the +environment so it has what is needed. + +.. class:: incremental + +Now, in reverse. How does the information that a script creates end up in your +browser? + +.. class:: incremental + +A CGI Script must print it's results to stdout. + +Recap: +------ + +What the Server Does: + +.. class:: incremental small + +* parses the request +* sets up the environment, including HTTP and SERVER variables +* figures out if the URI points to a CGI script and runs it +* builds an appropriate HTTP Response first line ('HTTP/1.1 200 Ok\r\n') +* appends what comes from the script on stdout and sends that back + +What the Script Does: + +.. class:: incremental small + +* names appropriate *executable* in it's *shebang* line +* uses os.environ to read information from the HTTP request +* builds *any and all* appropriate **HTTP Headers** (Content-type:, + Content-length:, ...) +* prints headers, empty line and script output (body) to stdout + +Lab 1 +----- + +You've seen the output from the ``cgi.test()`` method from the ``cgi`` module. +Let's make our own version of this. + +.. class:: incremental + +* In ``assignments/week04/lab/src`` you will find the file + ``lab1_cgi_template.py``. +* Copy that file to ``assignments/week04/lab/cgi-bin/lab1_cgi.py`` (note the + missing '_template' part) +* The script contains some html with text naming elements of the CGI + environment. +* Use elements of os.environ to fill in the blanks. + +.. class:: incremental center + +**GO** + +Putting CGI Online +------------------ + +We have CGI working, how do we make it **live** so that others can see our +work? + +.. class:: incremental big-centered + +**Put It On A Server** + +Apache +------ + +Our VMs have the Apache HTTP Server installed and ready to use. Unfortunately +for our current purposes, Apache is not the running web server software. + +Load ``http://.blueboxgrid.com`` in your web browser. What do you see? + +.. image:: img/nginx.png + :align: center + :class: incremental + :width: 75% + +Managing Server Processes +------------------------- + +.. class:: incremental + +* Nginx is a great webserver, but it doesn't support running external processes +* This is a good choice for security, but not good for us right now +* We need to turn it off, and turn on Apache + +.. class:: incremental + +SSH into your server. Then run: + +.. class:: incremental + +:: + + $ sudo /etc/init.d/nginx stop + Stopping nginx: nginx. + $ sudo /etc/init.d/apache2 start + * Starting web server apache2 [ OK ] + +Check Your Work +--------------- + +Reload your web browser. You should now see this: + +.. image:: img/apache.png + :align: center + :width: 75% + +.. class:: incremental + +This means that you've stopped nginx and started Apache. Congrats, you are now +a sysadmin! + +Default Site +------------ + +.. class:: incremental + +* Apache on Ubuntu is set to do virtual hosting +* Config for individual sites is added in ``/etc/apache2/sites-available`` +* Activating a site makes a link to the config in + ``/etc/apache2/sites-enabled`` + +.. class:: incremental + +Check your server to see what sites are available and active: + +.. class:: incremental small + +:: + + $ cd /etc/apache2/ + $ ls sites-available/ + default default-ssl + $ ls -l sites-enabled/ + total 0 + ... 000-default -> ../sites-available/default + +Apache Configuration +-------------------- + +:: + + $ less sites-available/default + +.. code-block:: apache + :class: small incremental + + + ServerAdmin webmaster@localhost + + DocumentRoot /var/www + + Options FollowSymLinks + AllowOverride None + + + Options Indexes FollowSymLinks MultiViews + AllowOverride None + Order allow,deny + allow from all + + +More Apache Configuration +------------------------- + +Skip over the ``ScriptAlias`` for a moment (we'll come back) + +.. code-block:: apache + :class: small incremental + + ErrorLog /var/log/apache2/error.log + # Possible values include: debug, info, notice, warn, error, crit, + # alert, emerg. + LogLevel warn + CustomLog /var/log/apache2/access.log combined + + Alias /doc/ "/usr/share/doc/" + + Options Indexes MultiViews FollowSymLinks + AllowOverride None + Order deny,allow + Deny from all + Allow from 127.0.0.0/255.0.0.0 ::1/128 + + + + +Apache CGI Configuration +------------------------ + +This is the bit that sets up CGI for us: + +.. code-block:: apache + + ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ + + AllowOverride None + Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch + Order allow,deny + Allow from all + + +Setting up Our Script +--------------------- + +The directory for CGI is ``/usr/lib/cgi-bin/``. What's there now? + +.. class:: incremental + +:: + + $ ls -la /usr/lib/cgi-bin/ + total 24 + drwxr-xr-x 2 root root 4096 Apr 13 2010 . + drwxr-xr-x 66 root root 20480 Nov 23 2011 .. + +No Directory Listing +-------------------- + +Check the ``cgi-bin`` directory in your browser: + +``http://.blueboxgrid.com/cgi-bin/`` + +.. image:: img/forbidden.png + :align: center + :class: incremental + :width: 60% + +.. class:: incremental + +Apache is configured to disallow directory listings for ``cgi-bin`` (No +``Option Indexes``) + + + + + + +scraps ------ How to run CGI scripts From 0c99c89d8b18b37f07daa2df5e27c643065d4e76 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 19 Jan 2013 17:56:09 -0800 Subject: [PATCH 017/487] adding needed images for week 4 presentation --- source/img/apache.png | Bin 0 -> 10625 bytes source/img/forbidden.png | Bin 0 -> 12569 bytes source/img/nginx.png | Bin 0 -> 4694 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 source/img/apache.png create mode 100644 source/img/forbidden.png create mode 100644 source/img/nginx.png diff --git a/source/img/apache.png b/source/img/apache.png new file mode 100644 index 0000000000000000000000000000000000000000..5a7bcd38546e41b64a922e0ad547b370e9c94ef4 GIT binary patch literal 10625 zcmds-Wl$Vnv+yA#5Q0MjAp{9du;9)TAh^4`24`_61b1iA;O?$Va9G@37I)WW;qrfO z)s=d_y>&mmA7;+fRGq1w?&?1M>+VnmIdP14pWY!LAYe#Jh$c2 zwY)5-_7a*v1Ozm^e=bCX)bx)C2xJJ7qTf~A(vLH|?X~Be*L|0>8CdBol{vRn9Hr=# za2Kjch%5za;uksgdanEX6qM=Z7`_?jW8|p{;3qhj`_HMhD)ebJ9cw7Cp>EZo$;*_4 zW{-T5VpE8Zk)h?v?$1{eu^i~jdqbVArHrA0RDnpC!UID=z$L}P!g_ygxcg{UgtOXy zy9^u^I3;PjJ!!ST#rdxI{)b{h%VTnQxnB-#SWcVncwX_#O3OL%f3#Y1@})?Ru%-%)@y5-W>4{ z#rLq3r zt~kiKLCgJ1zjjh8c;`e4kkw6j`tU<>l`cha%KC6G&uRsk#H|D?%TTTRZ!)H!@Yn-K z+1^o6OFy3{6q~5=c(?Ns@TGn4D;RFEuhYH52v*jOX~S;cy~CQaT2OA|&DFPjQS_(m zQQ<$FtF4PiZhWVl-k;tLcMLQ{^1UNXN(HdPIr7}MF}RuK#&nWcTJv;9W*}EPWjVA` z6bvT^3(J%++xFOjoOj;ARlma<&UP-WDmZyOI5Nr!bY28aXygb_W(O+syTi0@l9bF=x69a2qrus{rYyhX0qzy zx{Ae9@iH{E1*X#fdO=i3LsO)fuTYp+eD1bzIXz3SJ~5*SqEbr#{OFnUZ2!ww79r14 zw;`3t4xF*XRbHy4naacV<57J^-ZHsPZ!on&&LD{(TI_BV0!B!h^oDsa*A|ynj3Cr1 z$G0VMa+P>*YpK;GVyZ?JF#v?t#+){eJ0(Ve#U8ElGkIbZ-b7VI8h?Gl_6mX7DS zk6^g@!>MrjNuR4$dDUP3=6y9K-4~iyiN11#vZHgTyu$}7Pxn-YE1(ccDg!zSvO#MZ zbO`VFOWuyynoKjXZfIScv6~55CX*H00oU*$uW+11UyrfU4yybXQK5LR>I@U@V9tt| zjc!EeUK{R0(`%h;uj80l6VL(cIxr!D2shOHFe>Q9O_WB-DM!j8f&!qIO)>|B&}&%l z>18N@ox!rSVy7h?8*GVtBju1eHe0lbK71Q1D<|>iPwNIML`E_yCBzL9AJ?jHCVGKd z+_gGxAz3n3U}{8Wky;n2B{_yO;Hz0Blj@F(hvSft0DB0g%9I#tJFrA;m0sk7vnCCM zNvJ_7;8gmrr1}fVJbUyn0y}A@T>6Ax{Fu%dC(bOk`XFx|eL*@Qu{{b|w&KwXm$^9p z&mRztQY}XHUH#PzjL);YhP~Wdc{qcBG^T& zJ5%aZQ<)6ry>R;0W3peGM1Qi*{0ejZy{f$UlA68o2AE3^+$Bu$5)1P2cfGrB0vS0q z|H3_&RmEKeJkz0=70Mzw@#@+)my;?TeHN5pG`V$P9xI)txbL$Q|d^3U=>uT z&ldSTPp{@VS`Yj&7`PFJA+YTG3||Ib@*Xl{*s$@tRyD?aLqz9Ip0TZdU90X!ZrysU zrIp4B+}lHC%^-3!fC)IMg<5XIi7rXn4=#p|N?!v1{6?H?s?+lCer5M)&aSy&x$b>L z7YszPYZ71i=XI(AIg(9;b@WwfbxBSB8(~%N&Avk$8{U}V#m5BDR|p!g zHZOyV6En4E*CN-Pv_<^h@}(159Og`0^7>pG? zM|-ptdm63az1gC2f@rIGZ>g7F&eXDV)BiS*WJ90@FD8d}=vUM4cr(NA3fq4>1gw{c z5QDS$=E~N=tHXsZxh<~ACp8-sh zRC2m#Uek_$w(GaM6jycc9!ZK;0jo`Tm=dVo7q=S)+S#TimnLm{+*J+IlkLh}Fj(@s zQGP0)4TpOsGFbr z`_KqkKW7|~@(cJHNcvnK>67{tm+1lfc^gQ1rM4pv$Z5d$$tq9i&L(sExKpIrYA?sZ z+rvCi=q1I}+C6Wt%=YiJd|tYqo3lWgtc~>>&v~>LYiQM@dU(HNP(c40idFz@qGn9@ zL!-s>-V@PJsl)sDLI@Yl$Hl*meY?u{M*#0iC|sU2dR70T!t@e1ev4o;*%?>iq~5p0 zr?SqQt~ag2>I4oXS1k=RJhfqp%Ax~s*4=*3Q7Fw(BuUs2`n&Z6wCJ37b(P_vjWhic2+S%Jzv(?4&UD<=XP{R0>zWN8fzt6;oocc>;ZC(f1+HOH( z+>(5bE*EWKQ$g|l_T0z#JWVU`f|f5+=m+Yxqbs57rxG$b{rNuTbPeV7yOmyjjAAm9 z^Y=rW1=}-bQIg}j6o~jvnH2-Rxrnt}%1;DEi&ym>fB<7j&>q*)S%-?Pa9pl`n=MIY z(@(GOEX&`E7aL}`2sDYxD-u zSwhy)dXK&Dn5(wyh{Vn;?C$JZTXf=kc<+m^u|9G+Xl)?6Vp4E1ZU)FZhT~>LWmfx%?_q5k9V{Yg^7rana z@MM?v^+lTP^x*%@d{1SV&TrXYZ1#S8@_T&2KiToT=>Mnd)^fa=S<;lb5`M3;jNAy5 z&{5YS=xxpP>E}S8#{qgXvQ|0?;BRRBW_spGI&e*Sb90z;^4=(xr+a$;a(n7>3>x_z zV|0oqn|7$TpVG3xt)MZqfcg-;TIrP*&@RAU&$Kx@E^iege|~LKs?mC&re|#trEAfO z>!{3mrA^C&jAdI`T%4GA`^e~`%I{E=oOpZhHs6$#2+`ut2s3DcvXjvmbg?WTy{jpLUC>V#)}elx?GYIQKL z$>m-V-yOu!VEHjXI2ZB<_V>VD?4__A9VeL`*k^O~hdbyEi5fy(M;fQ!Omb~meqcid zhSvt*Hwdk*e8wvN#-(pL`phVqgM3XCzFe0*=ozJvei zA1U6Y=vca(jn_s`nNAeBuORWm1`6(x*l2hzOzbvhkIkZ@c2D_6G6e^#yX9+|J^5&q z5D2447iC><%{Xtb##b(BX=H5`8S7Rij*qR~KN)#8Osv#_aw{|Ir?JRfAGo7$oOU5C zo;;7x{l%cdKKGi&w1N{`j~4BPMU;dsCZHx^6#t?KtWQ_y^_;GNlk4e@33dNquKeWG z^vKT03OmQO{ap{}k+I`AZGV5?>~_OpogKx~b8mm&@bZMBpz&AfQ6@wCcFM+HZrc9I zes*DDaxRU$V^Jf`b8~C3w|Jo+9p;TKla=-u^I$Ql}i!0+x9 z2h9ySIkDvgctpqqTzrLR)1JEJk?bov_^+c&)u<7MbQ2`S`p0k!*}tZu(+vIb3(AUZ zKV+dqNrZ()7E6c|+vMgjWS=-5*nlS~C)$JHaF@dxFCnq01i+C*4@aW>#!5jxg=@ca zcq5-z8fZ?_gY=7rK@w+B4l87;pv;<+4oNWBPZ=4CDoGs|ml5@jY}KC-2Z!*6@RcA4 zA4d`sjcl~jBKwjMmHWb*>YcdJ_uX{glB0@g0hYMAnVBqRY5Yg%+u_K4r)i2Nin#LK zWZW!X?=SmUZm+TJCH^K%MwyanFo^3sRf%@{u)NEH^-q$k`NY&+@$DXGz9ldv#Qhw? z#qLvJ91|5v^x9Pemptw>8iCX0fW}X;F2UXO6U;_!bZm867fhDMv-t|m$|S5lUpD4Awcn+A-3?Hp;w3qM%WYyZ zifW0dLNKxx&w_K>x-}DS+0~iBIcH!qLAQ9cj~i?6N_lI|cTYL$%Uci$ z>i-qcwB=(Ikq^#+&hmI-04n{+@81|Df+8akc1i+bMtu~_H}FL zBM~n`TNY%OMAcM!h$vR|&!rhM)yRYI6RUu%bd#z4YYmY8yz(A}hJ5&i>loY@z5e;#OnM;(}AS zLKzm#w}W3*llEOS=4)4M@shdU$S!%zQj0&*u)IXEgt9kU?%rGo#an3z3^phlsm#`v zESj&!C5As}F_1Nk9M0VOgP!PZ;pj{TzGr+}5)N)wq|v@E6fRy`YouWpqh^Xm9oAjk zX|EPpbde_-{KtoBN$(!TZp0q!KY8B;o4al8$Q@$hFIHsw*a#gUc^$064!OyD$Mlfh z@M`OXL~7n`Q7<$)FnSv6^-aFgKiyum**zuxo#gDg$z>p~{~N~rW0<(}c9H2u@Rq|i z^>f$Ev+7QprK$7|fl#3QlA4i$r|h&2fn?Q<2*iT~y=iZ$J~9}KsknzmZ zkd+*}8R;Zw`D8xWTESS#3H>>a&xQ|A|5kqc6~gGPK#{36yLrR6w{*$z5Jk-ceS0CS zo_#I6MK@H5!&$+8SQ%%{tV`EaS8mom9V+5=KXZF|ciAP%?uU4^4@10OO|Yud_3Rz` z0fZ;n6AGCSjU_Um8{KfHd15Mcl;sB;+Ohiyifw|LZx9|2tOIH;WCU+1J&mzJKEIq9 z-&4>2nm01boLX9ynvrUS>~CR_+zOcxG}`cVb}$R}L=o$S9GNcZ&BH@EfZhw$`QDbH zdp+#lLboOKj1SBcHWg3Xvpxu%tKLNGTO!A()N3vNZc0ssrM(TA^_Cj}hdM&PNwdCc ze!N+vdnmfvUT7iGm=ACMdDPe7-cCC4n$t_6{8{$)xW^#GW>j|>K2LK=zhwif>j1pp z&X9uVfl{cEW7v5VQ!nvEwt9+%HKTm*745kkI4KOqKk*vJ>YTOm4W@}kcYK^@yJBb!JS2gkC%O*UHo4LuELFhy z1LDoO*`B;R@DYsy9@qY=H#Jw3agud0Uo@b(urKw{<>NydmTb(CR{jIhLUVHp2j4XS!ZqW@Q>&$dq(s7K9~4|9z0R?nQ7B@bZIx8V~io<6Q5A z6<-SlfhfOSwKVHey(l|O45PO}v;EdFIv?xj;o9=G=g}w%QWjj|yrdyheq`IU4{KMQ z1Yk_!8g>!Yb>P1%+QZeTg^7(`C>lnOSL=Y<6w%D;`t9pPTw+`h4a0<=r)_@ThCO7B z7*^`l+|5Xm{N*DFVP=KSeoB)6n|eH)L45osGW*uYbDGM=ab|MM!6AtOWwTsn9ZwDe zh9kyXl#q=J2{L|$(A1hqR_wFk1td&V(apF>@k@HG@Ah|j0F{K}q>0}H8j|{$(ad17 zzU^3pEh@sdO}jAHf691YtC#4I3OWX1G*DK`Z@l0<`U9qCoig<$X35Y8U0|sO;@=N3 zEb$+*dLO>feDDE6&YT*s#ngNxq{fS^)1J{HsSfuv!|p$Zgiso72tUi6H(iDskQ+2UWZAU_-eRdwLeT&)_^%$svJl|RqbKm;SEgN6j2&|$ks+p8kxxdLuHKrf>#nxgh zR%-WDTi(YC3u}~r01|CiQd!8zn$83NGYEwN+TH!w!0| zt9OLt+^yU4j_|ja+CZc zTIxS3yfm1os}xmPF(KSf&+_YT^fDoG)-$5rW1pQpp4yXgJG<@~hU(6~Ln^O3(Pqo6=dZS}HI zCD^n50vPMPZ{U&d?(#|JFJb|npd8$pcXtR_iW7VH^V5+R5Y2y z?s`6+0 zOxNAt3}5opn3xcQ)VNL|S3Ni;)z^(r)cZ4g@$?MIB<+~0k7H6M>uCk7)?B1|<$!yx zT2f5@7b1DOUstOh-S^KiH~ge#uif`AbbBgB(Qx=anhD%^Jn%TFPKOSV>X&RT(}r7y z*O#HOG`2JD7Vntq)L(oadJ!ha5wn`|S|U0O?X|f=9JQ$&c5tPBmrpXnE4k2!k-1?x ztnfL*EeLw@RkTc+GdWJBGJ3GcXUt?#BNo(_&-Y_NB3`jgAw5*M zK0~8rLL}6XU)i#ti=?j>p6~&4V>CukAI=Mq zS{A@po#&3B_8+19q2P1RqfNAF_xFVt)D2l(?z&i6v2jt}MhUO< zRB;QvqF^IuWkfXZumyvDh2l8;T0cmx3z4WHTf#{>bmcw3S;iThjn~ado+5~Q@+({? z3q~JSam|PfeiJhg5h9_}#%;=NInjSNMs)-nr6LbrVnhz1zq*C8VcSDA9O5L<-*QtW z>4mhV2nbBEI0UR?N(+m|85^<)by65x#{O?AW97raLF(BEACe*evM&Y)5PuMAdlQTa zLr2V#F*hH!xu0a?H2y+gEuo+z_9RLwt2M7XTP6n9cc&&r@t+Xx{RiDxQe(;@ejvTk z|I!q|`WYjs#~yy+sCzg=fFmgluAK)Dh&Fvp3wn+66-+4!*O0^1o~MZ``@H*3e{QBx z&RR8=7!NCi?Hj`aE=&h*?EGSi{Gp^&piqf}CcY0>#?sGT@O*?ipRpB3e@4Kus>VF| z0_wS+!X0i>2Fbt}-Ve>|p>pe@xdxJ6p3)+#YyeVl1Z5elg6|2RVJNZSf6$s{EDl(t z^Gmjb3i(9Q>vsz)XVEDxAFg-6+vo%x*xNJ@Mmf?_okG6?E3K1i!q?UxyMZ;vUt9&b z1FB1W;;a84K=;Sw`Txau2m4tGe{v~{^QPiH#O@byk@`(Mev`Xu?Kz8_o@)-`=ktiV zZhak5!~7Z;uWG?y=R3}m{QJU~0FNewjhlC_0OuJZBS;3LsUeR`Gz2SmexZgZ=mSF`@Fb>nA)qJ;iW(dGWS@`eOC@8y$Y+9hy9c$A@pa9UhW9c zL$)o$T99LwgB(lfIy`hYtGs{MGyEkTNZwN{&XP zI=|SL`2d=KW&t#N!N+dpYz=BR8S%%78uPf(Zc?LGII&KeUNiKKleK!#`Vy!>HXFxcg3_H?()Fv3;K7@RyzS)&3-sfj2T8p!6NHzv5-}%GcoeNs-#$W zsKMvHN8SaFw(uicgOCn?I)k|J)h`Aic3!UUM$xP3cQ)e>mk>N_mY98Sm!Id>;INMf z=C!KuhJV9JMR0WfF@p4^u$GnuvfATH+w9-84PTr{V zXN3i*vi0J@7C~u{YXl{-jWo`j0P6eiXeoKVFVoDZsb~2Ozs7ubZVa?!W2>5oh4zlh z$_??4w{wT=>e@)zGcnEMkdJ$Dh06g_kIzR)CARfTW6p1DL2FYbMw342a8X@gRJF$H zV9CPT^zPgh)~PX41I=!@=4as^xRE7pFwulnOea0;#(Qhlvt%t*MLdf^Km3e5KE%Ia z1c)!u7gz zL_=%+uwAEhq$>#7IJ;wojo%Sy4sSr~`r5ll*I2YxlZk@F^x$H%xe)-dFLwjMg?ijG z>R-23x6!`89yu2isZQK3=klLF%p1VE=Z_pJneP1^G*&3qKVoEC8}^L6S-&$sTgTkX z7H;V&tF82SWa`Idl~?Prt;RX*c(%c7b3E>j7VU-+bo0zHMhcFw>uJ0Cz*Kg$6%uH$ zDOLM4RB;2bU0`%4Gav>0Zgr59|HOZQ$#%)n&s*OsgqW`l zdjZnWUIoLm`V_a)Q77tTlq&egb0$%>y+H0W6jIrd)t^N`or8#OAioxEQIr3?P(t8f z*J4M5EMg5jfu8gWYNqfXJ>+U-)@L%;{LDZLIonjebOcsrsuXg-#Y`y0CH^hBI|Ff?~ z7Ix6<-`v6IRh2#eb6en)!>|1cBQvuS;G8hhzGh7;SMHTjX$2@afRseuFPjlRNA{K8 z&oebvo$fzYW#t}U+w8AD5Mlg@o^Vry{Q~$n;}@yha)^yhnl3c-1Vzliwnn^;ut-sY z<{csUZ@q&)ywSXI?0KceG}rFWM?3;h$!rDa33K}DyV*JnEPMMFMil(OrFd%of%$ai zhc14JHPvob>JUbWhUL1l@z}l4#irU##OT>)PRGYXj)~o^ZXKTx(g^i;uuRVNZw|yG z*F^pFwqt|$VJu`VHdzzilyjzo>bhVQ8VISK1^PsI0mtI{9#-ym-@GxbHt>04kf)J- z#{WiL!Kgaqb(b;5Jpg|Q0z}DW<@_|t%-;Fs?|@&#NP0z0{)9$~CvsXtRqH!EQnUVx zaCv)3r-lyltH8vbAZ=u7T-N8$>>3*AF{6OzzZ7_Z)pbnFbM-#(Cb#dOGykBYV?jDQ ztI(q(hI(Wo3%Re2nlruY``kN_th{Y{)IfDzm;6Hff2%|v;FoBCgQ1dK=|DzUmfJje z!KZlD?POkHn(E{8=51yTL8Wuw>_K|9VAesuHQj83SMzwZG%~fBi5Y_yt*ev;8Fis} zK+-m#ahy%F(58kxQztw1GDkv5xWbEcV*g%qXi}VdGmGS~^1iI&JtU6@hmJ{|>5-61 z8u&jz`H%TY?MA4CRt+oeMZ(}&U?~AKAwDq#64SZ&NQvv5?8`J;%E(7I(QFERL#&HP zSjxft0i|yPKN^CK9*r(vXmuN#fei+(x&-slPJJkKG0P$O%cd|f)wQj8NEa6ph(3Nb-L^S-b_E|>!HE}r{xk}zH+XT64rto|yKhlsd> z7L2&?C-3K+!W_2#6W>!^#^_a+f{hJNA048ZpQ$?kMcScBWlhc~coN zZCW0}L2QNk6d>KMp^6XlRVmZfsk2cHj%$lIzCkMQ7TZI%9{TpUi%KbNHv)XCUB$XeRvW!Mru4-6svkn(b)-^aQ93O~n*2&l> zGNMHn1FyrKAD5!$JdCXj*PtV^&ZFBhVGHba&UF*%kng}B=FUTm*JX1q2ei^^7&ys= zdnMWM>J`~XfOxvdt;$@{itF_q_+O+RY$~G{^U}C{Clo}{UT(dA$r|hPi=&r~4H(qj zD%h8I=*jQ1iqAziv=p;Uxs+VCEkeP@UswFNoI(uf15(&Itaw6~9e1T8OtVZ^-rO;j zNh&Kcktz4zR3D7C2g)NOvl#gm`X&ItzTJTfKxM^MrY)uPOx>=q(E}@RJc{SHmm!h$ z$Ub*yl-68!csRA}kLFI3QJIU$J^JBS#1M6d_Ub6ik)*ImY!KU~*Rwcav&O1rf5F}m zm)c_TWi(Ck{Sw1al+ZsIe{tydvi)Vyp?dHcB@fAqmi00}`DLaOLGp*3XoaxBum1qD Cua`Ig literal 0 HcmV?d00001 diff --git a/source/img/forbidden.png b/source/img/forbidden.png new file mode 100644 index 0000000000000000000000000000000000000000..69960b90a5a9ff7d4789d2d7b10ad431742a76cd GIT binary patch literal 12569 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 H83z6brJgmV literal 0 HcmV?d00001 diff --git a/source/img/nginx.png b/source/img/nginx.png new file mode 100644 index 0000000000000000000000000000000000000000..d8e9e1fa704f18d071e4ec33a24f17613813b2eb GIT binary patch literal 4694 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 T6bHEmMF4G>uKEX6Tjc)$85RS_ literal 0 HcmV?d00001 From abdb65f88c2177c522479489553a72d74d17f171 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 19 Jan 2013 21:36:36 -0800 Subject: [PATCH 018/487] * add sponsor slide * add sponsor logo image * push week 04 presentation forwward into WSGI definition --- source/img/bluebox_logo.png | Bin 0 -> 3831 bytes source/presentations/week04.rst | 117 +++++++++++++++++++++++++++++--- 2 files changed, 109 insertions(+), 8 deletions(-) create mode 100644 source/img/bluebox_logo.png diff --git a/source/img/bluebox_logo.png b/source/img/bluebox_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..229cbb4bd5a9d544361f4303b1aa89bf35c3840e GIT binary patch literal 3831 zcmV000W>0fLJSS^xk59&|-mbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gH7+r$A4ux}000$qMObu0a%Ew3X>V>IRB3Hx05LExH!m?V#p>}l000h7 zNklbLQW9p0v>XL zFeez^o~nzJepRmLCxKcP>Q<|})!h92`4cl{%y^u*8FTY;d-wvN z0Z^(>okc&U=-72ERKDV({hm@E$<48GhRUIEA_qJLy~kN}uf{Ktox!S4=U48GhR{(xk} zOG54G3jq17-amZI41RZTX7J_q@Enrq78mQyDT+FaUR;URj0<9B@Vmnkmy4F$!&CS% z_rA`e8vr4sA#O+aH;(t00M^Ux;rViV`0jYmj2SaJ=v~1z=3aTUo7Y+N+R)xJYD@nF z`n>=)kiw*-zw0`SzIxDCw4Or>86}ujkizG)Z(CzPTbocT3IS~DEc)k~{kSWr75vSc zH_sq{dq7nIfJO-M?k@WEU%)R8*X-fP+yJl!z%n@Psc!)s8J2{|3Yw8^xjpRBGUi&p z-UBGo?&b1IgUFuX+z&5E#{T2XJci8o*We&NF5_6eLOV3X(@k0E;9^0s!&Z z3Qp>A&a}ZXH^}(KS;xK9^iG@Km^Rn6SD!IshK3|blo5AFMHPKdPZ(VDb#qu-tiHMF z9*=&yv^np^XUsUq22$e=(R#cZ0IMT|)9R>Ou64vcvE#X+JoN2pPn(+&?ai3+Sg{a7 zsEE%PKp=$p2OuMx=Iaian|FPFV_MlOrYaz)2Pj5cU&0jZvE0Bn9CLs*w-N&u;6 z^w=I|h8!BHv}ejT0R9@-9t+Z7LdXFMwJJTCMRBc@Zlt9I^lw14y$;=w=5&nUtFy>^ z%sS(;K)bh7npJVBW51f=NYPd(K&KBiwRCFQdc<9*Rh`TSA%xd_NRmV!&x#n+w{LGD z$D;sHsy+xIUXy!l4LLq*A;gbks46|oU`+Vra(nn2{JwiNv|U4D38(f9{YmRA`at#1 zAdM5<_D#qkwHmKUz1$wS(-tAuj?c9QTI`8GIvd~wYGVU8ZK;72#HmRLX`!lI9)Us# z@d7w9zy@uoavur+`4C3oK(3|@+#@&lM89_-Op=6~i=hz0c`lLAD>}u;@#FAhxjp2jCdUQ+c)(11Of;!pRFln%JwAGT>AJFJb!WR9`OW{ zfeHZ4a(nnR($~BP?-P$l7~8($+<+GkX-k17aXO-jHGp!cpZ`9BgnWr{o{tUWxOhG5 zBuU=G?7?xt3P3^ac!BOI;D6qtOTVP(H5ak zYv6>&P-{9ji5t+#vpS1z)CY31#s>Ndx!U49L=YpIJRl9^Bns**`nArY7xcM-9RI>_ zpL*6V+Mr3O_=w?q?gFi)vO+5?Vw?|513B@GKhk3K)3Jjz5LpLH z3*qHdIcs0;vyqJwYOpR+$TRDG<6?W>`#OtW_88f^C?F@V)k3cANlk*@XuvWUtB!q! z1M`fe{}w#cu2g`EMx(&_^GSseA8h?oP=0W3756qGk;ES3rw-}<6mswi`ozq&N}7&A zTxZcc7xxz#AVcuddx2?Hy{mvUHBA%u7dvv4tK zC4j{kEQEOJvNCG)Q(yW*h`+!Kn6A-nhx6xCx-vJ=GI-9^4OxYE;G^L#g)t1i@y+Z) z6Mh5!wA3{H{uOY_yHX{Hnw&Yca4fi?Y32;2URdwpTn8)%WgiB)R3A18I;0JJIa?{w1aR*)% zWTXt3D&uchZVyjMB`;yNIyaC9lU{l-cY_gghXg~#RB^wB6>4MBMtRa#_uPX2&0&%x zUtn;F=_OmuBX#}K56n=@5ow+z<=*H>d? z8VQ6Fb|JQdv_<%)*V_3;g)vB(vK2+80XRmeae~RF&QC_a3kr}i8IZf0k(X+&pfh;R z)W>}dSdv2kbY!j0qOX*a=>tjj-yl~Hwcjq_o^iDcU#6Pstt#B42p*7{9x`Qlw}66Q zzCcdIz|d9&X$W+(XSmSy1x2%Qb0{=?S7@e)gma|NA%@$67khPxaAa`9i7+ek^t|Py z0h1s?qjyV;|AAaDzrvsC8~CfmHkX$(XuP=o1yi(t1q4jliEV+5a3$>XAg#0Lw-G|K zoG_-mV9El+ciTOeqJIX`T;iT~H@>R5LN}v}b3lnD^UJYQzM-!MrnfOMPmic|3pSIJVE~b>|fg{cPhRRSL7|MsZzBt_V z^Wf-n_gsqp8MJJuHY_mEcEm9_*U-k{6-EuD+B`Zbg2giLD?loyY?3{)IzP`;O}VGM z2t1i|sOyVE#gt8HvoM7bbKmcR{t0MRc6HIMk|g=)+o3ZCr-$E_IxCRN%hHxD>#8$+ z(>C{jlb%zhUuLE5r81m&AaJ~{=&3I;&h>Q$gC%$|W{;_0@o^W1?+R95^~ChM$iZtc zYZ#&>eaFi5W|Q2f5lExU=!s1}cBJ+XDL%Qg$u44d4J$|ovp8FokhQo zd8QU2%4>1arqvPM7fLEpLgz}-7JeI0b-EM%&76acdZ-&e2wxQW4iCTc!~(ZwNc z^HA-;wB;BqwaGsmIMVV(#gzG|k*u{%{}ObV^(oGQW-na;>u!&j4V^p zSJ$UZRi(-;p{!o}ahAbJO?PRe@GyAwVGn*H4|Rtrq)gcY?&peGh}1jUv7(rYax8WZIER4yj`qATz>v&j(-nmeflCB}!EP z&`Qo->%1SgyafKa5dN{q=xd` zH|YnBO^H_BURbiaaC8@tOy-e$s;^v=NGeM|%*|^4P0;6Q6E*+4R7foTFcHsDp2 zLGCbDXla)?b;lPeMRrZzS7Q7juA>|S&o+~>G#zp;gA_8P)#_#=gHniTybpWGJZR3| z7P>aTG$+c8^bJ{20hz_d#{(6^;Py3Tk8yt6g$~+#tl~ZeV!BiD?DbLHpAk{O3>wxeAV& zH^d<60Qx1-H$F>Z@J*-f2J$VSzOO&(KHuZGb87w|2DgDGSb)?0YhbuMue0bi<@cKM z1e!Bw8?uJ%tBKjwUTilc7JIop{EOCbri_ufOIyTn8}R$=3hnEZZs~e80ScX-uWwtU z8^Ru*TtH5+y-AyKVQ>YSz%lH$j|%N;izba6BtfI*gNeSfN9=qw2JN@SkS?)7LWzQ8 zlvZuchBG;Xn?Mt9fp+B&04ylG%e{c6nJ6?99f_O_#CVHq_iK6jLPS6s7oAog9|rHD t>o%L3p*`t0LlZA_+I%`TMU`tC{|EQZ>4a;^B%}ZU002ovPDHLkV1iV|Kav0d literal 0 HcmV?d00001 diff --git a/source/presentations/week04.rst b/source/presentations/week04.rst index 2c3455af..d443c7f0 100644 --- a/source/presentations/week04.rst +++ b/source/presentations/week04.rst @@ -516,6 +516,25 @@ work? **Put It On A Server** +A Word About Our VMs +-------------------- + +We each have an individual VM that we can use for the duration of this class. + +.. class:: incremental + +These machines, with a value of $8000 or more, have been donated to us by Blue +Box Hosting. + +.. image:: img/bluebox_logo.png + :align: center + :class: incremental + :width: 60% + +.. class:: incremental + +If you need hosting services, consider https://bluebox.net/ + Apache ------ @@ -572,12 +591,12 @@ Default Site * Apache on Ubuntu is set to do virtual hosting * Config for individual sites is added in ``/etc/apache2/sites-available`` -* Activating a site makes a link to the config in +* Enabling a site makes a link to the config in ``/etc/apache2/sites-enabled`` .. class:: incremental -Check your server to see what sites are available and active: +Check your server to see what sites are available and enabled: .. class:: incremental small @@ -679,26 +698,108 @@ Check the ``cgi-bin`` directory in your browser: .. image:: img/forbidden.png :align: center :class: incremental - :width: 60% + :width: 75% .. class:: incremental Apache is configured to disallow directory listings for ``cgi-bin`` (No ``Option Indexes``) +Copy CGI To The Server +---------------------- +To get our script to run, we have to put it in the ``cgi-bin`` directory. +.. class:: incremental +* The ``/usr/lib/cgi-bin`` directory is owned by **root** +* It is **not** world-writable +* You'll need to put it somewhere you can write without using ``sudo`` +* Put it in your home directory +.. class:: incremental -scraps ------- +:: + + $ cd /path/to/training.python_web + $ scp assignments/week04/lab/cgi-bin/cgi_1.py uw@:~/ + +Move it to cgi-bin +------------------ + +Now that we have the script on the server, we can use sudo there to put it in +the right spot (execute these commands on your VM):: -How to run CGI scripts + $ sudo mv ~/cgi_1.py /usr/lib/cgi-bin/ + $ ls -l /usr/lib/cgi-bin + total 4 + -rwxr-xr-x 1 uw uw 42 Jan 20 04:34 cgi_1.py -- locally +.. class:: incremental + +Does the file have the right permissions to be executed successfully? + +.. class:: incremental small + +``http:///cgi-bin/cgi_1.py`` + +Do it again +----------- -- on a server +Repeat the process. This time, move your ``lab1_cgi.py`` script from our first +lab exercise. + +And Now +------- + +.. class:: big-centered + +A Short Break + +CGI Problems +------------ + +CGI is great, but there are problems: + +.. class:: incremental + +* Code is executed *in a new process* +* **Every** call to a CGI script starts a new process on the server +* Starting a new process is expensive in terms of server resources +* *Especially for interpreted languages like Python* + +.. class:: incremental + +How do we overcome this problem? + +Alternatives to CGI +------------------- + +The most popular approach is to have a long-running process *inside* the +server that handles CGI scripts. + +.. class:: incremental + +FastCGI and SCGI are existing implementations of CGI in this fashion. +**mod_python** offers a similar capability for Python code. + +.. class:: incremental + +* Each of these options has a specific API +* None are compatible with each-other +* Code written for one is **not portable** to another +* This makes it hard to *share resources* + + +WSGI +---- + +Enter WSGI, the Web Server Gateway Interface. + + + +scraps +------ How does WSGI differ from CGI? From de473fe35203a7951a01614c0d36df1662ccc421 Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 20 Jan 2013 15:32:56 -0800 Subject: [PATCH 019/487] push through to lab 2, wsgi on vm --- source/presentations/week04.rst | 303 +++++++++++++++++++++++++++++++- 1 file changed, 300 insertions(+), 3 deletions(-) diff --git a/source/presentations/week04.rst b/source/presentations/week04.rst index d443c7f0..0adc281d 100644 --- a/source/presentations/week04.rst +++ b/source/presentations/week04.rst @@ -796,15 +796,312 @@ WSGI Enter WSGI, the Web Server Gateway Interface. +.. class:: incremental + +Where other alternatives are specific implementations of the CGI standard, +WSGI is itself a new standard, not an implementation. + +.. class:: incremental + +WSGI is generalized to describe a set of interactions, so that developers can +write WSGI-capable apps and deploy them on any WSGI server. + +.. class:: incremental + +Read the WSGI spec: http://www.python.org/dev/peps/pep-0333 + +WSGI: Apps and Servers +---------------------- + +.. class:: small + +WSGI consists of two parts, a *server* and an *application*. + +.. class:: small + +A WSGI Server must: + +.. class:: incremental small + +* set up an environment, much like the one in CGI +* provide a method ``start_response(status, headers, exc_info=None)`` +* build a response body by calling an *application*, passing + ``environment`` and ``start_response`` as args +* return a response with the status, headers and body + +.. class:: small + +A WSGI Appliction must: + +.. class:: incremental small + +* Be a callable (function, method, class) +* Take an environment and a ``start_response`` callable as arguments +* Return an iterable of 0 or more strings, which are treated as the body of + the respponse. + +Flowcharts +---------- + +WSGI Servers: + +.. class:: center incremental + +**HTTP <---> WSGI** + +.. class:: incremental + +WSGI Applications: + +.. class:: center incremental +**WSGI <---> app code** -scraps +The Whole Enchilada +------------------- + +The WSGI *Stack* can thus be expressed like so: + +.. class:: incremental big-centered + +**HTTP <---> WSGI <---> app code** + +Using wsgiref +------------- + +The Python standard lib provides a reference implementation of WSGI: + +.. image:: img/wsgiref_flow.png + :align: center + :width: 80% + :class: incremental + +Apache mod_wsgi +--------------- + +You can also deploy with Apache as your HTTP server, using **mod_wsgi**: + +.. image:: img/mod_wsgi_flow.png + :align: center + :width: 80% + :class: incremental + +Proxied WSGI Servers +-------------------- + +Finally, it is also common to see WSGI apps deployed via a proxied WSGI +server: + +.. image:: img/proxy_wsgi.png + :align: center + :width: 80% + :class: incremental + +WSGI Middleware +--------------- + +Another feature of WSGI is *middleware*: + +.. class:: incremental + +* Middleware implements both the *server* and *application* interfaces +* Middleware acts as a server when viewed from an application +* Middleware acts as an application when viewed from a server + +.. image:: img/wsgi_middleware_onion.png + :align: center + :width: 38% + :class: incremental + +Simplified WSGI Server +---------------------- + +.. code-block:: python + :class: small + + from some_application import simple_app + + def build_env(request): + # put together some environment info from the reqeuest + return env + + def handle_request(request, app): + environ = build_env(request) + iterable = app(environ, start_response) + for data in iterable: + # send data to client here + + def start_response(status, headers): + # start an HTTP response, sending status and headers + + # listen for HTTP requests and pass on to handle_request() + serve(simple_app) + +WSGI Environment +---------------- + +.. class:: small incremental + +REQUEST_METHOD + The HTTP request method, such as "GET" or "POST". This cannot ever be an + empty string, and so is always required. +SCRIPT_NAME + The initial portion of the request URL's "path" that corresponds to the + application object, so that the application knows its virtual "location". + This may be an empty string, if the application corresponds to the "root" of + the server. +PATH_INFO + The remainder of the request URL's "path", designating the virtual + "location" of the request's target within the application. This may be an + empty string, if the request URL targets the application root and does not + have a trailing slash. +QUERY_STRING + The portion of the request URL that follows the "?", if any. May be empty or + absent. +CONTENT_TYPE + The contents of any Content-Type fields in the HTTP request. May be empty or + absent. + +WSGI Environment +---------------- + +.. class:: small + +CONTENT_LENGTH + The contents of any Content-Length fields in the HTTP request. May be empty + or absent. +SERVER_NAME, SERVER_PORT + When combined with SCRIPT_NAME and PATH_INFO, these variables can be used to + complete the URL. Note, however, that HTTP_HOST, if present, should be used + in preference to SERVER_NAME for reconstructing the request URL. See the URL + Reconstruction section below for more detail. SERVER_NAME and SERVER_PORT + can never be empty strings, and so are always required. +SERVER_PROTOCOL + The version of the protocol the client used to send the request. Typically + this will be something like "HTTP/1.0" or "HTTP/1.1" and may be used by the + application to determine how to treat any HTTP request headers. (This + variable should probably be called REQUEST_PROTOCOL, since it denotes the + protocol used in the request, and is not necessarily the protocol that will + be used in the server's response. However, for compatibility with CGI we + have to keep the existing name.) + +WSGI Environment +---------------- + +.. class:: small + +HTTP\_ Variables + Variables corresponding to the client-supplied HTTP request headers (i.e., + variables whose names begin with "HTTP\_"). The presence or absence of these + variables should correspond with the presence or absence of the appropriate + HTTP header in the request. + +.. class:: center incremental + +**Seem Familiar?** + +Simple WSGI Application +----------------------- + +Where the simplified server above is **not** functional, this is a complete +app: + +.. code-block:: python + + def application(environ, start_response) + status = "200 OK" + body = "Hello World\n" + response_headers = [('Content-type', 'text/plain', + 'Content-length', len(body))] + start_response(status, response_headers) + return [body] + +Simple WSGI Middleware +---------------------- + +Here's a very simple sample of middleware: + +.. code-block:: python + :class: small + + class Upperware: + def __init__(self, app) + self.wrapped_app = app + + def __call__(self, environ, start_response) + for data in self.wrapped_app(environ, start_response): + return data.upper() + +.. class:: incremental + +How does this fulfill the server part of the agreement? + +.. class:: incremental + +The application part? + +A Word on Middleware +-------------------- + +.. class:: incremental center + +**TRANSPARENT** + +.. class:: incremental + +* loose coupling means layers should not need to know anything about each + other +* You should be able to combine a server from one package, middleware from + another, and application code from yet another +* A good test is this: + +.. class:: incremental center + +If you remove your middleware, does your app break? + +.. class:: incremental + +If so, the code should be in your app, not in middleware. + +Interesting Middleware Uses +--------------------------- + +Middleware can be used for a number of really useful purposes: + +.. class:: incremental + +* Routing (stitch together multiple wsgi apps into one site) +* Authentication (share authentication between multiple apps, delegate) +* Cache Control (decide what to rebuild and what can be re-used) +* Debugging and Introspection (provide information about reqest, reponse and + processing) +* Theming (use tools like xslt to build themes that can merge different apps) + +WSGI on our VMs +--------------- + +For our lab, and for the homework, we'll be using WSGI via mod_wsgi on our +VMs. + +.. class:: incremental + +CGI was all set for us, once we turned on Apache. + +.. class:: incremental + +How about WSGI? + +.. class:: incremental + +Let's find out. + + + +scraps ------ How does WSGI differ from CGI? -What is WSGI? - Is WSGI Python-specific? How to run locally From d1af952bf54785c796948ae8f2f08b77e590f2d1 Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 20 Jan 2013 15:33:41 -0800 Subject: [PATCH 020/487] add images to support wsgi part of lecture --- source/img/mod_wsgi_flow.png | Bin 0 -> 23498 bytes source/img/proxy_wsgi.png | Bin 0 -> 24188 bytes source/img/wsgi_middleware_onion.png | Bin 0 -> 8554 bytes source/img/wsgiref_flow.png | Bin 0 -> 21611 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 source/img/mod_wsgi_flow.png create mode 100644 source/img/proxy_wsgi.png create mode 100644 source/img/wsgi_middleware_onion.png create mode 100644 source/img/wsgiref_flow.png diff --git a/source/img/mod_wsgi_flow.png b/source/img/mod_wsgi_flow.png new file mode 100644 index 0000000000000000000000000000000000000000..d7c2e84d4f4ddce50fa1823e128e8d563ee5c3e2 GIT binary patch literal 23498 zcmdSBWmHye)Gd6Y(n?5!ASK-(9g-qokkTL}-2&3xsZx^C2uLGHNsF{}NQ!{8l1hAQ zKj*yT8{_;wf6f>_4~X15u6?bw=A3J;9r5JR{Tn!xI4BhA#sft;H53Z%3w+;?g#rIR zzR#}+U$7k&bzD#=yiVjlv_y71Din$q^*~Nq!y|nw!(E$raX37|A_yq5EI*)%QzntS{^=r{L8E;}ACrdsTzpbK||Ll{eQ_2SwQ-_(V2bd4A0!A!}o4Ay1 zAJ5vC?}eCIH+tN@aKpsJY$V9KyJ(|aO07=Gm(Soep{3)=ru_7*RpqJqA0yj|*O{{n z1p*oqE?$*7f-AILp;4EMxI>l#NmlhIS?0Uq4>&aR@$m2hCl92tSZlY34G$VeC*ioW94#>>f+aNrSAs>WG}FvqU|M~p_F<~G_7;DXDQ>lGp+}vs77==bDn~U} zVf}lf5PTatQ)`23n^-o@fn8~`PVW}(U6_)Q5p&mOf|il-+VReJ+3lHH)mC4hv2vr^ zvZ2=l)QW4gs_g>*9q%%5a^CQ}JQspvM|@3WH|>t5ND*;iN>5LxO;l1AQPO*8nsQYJ zYmz~L{Q8xZ7fbEvrTPsw!|-p1J}L}KPA2;`Q5H2(rkAVt(O%2G;RP@G^)Fw(+_Sc3 zi=~l>q!O~vmX9Jm`SJQOkK^J!VPRn`8kBHZ^Ys**_rxS5bZ~vi+(rtnt^$#fkvtxI#@>H73SrR#HP|@KOG@pl z!%283V>*p_2r?esuhHdHEg8=%DhmIxx|%RIr(flHXsy=ZY`*;Sr-J19f%>cTblVt< znHwMNztd;={$+J?a-uujoMiU9IA!h~7`TIujxJZGMHHhT>nch;vUv!{)oyIC=&}^J z*=#suRZ?G{LQG2fs;No*Rch)3g&0bCR6HKFXndL8$5)v6G}?{5f&;1i&lQc0Y0>U^ z`}p+M+Dt0?`bx5LaWPrfzFl_}%^BS=#4(7l({gg+eO?`VTk26$b8|#c(AAfJ2814H zXb_KB*G|~i4XEkstH{X6C`OTThU;@N_51g4#b?jxo>!L^b4C?tpPEWz1O+HRgggYRqLL|2(GyGEvGcu=*K(Lv`EH4f zG*(;KZQtV=PzUh$_2eqNfw4z+r29ZnhfK{z@+t#%a8s8D|yAc26wjG(kaDRETyfsvxi%j@|&9x&^ zmw18pH7Xvqn!G&5gWZMOuz<2pp2XjItG)!=YkjVPKRqLZ@aD}cAu?#GDi{s=T;X3) zQ_Z|9m9T4N#5O~1Zj)vkA>D`fx0@-XpW zmcctsJ|h2!X@YL(bEv73CHej4z)RLAEW{^&H_HjBsG{oYg)M7!KRoSfUEijD z&-yoA^g)b5P-!X0*~v__yug_-qFAx1=Pt;^aYVNp?&!E})cdy5d$ ziBcU$SJ%#1YO(AQ%WDeJkIF08P|*(6mb(eo$|d8=g;~Ds!PrE@O)p(+glgL>Ee0s_ z^73d!MJaX5l5kr(|Dk|g>2qx73R z2qEx@^R!Q!6}{w|JR+tnx;i^QPft_82B>pWXXh~OiS2^@3QMGPNXwaeT4foTh!aC; z4L1yrHK~Ay0rD{>YOc}!F~P>4E{ma&mZ@-619J$eIHyXGzT)e6RC zw#OG!70nn%sB6v7e1G<3mQ#4iiidpp_Lk2pQd4}9Gq#&NDWD)+<%Zj=>3dD@C_1Ob zu3LGlJc)+2PkSuc)^k|BeMy8n`1bf^&lcL%ba0{$XuC{Ss02dIdF~3D^|sl&v|Sn& zq)T<2J;{~7EwE}gwBh9xso8|b4j;N|baBFvFO#RudKS@nfXmNuwKYD!l%Cp4z>HWl z^J|P2^IeEC2@5ii_VOzru`sV^#g|sO1gHF2X7L$k^MJ1c?AU% zxPlZhcdl2jU+;I|OF8bY{`irdosHVr*_q?>08}UksMYD$7^{7&nETE>uH=q^ftcBX z5zFCnBPkApPsBJOSKzm

~dxp~M9Q1OUYND4#U7a{p+#Cb^k{2bE9%V1Fv1;Q^$} z`?r09eb4`5NB2W{sI(qugM0wXls=o8oE&z%;CGvdN#*k!R`tD;eN(t28VU*u%Y_yR zh~-dNG!wWpav}R$Zd+4yCm*uBe`B|tEaQ53cw|EjQG~-oenLY5knEgwXdT$TefxG? zR}`7)Sdl8JQ@lx#`H*z7$Bl_9nxVeOQs=>Ul#`HLgNBCY=;p??TaerfiJQl6MnL0( zK83+2R{*}9LsFN~H>d=Sr>o4hKe=w;-d^ds?bliHtmEr<>2EFr+-Fxf3VEY6E8kL{ z)zu12LB@_xP3@H^c$kKf-AVq<4nfO+39kJEWPf}pi?A8YTev3@^V9Rn z%ehgDKYCvWZmX)Q78y2+LM37Pa;vkar^8af8N=-K_iFu%O;R;=b*G>G6xT2@8F+aK zvwV&y+;-+7;6j`(sczkhhGifIu=p8(Cjlj8Ki6uEQ2lL+-+@b064DV;NtH8+igw0 z|0gSAYD!xrU6>FS7BHhI-mVa3OY#yrHNE-k~ti*RQY|WnxKGf)z~LZj_8+rr`W5&diJn zn@kQW$NpFLa^tQ@k~w`%8)TucQ}A7bbliS+`ez^Zj^l1(e&JUF%+^}W$OAw4}BvJxc(H76e*U%k(_(NU4}`}gmg!nT`xh?UtHh>rWD z(arAcVDxdIVTn?H`>*j5)oP1}!NI{;7i%Z`E84KDNI7*iejfTQcVd_7RAa!J+)r&? zNo0Ro;d|~0JgiEC_EbFlsV=!9JkEk$iPzH;> z_+`8^*Py7RbaRgXo9^(s1REO;tkFvJbiQ)(wSRk;x>ta7AMAYBb6kR}lzsQa`1g-q z%WrwuIXOA?$IHvh2yC%OPx|y?lb(wUFCifzaOedjTu)EYpMx2=*`47Fjqdmm(1O#k z5GpcdTBh*GR?kVYQmY0V+l)U$@g*cD52w6qZT$COBYnpXO$H0lJdKoZ^oz}jw%J)K z;HVwlF;oc|83qL(GM_#NN*MwS69KqT5mvq=Fdzi{*ca%OLhP*wtI>jY5KQ5bk?oNr z?29WaL9jVdcTyvGO}lAnX;FZcx&XKEzWAl#y73K&9XeB7T3TAv$%zMS;gKJK=l1sY z_3pbgb+*&(c4-n`f`5;9mz%|$7BapL4kq8)z2SqO;uin1ImZtQOCc2 z&2X{>lxJo9sZkez^;oIPGoqH3mK0&9Wp(OLDa_~wBurgOOMbk{h1x+uK}h0O!*@C` z!>g*UcG~!MNB@&6_JaoxPF9nRcpT=%znJkg0sXg-k~G%Uz{bW-;eU;phg~`#kt&ikB<00PzVv;m-JXWk;?|I0EcUv;LzhA|}({s7`czz|e zSgQmeQ)G1X_0G;tB>BM>ZGW#>qC%5qK?lS$v$zbFy#4axSZZsg78i5}1)#`?w!m;d z7Retd{~%0!6WGdARpz)*E5hJV*C_?U^=1fJ9=yXuM}G$U9+4yf&;r?xg+%xa4?c+GrmgB^ntSL7)f<1-n_h)mLI?p*0R3MovY=lP8~tKfSQgZ*;rS=(gSd zPBzSO@iQ9aDp{u2&!#G#A<$uIdAXf}#usfWL(F|R?*Wmt-utKJv9LIA|FI`Oc=QPG z;_T1kt=W(GPs@$ub$lA}a3~+| zJP&^%EE~QY&MA|HhJ?@oV1?q1LV0+3<(l^;O||%l{TxVRo;uEOpI?eR)nFs}Ig}NL zO~izyR(9L(jQ6++jI}^A*~#A0T-~D#(Rc75 z!o$Nq&o#JIn)i_ki;1}`^z`;(vul-phI2GrPB*>ehx|awq5YZj#WW;$B#0rquD-9& z3L)EWZe`()3A!ceUEgb6hK@^$)lJjimcna#Ot_V>K42)%d zSPOCv7B+UJBKN=6doih6CGs8~!tEU$s(|^gVPNR~IC+>R7!nqSiAZ4<18I>O*y zuA&f-=iG1$9+}6%I$@p~tLM=c>&YeD4IK*$mbA1q%73)*u_-)my4Ik#I88G$Gc!m^(g5}hlB0iFU?m9kFjy&{PbAbT zViIuhulpg@)wDbo{@la~jcn+toSNG%@+94iijr`-V;1ZoW1-H9VcDB4KGpZxoW zdrJ=~@KAAW7g`MBX-F0%mCLlQqO2!B#PlU|%d#aVeRBAqTgJsd^+Bha>AgmAAgC7o z=_1u*|3E2f_B@mUQ~@{%FG9}b_s368D;N;1c-dxK8Ff*YB4>slBGs!K-rnAm!%3q`=T#;9*#?(29_uldox@`FLfY58!$qnLx5V78gT@Ah(sJ?x z^~a&!*UZX?;-^jLN3+_EZk$N27qpwfnx6#$xvHv)$D|Vrbw^?_JRA%3#6cY*nR;uZ z?7W^&4hxcqghcid_*~oFNq{kOa&m|)9XK24^ShV1Nbe&T@POa8%)=Nwdg!6WZ$eLe zLd^*;@%U1&UtC;FHM(=#&o@PouxmLce9-3#Gc5o3iExEV!*j$F%GgSrlmgUBJV>H& zU)bHD9K~glK7aiQ0zuJs-q4H$Nep0X7%(lY?%SGdBo_TC0g!2ys)r1v43uFH zA-POUp~^(;#5lH76=+XC=u1O#aN1jxh7^f8S#Hz=QL_iKn4argEr*IG1u!N;DnZ-N zAgmDFy46pipi6FQXGf@3Rrg+n36hF*9E}A0Lp0wEyp?f4;VnT4zqqD6{0*o@~0L52e)k0TEKK`87+S1dvPliZeY*51%yj ziqQ*HO5dpz0RC$^QAz;>Y6OUGn^$?uUpB}nL0el}YN~(WmeEsHLIL9I^9UNk7WF<| zO-{LML;A7IeRp2ib)6tEFmQ2qcgXJe;Gh$3WCZpqUvgnJ@ng1TcV}lr+v9oGehsqk zRbWm?EhyWe4S40c2C#j=%6-yK0gQh2x>WJcc4exF0;VSqvckKsP( zv}h;@&~^Y7uuhmEG6A6EEtZtGEMMHGPsoM~(T@Z5cLtG3lw<7vIDy~@pXari;IJ>H zV!;+%>rV|DlKdC_k6P4iD;!X&>CgVuIj2OWI}ojq|F5DDIn(!K2@^6D5wI6Dx@$m~ zZXSGq=2RS_K@c%NLIM}+9N@4}AY>+sp93yeU6b0?)Fl`@Rqkj1nJk*Jl#>}HX=rHp zGB6+y%?=q^SzhNKiY@{{0k3dv;FM4~W%HF15oq=N`Ey|rk+zW$LeLd(LIO)}-zRu6&kMBTEV-;Ckl2(|~pVJoSg@cMPon>WPb-X{de zQ=G2K&qm3pC@5e6uNr}nE+O`eNKj-%RF6VVGBUD9dP@1PMw2|YqGvEKMC+1%LOKg1 zmZZMA23lJQ>`CYk(FqBWK{>qxFcX-vF4s0v-sk4#D%^JsuTzT>BRUT}i)%u!E+IN0 z_g%{!35U*)ezPYDR8`*(s3U;rh@Q%(`92sBLt=3?92wcRv9Yn1BRS}Al+25LoSmKH z-@FNaYWOmwq=^Kia`@Y|THP2(gi`M46#$f>3$VDh76xV4Wyaan6<|Q1T5&K0F;rB& ziZ0LiXg()r=c@NE*OWXT)V!*uhdN9Gy@HL@V~64FfbW`D-UgCt>AbG${#X{F!RBMV z1iz4Yq3)y(6fA241DlJB>oGNRDU{Mr?zjoH1lkzW;L~ zv803@9{xzBX%FA=#zJfBz~KEl;sRgH$}Cm~?a0KoXOFw1pXu>zpScs`bgA3$00Gpn ze&!W=T4^6a|6ik85a)lI&!2zcspYHboVPfVP<)C`@}MY*jLpquK)rd%PTL(NTdtR= zWWJiDO`50_0=+#Opmv-PJ1f-_DhqmZ(!ZaMB`Y!(>DInq)MAbP9m0hM%9q&@ znw<^91PQ8ulV8SRK)z5}L&FF9Z&2wo>ruihUGJjy8yg$bn%JZAD^h|uHtYC7Ka*8b zip+nz|4o|P%+u7u>w_UDuJ1TwvjM4reyUZU_ppm{vKqgpf#nb-zj=949l(W559V9l zQ3%s^)LF z#oV^;f$FL9>+37QzEZs34}>`K``$vvj@6@#R=o%g33&%4I}knRA$I@#^;C~Gn~O8C z_naW4A^%iV^u>C+vh9qF%O4YbDL0rP6|*opHhY&kg9p0O#n+aJg_mO?`Y#EOoN!BPuMM4YCrX zK}@8hxH_RFZZVjSjgOCCV?7=zwtHri=Fr$5)0Om=NbG*G1`af_Aa^6VGRyCx4OB;m zh@VZw#AIZq(49d-5#+}1@3!M@Z2@}1pXkZ?vTI!OX5Q=8vVj;81d57t&_y)a8ie4< z?>=rsF48Dg3lUp0SB?l%s_;6Kl#RuE7WRT!$r!p4VMS=e*K-E`>CZ}_Z7NF-R37Jl# zBPx7)8v52y8>(hVS{fA)^zfdz+jK%Y&A6MD$%8@^m63HY8vS#7pUSn&j3&3j}oBNq~j z%)8H@1FkM@Z^uB>28eav&4Ksv$ZCPk0UQaT?n^s6c+eee&^KfgepkLNGVpaWNq7%V z<_M)O@4@SOFTR5Oe4WN#H)Y^90H6XPBoS~1JuqVZ9#H=_Jxhtz1*2|zuoB|{WkAU5 zRE-tUyzjqlvX-zPef^mdUOdL1Q37@|#E2GU|60LoYx#OeejqofSx=lsxF0Y)ZqOf; zxN`L>!VXN};t;igkDq^Fx(TNT>K>$>`#{P~&rbF&$KR8j?jW|TU=a>1cBtq;?+{^$}5l^WT4!>6|idmPB0C8 z8B+TbwnSL-VAvWm?+C(&XuJ|M)bI5^d~+(aQSd3pj|2z(t&l@36fO`EOo4(TnwS48 zdE%lv@_W#br;+ds22Jd2uLD1Y&m0FB@e@vi(sf8=6oQoD`_u&z z(%YIkf>Gt{P!6H;eFixL92(u=L2+6iru*^Z$LHSO2>##8R0^%p(A`HWEr=$-&3a&c z_h9jt;a3rS0K9Q&Ypee|d8*_ar8}S|OqTq}Qg@l<#OD3OIayo*{tz&9z+;Mxic;0r zj|NR09w9B1ZSd59vU^`umC*h93B=YCWGXPpm|b0Z{CRww1j?RliB=gRjSM=Dh&7G2 zE{i$;q0X0xB~yJ~G`f*Jy75F`|2h=moE-W`df=;=qh8vm0}4({M~4QOb2*){LjZE9 z0ZQnvzgh0aWfpXx;J7JIyT-{RK$;Jf;?GR z0$n~t!2yngTvp#LNocc&!bRo+r$gw>^Q@CN$mwn4q_C#^=nbX(o3IOtK&_e- z(^$(n(>H7GH=|vfmhMD=JAW=%}rdmb3okC-GW>!TQZL0 zD(6K=LZPl1puvsQKKM`M#(oBE%&$bH{6*b@$&V6b8>n_xIbcMd%`I;Ra@wR8EbiLR zkpmb5#!&BfDT#xF13g{gS&XK1!Kh!+*2REQ_1&VZqh`1-+Nat4@TcaFb3yBAb|QCzu9#oNM5 zRM^7SuCMr)I$D7Ngdr@txh^O!N>)*qQp>zb?fxSDs%lm_Rxp1xyQ#jb6ocjK0H%RZ|>JP6Z&3 z)yUeBzIdf!bas3?Q{{T6MBXzV++?)DSU7B8ry&baUAvD(s9$tIpV+qwjyhO^beA8; z7#tKEYp~lv*8#zpL1)u~xiY-L!GhD+m;w_yvS8`MZigWkL;;P$z<{XaY3)SckHvY z%dwG?D~zf(d*YBl!$?ALS0$KWaHCj*ZE$Jie8U%XE?{NIgP~gyQ~dnfD)P_T&(+UM!K!fB2M zeZ2qN54ezTtfGGPeq#@n@Yq8E@j+S*z&5Q$O#jq&;j36Bg=M|V#`k>|TRfk8=Y{zQ zuj1R#Y}E#tcZ->Sykayg!EWV}2hIxc!WeXuQ5*XPDPT!EJM*Cyf3Nm|fsAi+ANA~- zy|pGjo8UzXfzB49zMD5O&4(h*{4Yx}Y_TipLs%Jjs&@3UbxPJ3Qh<-)v zLGB0(O9@$A*~n|z7;>LI%x=z%p~nv&uG;^23HmMckGttdqCF&8QPLC=QY6y1y`Qs^ zz7++#n>KxF&0nr!;yDg+8#ZA%I5Kc%eH6_PIf;X-KSbk@dDophn;xKwAfktmyU0pCXo9%3md0e%R&wX*|!54SCHlR zj*b-c^>0DNG_NzgQoyc_w&d~FBM~3i%vUE}7YSLHj&chUOydLnJ+JsPLk21KHuu;h z*H@L5l`I?_a-bcfy&>MzZ}Fyp=AqE0Qs2~e(5Wh1)P?Y(XAPoD%Le-e5u*aiBd-_vE5&D#Jk9-sK9iD3!PU)nuh*a$4SM;;ZTMuL8e|sgKO)h8m&8wG~s7!Ob&0H(oxq)$2 zNGMhG$;A{y>+gBBPhX+5gV_-2EkG^@3Dy)uNkv7)ilVxcPm4BD3$g0H;Br z0JaB!atPWqSSAK+dq~NwBG}Q3TRLZQ$~O+JA6~V<{#vDDVxZb6-@}gf=Bo-SpWo=` zGH6P{fb77d6$mO~Hl+3S@e(pXf1DQ8ovd0dS|@`E3ylJ`!VR@G;4s9-QYY15JO~DJ z*N&X(+Lzl@Y$g8f=_ZZP{Rih7x9xlr1+Ox=lJ^Oz8{rxLwNu|ay;o<)O%j$=oZC3vbx}_k8}4a!bU zDp3)UX8_hEigu=ZJuY*>%+ zek-;`DWM;l^yimAA0%DMk48C(V@b+D{yupCr5FfRmvr)ZIg|2wg~ zcqY>Y`v=9loP{lp{e$+&|ZSnV?4?5wP;+8^zypB7=fv9tjJ5$Ui2 z-wlQWll-qTE02BAXa)Vv4qc0FY{Fx}+y%y`gTrqHZ6Ieky1U^X;E-`;PLRM;)zye%OO>YY8u%kx*DUN#W|r?CnLJ0OOeBen8YgoZ$N+(8upS3) zE=|v>Q&aFTOC8?jHdNw!p8ex=4p=isfE*}RdtD&AZE9LqhV=%9Sa4F zLP1&@4FEsW!?(f6S^>I%BoUw!ds&0(H?&Qfc5pwW7gtUQzVr4m`xwd?Xac!}r@-Xq zV(WAJuQ%gZf#gPWTHC;`L-|9xO!gc~=P^jUU6;dtujn@5Z1@@MrFoXaOp!`=yJWAdYbvUMDmvfH{?roSXYt+rh5KKpNqqW}8; zXj1=|1|t5SIm{QsgR7v3Izr3fw`G(8bazU>UsFI2vFZ~5aLCKc3;J<&ZCbm>1CM8z zFVFwJ=uhQe%O|vhgxzv}q!%0-s@upKjnfT1q^l^NzN8Hn9~IOCH$KkA z3~m9A6q_1vxVG$39xIMrb+b(g{RU1E`OFn1*RGmF@09P-YP|cGztJrmOmeUAlV8`e z@BJg&btgfQHbJr8WoW@3Km4wIR@#jH<6*biw7Sl}OPk@=1DPy+3e$}(FuL*G3YW$1 zql%pnnT1QdcYEhuYkN25b%u#bn4D| zsqnMwHRF@Je;=`*%n7#8Rg)N~0=l~V2qlq3LC>N2kaXU2lha0MB?Owi(0WCzl_C!* zVic;;k1d?yHH^XW|F2|n6Z%a1YMgAwo3JmS3SLEgoXCCJ`fpS4`Th*BjwEPzH8(|e z4R`@OwreM$C#Xch^VzND&ZAtl7;w>puu#BB6~smQZrqygbz*&am0H!Rbc3j3%W&sl zLIIOeojkfNHH=4OJi`3XX!QKc3F~zmhC#(A$OUnkce;r_4K>F7Nru58Z1hgpkck}U44!1utDg%cuEk#R)Zr)~sG zG8Vs|k*ko)IwZ^c6}wEU51m^>V=QGlkdO$|;4Cw@nV7mM8fj;aunvYdbb-1+Tao%m>vs`@^T14vycY zVga9Am!Apz&^bObrplLQK0CY+_DiXJGA*4>Xa=Ro1pLGZ?|Oralg5%Aa?^e{WCncOx@v*%FD`_Dm)< zkUFs(OBS=5cE8uQBNI)2!ojDf!zq`3B{zUSFno<2Z;od3CmrzJZ&;`zq7m>g*L028FEAt{W*qH4jgSfYW@o#deyA zlA5q%hp7N#=$3y0gShSEM~}LplV2Z54|5OOvmZ?_&Q7%(obQ0Q7yVzBu+tTYr9eCI z)K1meQ6;P4VPhj!6DX-+;N@C@u9wA`#Ss4Z%~~{*S>sXDc$CshH_rebTYTRi9B#37 z*8L}mrFCYV|RUgpZU=tbk!h|v>JR^aw+p94ae2||atGbs1(KyOPC za-f0E8zC4>;o_EIPG|Ax^5Wm_{`B)KY{?ZU31Eh!hu%LL3OG^^=zUA8t07;B2S2LQK587 z8Dfd5v7Nq&7=Y?lL1O{0HAv%_C=Q(}WWcQhj*U#4bau)iK2w*U{cUjnS(_d}E89WU z-(PII3L13cru$3P&elYcAkS)Wt1q{`4BdWaZ97Ej$Gv|*$XVo^X_9<|myY3f3)-{*-y0{ZJ_apx@Od}YF2!RqV;p_?WYSb@TIiGaNp<9+0xv>Md#VVb+T@sBb@$Y z{NAo${`nNsUvjIl!P9R#e2Y zHP=7{^NS8m`xqz?Ffg7JYrv3WxbY?b^Fe=tE6`m+`A0=57w4pbaYwsge>M7!ZGc@E z_GJPn=qBK<1^-C0=4_?+sWbSS^=fZipIy2*|EFDLhP^Z2Y_nbPrWc+c;yAERk9wvz z{7;Qbw+0J13nH8Qzw)9VOyRw{w6rAbdBB22hxkIltQZQ#0ujAX{;(Mn6j$8tCsY9UdP< zM#!K=9{`(9r;*j%`SiCrhhY=>^z<~TR9&0#JuR&y9Z4~M{!xxB8!N>30}DY1Mq>2> z6~d-tkpB^G1=dVQCnsreIK2Z4h2Nzwm-*kHX%0CylOK?~6&DvrHWPH9bXQ8I&`G{Y zV_;(Dg7+O{fzI95OPFQTz(P#2@I8&Bq$Esye$XjEZB*l zfr~c>lXRfd-v^})>^00O1**krchVurfP=LgTHXXOk)=~@5kL?KfZ+-X=^Q}m*EtZI zW?S{_Fw^_bz^SY(3tmeE+(Wu@`4jB_N-rOA+<=|e<7AHxj51h&(V=;ROjZOAd4iCJ zxIz&h8r=5!w|rb!O8Tiau)u;jL@GWboU|uy5SB1JWt9g%h^6Y@LsH z3|?hsJ_4^HG6WhC9nA<-bFSs587yCCUtbh?j6#*iz6pJz(gQ6m(&GylhQvnkxvoE1 z{`E@9W`iSO7#8}}bYQWNV|twc>*btP35NchCoGEKAb$Ye zn{c&aMzBjVjaUj;NIVXHbLIvjHZ$1g7?9bG2Ip0r-u`|@klxI|sFJ5!Ykdus&}()L zbqt(ZNZAWke@Fk6^VZG9g#iWvm|&rQK;$rr zh@^r|>n(UY6Tp`kHC6iD94LGq7-#Z;ionqJmzjY|9Ml&$T`w%KBIv0NFznF)w(;Jt zU+E$3=0SrE%AyGm`PWqs61FZ~4UJ$pRP=2r8Yo7P;zD820G^Ak^#Yjnmmq^6kqiCe zrHze<<9V;Rw0|`)5RR}8etsetr@(~4E9h*7P>Z>tSR#HPIx;fu2pUjHC+~dAkRWW$?C!z;-r;y&fJDv)WymY2Nh;K~~UX1+OHM86Zh2m*t)cK(_=N zWePDLafe~kfGnT7cy#jAFQaPbJ*-quq6acpm+8{kA=hKZs3 z0L=Cwg))Fj2H9E5YIM{ChTJP*ZkF-R9WaEA%nZB~@leIbrTQgpztEC_qP4QJnyZ6S zeiIPH&fRTkE}g2*AD0D%g+ww~U~FfClKf-7)%RSq*r-)96)+}Ua6A|wZ=wPXndySh zz`OAS5L$5jtNC8&ja=J>5z0)PA@Hk4fRCtmaFBFs6s9@&!2NjXh>?kZ<|puTch~5B zvSnFVP*4Z|?ku#7tDINAlI=*h0F0a4goq_X1=^8u8#1C4;UxrMBA4SzehtV>2aZ|m?rKb*{i)SCx^X$DahOdtch zzU$EbX{oj}DjsI-;-R-KgGGnrTo|yI!J@cpO}vkk6<_Fas}^fmY)At%N!UzGK6Y>z z41*j9g9BzzJp{*t%(PoDb>4N;`azO{u_h2e(`J)k_73JOV42?`Ht!>FpULmF0zANc zQdQ*xZVP18$acC49TGXrvQpOQmKob792uWvVWYqRNZbVD-Ytu@QBkeZL^&qxEiPCSVd^RenZSW!389jwwn0?#0EQ+)IrZwq|L}gLWGAe)n-$yw zQ&>NV3bbsYpAT>cIs&w=+cPA5(^1MPmsG5YN+^P8qEVcC&4!mM>`D5qzSJ;u2&W<2 z8imxjWYjQIc3S8Id7mtWf%r)%>b?^Vo)(o1 zQ4+R990*1Bd@mSif`LMD_r^?g7-vCzrbt=<8;THgOTzx$cnH=WUU;)aG?mcckAI-& zA`>`pptCujjb1-q5_qhyuD&XORDv%=OCplAR7X>&q7Y57IE0I>XBI9FD4j6eiZ(#;2 z6+9L$^zNQ?^qVFiks?kYXrj;qs06T!7(u{^j18U~>lb)%S5Q4l=VqP2!lX7h_MiD0 zlwibXL(XT0g$#GYkQ~@A5|!n1v~fR=X8e7v#qkbL)0=O!NYQX#w$J_Q_7k@2Q94`YJjFuWth{zDckvZ|fOeaOswew}LJ`p!-) z1PwjlWZ0(i0HK^+TvCI~G}5hTU~~U(zc})`gPr}>%X55?i#s8|v(=Li0X{vsMCRd{ zUcUq5wXn}$0Yo_m(}oFL4FYw+Q1U^)p*<$G#&YCJFoC@{77Io4!QP(7&zJHL3HM=o zLbt{;pvC8(a~yQ6)Q+91iD4A23+$MC(6L#Bkf>sdqF=$ zX2NX0e!b*dqnNh zhbcthK4T?M?QFahEU`s|NZ1dCXFeE)y@!LLt%@0Ngq0vo!lDJkUMhvQFE1nnqc zgCMuppdX8@eBtO4oC{ea#M3Rm2rmhd0WWa{%m72JpofBl@NkG^LIQ$4mF-MPA5nO( z3^GIj)_6n@K3UI=6Yh9!hXgHRi3d`E>~UB$G?Hm> z+NQ)6WXitMtoJ4?v~VdCCWlF?&rrOEp&~t}xl(Z#d07zh7L>V7060!v zdaKeZD%TDD&R>9y301K}e{&*7M)(Vi9D-MeqIj&nF-B91kpj#m z7j~ot{1gUub)5fteh3M@{I_tqxV#()b>tl~C(`VB_h{#P6ih-vSkl9kdPqn}5!6Uz zkPu!1g79@t-5QSqH<%>2jf{l?pFxKr3wYH8S~^qpP7EIf-f%9iuZKfGE`ttH53g8& zo3Th*0Z2p-o|cV`4H!pxr?aNlf;CiS(hD>i2bkIQTfzj8YJsE>*2v67JKGL>7T)I&mkK8j1>US{=C<2;_TY@79T1< zc$ZJIQ$;r{Z-Gp-^wIjrN`#dZoOtKHFF3sYZ(jWaZ)gFtDlW{oJ}8b@hx_lqyzT7| zwG642`up7w46wLYvh&uFHxIy)g{c*D+&xVqUD;b&_)dj7J3Djy^YbB;S7b~HlE&QH zEIsHn`APL`-0-ZPCk^@BTwW*wB#~b;R%Nc-Ciuyu7a6L6+zLw$BY^6|L{4sQ-7rF( z0OR7ox{<>G^(5!F=y&;82~{qCM!@B#3fT13D+a(kkK8bfK{&yAHOdXC0e9UzXz7Wj z2twvvVNws=X>-D24@ZGuPqC?U11tx~XVW$Ul&%nDeSo5q^BAK(y0Jg0 zn(Bg?9ONx6@V0~;p!aj{#UN(%9S$yM#6C_Hy=S?8$-gG}G>2GC^>h1GM#XTtU*R{~ z?0*YKRS9+0_&Pf&nrNM?7E&zffUE zVGf+qXRUC4u}cs@ka z^!HZ@((6EF7uaaf_?2nJ^j zGJ%XQaX=t>`h!UPa7Xxu03XWMlh3~UHa~Dnw*4vI+UrG&o%OJCqjhvDaTmu6G zb%1JAmSiW9`R}2rcsf zkl1A(cyZwip!7C(%LzS9q-6RW=^Pv!EJ9AWamL}SRVw``*o-d%*d*u~509UaTPRuC z+jj%38JV06gFHdN-L!XQFjGSB#dc<@Ff!%)`7?^<LqH z^=HNBzvMpbw>#asCE|R|&dx4}U+8AUB2WVp{Wysu^1uK7g^2ug776ZHdi(LANNf=D z!VD-c#6Pj31!zcd(2*geWiMpkl8ReySy(9$r#=eC~|OkNcXze7?4)(hd-hfOE58XpXqh#@LfZAp2SgIs$nVcQUQfq zRl{?0(STMW@ctqJ4u<2OJvw~>6rE)s=YQ#DB~K~_4c-t6G9&;0TDcZ?rrS5Z5b>fy zYgo)#4sUbH;YE@2p>iB$GLge5WWSe^uuNuT)Ep|zkVBD-!V=NKh!_fmcMgfSSW^zs z`|SPw{)FFkJ=gczb?y4@dhTb>eLtW3e(ukQ5GDi20DQmUi)t}I;R`IM;^5TOvCn38 z(k0vt2KJ~o%gBE)aj5?LoiBiX4D5Xd`l<(qhw(Er7{0dH`5p8TrWq2y!lBnJrby&q zU`!2u^$)Br2S}B4frhfj5%2XuXGS6$2iQoDYR;~MK>aLsF$X*91Ad%Nrz4;l)VjKX zwQX=cr9y7(`|3@z&<%Ae((-;$o}B`v@qwcp)#f6VB9D z*_qvE0>H!%10b-+#>NKlw=>uqyGXHJ{-A%HFZlsnWfiDq@Tqx#EVeK0a~--B3K9`( zEVgE0;_C>QjZ4TpG)anA{`b?V)4%6g z{OHa4v;U8;3{H#g02gdN5J>=cB@sAX=J>%@0BC=LO;!R!Jys@`$MSpZv@;{=&AE)tl@+Om8n9PoznSrS6kVdtgB; z-owogVI|hQw=;nkMYjm-6lV^u7fdT1v(Fr*d=<;ibW4O7EZWAXD2db~^18e{W)aW` zwvc*di}LL1+jpi_d(~sO<%!?rr|!mjQd2uIdU&>>E5lw+T3ozy#jppVbjyC&5Cs{= z-Nzj`?tm(+=-(4rWne!fi`9jVT`&h?0bg8!Wi&T0& zD)r^5OrxN?X*z~tK?FcQlMCGLr8d-Bl4-BRUm?Z$oCuIzSs%Uo3S4xNS#uyd+8{5(?O|$Q%F><4 zk}x@C@}APSn&25&56kIM1w)y9(;;B?7NTEuuD+7P#vN*@s`v8(jkP|t*lx?pLEnDeP}-PY7>?1hMlChgO1DFKD*5fjksX@c)(sR)~n zbj#3rSh~%Pk2PID1@0QTXiZJ5wL+Lhtdd_3G+Judp_inQc?1?DD47!f9%QMDL z<|Vl%VMk?^4ziy6KAK1f4D=MFbo1ULmQF+(BBb3Ua{PIQ(j^N{XkO8mB)cDVVRF55 zPqgC>WY|(`+^dA9e{pLfCtjMIuZO{3V_Y|q7#EPNA#V`XR_$2m;U#UU z^k?)Fw_1I4UN%MEW(AK@PGw)ZVNG@G5%tn?!14^Zd3Jx_Ub!aW4lTsMK;@}u-XZx- zQzVSA>vi-y#I@u1tq9giWE}aOX1*J`*u~xdx~PEvoCz-Tra(Sw$d>6i=QZlN-JNM1 zgR?er)IVjkDwbm^^~7puxy(~5J;=S*2`n((O9%QYXCF%ab6SzekhqsJTPxMC4aK=L zrIs)yt`C>&jE0YGo^SR8VO}$jRg19wCB%B-SCG#*+0_vdQz;?B%_w@JukYB)bG*Sd z3(8KBEx1S@?b$acOwWG{?=QX>D$Yxc1!|e_S(m3_^O|+`&! zU2_^oU<@;2m4H=YY4CwzL$s?`_!{fT=c5jt$T$_#$!BBO=Sse@(G@zY99IY_{kECHa`IkJMcwxa zR*UGHE-D|YlC|8n z>gMVYd29wE(frj;PSs5}s^_V1TxN&1_P3Tpyy>~!OW~XO{Vf9F!<4Z|ree?smj_K1 zT?nk&@e>6`eQXHGt*V$&v?XG|H6udFC+*Y1JxFj?TPeXFxbqKfm-YZYbi}~+zC!@q r0b>gO3&;qo|H2{y#{B>D^^PFvbny~a%hC~ub3+_$PukR42c-N1NoI%N literal 0 HcmV?d00001 diff --git a/source/img/proxy_wsgi.png b/source/img/proxy_wsgi.png new file mode 100644 index 0000000000000000000000000000000000000000..a95aec03a0b6f0b564a7f110c91582fce9169993 GIT binary patch literal 24188 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 RVjw5aVS%?XuQK(F`yXsWP?Z1x literal 0 HcmV?d00001 diff --git a/source/img/wsgi_middleware_onion.png b/source/img/wsgi_middleware_onion.png new file mode 100644 index 0000000000000000000000000000000000000000..17f486b240c30276ddf29762a8d0174e9f18e63a GIT binary patch literal 8554 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 literal 0 HcmV?d00001 From 2c42bfc27716ad62289107010786a0c5861d7632 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 21 Jan 2013 17:08:47 -0800 Subject: [PATCH 021/487] * remove rst directives from the plain text assignment --- assignments/week03/athome/assignment.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/assignments/week03/athome/assignment.txt b/assignments/week03/athome/assignment.txt index 42582569..11d78319 100644 --- a/assignments/week03/athome/assignment.txt +++ b/assignments/week03/athome/assignment.txt @@ -7,19 +7,13 @@ interests, the Web has tools. Put them together to make something. Place the following in the ``assignments/week03/athome`` directory and make a pull request: -.. class:: small - A textual description of your mashup. What data sources did you scan, what tools did you use, what is the outcome you wanted to create? -.. class:: small - Your source code. Give me an executable python script that I can run to get output. -.. class:: small - Any instructions I need. If I need instructions beyond 'python myscript.py' to get the right output, let me know. From 74b647d75a7aa927e09f473224a1dcc95adeba67 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 21 Jan 2013 17:32:00 -0800 Subject: [PATCH 022/487] update lab cgi index page to point to other samples --- assignments/week04/lab/index.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/assignments/week04/lab/index.html b/assignments/week04/lab/index.html index a5c1d715..90356e3a 100644 --- a/assignments/week04/lab/index.html +++ b/assignments/week04/lab/index.html @@ -9,6 +9,8 @@

Week 4: CGI, WSGI and Living Online

CGI Examples

  1. CGI Test 1
  2. +
  3. Fun With Time
  4. +
  5. CGI Sum Server

WSGI Examples

From bd74e4eb392c7a6e88192d16422706038673e8f3 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 21 Jan 2013 17:33:17 -0800 Subject: [PATCH 023/487] * update the outline, fixing due dates and linking week 3 and week 4 assignments --- source/main/outline.rst | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/source/main/outline.rst b/source/main/outline.rst index cbccd589..bc3c86e2 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -79,7 +79,7 @@ You can read the assignment at http://github.com/cewing/training.python_web/blob/master/assignments/week01/athome/assignment.txt -Please complete the assignment by noon on Sunday, January 13, 2012. +Please complete the assignment by noon on Sunday, January 13, 2013. Week 2 - Web Protocols @@ -162,7 +162,7 @@ You can read the assignment at http://github.com/cewing/training.python_web/blob/master/assignments/week02/athome/assignment.txt -Please complete the assignment by noon on Sunday, January 13, 2012. +Please complete the assignment by noon on Sunday, January 20, 2013. Week 3 - APIs and Mashups ------------------------- @@ -259,7 +259,11 @@ Bonus Assignment ********** -On the way soon. +You can read the assignment at + +http://github.com/cewing/training.python_web/blob/master/assignments/week03/athome/assignment.txt + +Please complete the assignment by noon on Sunday, January 27, 2013. Week 4 - CGI and WSGI --------------------- @@ -320,16 +324,20 @@ References Alternate WSGI introductions: +++++++++++++++++++++++++++++ -* `Getting Started with WSGI`_ - by Armin Ronacher +* `Getting Started with WSGI`_ - by Armin Ronacher (really solid and quick!) * `very minimal introduction to WSGI - `_ + `_ .. _Getting Started with WSGI: http://lucumr.pocoo.org/2007/5/21/getting-started-with-wsgi/ Assignment ********** -To Be Decided +You can read the assignment at + +http://github.com/cewing/training.python_web/blob/master/assignments/week04/athome/assignment.txt + +Please complete the assignment by noon on Sunday, February 3, 2013. Week 5 - Small Frameworks ------------------------- From 7c5e042dce2da12e909a856e457e26ffb90c931a Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 21 Jan 2013 17:36:49 -0800 Subject: [PATCH 024/487] * update outline, fixing links to cgi example scripts --- source/main/outline.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/source/main/outline.rst b/source/main/outline.rst index bc3c86e2..c9829bc4 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -300,9 +300,7 @@ Prepare for class: * `CGI example scripts`_ - Use these examples to get started experimenting with CGI. -.. _CGI example scripts: http://fixme.crisewing.com - -(https://github.com/briandorsey/uwpython_web/tree/master/week05/cgi_example) +.. _CGI example scripts: https://github.com/cewing/training.python_web/tree/master/assignments/week04/lab/cgi-bin References ********** From 8ab0ceef01d0645f5760c7aeb652a97a4bf18e50 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 21 Jan 2013 17:37:17 -0800 Subject: [PATCH 025/487] * complete the week 4 presentation --- source/presentations/week04.rst | 339 ++++++++++++++++++++++++++++++-- 1 file changed, 327 insertions(+), 12 deletions(-) diff --git a/source/presentations/week04.rst b/source/presentations/week04.rst index 0adc281d..1d6cdb96 100644 --- a/source/presentations/week04.rst +++ b/source/presentations/week04.rst @@ -60,6 +60,10 @@ Let's think about this same problem in another realm, the command line. .. class:: incremental +Windows folks, for this next bit please open an ssh terminal on your VM. + +.. class:: incremental + In a ``bash`` shell we can do this: .. class:: incremental @@ -211,6 +215,10 @@ You have a couple of options: Let's start locally by using the Python module +.. class:: incremental + +Again, Windows folks, this is going to be most easily done on your VM + Running CGI - First Test ------------------------ @@ -238,7 +246,7 @@ Break It -------- Once that's working correctly, let's play with breaking it. Start by making -the file not exectuable: +the file not executable: .. class:: incremental small @@ -329,8 +337,8 @@ Let's fix the error from our traceback. Edit your ``cgi_1.py`` file to match: .. class:: incremental -Notice the first line of that script: ``#!/usr/bin/python``. This is called -the *shebang* (short for hash-bang) and it tells the system what executable +Notice the first line of that script: ``#!/usr/bin/python``. This is called a +*shebang* (short for hash-bang) and it tells the system what executable program to use when running the script. CGI Process Execution @@ -344,7 +352,11 @@ just like you calling:: .. class:: incremental -In fact try that now (use the real path), what do you get? What is missing? +In fact try that now (use the real path), what do you get? + +.. class:: incremental + +What is missing? CGI Process Execution --------------------- @@ -473,7 +485,7 @@ What the Server Does: * parses the request * sets up the environment, including HTTP and SERVER variables * figures out if the URI points to a CGI script and runs it -* builds an appropriate HTTP Response first line ('HTTP/1.1 200 Ok\r\n') +* builds an appropriate HTTP Response first line ('HTTP/1.1 200 OK\\r\\n') * appends what comes from the script on stdout and sends that back What the Script Does: @@ -674,6 +686,10 @@ This is the bit that sets up CGI for us: Allow from all +.. class:: incremental + +More about Apache Configuration: http://httpd.apache.org/docs/ + Setting up Our Script --------------------- @@ -788,7 +804,7 @@ FastCGI and SCGI are existing implementations of CGI in this fashion. * Each of these options has a specific API * None are compatible with each-other * Code written for one is **not portable** to another -* This makes it hard to *share resources* +* This makes it hard to **share resources** WSGI @@ -1095,16 +1111,315 @@ How about WSGI? Let's find out. +Apache Modules +-------------- +The abilities of Apache are extended using **modules**. You can list *loaded* +modules with the ``apache2ctl`` command. -scraps ------- +.. class:: incremental + +Open an ssh terminal on your VM: + +.. class:: incremental + +:: + + $ which apache2ctl + /usr/sbin/apache2ctl + $ apache2ctl -M + Loaded Modules: + ... + alias_module (shared) + auth_basic_module (shared) + authn_file_module (shared) + authz_default_module (shared) + ... + +Another Way +----------- + +You can also see which modules are enabled by checking the listings in +``/etc/apache2/mods-enabled/``: + +.. class:: incremental small + +:: + + $ ls /etc/apache2/mods-enabled/ + alias.conf authz_user.load dir.load php5.load + alias.load autoindex.conf env.load reqtimeout.conf + auth_basic.load autoindex.load mime.conf reqtimeout.load + authn_file.load cgi.load mime.load setenvif.conf + authz_default.load deflate.conf negotiation.conf setenvif.load + authz_groupfile.load deflate.load negotiation.load status.conf + authz_host.load dir.conf php5.conf status.load + +Available Modules +----------------- + +By default, not all the modules that are *available* have been *enabled*. You +can check the ``/etc/apache2/mods-available/`` directory to see what else is +there: + +.. class:: incremental small + +:: + + $ ls /etc/apache2/mods-available/ + actions.conf cern_meta.load ident.load proxy_http.load + actions.load cgi.load imagemap.load proxy_scgi.load + alias.conf cgid.conf include.load reqtimeout.conf + alias.load cgid.load info.conf reqtimeout.load + asis.load charset_lite.load info.load rewrite.load + auth_basic.load dav.load ldap.load setenvif.conf + auth_digest.load dav_fs.conf log_forensic.load setenvif.load + ... + +Adding New Modules +------------------ + +.. class:: incremental + +* Debian/Ubuntu provide pre-packaged versions of software like Apache +* The pre-packaged versions will come with popular extensions included +* We want to install an Apache module which is *not* included in the + pre-packaged Apache +* We can use the packaging tools in Debian/Ubuntu to install it ourselves. +* The packaging tools are called **apt** (Advanced Packaging Tool) + +.. class:: incremental + +There is more to learn about **apt** than we can hope to cover here. Learn it +as you need it. + +Searching Using apt-cache +------------------------- + +You can search for a package using apt-cache (``apt-cache search`` *text*):: + + $ apt-cache search mod_wsgi + +.. class:: incremental + +Once you've found the name of a package, you can use apt-cache to read the +dependencies it has: + +.. class:: incremental + +:: + + $ apt-cache depends libapache2-mod-wsgi + libapache2-mod-wsgi + Depends: apache2 + apache2-mpm-itk + ... + +Installing using apt-get +------------------------ + +Okay, so we know what the package is called, and what it will require. Let's +install it! (we'll need superuser privileges to do this, so *sudo*) + +:: + + $ sudo apt-get install libapache2-mod-wsgi + Reading package lists... Done + Building dependency tree + Reading state information... Done + ... + Get:1 http://us.archive.ubuntu.com/ubuntu/ lucid/universe libapache2-mod-wsgi 2.8-2ubuntu1 [63.5kB] + Fetched 63.5kB in 0s (197kB/s) + ... + Setting up libapache2-mod-wsgi (2.8-2ubuntu1) + * Restarting web server apache2 + ... waiting [ OK ] + +Check Your Work +--------------- + +Are we done? Remember that command for checking loaded modules? + +.. class:: incremental + +:: + + $ apache2ctl -M + Loaded Modules: + ... + alias_module (shared) + auth_basic_module (shared) + ... + status_module (shared) + wsgi_module (shared) + Syntax OK -How does WSGI differ from CGI? +.. class:: incremental center + +**Wahooooo!** + +Configure mod_wsgi +------------------ + +Like CGI, mod_wsgi requires that we do some set up in our Apache +configuration. + +.. class:: incremental + +Open the file /etc/apache2/sites-available/default in a text editor: + +.. class:: incremental -Is WSGI Python-specific? +:: + + $ cd /etc/apache2 + $ vi sites-available/default + +Adding WSGIScriptAlias +---------------------- + +mod_wsgi uses the directive **WSGIScriptAlias** in exactly the same way that +CGI uses **ScriptAlias**: + +.. code-block:: apache + :class: small + + ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ + + AllowOverride None + Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch + Order allow,deny + Allow from all + + + # Add this line to the file to expose a /wsgi-bin directory + WSGIScriptAlias /wsgi-bin/ /usr/lib/wsgi-bin/ + +.. class:: incremental + +Save your work and exit the editor + +Give WSGI Something To Do +------------------------- + +We've set Apache to look in ``/usr/lib/wsgi-bin/`` for wsgi scripts. We need +to make that directory since it doesn't exist by default:: + + $ sudo mkdir /usr/lib/wsgi-bin + +.. class:: incremental + +On your local machine find the ``wsgi_test.py`` file in +``assignments/week04/lab/``. Use ``scp`` to move it to your home directory on +the VM. Then on the VM: + +.. class:: incremental small + +:: + + $ sudo cp ~/wsgi_test.py /usr/lib/wsgi-bin/ + $ ls -l /usr/lib/wsgi-bin/ + total 4 + -rwxr-xr-x 1 root root 955 Jan 22 00:06 wsgi_test.py + +Reload Apache +------------- + +Any time you change Apache configuration, you need to restart to pick up the +changes. First, you should check your work to avoid +crashing Apache:: + + $ apache2ctl configtest + Syntax OK + +.. class:: incremental + +Okay, our syntax is good, no problems there. Let's restart: + +.. class:: incremental + +:: + + $ sudo /etc/init.d/apache2 graceful + * Reloading web server config apache2 [ OK ] + +Looking at wsgi_test.py +----------------------- + +.. code-block:: python + :class: tiny + + #!/usr/bin/python + + # This is our application object. It could have any name, + # except when using mod_wsgi where it must be "application" + def application(environ, start_response): + + # build the response body possibly using the environ dictionary + response_body = 'The request method was %s' % environ['REQUEST_METHOD'] + + # HTTP response code and message + status = '200 OK' + + # These are HTTP headers expected by the client. + # They must be wrapped as a list of tupled pairs: + # [(Header name, Header value)]. + response_headers = [('Content-Type', 'text/plain'), + ('Content-Length', str(len(response_body)))] + + # Send them to the server using the supplied function + start_response(status, response_headers) + + # Return the response body. + # Notice it is wrapped in a list although it could be any iterable. + return [response_body] + +Lab 2 +----- + +Let's repeat what we did for CGI with WSGI: + +.. class:: incremental + +* In ``assignments/week04/lab/src`` you will find the file + ``lab2_wsgi_template.py``. +* Copy that file to ``assignments/week04/lab/wsgi-bin/lab2_wsgi.py`` (note the + missing '_template' part) +* The script contains some html with text naming elements of the WSGI + environment. +* Use elements of ``environ`` to fill in the blanks. +* You can test and debug changes locally by running the script (``python lab2_wsgi_template.py``) + +.. class:: incremental center + +**GO** + +Assignment +---------- + +Using what you've learned this week, Attempt the following: + +.. class:: incremental + +* Create a small, multi-page WSGI application +* Use ``assignments/week04/athome/bookdb.py`` as a data source +* Your app index page should list the books in the db +* Each listing should supply a link to a detail page +* Each detail page should list information about the book + +.. class:: incremental + +Use the Armin Ronacher reading from the class outline as a source for hints: +http://lucumr.pocoo.org/2007/5/21/getting-started-with-wsgi/ + +Submitting the Assignment +------------------------- -How to run locally +This week we are going to do something a bit different. Get your application +running on your VM. Then add the following to ``assignments/week04/athome`` +and submit a pull request: -How to run on a server +* A README.txt file containing the URL I can visit to see your application. + You can also put questions or comments in this file. +* Your source code, whatever is up on your VM. From b737a8b8f92e5349d5cc091226f668a28d214cb4 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 21 Jan 2013 17:38:00 -0800 Subject: [PATCH 026/487] * set up assignment for week 4 --- assignments/week04/athome/assignment.txt | 23 ++++++++++++++ assignments/week04/athome/bookdb.py | 39 ++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 assignments/week04/athome/assignment.txt create mode 100644 assignments/week04/athome/bookdb.py diff --git a/assignments/week04/athome/assignment.txt b/assignments/week04/athome/assignment.txt new file mode 100644 index 00000000..0e043082 --- /dev/null +++ b/assignments/week04/athome/assignment.txt @@ -0,0 +1,23 @@ +Using what you've learned this week, Attempt the following: + +* Create a small, multi-page WSGI application +* Use ``assignments/week04/athome/bookdb.py`` as a data source +* Your app index page should list the books in the db +* Each listing should supply a link to a detail page +* Each detail page should list information about the book + +HINT: + +Use the Armin Ronacher reading from the class outline as a source for hints: +http://lucumr.pocoo.org/2007/5/21/getting-started-with-wsgi/ + +Submitting Your Work: + +This week we are going to do something a bit different. Get your application +running on your VM. Then add the following to ``assignments/week04/athome`` +and submit a pull request: + +* A README.txt file containing the URL I can visit to see your application. + You can also put questions or comments in this file. + +* Your source code, whatever is up on your VM. diff --git a/assignments/week04/athome/bookdb.py b/assignments/week04/athome/bookdb.py new file mode 100644 index 00000000..49769f37 --- /dev/null +++ b/assignments/week04/athome/bookdb.py @@ -0,0 +1,39 @@ + + +class BookDB(): + def titles(self): + titles = [dict(id=id, title=database[id]['title']) for id in database.keys()] + return titles + + def title_info(self, id): + return database[id] + + +# let's pretend we're getting this information from a database somewhere +database = { + 'id1' : {'title' : 'CherryPy Essentials: Rapid Python Web Application Development', + 'isbn' : '978-1904811848', + 'publisher' : 'Packt Publishing (March 31, 2007)', + 'author' : 'Sylvain Hellegouarch', + }, + 'id2' : {'title' : 'Python for Software Design: How to Think Like a Computer Scientist', + 'isbn' : '978-0521725965', + 'publisher' : 'Cambridge University Press; 1 edition (March 16, 2009)', + 'author' : 'Allen B. Downey', + }, + 'id3' : {'title' : 'Foundations of Python Network Programming', + 'isbn' : '978-1430230038', + 'publisher' : 'Apress; 2 edition (December 21, 2010)', + 'author' : 'John Goerzen', + }, + 'id4' : {'title' : 'Python Cookbook, Second Edition', + 'isbn' : '978-0-596-00797-3', + 'publisher' : 'O''Reilly Media', + 'author' : 'Alex Martelli, Anna Ravenscroft, David Ascher', + }, + 'id5' : {'title' : 'The Pragmatic Programmer: From Journeyman to Master', + 'isbn' : '978-0201616224', + 'publisher' : 'Addison-Wesley Professional (October 30, 1999)', + 'author' : 'Andrew Hunt, David Thomas', + }, +} From 70ed54da52f792fa07467ef6fe1f8c3508031e21 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 21 Jan 2013 17:38:21 -0800 Subject: [PATCH 027/487] * add README to clarify how to run the examples before we get to class. --- assignments/week04/lab/README.txt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 assignments/week04/lab/README.txt diff --git a/assignments/week04/lab/README.txt b/assignments/week04/lab/README.txt new file mode 100644 index 00000000..98d18b5d --- /dev/null +++ b/assignments/week04/lab/README.txt @@ -0,0 +1,8 @@ +Start a test CGI server by running: + python -m CGIHTTPServer +from the current directory and then navigating to: + http://localhost:8000/ +in your web browser. + +You can also set the port manually by passing it on the command line: + python -m CGIHTTPServer 50000 \ No newline at end of file From a433da013869f3b29a936334fd697822b236a749 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 21 Jan 2013 17:39:00 -0800 Subject: [PATCH 028/487] add two additional example cgi scripts for fun and profit --- assignments/week04/lab/cgi-bin/cgi_sums.py | 23 ++++++++++++++++++++++ assignments/week04/lab/cgi-bin/cgi_time.py | 22 +++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100755 assignments/week04/lab/cgi-bin/cgi_sums.py create mode 100755 assignments/week04/lab/cgi-bin/cgi_time.py diff --git a/assignments/week04/lab/cgi-bin/cgi_sums.py b/assignments/week04/lab/cgi-bin/cgi_sums.py new file mode 100755 index 00000000..55b6b22f --- /dev/null +++ b/assignments/week04/lab/cgi-bin/cgi_sums.py @@ -0,0 +1,23 @@ +#!/usr/bin/python +import cgi +import cgitb +import time +import json + +cgitb.enable() + +data = {'time' : time.time() + } + +fs = cgi.FieldStorage() +a = fs['a'] +b = fs['b'] +a = int(a.value) +b = int(b.value) +result = a + b +data['result'] = result + +print "Content-Type: application/json" +print +print json.dumps(data, indent=4) + diff --git a/assignments/week04/lab/cgi-bin/cgi_time.py b/assignments/week04/lab/cgi-bin/cgi_time.py new file mode 100755 index 00000000..f6cbd18a --- /dev/null +++ b/assignments/week04/lab/cgi-bin/cgi_time.py @@ -0,0 +1,22 @@ +#!/usr/bin/python +import time +import datetime + +now = time.time() + +html = """ + + +

Here is the time: %s

+

and again: %s

+

and in ISO format: %s

+ + +""" % (now, + datetime.datetime.fromtimestamp(now), + datetime.datetime.fromtimestamp(now).isoformat()) + +print "Content-Type: text/html" +print "Content-length: %s" % len(html) +print +print html From 49aca500c4087e9d068cd5399ac2042a27ea24de Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 21 Jan 2013 17:39:25 -0800 Subject: [PATCH 029/487] * add lab source scripts --- .../week04/lab/src/lab1_cgi_template.py | 42 +++++++++++++++++ .../week04/lab/src/lab2_wsgi_template.py | 47 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100755 assignments/week04/lab/src/lab1_cgi_template.py create mode 100755 assignments/week04/lab/src/lab2_wsgi_template.py diff --git a/assignments/week04/lab/src/lab1_cgi_template.py b/assignments/week04/lab/src/lab1_cgi_template.py new file mode 100755 index 00000000..7096c6f4 --- /dev/null +++ b/assignments/week04/lab/src/lab1_cgi_template.py @@ -0,0 +1,42 @@ +#!/usr/bin/python +import cgi +import cgitb +cgitb.enable() +import os +import datetime + +print "Content-Type: text/html" +print + +body = """ + +Lab A - CGI experiments + + + +The server IP address is %s:%s.
+
+The server name is %s. (if an IP address, then a DNS problem)
+
+You are coming from %s:%s.
+
+Your hostname is %s.
+
+The currenly executing script is %s
+
+The request arrived at %s
+ + + +""" % ( + os.environ['SERVER_ADDR'], # server IP + 'bbbb', # server port + 'cccc', # client IP + 'dddd', # client port + 'eeee', # client hostname + 'ffff', # server hostname + 'gggg', # this script name + 'hhhh', # time + ) + +print body, diff --git a/assignments/week04/lab/src/lab2_wsgi_template.py b/assignments/week04/lab/src/lab2_wsgi_template.py new file mode 100755 index 00000000..8c50b2d3 --- /dev/null +++ b/assignments/week04/lab/src/lab2_wsgi_template.py @@ -0,0 +1,47 @@ +#!/usr/bin/python +import datetime + +body = """ + +Lab A - CGI experiments + + + +The server address is %s.
+
+The server name is %s. (if an IP address, then a DNS problem)
+
+You are coming from %s:%s.
+
+Your hostname is %s.
+
+The currenly executing script is %s
+
+The request arrived at %s
+ + + +""" + +def application(environ, start_response): + response_body = body % ( + environ['HTTP_HOST'], # server IP + 'bbbb', # client IP + 'cccc', # client port + 'dddd', # client hostname + 'eeee', # server hostname + 'ffff', # this script name + 'gggg', # time + ) + status = '200 OK' + + response_headers = [('Content-Type', 'text/html'), + ('Content-Length', str(len(response_body)))] + start_response(status, response_headers) + + return [response_body] + +if __name__ == '__main__': + from wsgiref.simple_server import make_server + srv = make_server('localhost', 8080, application) + srv.serve_forever() From 53464bd496f546db5be2090c0c5398298a96f227 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 21 Jan 2013 17:39:47 -0800 Subject: [PATCH 030/487] add wsgi test file for labs and local testing --- assignments/week04/lab/wsgi_test.py | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100755 assignments/week04/lab/wsgi_test.py diff --git a/assignments/week04/lab/wsgi_test.py b/assignments/week04/lab/wsgi_test.py new file mode 100755 index 00000000..a14a2de7 --- /dev/null +++ b/assignments/week04/lab/wsgi_test.py @@ -0,0 +1,33 @@ +#!/usr/bin/python + +# copied from: +# http://webpython.codepoint.net/wsgi_application_interface +# +# This is our application object. It could have any name, +# except when using mod_wsgi where it must be "application" +def application(environ, start_response): + + # build the response body possibly using the environ dictionary + response_body = 'The request method was %s' % environ['REQUEST_METHOD'] + + # HTTP response code and message + status = '200 OK' + + # These are HTTP headers expected by the client. + # They must be wrapped as a list of tupled pairs: + # [(Header name, Header value)]. + response_headers = [('Content-Type', 'text/plain'), + ('Content-Length', str(len(response_body)))] + + # Send them to the server using the supplied function + start_response(status, response_headers) + + # Return the response body. + # Notice it is wrapped in a list although it could be any iterable. + return [response_body] + + +if __name__ == '__main__': + from wsgiref.simple_server import make_server + srv = make_server('localhost', 8080, application) + srv.serve_forever() \ No newline at end of file From 4bc4271971bf6b9667fe48388a8704f4776407e0 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 21 Jan 2013 18:08:16 -0800 Subject: [PATCH 031/487] edit for potential offensive term. --- source/img/granny_mashup.png | Bin 226117 -> 216410 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/source/img/granny_mashup.png b/source/img/granny_mashup.png index a0a57c9ee47290048b14ef18b4e15da711003aeb..7ded8365d15b7625555a798e8bfd7fabc14eb79e 100644 GIT binary patch literal 216410 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 z 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 z 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

~D!^9GwR3<7{z%?}+5JUxR=5=@GIQATQjWhaM z4uj@mXGS}2ehB7gRT@0mIu%3e_YkE3Hws|x-5x;ptH9y(jdx=)A1dOLKUQ|~P*QxV z<#^-8_><1Ow{*o~^?m_&h}+-!6ziF&&wTB~k>mK{Xm$N+c+KD3xmF>e?DUr| zRR^Z7H_|B%*zwS+!0{z;nMqTk;?w4|%5s(gdzlj84;MG%Uxa_Iq?jK{G8xGpq_b83s;w>%%V7{QnhdXtLy2SZ!*J+S55<7`bve^dIQy zLLSYhj!y~i!C0a_4r=u#3wJKcR69x*{k$l#*YZ@z!lF`6TdY^Kvf`Tq15ch!jk9zO zb!D7A{9gVjP_4;_;{xkS^sTm;I+k_Gv4VhqE5rkj2LgaCjU8*OvSEXl`*YY}J$^kP z3TF40;Lj!dKWY~mr`a$;jt&S0R93KB1>ZRLK+arANl9ANzw)lh$eY)>*;1bebAA@g zY235F=fw??OF#|d{<}r}BFOXJiHU|eRUoZ&w5w!pdqqMd$(l`7$j&LpNwGLGA_<|E znnq3b%6vED{K_&U7aAvV5xa1w2?pM0xp8(`ZT)z4h=OwbW&K{vkDlmXzwkDLcWg%d zOP-i4iJjweqe)#QtIVWp~#XhEFG0?KdN=QDeK63i%%=YKJxf;Tc?q%^y#oS-@YdypOM>=u{G!_-!iM zb~tjI3b#Za#hw|lchxQ&X`$+rNbbcHQS8nTOy04Uv;J4|lYJb#{HC#?`UxmwRZma4 z=2xHg^SyI*ovrOhi$NUW0PGKeMKD^A*HaI8!%KjTemN{XoxVqof^q99s10E(_tx7(ZBT6TYf#34iag+T@kT(ye)RTZ=o!tX0-)MrPi?CJZ_(s zi}P7$I`8no@`(?E5hD&xn)yuM{a;WEZ-YH@)3U@#U)U+u>gCVq!@sL|1@iw^fv#v% z)uh=hV`Gzf0--tZ+Tvs7l0iH~Wz*MP+F$vTgLlCS(l*oEp=Q3R;C!yb-=n?t2xc1( zieQ%o=QqsdlQRQXB{+ymEa&e-GekKFA~ggvD)l7a?qe-AHfeaySA~;k#P;} zvg;sjF8fqmNX`8H+?Ac5$C6VvHN{D$oZp7;-3aNWrR6)kpn_LnN|vA0QcLBrFkOl$ zqr#ty3*u6g?BeJ3Dk)7dBP7jK-FFbdc$ZXVP(eK-63MZMi|KpaL2aoC_?-Jj&Ulc7 z!I`0WSm~ga=X2qv6z$7-h&0Owtao`cO3rJvIyE)%V&k}|Cl5U-uk$g-kFObdk;_w78}oChmnIuIl+YZB|}~W*3Z@JQmMFs zI4#-}zWMu0Ey2JCzTgnm2#x<3?>BXksu#UEs0imGh=?3xO&yb9IAb~A)|sOVRLonr zZwdppdNL-oz}%e!())>6pbHf|l!Lbbm-okYy_iiry#P`RfB~v%Ra9mS@_d;by6-tE zK%`iJD*|;i5d(<)fWv$)J*{f3+7}$RoG8|B7|Fs<8h)-3a0{@Lhgci43?`y zpmygCu*%K?4oVN;MFuSLvPPFJC`DB;dwZzny?bI~j81#$XWSfcu11qCER1PmzSrgo zLB_+>`-n#4J#-x3XJuw)R)$N{r6d~=w`%7rB5-pja|o^ElqWe|t*sw8c}5ZAYZJpR zo#KVv(EVaJfP_~N3Knw^P@z-lAx4bLjl%Y0+!w^^VZ~JV)$f{j{AHHjbVWG6|4wfR zpFXPwHZ6H0CX&5w{MlRY?2JAP?3`@Bz4a5< z3V6z6I+r-RZ6j3uh8fmzCcl@)hsXWP;Ke_^nU6C4J6-BZg!QP$A(%p1YYYr zk-F}%g0IiBU(T#VkX(XI-wcAh)9frWWDz|*-NC1OGhp-fmTiU3_8TeQ%AsN|*OjiE z$J`%90J2(s(Zs|&0awx0#VLeF^Fxu$D4$zfS@9UHYwVf~vKVV^ghzf3B!1YJPucEo zhnbDF*rbZ~y$W|9dvgRs;^C(95RDE3tzeTFwJ=H9nttJ$lHikTrvg_T&LSSKqg^9& ze9o4vtSlfw17u04HLA4+LPMp;qy-180Fj`DO65Q=IHd8Xrrscx-0O>O zx4B*N?y2MQ7P0*(m{}f@a2SjQvJ4bLnJ-@-646$$w;x6%4>imsi$8w2R=aTgFB6Pg zfok1a4jf}0>Qx4oD{Xuwee}B)SR+p}d>X>op6wLuElw&^p22+qQsK|>+oJHW%X#PD z32tt{!Ky6pblT?E8xjM4q($hRkkq(7`#7lmklqau1B};t?%bNj)0odE%WgvDd^ypD z1@kJ3b8)lEH9ij2z1R^moBuX1UY5B0yrP^lnY?Mm`3Zeu(#F)Wr=-B(!pXfP!LMiz zb#d6^_ycLrVkb8e(JXv>)dhugb30?hN4vc7|2%_#-kiWfm)xrc=R|)g^K2Bt@0s?WV z12cTGrE=k(P<;sDL4^}{ zq3-C)8vSnW?x-(Y{%jmOJ5B$@&cM8Qn(=o~QL6K0Gk}z&r)SAmL6|aoR z!TnwUbBJQ*ke1bcomBZoUgzHhFq#lh{eQse99Z$(I{vG6M9{B>g@;enwAeHUj#s}M zdL75qyQr07VpTt>7pN^lKZ~0$VKEFID$|m=DbEi!BA**lHgzoL)Gek@p8V4DHN%cP zP)SuD;7x|gP)d~%b~3GAW1o4h~^M(0?a{&zaJe8mOqNRxw5yv z_WkR|21+7g5o}}B+&X}L!jNN5T`+4Uf&d824`|na(NDP=V$vi5UQHOyFUfmENN5}{ z@h{WW0k#xU(Z6h6Cph9Pa!-!>aeh=_w5uhZP|wIA$`A?`@*zVT(xd+{JBNQq4;j_( zv{prc;BjnJueMP5^`98`^&yJ^kDZ%3$M@zuBp9#M^=5we@vwGrhymLVEB}vDBLU=M z$iNzSvHwOsuS7hC13K+0~YjIFF3;hHp#D9P{)`(V_EZN zX8OnptaGKn5Ft}6S8J=}{BxDMQpV!!UFXCi;pQBYzpZ)nGoK6hvfBkq zkb-RJb17}GA6_R|O9(#R|Lq1rV4SwFE)FJrOOq6VFEe)6sJRh_KGx4)Kex0HlGyZb zXYZ{J{wd1lN~4%LE2YSm&*Nq}3GR&*_K+$Ync1!J@z$O76k8cM^|g-m-hK!9ttBWG zw1v|P&P@s$e0^v3OjSnwmBfJ3EQAWQ0&F0v9n-m<-lJpLgMw~^wMK7&szCacRwL`F z6QV-s#$*$PUa&F~80(qq>D-q(Tzz!-=~0mCX}v#x75_D5bVggJ((+$(Kr-HRhoGt+ zeA1I!;ftQQx$^SOvFW|xl;Nh0r=V1>J!zS#m-oCu<9?{l@yVJ1P=UO^S<`Er@;YmP zJLNi^2CjE?(#A|^V7bNQNu-|zdb`i7VNFfp;47)8h>*6o@5y25+7w{E5_JPDFN7S% zBIEd`X*h}TY79doQ!^_Y@7J%xI6n@A^;4(;fAMk@)Eb9RgV#@8Z=Y-NWBA!+uH2J| zFODC<^XjsuyCz`-J;|POj3t{oPsrYrM=_xh(d}Sd$Nl~G1Z?`ipt%-ijieN>w~kXK z)FEQ;dsUp3FRnsfW2TSz;MU*e2j^<|E|Ik%K)p!UDkq2S0bKsR*7km#*VCw9gTOuX zH*;s&VlPHzbumViNaTfCV!i5qsCrr7P!;w)^{lHSXD$sSto9~BvmN}=W@@!htc%49 zpFqhCI5=XbE(T1Rk-DE}-0bBx@mVxs)N9~8Xw zwPC{flenr&2{{+pkqw& z8kLAWisCg|jo2DGOzTbT1OS7+P2LMlNz4w;R_eQiw5h)LHyalg4l zE72|#sbXbyHTH+ISbndU&pi{CH{^x_?-A;SUi8t&Wh#X2>Hq`G1%0I=W(vD<4fLiw zel&7DN*XSu0|U1penla4cAuB}j=&LLdn>FAFsDjzZw#<;`;O z?xs%iLx>SPX-hzdLNZj6?yV9LuB2UK_(fnGY8XQZvhJooa%L~=5laU1EVyKO0EYa zDoA-_v9NdG!k~E3`(*b!`04D~L*6({{J9UmKb1dXE}w9pA<9+L6W#mGPXiMW(_dTk@E4Xq{VgFgTmnVFhrmlOY0&#J}Cs6X4 z*g_@#`~X^;4k{AbQ!@Me@-OmqeH?0dUbQxhi;TQn^%<3hSj=HN z&!m!|e=4-<#pdx$j9gXL_ak5mW6}_LqQHw)@}9Kr+%=xlVa7F0-&(iJRr&Mv`^GKN ze=B1|wH@-hfV%y|#mbqTRI(Z|PgL06N?$;8oB^%;H*BQFDuGU&0Gu9zGlqBd`Xh|I z7jrHN8NSL=0gxUa#+_QiAW}meHTqhgBdwr-@G)Yv*U9OKKAhRw`~@?l9PgeqTEj{$ z=u+wd}@>|DI*inXLlENUL!6i6?8`KP1VM37Ct(h6)D;WZCJ&i z=>%o&{j1RBOY$iXMm1H$e5qy^*eRt(+ODr5401fr+_TB`M34MAoq^^T!jO!&=sfxI z9I(fG&Cc0cb2L={lmHuCoy}F$M3seyR!oh;x?XSU(IU=EH1KtZZvWbUlOAnRM>QOL zaUa1y$A63#r6WOX3~2qtZ~MJHx1O`>;{&r}_C*Z8<7qvu>(i$~TR(wnvd}w}wE#S9 zic4%n*#AcR6{K2>dD)FH+TeSwooF}5P$QR#Q*ac+;0Gq9-Ub5{0io81*z*-ina&CT>MEKHuD>5W8^G!+A;BUeAOfd)6&oT?l)g%NV|w~> z*dcD-^+I)Cfe6f5Jlw8-qzjXkO!ODdH1h0lK$p66vHFzcGUO;1N^{0x-Y}M{5H`WC zXI|~9aN$`a#BA!2ljP??SFTK5nrdMsm-K@eFIz={^A-MZ=7#;4bPg;QK|&~tKNjqS z+`XsC(%VQS?ne}#ffmGJvN+>BI6#Q6*8DI{c%)!K4k@o`D7Wqk`b`_X>?-?pB{#FO zMF}U=PP3*?R|M>0~%M`(&G9fwt z23jsIe!lGyZ+iM3=&B!f9{vykS754*U~85*_fIvmZGHI5x{7*xXCE9u0q<=cl)fKs zhF#KK5TW+_Sy`u_HLyYmwDt`>c*cq4A4K<|nx?3PjY3KRLkW&97n#sDLcP$F00jg* zJ0z?|3(HiEvNju{+ED=-1$a{J`;^Ai}^N>1q>L(EwyLx`=qk(@?^93pf}BXWp|(U{xW409}}DLLG@Q7y+s85y^P zoMN{eZ!3owzjxi=>-YQjw?B4W+h_ayvFrW$TzkJ>kLT;5p~VMPa0rYZ6g_idSTNqr zarmQ(l1EWVqPJtk#iZW8Au%&xQ|jpi0mutQ30;IYRI@mj_(r#kMvJ-akavVHz{LK^ zIllBm)@GI>u=jDBtwphNqXkU6Zrg-45-T92Gpi&3s_h|^KSF4XyH2~3zmKQd^ z{8zC_egcv_h0+lIgL?F;$Sny@5^nud1U#^y+c)GLb6c3U+|>n?v-sT@zsa(L?3y@1K~0JC0W2)AY-2Ly?t3tRH4GuNKEbAr4wmg#Z3kBM_~B9dD5Q7 z_{0SFdp7<1=f~N3!!-ZJu-=^xLvz<)vApGAR<+GwFTeGG4-*T<8~9;lwh|LCpMSHs z3-0l|2bC3~(}M$0X$Q!P!K;y)yWgtA8-<%}VQaArnmeLhDCjq05}FD#pCfcq>oZ$u zPeQVKdr<7dxVYDLEw?&Vm|-4nr=J7uI2b3Ij7!i#?kMK3yQYFwdpH)EtEIK!gdX)% zLZt;c$w^w7i7LC!`xN=~lYvi*&q_%}>!8Z%f#|L!=RUI>G>PczD^C`JJ@)V@UFBd1`R7jV81=dxu(3!Jh~t$mcG8PdI* zl-+tjMsufeAtw6_(e?8(EshY8Tn8JFZy2$V?`fKh+600P&vDl~jbkL5ukZzoJSi~> zN>w-Ua;y;Tm^<}YCfzhP)ANtdl)N(9Vm0kFBMXTTe$0`Yp)%YhcPd-PC|JDKhW zCG!5wAKsMK4SU?JwP4Fa#1<1hMsw>EG6yeU`c8_n9duF^rBmfdiioh)ssUJ*XrAiG zsGIdz4y>iOwK_{o{SLSw!rP1|{D%KHh3EsC-?vq{WdblEhUfcgnHi0*9I0{?B7M^w zJ;6DjSx>c>sx(GHq*5*+98NkN1I~i+rOas`&vbQ9 zJoX}J$rOq#b*JVbB~t+*sXltiOEH_6y`+Gy7lNCFxoTyxd-(H3B~Oe>lV7cXHe zl90k=X;}Cx0@V0oyqmL19RxPkf(&>F&54w-rm{nFSf_7!Yo10Q-+su&_9$M&plc11 zI!5SRJrb~I&j7piT9sT70uPCd4CZ{9tHMbIF>8iO)=WnV z*ZZrg=KB;13fv19M)}~>eUpX0weg3@eJUj{2>q^ zuI5HjHPzh z=&yhEj;IH?rgVJm+;LF9(Ezq_daE?wB%Euyyz&j+RlLLD#N7GJ;lxYVO*+f`9j?qK ze0s^<3;i%h0k|^S(hg7}tvv0dzB$^Meet@pgqzthPf3O%VzWtzj>q-;{X~l|*;_6K zAAvADZ}1IMT#{h0omVM1`(d28y4v%-m5dzK?@K}_k5VcHAQd*XWR=NquQAikTe1O8 z=`rT{4MV(4T#l9c;KHEJ5p0pIoC`8vDrkXEG)0uLP?Ht zW5Tr(Td`6{_r@Z-lC9XB^5e2T@OQ&nJD9DQC1=ANhlNT>E8Vyc(uPJWo9l`mNlM>` zuj0caxh4L2h1|z@JDn>QzLF$eNun;MYsTt7R?g<`3rMx!x(poNL7-($YA*rCO$=QH ztymU|rJKCd0Rr}hRUs~$?-zj{%b}|J_%KK)`hp0?Q_eSmjjfD!&g(=w-BNUY6*Qf6mWdM`>ws7Hg)$vMimi9cgm)D1R%u^&StN?)jDGX1u zg`70W_~}ps#Ebz5jbDd6rGaT_+?R5U>APDiV7o=92PMB%rj{k-j4WP3w!Y0E`?(c# z%cpf~mkJ&!jx7lcbXJ~d5b}G;zD5c3zJ`boOqaXdnH)GlpoK7>*)MwKQx<&Z4B%RV zMYkO;6Ck*Pys`_O!Uk!w?KGMR6rdhU;~>lf_Et)~5DL4Q_pJVET17?QzNO58vscVN zWBsK7iV#Rf{h4Wb&Kfm+8Kx6h!6Oq#Q`*kv7<5raVfu+dAeyC}GPd0E;Wq5OMv{N4 zUV!+|W>y8&?CCg{%bgC@&F>c3EK9-%WM==>uyJPf~!k})kNrvr4hmanuKPfRs zb=Cp?rTlo%L356Ot+&T#6ZvV6HQT-Mu&d=BM+9J`UUDJ-Eai=sY}OSXlEgX0ZcU%< zA)$VO4qCa$r(30AC?`+cs9_vu0qKHmlP)X^P81PS{|nXfh>bn?08??KdnfJt~t zhpr`k``bCjY^F^jE;;D8T+xKUblbe=Nj8Iz7L((nm-3Yj9Wm)wuVD*%`Z(H5&TI!O zik?@t5Gu8@x(X@s|1!Bd-^2t1=zqu_Q~0{kZWrIJ#a3%f@x#Ng87joTPd%d9XNb=N zlj+I=Xts!#(`Xo-QW18A668(t{nic^Yh`6)1vu+S#k>5Cd<7B;*Q!G+rz=%{Nh^V- z`{shR5*hySRLUiYur=aAXlQt7DCD&`>rRs?n!O9ES-$`%U_aR$9}%$wq?YC7LQAXK|HO%BWE^88&lj==^V z>$C9?H3dJhehBjs>-U%MSjDRLQ*Q-~$tMbcX!}5kXMYk)_h)Yy0E2Ln(6~YWl0n7q ztS9LQdTRvKA0NH@<<5Q^H->P9HPC}O-)-k@HMF!C5OqHy;@p*gruQz?fueH73khkr z%^J`Fcn7MKF8{1q1WC<)ooJfO^<~<;*n;)z{k&^^jpNW+&z@);s={WKywjA8xle!w z4Yh=H8Qm)Qwz{Lb&rfd_T6!atq2C9&SBZ?Wa(?{?st?(ojc zb!qDRuy&gy#@1#{1bWKgM0Oo6skH1t6q#PjN0i>0bCET{1wf*yK}m0gjOyD0u!9tq>qti2Q}H76ui!)?n7x3tyf)`%0MC0;+ji*xUNr~)C^-Mb>6p3>mOn23 z|9-0XCkp!SL1)yD-1>hH{+nm{_e()@_x|^NT=)O)Wc$ur`$CZU*Y&c{I~fBI@c0#D KiLN$ri}@dUAk1_C literal 226117 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ΝJ%xFmT)g? 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 C)THA8 From 0415ac0f2f5a33441f82dce054555aaec2548df9 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 21 Jan 2013 20:44:24 -0800 Subject: [PATCH 032/487] fixes from dan --- source/presentations/week03.rst | 110 +++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 38 deletions(-) diff --git a/source/presentations/week03.rst b/source/presentations/week03.rst index c12813a0..ba6d6581 100644 --- a/source/presentations/week03.rst +++ b/source/presentations/week03.rst @@ -152,9 +152,9 @@ it supports standard file read operations: .. code-block:: python >>> html = page.read() - >>> len(page) + >>> len(html) 373447 - >>> print page + >>> print html is just the name of the environment you want to create. It's arbitrary. Let's make one for our BeautifulSoup install:: - $ python virtualanv.py --distribute soupenv - New python executable in fooenv/bin/python2.6 - Also creating executable in fooenv/bin/python + $ python virtualenv.py --distribute soupenv + New python executable in soupenv/bin/python2.6 + Also creating executable in soupenv/bin/python Installing distribute........................ ............................................. ...done. @@ -280,7 +280,7 @@ When you ran that file, a couple of things took place: .. class:: incremental * A new directory with your requested name was created -* A new Python executable was created in /bin +* A new Python executable was created in /bin (/Scripts on Windows) * The new Python was cloned from the Python used to run the file * The new Python was isolated from any libraries installed in the old Python * Distribute (a newer, better setuptools) was installed so you have ``easy_install`` @@ -445,20 +445,22 @@ Testing it out .. code-block:: python - >>> for e in entries: - ... anchor = e.find('a') - ... paragraph = e.find('p', 'discreet') - ... title = anchor.text.strip() - ... url = anchor.attrs['href'] - ... print title - ... print url - ... try: - ... print paragraph.text.strip() - ... except AttributeError: - ... print 'Uncategorized' - ... print - ... - >>> + for e in entries: + anchor = e.find('a') + paragraph = e.find('p', 'discreet') + title = anchor.text.strip() + url = anchor.attrs['href'] + print title + print url + try: + print paragraph.text.strip() + except AttributeError: + print 'Uncategorized' + print + +.. class:: incremental + +Watch for unicode encoding errors, I don't get any, but you might. Lab 1 - 20 mins --------------- @@ -477,6 +479,18 @@ Lab 1 - 20 mins **GO** +Short Break +----------- + +While you are taking a short break, you might take a moment to sign up for +the geocoding service we'll use later: + +http://geoservices.tamu.edu/UserServices/Signup.aspx + +You can also view your profile once you've signed up: + +http://geoservices.tamu.edu/UserServices/Profile/ViewProfile.aspx + Another Approach ---------------- @@ -575,7 +589,7 @@ we also allow *calling procedures* at an endpoint? .. class:: incremental -We can! Enter XML-RPC +We can! Enter XML-RPC (Remote Procedure Call) .. class:: incremental @@ -730,8 +744,8 @@ First, implement required methods on your service class: f = getattr(self, method) return f.__doc__ -XML-RPC Instrospection ----------------------- +XML-RPC Introspection +--------------------- Then enable introspection via the server instance: @@ -754,6 +768,26 @@ your service offers: public_method this method is public +Introspection Question +---------------------- + +I told you when we added the ``_private_method`` that any method that any +method whose name starts with ``_`` would be **private**. + +.. class:: incremental + +But we also added a ``_listMethods`` method and a ``_methodHelp`` method and +*those* methods are listed when you run ``proxy.system.listMethods()`` + +.. class:: incremental + +Why is this? + +.. class:: incremental + +For a complete discussion of this, read `this MOTW post`_ + +.. _this MOTW post: http://www.doughellmann.com/PyMOTW/SimpleXMLRPCServer/index.html#introspection-api Beyond XML-RPC -------------- @@ -896,17 +930,17 @@ required according to api documentation, it is safest to provide them all: .. code-block:: python :class: small - >>> apiKey = '' - >>> args = {'apiKey': apiKey, } - >>> args['streetAddress'] = '1325 4th Avenue' - >>> args['city'] = 'Seattle' - >>> args['state'] = 'WA' - >>> args['zip'] = '98101' - >>> args['version'] = 3.01 - >>> args['shouldReturnReferenceGeometry'] = True - >>> args['shouldNotStoreTransactionDetails'] = True - >>> args['shouldCalculateCensus'] = False - >>> args['censusYear'] = "TwoThousandTen" + apiKey = '' + args = {'apiKey': apiKey, } + args['streetAddress'] = '1325 4th Avenue' + args['city'] = 'Seattle' + args['state'] = 'WA' + args['zip'] = '98101' + args['version'] = 3.01 + args['shouldReturnReferenceGeometry'] = True + args['shouldNotStoreTransactionDetails'] = True + args['shouldCalculateCensus'] = False + args['censusYear'] = "TwoThousandTen" Making the Call --------------- @@ -1074,11 +1108,11 @@ pythonic, no? JSON Data Types --------------- -JSON provides a few basic data types: +JSON provides a few basic data types (see http://json.org/): .. class:: incremental -* string: unicode, anything but '"', '\' and control chars +* string: unicode, anything but ", \\ and control characters * number: any number, but json does not use octal or hexidecimal * object, array (we've seen these above) * true @@ -1126,7 +1160,7 @@ You can encode python to json, and decode json back to python: >>> array = [1,2,3] >>> json.dumps(array) >>> orig = {'foo': [1,2,3], 'bar': u'my resumé', 'baz': True} - >>> encoded = json.dumps(dict_) + >>> encoded = json.dumps(orig) >>> encoded '{"baz": true, "foo": [1, 2, 3], "bar": "my resum\\u00e9"}' >>> decoded = json.loads(encoded) From bc76e85d149975862e772c30768decb9a144f4d5 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 26 Jan 2013 14:23:23 -0800 Subject: [PATCH 033/487] fix up templates for lab to ensure that they work smoothly and contain no traps --- .../week04/lab/src/lab1_cgi_template.py | 25 +++++++++---------- .../week04/lab/src/lab2_wsgi_template.py | 25 ++++++++----------- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/assignments/week04/lab/src/lab1_cgi_template.py b/assignments/week04/lab/src/lab1_cgi_template.py index 7096c6f4..ae6dfe31 100755 --- a/assignments/week04/lab/src/lab1_cgi_template.py +++ b/assignments/week04/lab/src/lab1_cgi_template.py @@ -5,38 +5,37 @@ import os import datetime + print "Content-Type: text/html" print body = """ -Lab A - CGI experiments +Lab 1 - CGI experiments - -The server IP address is %s:%s.
-
The server name is %s. (if an IP address, then a DNS problem)

-You are coming from %s:%s.
+The server address is %s:%s.

Your hostname is %s.

+You are coming from %s:%s.
+
The currenly executing script is %s

The request arrived at %s
- """ % ( - os.environ['SERVER_ADDR'], # server IP + os.environ['SERVER_NAME'], # Server Hostname + 'aaaa', # server IP 'bbbb', # server port - 'cccc', # client IP - 'dddd', # client port - 'eeee', # client hostname - 'ffff', # server hostname - 'gggg', # this script name - 'hhhh', # time + 'cccc', # client hostname + 'dddd', # client IP + 'eeee', # client port + 'ffff', # this script name + 'gggg', # time ) print body, diff --git a/assignments/week04/lab/src/lab2_wsgi_template.py b/assignments/week04/lab/src/lab2_wsgi_template.py index 8c50b2d3..476097e7 100755 --- a/assignments/week04/lab/src/lab2_wsgi_template.py +++ b/assignments/week04/lab/src/lab2_wsgi_template.py @@ -3,35 +3,32 @@ body = """ -Lab A - CGI experiments +Lab 2 - WSGI experiments -The server address is %s.
-
The server name is %s. (if an IP address, then a DNS problem)

-You are coming from %s:%s.
+The server address is %s:%s.

-Your hostname is %s.
+You are coming from %s:%s.

-The currenly executing script is %s
+The URI we are serving is %s.

The request arrived at %s
- """ def application(environ, start_response): response_body = body % ( - environ['HTTP_HOST'], # server IP - 'bbbb', # client IP - 'cccc', # client port - 'dddd', # client hostname - 'eeee', # server hostname - 'ffff', # this script name - 'gggg', # time + environ.get('SERVER_NAME', 'Unset'), # server name + 'aaaa', # server IP + 'bbbb', # server port + 'cccc', # client IP + 'dddd', # client port + 'eeee', # this script name + 'ffff', # time ) status = '200 OK' From 98ff121613b984abfbeed79fa348ec7c507e84e8 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 26 Jan 2013 14:24:05 -0800 Subject: [PATCH 034/487] start week 5 presentation --- source/presentations/week05.rst | 61 +++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/source/presentations/week05.rst b/source/presentations/week05.rst index 8a27ea12..4c43b4ca 100644 --- a/source/presentations/week05.rst +++ b/source/presentations/week05.rst @@ -1,2 +1,59 @@ -This is Week 5 --------------- \ No newline at end of file +Internet Programming with Python +================================ + +.. image:: img/gateway.jpg + :align: left + :width: 50% + +Week 5: Small Frameworks + +.. class:: intro-blurb + +Wherein ... + +.. class:: image-credit + +image: The Wandering Angel http://www.flickr.com/photos/wandering_angel/1467802750/ - CC-BY + +But First +--------- + +.. class:: big-centered + +Review from the Assignment + +And Second +---------- + +.. class:: big-centered + +Questions from the Reading? + +And Now... +---------- + +.. class:: big-centered + +Small Frameworks + + + +scraps +------ + +What is a Framework? + +What types of frameworks are there? + +Why choose one over another? + +Intro to Flask + +Lab 1 create simple multi-page app with flask (redo week 4 homework in class) + +templating (jinja2 in flask) + +Deploying to webserver (virtualenv and mod_wsgi) + +Lab 2 create a simple app with flask part 2 + From 7be7d8cd71f067ac4ab1b833699da94429229e7e Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 26 Jan 2013 14:24:25 -0800 Subject: [PATCH 035/487] * add in answer files for the two in-class labs --- .../teachers/week04/answers/lab1_cgi.py | 41 +++++++++++++++++ .../teachers/week04/answers/lab2_wsgi.py | 44 +++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100755 assignments/teachers/week04/answers/lab1_cgi.py create mode 100755 assignments/teachers/week04/answers/lab2_wsgi.py diff --git a/assignments/teachers/week04/answers/lab1_cgi.py b/assignments/teachers/week04/answers/lab1_cgi.py new file mode 100755 index 00000000..df46c1ef --- /dev/null +++ b/assignments/teachers/week04/answers/lab1_cgi.py @@ -0,0 +1,41 @@ +#!/usr/bin/python +import cgi +import cgitb +cgitb.enable() +import os +import datetime + + +print "Content-Type: text/html" +print + +body = """ + +Lab 1 - CGI experiments + + +The server name is %s. (if an IP address, then a DNS problem)
+
+The server address is %s:%s.
+
+Your hostname is %s.
+
+You are coming from %s:%s.
+
+The currenly executing script is %s
+
+The request arrived at %s
+ + +""" % ( + os.environ.get('SERVER_NAME', 'Unset'), # Server Hostname + os.environ.get('SERVER_ADDR', 'Unset'), # server IP + os.environ.get('SERVER_PORT', 'Unset'), # server port + os.environ.get('REMOTE_HOST', 'Unset'), # client hostname + os.environ.get('REMOTE_ADDR', 'Unset'), # client IP + os.environ.get('REMOTE_PORT', 'Unset'), # client port + os.environ.get('SCRIPT_NAME', 'Unset'), # this script name + datetime.datetime.now().isoformat(), # time + ) + +print body, \ No newline at end of file diff --git a/assignments/teachers/week04/answers/lab2_wsgi.py b/assignments/teachers/week04/answers/lab2_wsgi.py new file mode 100755 index 00000000..cf55c71a --- /dev/null +++ b/assignments/teachers/week04/answers/lab2_wsgi.py @@ -0,0 +1,44 @@ +#!/usr/bin/python +import datetime + +body = """ + +Lab A - CGI experiments + + + +The server name is %s. (if an IP address, then a DNS problem)
+
+The server address is %s:%s.
+
+You are coming from %s:%s.
+
+The URI we are serving is %s.
+
+The request arrived at %s
+ + +""" + +def application(environ, start_response): + response_body = body % ( + environ.get('SERVER_NAME', 'Unset'), # server name + environ.get('SERVER_ADDR', 'Unset'), # server IP + environ.get('SERVER_PORT', 'Unset'), # server port + environ.get('REMOTE_ADDR', 'Unset'), # client IP + environ.get('REMOTE_PORT', 'Unset'), # client port + environ.get('SCRIPT_NAME', 'Unset'), # this script name + datetime.datetime.now().isoformat(), # time + ) + status = '200 OK' + + response_headers = [('Content-Type', 'text/html'), + ('Content-Length', str(len(response_body)))] + start_response(status, response_headers) + + return [response_body] + +if __name__ == '__main__': + from wsgiref.simple_server import make_server + srv = make_server('localhost', 8080, application) + srv.serve_forever() From 334eba1ff3bf0fc41fbd73f4cd478f28bdfcf946 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 26 Jan 2013 16:32:41 -0800 Subject: [PATCH 036/487] * add answer for week 4 homework --- assignments/teachers/week04/answers/bookdb.py | 39 ++++++ .../teachers/week04/answers/homework.py | 117 ++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 assignments/teachers/week04/answers/bookdb.py create mode 100644 assignments/teachers/week04/answers/homework.py diff --git a/assignments/teachers/week04/answers/bookdb.py b/assignments/teachers/week04/answers/bookdb.py new file mode 100644 index 00000000..49769f37 --- /dev/null +++ b/assignments/teachers/week04/answers/bookdb.py @@ -0,0 +1,39 @@ + + +class BookDB(): + def titles(self): + titles = [dict(id=id, title=database[id]['title']) for id in database.keys()] + return titles + + def title_info(self, id): + return database[id] + + +# let's pretend we're getting this information from a database somewhere +database = { + 'id1' : {'title' : 'CherryPy Essentials: Rapid Python Web Application Development', + 'isbn' : '978-1904811848', + 'publisher' : 'Packt Publishing (March 31, 2007)', + 'author' : 'Sylvain Hellegouarch', + }, + 'id2' : {'title' : 'Python for Software Design: How to Think Like a Computer Scientist', + 'isbn' : '978-0521725965', + 'publisher' : 'Cambridge University Press; 1 edition (March 16, 2009)', + 'author' : 'Allen B. Downey', + }, + 'id3' : {'title' : 'Foundations of Python Network Programming', + 'isbn' : '978-1430230038', + 'publisher' : 'Apress; 2 edition (December 21, 2010)', + 'author' : 'John Goerzen', + }, + 'id4' : {'title' : 'Python Cookbook, Second Edition', + 'isbn' : '978-0-596-00797-3', + 'publisher' : 'O''Reilly Media', + 'author' : 'Alex Martelli, Anna Ravenscroft, David Ascher', + }, + 'id5' : {'title' : 'The Pragmatic Programmer: From Journeyman to Master', + 'isbn' : '978-0201616224', + 'publisher' : 'Addison-Wesley Professional (October 30, 1999)', + 'author' : 'Andrew Hunt, David Thomas', + }, +} diff --git a/assignments/teachers/week04/answers/homework.py b/assignments/teachers/week04/answers/homework.py new file mode 100644 index 00000000..cc20cf38 --- /dev/null +++ b/assignments/teachers/week04/answers/homework.py @@ -0,0 +1,117 @@ +#!/usr/bin/python +import re + + +class MyApplication(object): + page_template = """ + + + %(page_title)s + + %(page_body)s + + +""" + + def __init__(self, db, urls): + self.db = db + self.urls = urls + + def __call__(self, environ, start_response): + headers = [('Content-type', 'text/html')] + try: + path = environ.get('PATH_INFO', None) + if path is None: + raise NameError + func, args = self._get_callable(path.lstrip('/')) + body = func(*args) + status = "200 OK" + headers.append(('Content-length', str(len(body)))) + except NameError: + status = "404 Not Found" + body = self.page_template % {'page_title': 'Not Found', + 'page_body': '404 Not Found'} + except ValueError: + status = "501 Not Implemented" + body = 'That URI is not implemented' + except: + status = "500 Internal Server Error" + body = 'There has been an error, try again later' + finally: + start_response(status, headers) + return [body] + + def books(self): + core = ['

Book Database

', + '
    '] + tmpl = '
  • %s
  • ' + for book_id, book_data in self.db.items(): + core.append(tmpl % (book_id, book_data['title'])) + core.append('
') + body = "\n".join(core) + context = {'page_title': "Book Database", + 'page_body': body} + return self.page_template % context + + def book(self, id): + tmpl = """ +

%(title)s

+
+
ISBN
+
%(isbn)s
+
Author(s)
+
%(author)s
+
Publisher
+
%(publisher)s
+
+

More Books

+""" + book = self.db.get(id, None) + if book is None: + raise NameError + title = "Book Database: %s" % book['isbn'] + context = {'page_title': title, + 'page_body': tmpl % book} + return self.page_template % context + + def _get_callable(self, path): + for regexp, funcname in self.urls: + match = re.match(regexp, path) + # if there is no match for the path, it's a 404 error + if match is None: + continue + # if the match names a method that does not exist, its a 501 + func = getattr(self, funcname, None) + if func is None: + raise ValueError + # get all subgroup matches from the regexp as args + args = match.groups([]) + return func, args + raise NameError + + + +URLS = [(r'^$', 'books'), + (r'^book/(id[\d]{1,2})$', 'book'), ] + + +if __name__ == '__main__': + # this block will be called when the script is run directly + from wsgiref.simple_server import make_server + import bookdb + application = MyApplication(bookdb.database, URLS) + srv = make_server('localhost', 8080, application) + srv.serve_forever() +else: + # this block will be called when the script is run on a VM via mod_wsgi + # + # we need to place bookdb.py in some location on the server, and then + # add that location to the sys.path variable in order to allow mod_wsgi + # to import bookdb + # + # in addition, apache must be configured with the following: + # WSGIScriptAlias /books /path/on/server/to/homework.py + import sys + sys.path.append('/path/to/directory/containing/bookdb/on/server') + import bookdb + application = MyApplication(bookdb.database, URLS) From 92f7b57693c5e3ba6b5d51bee83d53105a5a7dd4 Mon Sep 17 00:00:00 2001 From: Dan Rutz Date: Tue, 15 Jan 2013 18:50:28 -0800 Subject: [PATCH 037/487] Steps for forking and generating pull requests. --- ForkPullSteps.txt | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 ForkPullSteps.txt diff --git a/ForkPullSteps.txt b/ForkPullSteps.txt new file mode 100644 index 00000000..be46893d --- /dev/null +++ b/ForkPullSteps.txt @@ -0,0 +1,23 @@ +Most of what we need to do for this week can be accomplished directly in the github web interface. Here are the steps you can use to get the job done (steps 2-4 were done in class, so you can probably skip them): + +1. Log in to the github website + +2. Visit my repository for the class documentation: http://github.com/cewing/training.python_web + +3. In the top right corner of the repository listing, find the button labelled 'Fork'. Click it to fork the repository. + +4. After a short while, you'll find that you now have a copy of this repository in your own github account. Clone that to your own machine (git clone http://github.com//training.python_web.git) + +5. Complete the assignment, placing your final scripts into the 'assignments/week01/athome' directory in the clone on your local machine. + +6. Commit your changes to the repository (you'll need to 'git add' new files you create, then 'git commit' them, e.g.: + +git commit -m "introducing a client to add numbers" + +7. Push your committed changes back to your github account with 'git push origin master' + +8. Back on the github website, click on the 'Pull Request' button at the top of the page listing your fork of my repository (the copy in your account). You can write a note to me if you like when you make your pull request. + +From step 8, I'll get an email that tells me that you have made a pull request. That email will contain links to your fork of my repository. I can use that link to review the changes you've made. After I've reviewed your assignment, I'll delete the pull request because I don't actually want to pull your changes for this assignment into my repository. + +That'll be all. \ No newline at end of file From e494c5b1b668801e4cbf7ee177748ca2d795b77d Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 26 Jan 2013 17:48:03 -0800 Subject: [PATCH 038/487] remove dan's original source --- ForkPullSteps.txt | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 ForkPullSteps.txt diff --git a/ForkPullSteps.txt b/ForkPullSteps.txt deleted file mode 100644 index be46893d..00000000 --- a/ForkPullSteps.txt +++ /dev/null @@ -1,23 +0,0 @@ -Most of what we need to do for this week can be accomplished directly in the github web interface. Here are the steps you can use to get the job done (steps 2-4 were done in class, so you can probably skip them): - -1. Log in to the github website - -2. Visit my repository for the class documentation: http://github.com/cewing/training.python_web - -3. In the top right corner of the repository listing, find the button labelled 'Fork'. Click it to fork the repository. - -4. After a short while, you'll find that you now have a copy of this repository in your own github account. Clone that to your own machine (git clone http://github.com//training.python_web.git) - -5. Complete the assignment, placing your final scripts into the 'assignments/week01/athome' directory in the clone on your local machine. - -6. Commit your changes to the repository (you'll need to 'git add' new files you create, then 'git commit' them, e.g.: - -git commit -m "introducing a client to add numbers" - -7. Push your committed changes back to your github account with 'git push origin master' - -8. Back on the github website, click on the 'Pull Request' button at the top of the page listing your fork of my repository (the copy in your account). You can write a note to me if you like when you make your pull request. - -From step 8, I'll get an email that tells me that you have made a pull request. That email will contain links to your fork of my repository. I can use that link to review the changes you've made. After I've reviewed your assignment, I'll delete the pull request because I don't actually want to pull your changes for this assignment into my repository. - -That'll be all. \ No newline at end of file From 8909673cc667c27413aa400a41b47cbdb847aa86 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 26 Jan 2013 17:48:33 -0800 Subject: [PATCH 039/487] add assignment help page add assignment help page to main index toc --- source/main/assignments.rst | 42 +++++++++++++++++++++++++++++++++++++ source/main/index.rst | 1 + 2 files changed, 43 insertions(+) create mode 100644 source/main/assignments.rst diff --git a/source/main/assignments.rst b/source/main/assignments.rst new file mode 100644 index 00000000..2abfcf04 --- /dev/null +++ b/source/main/assignments.rst @@ -0,0 +1,42 @@ +Assignments +=========== + +All assignments for the course will be submitted using the Github +fork-and-pull model. Here are the steps you'll need to complete to do the job: + +1. Log in to the github website + +2. Visit my repository for the class documentation: + http://github.com/cewing/training.python_web + +3. In the top right corner of the repository listing, find the button labelled + 'Fork'. Click it to fork the repository. + +4. After a short while, you'll find that you now have a copy of this + repository in your own github account. Clone that to your own machine: + + ``git clone http://github.com//training.python_web.git`` + +5. Complete the assignment, placing your final scripts into the + ``assignments/weekNN/athome`` directory in the clone on your local machine. + +6. Commit your changes to the repository (you'll need to ``git add`` new files + you create, then ``git commit`` them, e.g.: + + ``git commit -m "some steps I took to complete the assignment"`` + +7. Push your committed changes back to your github account: + + ``git push origin master`` + +8. Back on the github website, click on the 'Pull Request' button at the top + of the page listing your fork of my repository (the copy in your account). + You can write a note to me if you like when you make your pull request. + +From step 8, I'll get an email that tells me that you have made a pull +request. That email will contain links to your fork of my repository. I can +use that link to review the changes you've made. After I've reviewed your +assignment, I'll close the pull request because I don't actually want to pull +your changes for this assignment into my repository. + +That'll be all. \ No newline at end of file diff --git a/source/main/index.rst b/source/main/index.rst index 51a92133..bf2225d2 100644 --- a/source/main/index.rst +++ b/source/main/index.rst @@ -15,6 +15,7 @@ Internet Programming with Python self outline + assignments Winter Term, 2013 - (10 Sessions) From 8bec22d1e5d7cb44a4478cdcc224628bdc20fc77 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 28 Jan 2013 21:11:36 -0800 Subject: [PATCH 040/487] images for week 5 presi --- source/img/bike.jpg | Bin 0 -> 195579 bytes source/img/framework_quote.png | Bin 0 -> 16261 bytes source/img/skateboard.jpg | Bin 0 -> 329265 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 source/img/bike.jpg create mode 100644 source/img/framework_quote.png create mode 100644 source/img/skateboard.jpg diff --git a/source/img/bike.jpg b/source/img/bike.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0ea0fd340499d1e0f3c89e8e40e4c4eaca1987be GIT binary patch literal 195579 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

Y@Isb-T1t9^ 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 literal 0 HcmV?d00001 diff --git a/source/img/skateboard.jpg b/source/img/skateboard.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ed47cd9339ed6e00d189584feff48402f531b1a1 GIT binary patch literal 329265 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%0AqB}n)Ls3|=l6ywQ1 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 z zUUajud{sk>W=5zakH0)n)Uxhf2SvcbfAG4>)ulAXoOebyfdi1~jkimYw!uW#GOR6q z@~)kxkkQm24~7-3f**y3cO`2#cddU`w}&&nDcaI-i5~4uT8_T-f=Sqkfdj4=;rgT( ztkXEHgNrGA+2;k6(#n6;4P`jwqA0D zg~TWm_v?$D5#{zSD=V(CtZ@J?g5J1WWuUUOmaTf;DG6=1n+0zzMgkBzsY)Rrd6A7R zQ?@epS%%BECxu}+1;Oh#1hW0nYNlb_@py4HH+S3IAfz7dnWO&z+Gr_4f2nF({{X56 zVzaLz(%NEZ-znzazMpc+*SXblZ{eebI4bJw0$8jGN!Wyvf4RnOzZ3OGyL+kKx7aBE z03gd?gsDeaO!5kl>H<#u{5pTeI+slKZ6>D8jy892RebdBjNNNo?ey)XE+OSGlDJZW zbtNaJuOU5turX28-wUX!nq;RXkM`j^1#_FuR=YH-OUn+I)u0rln3YU!3G@BF6PMCD zVrXRBS9dkMd#B`>5q9@qR3_U|-ZVpD!WE@@QlqGE>+YQ=;~2lG{n=0FF@WR839;fF zUkNqpIyy#B%?o9f5gQ*7^HJw2^*G}FUr$2N1t_!6r}b7e?|Cmp(KS)+IpYu zjBOz-!~3Z&%F?c=X)Pt1cGB506A9Tpb$(?0@XdW=Z?&D%^zmOVSfaGBgtq$IQ?HRA z8I*(OK7Da#rS$vW(BM493Y|cbK;bI6MKj)^8X`oIx&Hu+PoF|_8+kxb*-@M(HgnBZ z?5%BaZ@AiOAe}tOPn-^?kQmQuRT0y$f>pkoM(Lfn@Tq1006ACOs%o#7R*ERv@ifOZ zEdKyPI(U?0mmmnoAl0hmsDD0Q!E`!GRy*?z6KHuXzOcCmEN=y9~b z4mgrGDpCGeJ3!KK*wZY~9H%;B(dAEUyH8@v^y#I@nF5y17CHYCxM^AE@bFjB4STDV)Xe1#(f#g5VI*&(m+v?^33=UOoRQBN*_FWZDspo+%tncO0 z0Qe1tJuOM5M+*ZQFco-|_ek|QJ(X&f(WK8#Sd?IAWbcjckle{kB!wx2l6?eWr&8zD zI42<--cF}L*_cTL0Fmj1vXomWjHMFhO=D2-L~oyObQd-Y!cT9y^~K3f6#V@=a;y9p~jtFvqDxx%`I zpcIgFndjC7<8sWbyTVF(oVwR|+E%m;%pcnl;cfX%fSLDNWi-^NEO>Vjx%gsPDG%i< z@P_>5i#gF;X_cY$kprRMm-)tXSA%m2^j2DQfwBvWuU@@^GuCv>nRc3~OLYwfQk3|o zNsdGF$2*~ht<^iXc}HcttT8$u8ZxHN)H&VyJ4He&oRqZLNAn1kDDscX9fM1YaI)sQ z?4f|&LVcGm_odg<)1mE6xS-;I+=D#N)Z*_^cY_JC%W17LNpignaDK~GS7)PDUX+!# zlL0+Fe?O);jaD?i(HUKyFSj~4weAf+J%FGt3WIppIov`5}QPsFTKTLIo^<6g5 zLdvtF>Q7}}_>q&<>~FZsV2}=x5vT5dEEoQ?rf4}+Bj{OxeZyddV0?)$KpSr$*pF$X2tl?ok!F z!HSa9j`yJY{r*_<*1b|H>vuP@>7OoXsl;V^Psnu5(Aa3gWd}(5Ml=+S0jn8Q?=pL~ zWPlFbfDyJO+$hHUt>lGi3Mw1&<-gp1cr>CD8$Ng}bqWpx2~pb*M9Y-KxN71D9?dOg zXhKrx?=`5*hz3aC(|^kzp7?VJ@NeCD-{J*Byin1?fvq`zy|}5>y{!f%Bnjus*QPr4 z1TFDFT!&Mb?ZRi?a;;gqRum-&POXG;*m+}kB4HQ0%lzYp2wg($1yg9Cvs|8e<{Hr2 zyh`7fram}V*Orr&_2*8YZqO{er}oF()*EH5x|%eaf{;w3%b`A4e{pEaRj+`$fof*Klx+Rd zpQoonM~z^?Sscg18T~@9oU8g8LIuc846&cnnzOUkYfFK`xJm@_6aF!mZFc!~HBP8* z#;f4}00u5sJ8O4DyRE+9BfAaml}9=9oLjxF4OCBYz7tN_Pk73ejndXB#3UdjD1rx` z{{UQ2&ImbH^v(gk$=r+0d&<(4I-}Hd_+kgTusTPUY6zL}aU*~%sC&t|N8 zy3@Ppb*V$@TZ&n6&1xlJA9rE~k+9P|$-(IC4kvCEr%*IT>|`$3+NfSmTcp&jLqc?t zF`%n$imlS*xJ+d!Ok6@5FsLAHhcxkL+$dV}j@zkz%W1pa6d6cXl8vK%mWbdQ%5%>vp>r70mYl6J+%PgDkd zq`h(G%0aEV(!SaX7KJ7xM)A+4EcFQ*<8_O1?unqdp+mraX;0~jQ0p8fQ;CM(s7Oj$ zbwKmm4uk4~QDV_sy1TP60K~^ENrLxG&GvGbnXc60N$*mq2Ug?Lt~(D*$#54v)>l*(E3@cQ z?rMMbd7(f{M5Js0Blg7pofpcZ>L-5?u7zbRzAl$`?k=S(rni8Wr8_FAN!?%m0u}!N z?Jv_CXmqF5lWYLFo~vDN;g6|PD-;y1Ab%|`DoH9<%6fjuenw5h=7N zx|JG~yU<9O5&G@-7{W{N&L_%d@ppO!FXsprvdfeW1t70V2~ZnznCgB<3{CLak2vmt ztSD)-+i8}nr&upKU`mM~di|ciUTSq`2dSQj~$pPf_>R979{` z6FDz&vqIHSXxO{CRR-~#?s=ZzS50qrtq!>;Q}O|y>LZwu(|8!=+P1Fgo#o+esc739 zEK?6M2d}lw*j%Y%irq_0T(5Zx{{W{_u1P`v0I?^ZnuaK7sHJ)FJ1NYOtQ?)u&h0Y^3I71M$aI`v#}Q*}Q&LU1sh2NNsk&g*ctLdond{U^ z^ZxjcG&_zHPIZ#&${=@b6)AHf2Hz9$!_ZP&Dmi{p>{F>~)~Qm7j-+{f@ut$Koiu^0 z87eHVuusY>BI(&}Dr_afB~m)$)%`8g!itzO-ebz6l6}s(Tj{ruV^1zXjA{N^$s58c z+5~~PkrNSu@EnhDNiNWotC8o=%LFbtPBrTSjF2Hb&fws#QSU2J$~6Pf1GrD0++kNo z;v$ts2q!_4*UM}tct&Je%eRgEI%m>G2JnZ7lbyAP4y^%4;rsn?pl*~L5hBo)NrN6^ zpWgUEYk5P&3kKE`umBEVbHMPz0QxO;(1e4seqS6bXh(IdXvE1zka=Kj2=0h_lo7lj zo#H3#Z-KO0$Z)FHX?tTz$ybuJl*1&5<@dP5azregiTPd``)}I=yhO}P(nggHwCn_s zCUL6iqvcu6X})W&Z&c7SHI&F%Fn66h`uy>|jA3NuDJ7PJOD(QosBg+KCKF?1*i6ja zrkiC&34%;OBYu1SSeWh-CC>^u%NJ$QUn%N@LKX?zn4VvjD(hknVQ+LHaR%$v{{Z3h z$4s|s$kcZAR?@Jd*Lwi-G3)TgM^9-EILg++R5o0c@9i7J7W3uqf|lC)9%19&Cqu;sCz?kuImK^SQ~(HRQ+jHXf_Yu} z$u{b1MX8_y8-#!dG6vY<^1kjiT}n1s3ny!?HnhM}BYu9kU=KZ1l1EE{=9A$t9Y$D%@oy z!k~2#&wNYK<8$OMIb74KBx_BA?hUGx)7xpANK}N0+nzVkur{$R$@&x`;CIs?UBT;BIcS~rMDzoYHltNpbAw0`kycHkBp3K z=a5)keR!zU;iim&a=gFs_bYL}g6&yZn{u`4osyzd=8~i%)_U~c9jB!0Dd1pagK1nV zsdWd=^K7JE&zvl}@hblSO3LXTRT@?VsU&xV8G-QqvC~;p*-e?1&wRnwE7R{~j?32j z1qHor+S^rPf^_L`-4HhW{{R@ejjdq1c(Aw&a=JBlcF)6HzEaU`E`)zE!5gT5NdEY! z)O8zV6?do5UoKqr;wNak{o10g)nH<(rNt84L9k56K_47*4NF>koLI%HjsVaKv)_lV zP|j~>I*h@a>1)MHl?B9ipp7G-9+;1&)kr0|7FCtd?l)eX>`7@EeWv1>BsK&D?m2yN z&|6>RvY|A__)uPH$mqM=T~I-B3RbBiAmWZ=yxghu<7l$pweYosB_GQWJtqroFi$!| z>Yj9bJg06ymX$}Q*jIo8PWvQl?n-naUCJOHTYlJqSxvlHCmA)3)GL_sMdiv%f{=9T zKu);j=Zs}t+O4}6DodR|n?fT9-6jTAKiS-vMBJCZ)IxC)BxHQ$VwJ0`7g!*C*sip_U zY!#N7sBCaITnwP8bB4S?th1U?MCxj`kqPGpJn_vmhnS~yL}hO^8lf~H_g!Y;%~iuQ zAppXk$TIzMNyMm; zQhl?8j5HFZGK8pd@csE=@k|p!OsBmU4yjrI1_tMF2j89mkJ%TAWWKDEOxrFH$_CwV z{7g4Y%OJ9?oKCmW(52*UuS`J4P3ebP!D4k_3S@BIEmT*607{7yKh^QZi(Z$>V5?{w z=2yQjQ6&^j7*e(e9A>lv@>cSm+f#)sm8fi!*OxE7u>cF3DNb`${xQ`XDKV^Z7AnbbwSes^gPs>s2CZC< zIYzS)FDq}PNH(T7A8gDn+fd_cPQ5ZDd2fz4)YQDLsneAgHbCG2Q%tZMr(IP_)RvfN zb9vG{C?7HM0G>eMT{Rgk4QRyPM(cX1@o7(g z1u7feG8t7$oIqp^MMq$f>x~6B#r-ZyUz*?LOr1Ji+W^W19$~gssvC8^LVu_oyzp9I z#w`}8*|J$GT{32UptciqqEePrRM1LFwW=TwjN@ZZ)*5Vs%OLep4LiqVhSJ5w?`~5s zp|ZVgw(JEc{{Twknm_=+=ee9?bq=GBu1h!UkI&snY#TnPr|EmwCtHj-i7C>#N+vgs zqhs*-?ay`17**x2EpXt4Dk*l35iHbHGOp>x_lg@5PczT-#yXc>ucMQ|k;UItA<;F$ z;cPCkzz}sM2u|d4>(BBy&_AzgAsd{TZ7WH#O1S0(vclXzI)Id+MkM~&%xgaqDk|Hv zfUGHWo4U%q-!IqN%BNebtZ+A}Km=?$?E@UnqNYb3(wnVx6w$C*fk)RG7Tr(&tbo!M zR#P$xy>ZX=om<5_0kcBAriX4)ce7F3=;~{df?)GJ$D1pk&0;DyzK=_F0zPk zd_22X)T#Gt6--=EQ_0c-l&O=ymy78bwWoBEW3qR}Wvrgoti9|AZH4JWZ8nrAc!UA> z^~Iwdza>L^hbh4N8&XD+0^(1GHuL$;BzQvCQNx^88)W|gu#g0N{Qm%49Cs;BASpK@ zWyRJl+m%{>^lg}I5Ik;wU^n=Yk3oDW=>5(4$%oNrbt=C%hSeg!K-v$55&7f3cmcRo zfzBh9qwIT;q;rp+3t>uYoDNY=P^6__%TKNdu%#IfqE2$u41j0!kt)UbvSwW~@%jfsp6h?hNkT=6Q~Y|D3QQs_Y~ zlz}2}iDVmgsS!6T#&>GvwU{$i_Pw;FVQYwxH}&+!&qIg?Tq+$~h0e;GSMw?mpaIpl zLPw{T;~O~HcHv}RnHN@?WULedWWn;n*y|M9inBZ2`)UNFnAnYpfO+D6>|H3k*+n$6 z%}G|NNL0b{{{R?>E>m08_w3umo8^)AC@CtPOEUli00YwnM?)E!C0E!!cvJ)3b`<$-j_ED@&o{o$JHiZBICursVF~xeev&>q$ zk4(}Hmt8lb&(TiHUE)jtU>;MBaPmpI+ard5&=j>i0MjJkn{=JQSH3K9*2h6fQpH7U zI^drXLR$XS6XDYc)I3Ra?iGW-EgQhZnoy7NK$v-&lsBOdpj$$=#@aU1lh_o zMf}61#HCt*003e!28qAL1xo4}{{ZpIkhqg+VY^G}4QVAI1L@_BPOQ)2;b8QcuP{|% z`ubZ1l}^8<5TXjX0n_`=Gtkpt0dz{LkQ=+OSJSb#8S?!_V^k=qLf#I9paM4Kx$`*D zX*9w!Wyd;(s6E7jyQO8lTdOE3+-cM(X#;*^8kVeEfx1vP3L;@HA~)nY{q2BV*#HPz z3|y&3;Yd9&t+(YNL_A}=va1bS3@20N5E3_^zuy*mcm`2&qSiXmmBJn;9p*8r67BM;c;LoD^nJn(#}*5Xt%|$#t-6<;0H`TD zgY)_0=YD~pGAPBySGTo&V9M*=H+w+-9=tTnRywwx%eL~Of{+y0G9%BXFQ?LCca_0s zUsaouxbJQ3C6#z%otIH#volNl*bTObPd(sy;`2hH@Nf|qt>CXabv*wm5Bo)2J2GoHx`zR5)G9YbZLl|et2 z2Ek;e&Tgyv=v$?`fEfUVYzW1B+h<)%w{WbkTxeF%GEf3gL~`Cf$;GrRF0l%_so6*7 zT!%}0pmC?$4kUvzIqi$6=);AIh}yy(g1GbABeBhf@tJ>$F-nH26zu9q>p02kJvR@D z;&4^GI?SzYm9gN508U-Y^z>_KN=i^AMD9mVhb&uDP&6{Yq5I9-vaD4GP;S=nmX-+X z9RBviX(6$)cjk+RRD{zl27pK&5wI994&_92wl+&#nt$MkNITv8iQALU$l_#E4_LOi3y1pe*CVYlZYFWeV=P0rSS^ zNt46KR8?_rIZ@VG$PUq;Am~{Lh zV(H$vpp9zr4ZU&FW3B<1S+ADdR+Zks-w*BXR@c2xM#n8nP)Jv%{bLxNZdR}tyxCvr zv6i?6PxH0!J#kv`{+Z#XOU&8UvO-Igl*&adJn~c3E@^4B{8c+_4mmAst*V>DfEWEZ z`^m!H(CV>LjncZx@bGJe^;{Fn4PP_8vYzXl7L|t{w(F{=wKD<`p9oZuC2oXo?)#uh zHMwf^Iuln-PGxxKZfrh_GpOocyeHZnwY{(1JsRyT!sAfwJGZx8b+u@4H9=Ca+2y=9 z%hw)vf9;t?ML&b8(@4v6>!cU?1gKmou0=Klbc?Y41mg*lx2JqB*db#9Tf z3aM=_1LRv-3LQFQdqew1^bWTlha{}}I>Y|};ZvdEY}V0S=x+3()g|B@3kh|#L24snl_pdU`jR$`BSX}lVQZn37yke- zJluaRyIZ}|D&h@sYnyLRr?1|fb$7JeDA!wFv@*&Btjv?>JkB=pb(KU+-uq+kRq^Tm zEA~f{kS&}?vE3aM^z{m9=#2^xR5=LqJ#h6m#N#2_>?w0}?2)&3DZu^B&gpJY(y?%S zrCrEVp&%W$pI(0v(-%jo%i%r~TIZ4Fx#3odJ3G&C2PvCTm@DYs?yhXI&aP?#1jkX+ zlw*@mtJXF`+M!~!k!i5KyP_!y=Xp!W0k8lYsa;fkaO71R&D6;0c70TNaipn!tkfgC z43`V7@5n~Ne)?jYU92bgY~fnazyRFjkyA(P?UyR4YAavgOKpkVjmo+td7sM|>0(Sl;wsPrAOXu?{<`y83{|s|iI;#lDe>DrC5dc9Ia0 z*Wyo^=Q#Fmn?~Argc0C1Wev%>Jk#P!-@(Do_<)`MC6wjD;X~E527=zHY< zR(+IC53yai;09B?HENpXl)ITD&O0z7s3JVS25*`?bX?k zAm*Dj?vl{^t+b%61wcfeT)#{%E>Uk6UVQs(aVI=w%auhvwQu+8c%cbUP@a>g`{C+( zQ6cjnDje5&RDIc+@0hb~Q$nf7>M9hNS2zTX{y5EQbYb!qjIN#2dYKFka_L2;%yPqx zT<#RhVZ^}Fp|tXu`1JorBC%;LYyEKsPgz=wjV^3B0U+luL2r)!T7z13}QhR3&yu5M?no0gTEucf-gGLHM*)RU*eI-F=9 z)l%NqR0pIPdOjLLoh&?E8||qA3H09!5FlO=KHi@RAak53(|{2Ntcu`3GLn5T zUI<0K1$PvZM&rsp{x~N<5%`Ny+k#+;21F6drW=HtqQ-0snUXFVL?ER&Lh5$ zI8vKBmGYI{np#~D5@(d*_@mftQxdq7l<&A^%4VrtA;YYK0P;AVDoEi(5L+s@=9RO1 zywj+X{ES;6ao7G0E_^`-7VS5j=%FIHrta)s4FP%0#hA+m{*Cg-8AlS ztp;4oG#82%Uu9sDH5loKnO@gmsPaO23ufr$8!eX?rg?!I;v~*x?wx_J?4!E7{VEou zp}_)2EHcsxltq@H%q)VKQhtAb96Dn5NChF*=PF8Kq#qF*2s;ceHwgJkb&e5dh!)>u zSTyL5F%yeObw&W0@RJZ`mMZQEQ)oaFDI|$M=MbtZ%lJwW0Hul>>q42hT6GW(-8RH& zE_qH9oTC+dLXW&Q-5wtYn9gHVKk-MWwO;8>M4|_YUM5|ZM6JpK`?`_aqfeTFY#P! znuH{1Qf-mEUAT9(`+ZcpXVW#{RAs*0k9#D$pBA&7oT#TJW}A}GsBy7xsVYGnz*1Wv z_22XBj}p(+pA~52BvDBFdmqTH%{GIhOgz;sZ{hicxnu1N+>iApO5!$E9Lu$~3b4X= z=ieo=kT)Bc$4%*fi=A^yJWWeZlsDa^+wTgaQt3)T{{Yj}G5-KZSpEjd{&SBFb6`lh zuPWbAvO+zf#vbnW8womx!=Cu)Fnn{&qq}?VXg}3b9SW*1_=yMF>v7Hza8mlF z->l((4z5po!BrN998mQINk3e59UnvJon|ohQb7Lzs~i3md-YvLA1{jW{{ZVB@|gLf zf)sR@3L4H8-)A5n%koG%F^Gq+r%UiU?~bJ zBqROERP1`h;@hKoN2ts!i(ZU5?BVS{pRn}`uD+s}JepE=p2zwh@}k}**{&8^CGmrY z?6jM`DAj(q0DGI=5(!IzV|b}(1t~8L$V!rR0sz4LXy~TP0oJsOc=7$9ID1Do{{Y-O z9#zjy*D=l%bzfoJ9_>Ef$GA%toX2I)wmNF-YoW>)3>K9EZLEJvlPAO{m#p%~2GKf_ zJw`EXTanxqcQpjGGLZ3~Udjr+Ejd>F7*U?3{-0KzMfki7Mh8|R&HvO zsqYRnX)0;mTI0lls2xc>PhXSBfQin9Og(y-~P~WM0m%FzdjkO)eEsvfz zkjWKXdtNT(lbRVR-?_YgzXZxwUQJ!?%WXQ_YK5eSD%~rP(oeeB{{X#w{Q#59OEmgm z&OigXKa!m;phH2m$?UZAJ>x26mX>O+^hNk2Hi6>Uas%|m2BY$kU(aKkq0C79~N#7DF>R91m6Q(f6AMf|q4VcoMHNp~@PxV0ZD%%EQx-n2K zluvQu1bkz5?g|`oVO)=sUQwUV}H29 zged%R#nn;mE0U)TJN9%-CLv~p|9NpK7{?(Z_nwvjnX1lKlOruDG zH#`0LVjhn2(0z(#t%1RDuZZEBW#QiFl_ALjPp_^wnr!>qVzW~+#aFwiSy$e}M+sqy0e{46Y&R92ux+sH= z(!DtLD#=4QRM}i{3+}tL6R1wFTx4eJ1H3{pb*Ohw4V%}io(Awz)lHTt8%;7)14%GP zBLf0JB=ho<6Lw%L0*)2Xw4JHjGXVHU>4ptEeG}qkA7{LsNk?pX0+}Rejg#rjdh@{+ zhKt!e$6T*I9kqC4OMS0hLsp81(A1KpH#%de+D;(VY7A)ea;|7#1m!_JnzCILg>087 zDo_yVB_X1nYU?xq02r&FtB1$um8F!1Fb0)l_}89kE!kS7g4?bQC22Y(Y4Z4D(^wF_ zmlnD@Z9umGs>{IcBGOb=uoaJ-=KSh$Qb-^N!YA&RDQlSJElQl!TQN5GNDqq5$PbsFN3556}IkvkA>L_FA?B zsb%FMD%Mg{x!)ZRNYfhT-*UxN*GShJCd(b9F2&G`g%x}3tPqzqCrf1Q263Twi?nV9 zL>imU3ToUly=>88Z?T`>osBdJx!D0G_Ag(-mDiO4!=&=IW}pw90M3 zRzL9TtQEX(wwK6DOra$zJ9AL$)0Qo&8+WxsXP{p5xB+#ePFA*oQoz#6M#egS&MsLV zEK^e6)(XO#wGjmSLmpczargUSvcY>KHP7@#3*9W3sbon%)q$}o+xsJvdZr*R+ED{@ z((meoE_B2X=Clk!@pAsyBEXLeKHAYF2iqI}0K1k5u{7t~vNSx>fc|qpZ^>hp z72u^c{-FevDq+@$=yhO(UWlIiEk{{tW=fe?uB;J+B?qG!q}+r!m>x?T4=fkU-zfL@ zS$f>#nxWlYc2wamqrcTB#0e!?bv^Q3C>`fWP}u#95u~ulN8%?nHEn$(1q`7@BhEGw zewc?XBgpcncaG`3aBBB(aB4%u6S*IMFP0;XK0T@AC?~Q(szM`jdjWOm7z=S-wQiPN&eU`2I!2oO&|QceF{3gsgh43v%kv;G|UN2 zo6##Q*&wo%d1u^}|H8@K6s-z9Qzlqr)7la^fa*u;24eSGFZD)LSi#rRs|H z6@ZrXDM?8{l`TO;1EnLZ9IsY&3|d_qt7Tz$Z(-d`p`enoX46FA((GLDl{hK*h4xY7 zU415B%REY>%Q>aSyT+`y_El`DC;%95y#7;=BWBj9#xtWoX#SklPlhBhIAYHh{PGpQ zQ2Z&@wC4Dd#l465o8}*ue-N&>v{KZv)2%$)jVnrcpHz`=ZbA#R*Dg49#fIVN^4zdkyM9KTVS@{t>^x# z3us!&or!H@N{^R{dH`n`TIvs&VLKZ3p2Q3O2L(!sQp0daDigfW-7JfC^}Ueam9%~*Yy7YX-$Bt zc3uuRj`hgasD!U**m47&+xpHaV%925XM4QI@F<-az6KRn&ACeF!aK9s?Y{<^v{zKcR7pOlpZ1JZ)Ks%op!tSkMi0by{6C_R zNfYR*JSY8!9D5)4{Zl7}xwV_ksdm@aw`wVur8|XcLHA%!N&K-x)4GW#!Yb!crP}So zf}WRL@GL4V(We9o=)jdAu}eZOmLK zXbCGQXy^q;nORSXYV#!SeFS4CRn>LXAT*l~PRhm&E}9Zw%f0fE?OZ*~*QKp>E-jYK zslbHt07)u8pFAa$^UN-8Qm3tno$R*m*-qt`12ne!Fx5(u9H??N=o2BMw#Sl{>OlUS zNo5nMq~ksPy^~N@2}a|`Z}Nn~7HOMZLoA}KK~j*I6Xp40)KBI2NOg+Zr=WTDfRw2^ zM$j=?HA|duiM9#vXrwf4tUBB)oD{^!{{TOxCQwG=a+;aRYL48OYLignNumODn1vYS z{qgC)g#8lAnZ-<_4OuN?Q7s!A%95MCx)PZQOnkKe0Bm~BDt)5Eg_PfObfBBkpvi;R z5By|L<%?fkvx{tVNOw!1C!fm%U~j5Oasa#15&r;L0CY3U1>rRwdkAOPOv$1~}TWd&O!9%W4^B&d}c4>&(o%T*bA z@ufrwEgp05#Hsa&wvY-YLvxkY?i%pfn^z2LMRlsFr%^$vKgpeHBbP1lmHEMK%U49m z?Tle@&$JF)dfUW`=IN+kO3P?liAzL;EXj$EW3DfBZB348%FODJ+FT;IQi_^v(PY-k zsBgVasYwy{`(kFbQyHfuIX9=qd{Dh(_8ra^YaIq(taV+|$Oux1A|w3%c;mHh+W!C$ z@E25xq15(XpL;s-ve|v0q@$*&Lxc?y4$+NHkEya&fYP${(3bXBeHDp%oeq?gg$NwJ z{PC{v1A?M68>U8NwW{LVh(Z!U>(dB+pK;1{m1U}|XCBWsoX+yxuA^zvb}7?_Mu{7S zRFB?gvSU+rQOlH0CE81SRPXFkQkaj+4W6Hj8-Sf|tm|bpb5~@GUHP|Ksb#gKh>Ziv zFyPQ*aI=#~Qg!YWK*wPGy=`%8p`t^2jFoqMzbrP+nuWP;5jwfV^0uwLhwSa$QE;kY zJp~{R?~(NT>xP}vaqirR*E@o)Rz%>Pr!UhtPKsotqzQxo4kouvYej-;O2Tlbt8PZ1 zVF>}01LYlXVuU9CWT!PYTA*j$ZN8kw2g!kgh|W)RteY(m8=(;!!0F}s;Qms`+daFg z^T)iGPjO)TR6sE(nt*p`u&gLeLS+M3z!BbC2t1ZQ}g-J@kicr$wj7X}gYht^*s+k&ZW#LD)ojpBo81p4fCV+*KvJ<%9pUB1|Xd=yb)iC!R z%1G=NMO2O|HuD|oN?dHKcmPjdKk#ubx%*xUdKQh#+Xn+~S7vgh7QH%yN#1tphXqmE zo|Z2%njOF0(uG2kswdv`!)~f~WXXW?o0U19_|D}d9$;aESoE<0TJ2{`>QqrGNhf&e zfGggCrghT&E^EEGgosQ}Q~G{*SI@lifq}_=oW*_a!Eq3iuPVF&*{331Upy*I;xtY0aoMnY6Y-jsx& zXmELLICRvrx-koruH9cuP}EhaA}5?r_rWq|p2-h{_X*63mPiCtstM;j{{TEnY^+dR z!`Ll=>J)ZxlOA|@IhIMv5pl82Q}X>VJf6rKpruXDuJI#d&jn@_M(DLAg?s(l{YpW? z9LV{?F?EjWol1g+OwTkA?SLX@HbXohnp#sb)iGC}bPRr2SAiMLkOYK@n6jm#GG+Vb zU#_R36qVF&(Ym6-NeNmCXO{3tG3kokPe_8M7sDe(oCr=sQ06>6yn?)jej@#ob8ib+ zuj022?3bELT?N3=W?MxWTf)-$As*FD9yKtfID$tsrPP@sPCjV-NBBzGZAIdqJ+HqW zzeVhChQATKMmC#PXF=?H3;J{{XtGN6V}@sNNFeK>1^;iv39c0L;>T_&?+FTzn-T`lA`a|dyA`Et5rWX~BY@nxsH+pku;l?upBJxX6o zo$F;fl2GS0AcG-8Wpk4K(AeYihW zR&AU&&0U{gdZ!})01&%mCLAugZl)H`=(wScx9VyC@j_GkX93kDn;6p{c^ zPlZWI5srLa9G`rB%Rf`3vCZ1s3w}5BKd*H*TW>b|)dQ4eq&-OL6os_vd^%OK zlAw8w$Ro=gN{gtxXiYSkX<1sWHSoKCbzbT0Re1*PZEPjSYzhT*t-J!ikf|No$54?d zB6s=Y%pF6d&7kU=q5lAd=Hnld=#*7V)G2KL0JboH%B>kwEL<`_7c)jmvC`Ds8F@`q z*_a1+sU8Ya5>$2pxOKHG@(oGmCIv4~yz0TUqV0c~zeCU9RQWYF8XfZ+7U2Cyr`2B@ zM-8(5J-UrIw5H*84X4@`hZKg?=QE@T+jtYqbLWojFG*=lXmvo``)4NCTD zX1QD&tF}7JNT(_x#e@P@1o`7VTdBB$*DXao6BSOrzNmtF0%N8<_0YW%G}<<` z=gvk~HLlbQvKKdm(5;-pP}}8=tD+6zM{Ar?LCluKN>cJh=6Cz)hOC@u zAT5UTEfD1EV0jbq+X*iTd0#o2sEh$pk_YGhFrDBd0F|b!)l2S&o1cyk#Rr5ed!p5w z8cwKm5#~0G4d}L_7n@n16M#=lHfKr~ZI0M0quK&a zR$;9@Ry^<#6cpw=fPkg1*VpgM0T~0jG-i6x2r741Qy4HVk~XZPH`T_HwZ}P+&+CDZ zk6^wNXEs(nm~HhGi`KNMB`ThvkNCr*BE=vZ94>KjE3xf|I$UZi>n+soIG{w73`Y3~ z{Su!yVxZ6e0C#Rkam6im78Fd#D3SN|!{U%xH*mgl@Z!h-rO)*JA`~N&dkg_a)OXF2 z3AjqS-D>kpm|9Q92VQ^Y4Y-1gt)%7_(0~J;n~ku9 zSx2J(0NxRy#F?L;?b8d`Q0$cH>Z)o=Qqb=eJ8nO|55sXuCc`MJwo|{~DBNTCbFKvq zFp`t|pNnJ6V#Gj@jicr^FF-UDgJG$zg-*`iDwcYFO>#-@dGUkE{dyHo4 zqIZaJw$yXQ;WsMx)Nsb*?CEJV%1mqqj#$^q97@J`p>AdF9bK(;NO`JMgmPFY0ZJHU zkdW(?Mq$E&dr)MY z7*U`3#QB*!+zITH8^af;o)cwtS}atQwKQ5(8xjcWKF%kG`7Bb*fT>m69UGt%Mw#eF z{{T!ew4`pbMybnmD%{g)AQ|WP*A589lcDFaT4~EPX&{PaB>8z9G+2j}B)A|V(cP#lRJxe| z0Jz~M6s5Y`Jl{q(^I(}qkX`Z|XZ0XG+u$N@MBB>N|QE7ckjQ*d)((DlQh zCddm?rnctNf{}MwJM)SAI3mJ$N@yOJK}KcFbdr{CNE^TkZ7PqbBd!wYpKeefcL{2X zI%eVo-RV|05?Dd~up1kP^Av*|fAvepJm#j-qHa`WK)@c(pY4VCZ#+1rjXN*G*Z%;_ zJl+nUZMUgY5Gm3D`-~Z5`@EwRk>4RGv7Yl)3SHE+mvZyh&JjG;!h53yiHX}y4%BRbGvG&P^?8^PNbzv z1RaniCSy|M@}sp1^rShHR`#~@g9EUern+d1G5@#ZQpon zkt?lK&C1aIlAQ@tfItqol%-2f#Ew&~BX9x4=_sKiX=wZuR@YQFEqNb#T$}Av_+Iv6 z;*~JA+A_kjK5VRERqhrl6pBFJ<_k^*p(zSZnF${6BQuIB-jt)4h5$;rqw4zTvAmJ) zxfN@t?YG!2@|O4^#~$w{(Y!?_Sk3h9+$_~>$k{BZK~1)ysDjd)03C>e4j)qZMNK&` zXt7V!b?k4&O|$P}yG_{p@sQwW5uUT;Ue`Gdj>{ZMeN9uddQEbl$``j)uu~TTLg>j> z-Q7@1L4X}zIqs?Os-6e#nleXnFK_kvkD_R6E|6ZHOOLw$0PS}wFtENK&MtPY9NP!zpWxn13Vx0Ac8TeL~o>q0%>V z1>8R|>F@36nAumfCk*WlT^@Ied1CXHX>N(My?PEMv{KY8!c$nO?$X&;fK()Ac9 z2qzlenwEFDtYI%{#q3Ap?e3MR(LA#6VHmxyf5ZHK3eMbaIcD`pidxIvjSER7wfkdd zN!mo}hJgGh~|c{oUD$?spB@2(9kqM{JkQm0o^r2+2&&~4Y# z2T7$#QbQapPw15GMy$wj8NHUG@@8{r7ig`mQ(KS}7^7~X1;CO?D_qgMbLX)cc-FO*XSg(0oEmk0#%&4#{&b@X_})*XB5(GyJ+{mK3lDRj+Uf z-(=4|c)pky$e??%vBasTWQQ z8N!0IM{N6^W0hIxZx1qcEBUA?-{Cm#vGpvD?PWrA^4us!x3qq9Tcu`+TbTEb#}Zqt z-|Zwi0uUMPE15x3S4i%!PNT~T{o>aY--c4fH))%+p8AdOPcD1m;a1c(t@gW0Hs+w} z9tuw|FtJq;y2ohyZlT{i;y05$Jun+l88*5Ox>rYNdn3RXD$E{Iqs!s*#GULT zlvXQ!9CNTb;()Cu(6322OIp&71@OcwH$WM_R$fRG9b_l{Bzm)8XA@`}rDnwFjL4vF4=A1|gB(}ZCSHd;`r zEXj|*o)n8{Tg=!g)FifzYCix}=d48ioLE&}k(m)n*DdN=mALF|--Nj6@~vDI5KFY+xvw^nwKY(H%F! zfVXr-EL%9km+2iwtED7QB{&8a*#mNt_S`AwEODzS)FcC6LRGNYK>qlU%J@Lblw%9K zDM36_%SvZbR?hH1B+eE4#t-|1UIn?jYvwK{SlptjQ0~_Q#RTnz{_&^m@pSY|&kL0q z_l}u1pEzHcHP+Bl^bkzPgnHv0SE)tf9IbQ_or4RoD#=#yAIeY2V&`D=SzW~ttdT>p z?h;P%=YsH>m$;;=&Kp^)Rs8Bk-1Uhk3fKlLl3jG)dxJS;(xPqbX(xXNGxmDnc=SM( zs^11O^A2~6(KMCJlcaBfgm+FRawRP&(9Jv!pBeJPED>F7f20~bnT>}2e7fMgG3bK$ zWMiCr0!dpBkq4J5rwFDg%IXLL6O~Z5gfL`cnw2(OM4<|_gX1Dx!`yWMjn&S zMU8_h2lT>zSRxKV{{TcS3Ej1P`e43TBDxxKgQ@0%4_F_st`ccNJ-~KBURQYl_<70r zV0@||R=e3%)g75h_>IZ^uwN{e9b}T`Qhmj2%FkICGf#^E;Xoe0C3uSn%5{l_cPj^% z!wvkgMZIk`X}B@rD0rqmKYXx*1A-wTKwY-2T+ry>nHvl!vBf*$`jxD0bz%yeawpVs z!gdscFS-z?tYm5kc`?>GU=VF&d(D=GO701PrNDYX=kdZ_xZtEZLU4#>%GD>tf)B%Q zIp6icv=EdYTiq3K)V8#6TgzM<-ybsyd1mgKVF{J#t?Ldq)2N zt5cb{)1EkSopRgERI^=`^0f_GG&WL%unlEV4puhU?=^R5X=?CzTpE&W=_ncv+-_Do zR_ZyX^2Kevz~x(PyOpvMXi98ZPbSb)1eAc)v55)fLGW%TVtVp0K^U>{Pi02Qw+r1< zZqmPo*JfVQG%3AS(Xqm;#%k7@iu|)?NnObRs5l*@)7-5@nM=VsygQYo>BUsg?sgk> zuF<7zOz|HlJ(R!Mx3cFB`#EqTzlOXS&%9Eou%({**7jy`)l<>BQd2B2(hwP8OVqWt zgr|Kz>>0!BeIY?s(#fL$p7yu&TS`qtya&YVg)(Gb4qdLc&3U_wDbCjYMGvuRqD3n~ zXbMWw9x7XjAw@fak|H|D#Zr70(Aw?tGk4d8YTb6Fm>-Wy2xb;j#X>1{rY0ZkKIZ(vX6n4eatnEwD3hHu1Ock8HpiL~{{Xp4^F$;MMJv-2Wr};=CkuO|G{^kSH&TXOa-Oo0 ztxLDRa7{T6xkA}RBdgax%RvH28bMe9DDoa$lj8Li6x26;yilajxxv>QEu(B_RHdMk z$m!c2FsRTSa$41+ZCksPkyT2SsCO3>P%n~JQ>^Ipk~xv|1J4wdw9zzpMo$gLzk7Op z{{YcRhC)rtcLdM8=9}JMJ=eBUT|ko|qKNVY<1Jg&6?9+1WV^?$mV$>yf~0QRS@))6 z{8qZU=W^o=u_}#;fIUYz_4UIH>uKj9vMIx+p=L%>jTU1Sw8pL7N_9dL-Yh0b=A+a6 zV^K>vc-_fS!-*19jJT~i}m z=HO(gRZ`mk<#XEQlM|aWE!QyLoc61|ZAz+Y98!Jd5wJ+;00AI$01SF6k`}NA0HN-% zuu|q+;Wdd&r3H{mw=$8>?s0n%ZL$D}wpHo}0aCiiy%r#O>+u>xBI5yo7%&6mfLR+2+|&<0ZPZgW(WK+t2dDZq}r3 z5`_i(qM1f_rXg!~y(#KJ*kQ(NPDA99n>m9z(yK>(Qc#|%7?L%S-A8pRf>3WiXIdl` zsctC%N|mJT@btsY)xqqG<(!jG9CHmj#kIQNjny+aA*;uHqBQQe3CB&x>y0}@yl|~C z?-_%Mf4m|olNt0!x7seVP)dfPN0=gd{=ZxUUl*!TjHd+$Xs2D7VbTXOc~AEEVJxm? z@RP8obuVZdcL*KR$xztJKU_ZA#uP<~ZJs$=R1{oEEWnn4XSmImD3*KL z)>5Idljrtu*{fjgmLYLS)m@-6z?rM2k1|1#_6{5Q`0tXIDPQQdKm20y+i0I^VMEa2 zx9YIBl9bvf@{sGhPUY4_qN+fiLwqvraskOp`4^^zUuw%*3cIHkzF+`$KYzX&{{Ykw zqxlD2HY$5q)9w=kS5vT@5$bq`6Q8@vMXl{yP?QBzwn}yfeqVdyGy0?tvM!!w2~GF= zOXe!Z9CfB$&cW-E5=Yk!w_lXt1hGWalXT)Y z5-wpq%5FRLNIT)r-gPH{fu&+*xpCsXVx=_qJqqVM#s|;U_D#N-p>I*-zAfLJ9ty@% zdG2|7VJ4!f*iCpXQgx4j`PI(lRd*YU5A7OCl0^Ri&JH>WB>QD3xHkbwir_yGnV?#z z^HyVNV`xQVfQmG3%UNm9GgXTYCaE%Xo*b!;^m8a9BvZ^};t4EpV`wfRUsF`(f7J*Gb*V zIV_|dl6^gJEQ@eCMh3)kz{<+nK`;^F*iHcn4Zyfq3^udwfO&0$wUOS|y7^RXkV#5sug3rcH|EF! z-pZhX;q#83m?Tb8PLhB;@Sw|twv)>FR_025-M$;(w&e}oiXht|os!?>gR)bfY!p(gbgSFC z1LZg(%Y-l9=#^#KQe{n~Zzsco@az(ITq2d0X-Z%KJ#ay&HP=NPtxRRO9ojK1lqVH7rx;xv>t*De+7E2_A>GpapfEO6!JVqAq30%8xdr{{XTtZ@m{sn`}?0HqK$PuH=O3K}BO_PAg%m0;MER zExFmtKHy0A+Wxm;SSs^9rl(zXEpsW+-dUV9NsHf#VbsO-F{wkYt z7SgU(+gm4c+ir${G5)|t-kw;QPemv5IYO4S@qf)HJA1UZ;twhH9lw-?60d>SAFeC} zZ5*gCnWY|@yQ|&OsVr3rXsS}{$3jT+1|xrr@5=#`Fq=1!pApMocH`Y9*5!+v)vjHr zYwgq*T~g{0mG^ZfB37;RxwLnH82}|=#Oxe5DYHuAORfQ17Te8B&#u{6%d{0}@aY=^ z9D;zIB!rSTC|DAe7%55(&JGe=DZbZWr?slla;h%W*s}xHU2lO>?Aa)ZYh}lW(xcx^K?U%}XR&KX6wrVSDSpt%>iN!WZ zeYVO|-XOM^d&0Dd1eEQHIl&okD`3Zt9l}lj0L@Fq*2ufC%Wc(^sIc4A_ZH2%;tB$b zjMado?v;o`sY%r-BMx8D;|z*S3Og#rOO z!AT^UueLFeR= zw%@)EwhcbCm%claazZdAj=(#FS}a+8(zDCV+i0E2TtR?+6gT{iDr!C+N0-AOR#5dz{>+V0-F8v0$`sGNSyF|i zM7K}fkqBAlej6Q!EIC7>OACV@tVX9C!^oN0+MnAg%_=0e00c*-J+0E(BPpoa>O#p$ zQhZD(l8-Ak9@G+K@+TL<5qt#soZ8Atv|3WjY1|}FFgoIFaoILj^<@f*wTT?#$lyrc z;Se?{JNb=&EF^N7J#f>B3D-RG67>o~kToP~J8nL4g~mzYG)>Am>vc1)1!?hZ`~LvP z%MX@|-4a?xUZHxQL2H=b(+cfn8Pbqa6;}^vDoT%XNj_usz!3wIj8qhujFQzdmV~lY zBTUBMPtOJ;AuLSO%Ghru(XH^M(>6DODVX`-%WcXAU=z)Zoo`()cB)oPrViZW3Jmp4 zc;!b|z7^SPT~Tt}!B+nO(jq7RaKqySsT=GrQ+@6YSd`k&@Yd5LauGXo!FXf3NSVH= zx_BvEk6(DB?A;qLvgr{HG{q~Tg($!s~9frMIe5 zkfXnp{l+Tx%4D;S6t4-JcvB^_v$boD{{S(!G=K<$GJJ`}lViB$M({^;%+6c_zECW` zMz`DP9R}S7B2+|23C2J>sKVor^DP?+WmOL;DIqXA&#oZNyKgFVaI~ohB5;d1U8z=< z->C2vAnZXK?SV@St{5mt7~Bw;x!;8u^4VTk_LqBvq`@=i)Z#rw47af<$ez>6jcz#) zGg3MmHLsVJMzQJBZ@yT7Xr#X?ZuZ$t*(-pT>!ms>Dym-96EJ2Y78KfBxp7h5P{G1_ zSN3gvEP%JFl#|YXd`Nbj+gPUlWG&3S*@~6tQi_1LM&9)9K3{yW>vX1f38&Owg)Gzd zQ_Gq{RYD8AbDAP!Y{HV!+Mn4W4KbNnRnTFvd`AK8m#4*-*x7Y zwN$8)rEAMt<@Z5`GCAp4||>4CEOM{)(i7)S;OD344FA~`~WAeg~`j0@y1wQbgZ7*^7h zLKFkcYVyKCvPf7Fx=fQZh2Oda{{S#w0nCXb&jouVp2&I?2~_Mh!R`l?Hv@|!ksC+^ z_5T2j0zDH_wPH(4cG&Gr#A9FGgS7FSL&>Q@#_p@PK&;Nds-CDM^JNUnu;sveBtLF}U(qHR=sm%O=KskehcZN_zWw zZRZ_J?T+<_&_9_>una99P1DIhkU<79p?iF{S*O^Hru{Wz_1245v?aJs)Sa1;( z&Ahvf(xnCEgw#8%t>fKy#E39O=@(SfKpoHGkx;f4vqgTkGUZbU?;LUDrNpTqz*t(h zQcRdph&}@fjZq|;E!$mf-icAZW;cv}NT%GiHD7VJa!_q)KfkZ5+uM=D+zEAOe@}3G3!2%HBpyB>p65i3tep2X>Ex76sG+%;F)l#2Y5X` z_Q#KUucdVwIlMQx=iIH#Gcm)3qG?u*E(Xx$N_GyZBUE_>bBtxodV^x{fxp#1xrF5* z-RWDxK>cUzoP)xZK2pshR>Fb6o zbZG;8NVEFxwDcORZy}GtQANLs`KvFyDQjMSs31brruN&PQ?@B#t(qrTt6B8;WEcTF zDYLD^Kiq8AmK+rhytJXF(v!EEkDwAs@&_Gbp|s=%y>~ zqez%B%zQEI$ti?v3>}s_C+6iw)V8+@f`IVHPMD6?Sxpj)*)KA}+t{b_!Lz8C}|xJaJPd+C5vwDp`c=AwlrvPn0_ zi@_-fom>2UaDw7fz5(@4mM&-vrU=-6bN+AxierP6oc+b1Ole6xu$!d@+~Elott|?H z=3@aC(h6fnU1l5Ttp8kB3|+OKuWyQ%3z$ zO>ktPDR1dAaEHHgb~O#=J5rL8q|%_E7}OE)<@Ce~h91g9YIxxVwuLkc@0(;TN(Yol zj9O^N{>lYd^Co{ATengv=Nf99zTu8Tmc~vUtv+ld#t(HtUaqUVX1aFTr&6iZ=9I{d zK_{QX6%H;hw`DoRZOXnmRixW2OgOY8I#MUfCzqxz+AP%>Dbd#=;H5Xr&XKn<=lkKi zAeLy*ib{pUXg~&ed4J9n8|s36TdPv1l9Zqn2s{1!FaaRh6M!PcNNlYxG7?e&J5MOY z#^pd?6cmA_uoKFD{y1^0B^U^WT07)|5TH!Sh?9r*w}idJgiSTIs$EN1K}`Mrm{S@D z2*rjHU3L8wQijM#DUG(PnhW+zzMV9}G#J z5cb%jiQ7%p47_$mx7;pum8!I%MaAkQAQ}9znSV`0Nj6su)ZPWIy&;)CW_>Za+Of3GXqvD@jCBbTlMa{L0b5>Dr=;8_=IEa{GXxtt56f(90JkU%l%whRlSxUw9O z6CHgplGJ9v*?dmGNRK%C^upR~nmnwB446@m-v(WD9KpasE)YRG&Ilo~1h`}$&z20J zBO{f7eB|K?c0vYr5ITHtESqs79gu=#fdrlB3fqgMk&B^}9o4@6m`W|y!VGWA%jM~S zh48-8M94GLU?N`>osYUc{{YSo$d|;)*pNTY2^kCEK;1`H#{m~*f}#~4UoX9|X+T|J zDpZd?SR^d4`qtY^QV_Qk0aPV2cKZVsT2(iTC>?^P*6O?{52|6QFCk@5wJwrMBXAP} zN{Q-8KPcN9*y+gOa*2IXd&^s$>k3w#NK$ob9a2C)et2Bq?IA{M{Mk%KE^bq~Scg)W zO>MHRPW96-1nrrkdte z%oLr5#%Gt`t|j=OsRE(5ve2!la)GSXTqzO!wL_06cd0@ahDL(ajX^`j%zLCx`0`i8 z2qc$Pdn3WUzaM4Vv^RlB(tQ@wH+HVCik4firn$S^7TZ-Xhe-(VFG(j#g2~ipNUsrRWSBcP{{ZnnugNM#)7L~pb8o~YhrP9KQn1Yv)Gj*ra;Ituiq`=wni{S_9QeLL5yoOTT}uQ;1_1AG z^0aL3np*YKUMT38zonG0Y7#XmZ53(=OUfG7(O4xieeVi@a7z6M##mVLxkl?agM{m0 zirPA~-0e@aYTJOeT{@Y334q}Kk_nWrVxCh3j7FM}JG!>htDjCwnfN6ORsQX_@we4p z!>TGxN@;^3voWJU{*lXbsDD)R9E0LlM4HHaXb+vey;i?L>PdV}wFAm{DSa7&)82+x zR@*N~8cc)EIed1^GYg{c>>(be&c~uO!kgn{s;XyJv zkU8zN83KKAOVoND2CfH=IO4|NdQ~k{kQ2B1Br1%jR)u$z^?}Bcp9)ARB+Tvx#N(OO zd@!kj+v#QA(ZD?a0D`Wf*BV8h+^u&iYHbuQ8qiRXq_jK8Gb78W=eMRW^xv7MZrR#J zy;3$ZXZa5*GQZ^9ub3Wkw%pYvC13vY2v33ERO|pgW9f-9>9JHD%oca2Vyz&kmM<%^ zJ%7r0aN{D-Sc})v%R;r*)YA%&aih&&6-0a|{l^}r_*K#4Pp0{a2c7=_kXdbFyw4`l z!2YPrp5!}KGbT}mj z>eiH{E-0j)Th8%?2OjB5G|C<5D^O6>439hp9H5=d)VJK2aVu9qaNc;Ku%i)4}DN+vT zihRvf!)>zSR@wgmq)6x|`{0`)2_e=(qRdsut4MKB&aEJgghxNq2@fdu9_h|ALW=@k z))bN^ch!eCC3#eI{$Z?Ldwtu>3MnWgD`AHB6piICFK?wBd@!SN948x8%XESajYJ4Om`P27wkj;1(%yw33M9dw*9PWx zDNK0@_mwTb!|4=T@|gAWj7X+#-V}O*3At5Ij(3WuE6pHUi7P2POmo5~7jRAm4CTvH zHafK3>lPBSJRoiYf6fx&-7LE5Z&wj%S8ZyIv?ol2>LLseOgLx4N_lYpvAV@H^O{1I zN{sRtR6HcVgzLQ3A*WIsR+wJ#)M3{;$TXhnLdi7fs%fI95LP$w7$4)N7YujhF(b(~ zQnD#UDGG3;pg{B(l38vPW9)<~+CfB+ncq~;-z+Jw2L%`&s7CWl%6veiOz*xF9N$!S z&nb(TvqNpL655liq!2!53`;QVpN>DlLe&?lipr7@SEe+iM?bys6g($`07^c~R`NoF zB1%W^&+CPPQ8L2;Bit#g&;k<5q{MCY`r#${P9iC+HL4oRL~}o{?}ypK1rCy)=GAcT z8U9dEB`2umhZt;AZ*Ux`1q{BVB}=4AR6sER;>bKG+ZRBB1d$tcGl?PUw{bW|5dsuO z-navtBsTZBML?6h{HF^}66+%o%mK^O1nv`Z8|4lR&rBl0BLrKz5Js)ah6s;DhjV3~ z=mhgWTp=FhP;3JO3Jod7lWUZ|$@5sg_3ik{-QdIP;FUtuZnrK{X_ezR--{I=9R=DjUWrQ(SolAMQd&bZ6 zQrSDGh?4{)iJUU$!0ttqAN@a77uYwl(o2f7)V)n|p{uv*T8b3Ktg6zMTXoQ+G(-gf;pNc%adQZ3MV4wxha8lRS6JjYDb$5M%>$t) zeqC@Sco`=O8{~05RH;hMV%w(`1jn?Wld4cJ;2Bp@g9fz6XgRFm#_Z$mQn*5U4ox z-mBBJ`h_=vP~2MwxLmr6P?nlv_7sBMn)`Ehy`0B$x6#-Z;*^VRr@TR_C*N|Wsajkm zWbV^p2?JuK$;MBo{uWSCN#ZzeKK}sKS=aSM^S5X_N4NP-e)8L7wuw!;!(ydCNNMe##ZD_hJ>Sl8VBTkA6hO{Xw4!)4vw9Tx> zuHjIkl?0MfxRj@nF&txD_^9a~TS71h$>jY4+R${H3wKoVn$$nQZZ~>T>7uW>+uw0? zRjsV31-O#hw5%9jq?INN$w^AQXaw~xozxvwOxdPx(pDnAjyNYVu-@Dh?5?)CRK;hr zp_kI)0eOch()u0Jc2G))335C-q(~qVAQ53(N4y(ytaR%C01WMTyGo`UUhKQtAm+z7 z)7giOmj*5i(^p-?oZS2C%U74XqK5-yDNkFRP$61TC=QK4!jv)PUy5G=#;YN#qkhSK z57|H9uG`ZcT~6418JTwf0N8z@{(gl(8H=`e8+$*r-5+T#%-meyb(_6RW@~!d%=v92 zP=Nhq8B?^$GOzlm5I_<^oOs^1r8Uh0M>4Q^FUU6^eg6QlKSk5vW}B!0VR$a?2-<$` z$%mDA)!O$qU25}>1N&F@P3;wxo^ZIu6ZG{Ik5Y+{(%z$SXd4)Z8VVg}8N;g8wb-8W zd*kxA_f}HrbWLW-U@ac0V!O2;ZaORV6%QJFEID?`Wxzj<@cQ(N#WlQ`9pzOV3Y4SG zdSNnljmDOfQ>~r1l<&8{^d0{I6as+IEG0xCv9W@6DC}TN`h(&B0K>4*+RD++K>q+M2dZj;#K#xo{erQ&w1Q_( z&_+A7c5W=F!1Pi6Xh`neTE`*EF&?Km3PS-<%}qcW#?T4d&k&sJCmIUUNAp2Y1noS& zKU_A}-8dTF=-PTh7p+{TXUKid0ci=tAhr|DrxV;1l9ZmG-wp=_8Ae%`Uw)#Q-0$n^ zFx&Z0M;-Erw^S@J;v6VhK2yqY1B!95fP}W4t6ZgWlcrCcbmf8w+}jHUw!2V5JI8@i z$>e&EOf0c9*&BP5$+@)nbS0$0f_#Vk?}muFcg7d8+qWTlQm(sCK7N=jfjCN64myRU zBXmgR<%2wQ<#Bku%Hh(*`3U0(&Jj z<+@s=C8Z@nJFl1@e6aW!%0rytmZqxm11hQSG$pjFr=I@+;|3uIvPX~Vx9WIwhZ!yR zK}rkOcIWW=VJ?LcsZpi-Ce>RswMv5tT9jZC2dD3b9|0UE8taRum9Hq=6yr*G66#$6 zKn{o3=Y$A~Qj^)BHtKZ}-nYBLkUb;v!4w9%VJsUb1%695=2}=S zg#_vw?>JMLVU%UpOSyjL^|$$HQShWBljr0=JQH3=2`S3Eg-u}#Dp6Og{rO<`l2B6C zN4^?Vp$bU0$|eSsZQ6&6e&zI8-ImYT=hTlc1#g4Y>Lh9U8h&>V_50(*hpe@3ATC!tJ zhSi{X&YT3GpA^|`hSGcq9E=W_SaMdyww$L*`hYDU1LmGym^O=~xLBnMe4fHJC&G|+ z_i*!Dd?udkE%tIH6R@I$C{Oh#@9bh^bpEOvo=4hCDajOxNC6vqVphZ0ruLUbFU+L(FFbJ3@0F%j0?j+oV5}=SZ zDo_-s0DK!t1d_Hn4!N2bnXs zms}VGrFex8xd3{Phu=&cy;FBz7Wo0o2}Tw`0EHdCSTt5bNP)KAdtg}=?u<%?(nmeW zz`7ezhGIF7D8qmR2w0di6X!iJs{|Y|gca^&82NlK*3<&l{-}<4N>bWNKu9D+iNb-h zP1Y8ml4d9L!nYJ)qACt0n65#5}8F zMKwKRv=uMf-1e8YRheGJ#0LKW ziBYJUi(BVe?!uIrNmicm5)X=89(!O0*(Jc*^r!ItzQ@Tx4NJ7eElqDukn{8Y(7@ zB_DURAgX)CAb6sbmu~88g-lw=Z@t60A;X@7rr`Ng zozsr$R;_@Y{utNz*ag=ku^j1+Q2IF#@a3@T`Mg%T$`Nfvejr=Q`MAVq||q7Z9030 z-b$OdFqM>{bpz$+Lc#DZLYpiu~@|oXS7q*CH3m3eFaDgUXm0B1TMFsYn2ip?i76vur2_|~ZH{f$eG3+&0gU4P?fq9k z(YlG7fp;Ns`-wa{?B8wTt#(r4hEdA=9OFY&?OYhVSgKKKdcKvyw6{{#OIjMKXsIhn z4kV~4Bow5OPtSjd{{RSIr&ah8GjKU;oBpu90ityS=7+?I*c^kEKJfE~S*5q=5taCd zd(F(KrBusxmja4!5F`*JNd z>PiHuDh(q^DG-vWl0fJrnDocJH0m)=10e?cKns^|+~VWhpgTLv>H`x~%u!}_uPidK zAerUqh}BQ*6t=eH1rW0T0JNn`C#mwpE#9hahh(Ejkd>1oY5HIXSur!aC6HP`CPv*n z@U8e!k)h-^m6bULH-Y)#0Qx00gz%VmYMN!f6cz!K0FHP|q#e|_*g&yK#=4oHG%c{8 zV0z&`AWKf0GxV-_lz*834uk253?s5)W|P8Js|_wgLQf+jpWF;BM*`_N%Q7BiT9c(S zJcl^KHXxJJYz;Y}Hel=$2E<`I3X<20WUb?GY@{xA7~}^$8=4Y)bLfDDidAV!jBPz< z)5{H|mTwn0M^rS`N=fjm&N}=sEQbBKO{$xES|p`0J8UqWfjAv}t!7y7R1#6Iq!ESk zjVdaMDQGW3Q`SKJaAlTB4;Qj&*HyVr;!=^xT;PAk5|p)7eGO?$Xe8;9J>i6xrri*- zd|EDauCXp?^ynwk^!Z`vUZcJuGLkP<7W$PG1f^T@2^-;3KR86kkc_w5DBf?tlqz8C zKKzCZWL*yw-ECH7cAjNHE$`(RY4Kbq+c@Pm&R%ASg#=2%fCI}6n97m39Ho1E1*Jql z3f#w}e)u*7M5UE0N_GTv+XO|eiP(Ta8)8f@w+bwy%&H$3oNBV@*jY$A zjDk7+#vo4MU6m!G!pW0ns-w1oPzQWK&^i4706Ye|$v|I)vsqSdk0qp)ByZ3A;ES)6 zNY7-Zrl&)Ta1~5PU%0~D%L|~K7B$h-C7>1vojVcd{{T2sI6*vJC}Ba?7LcJJ0r%&H zAf#NgUh1Q8qCQJtE%ei&KI$YL@Vu14J<8e| zPy$R({{S!Zg0dvF-2xzU^xG1J`B68JEV5cNu_ApiV54itbQZ#igC;so7I2(kOf3Mj z&u!<|mI}cI@{~5fx*!k~;0LVyIbjZV5ug?A5>Kbg1T%yzij{he`Czt`ebK^UTM_fZ z!x1c$`AqtBz$`#}ppZcv&+mZNAW@0<5xn!lNwGwIP*lByiS@w}f&hYc1te{@5|1e0 zNJsnnVIt{BR%At)014gTx=reMC~GLX;1U16n9IA8%~u3lAcNu zI^rFD3o2oB5^&*UxTP#`dwCgNZ1eROX#USUM!IDD=X}grdizedYUwMfE-ogT^G04$ zQBgu?`Hh4Yf|7h~t59B_4EX1*dOojAnA~{}1b1CCPt;?nWyd|iPrRG>g7$^Vp-Q@6 zf7JGLsm9Wqy(%0pX%YfdH{3xR?qG8D9269hza=hJL$G+&B3tsY^J+td9Us;Zuth4-=iRm#cz ztou9h9^pw_Z_JqySMKq*dz-xwrK!{)h;k-DKs(5h=rPqaZ`u-en^rI%$!Ds1T1Nex zsjnbq{FRlir!wV>b-jvLm=xiB1Wr0_F0)NDH^%Ts)mOR)gJKk8 zoA}k1^2IuxsESt90AW=qR=UXqg3Aa6YY++4tqJwTZC_BZd1L(4=rqT_{VH9X`)lR& zRMy)p&Rp;JmcrJWS_a*4z&n>2qA(K#?rIkvT*fHn)uxn?(ofUdEZ zCpM>x+-q+@QZw z(*dz+B9o6CbjX)7-fE}J)Yep;2zlFOJ=T$+Njtelw%;v)kVq*i8%E+WL9A#Ml8@su z{{Te&Jlbo%!>oPO&yYJ-Wjcm~+(V?Y*eq8Stxe`CONgwXapsAiXbzS zh}9(HZPMDSX<`)ak7!u#q3M4a##mo+t);Pnm}s89Tkdu|!Ij-KwUjk>*GhxToeGfn za5l9S_<>Hr5S0ZJyB%fLv$8iwKsfLIJ=S|j=@1>hr||y(Dh9D!dqQU1)p&4bT#IhX zj9i{HcPbiJT&8J&;*yr>8Cgo}YBZ#iRPjwZ7NrK+el;UGpmYq?&23hq?D8#t@1Mu; zRywCrHUr?(4iwgMJso3=S6wdGtL5+wyC1qw6z5&ZA_?XSSB>+AgXyIm;EA0#gu~< zRc7N3PTB^jEVNX#l;)b%Xrre|Z$gK5#VcumP$ZoJA_42lOyUf+O>0Ozt9m*qUO@vM zsw&LcZ!d8|mcy89n7U;w;Yr`q+wKhx>Ge~o(xXgNjcIWU32DI6wG_CR&=rn%)_pNG zWj^Q*$p-{~MbLVGUWJbE-R2&OLdkb*)ke20*`F}KnVN&$RJ_w|x`^Zz-K7aqOmis& zW0Ul*wWx}xQCDQQy_V9ZmJ-n{BEYA+*Ghf$EE7FWIz`lG#bkw1d8bVO05X4E7T^>6 zfKfJYbrr~1LY4&lci#}|hVB#5$TwX_bkr|2l7O`VzfZltwjwq%Fr*oRRc@Wu(xMEi z4*tJ!h4^U>lo61Led@F*fK{ZKld<{X1SPaE7z5s>D5|-%MuBH%D;ZDTI?}xx}K`${| zQUDJjN2aeVJRDJ3I%sQ@<8VNNHxY%0`lyny1YJdIY$%f);{dM+`HLGF{EQVzH(5=Ovv`#1^Uj;4GqW+pjAbihfMEwUBEx`ggT7(ab*WTeG=WhB$B zq$nz6%orOC08^=56$o}4Bu6hju;6{uPG}xvpIdBc=GLf89SpShW4LTA!HxQQ;F{|qT4}djop`OqxUsHA&|~ZzJcx_oN|q~m zOF*9RdPW^!P~RQ9r`uFXQZy<;zfJ!DOf5E&s;y{Rr`;QUi~;GCqIwo7mnJY2m#xNXg{eXa+DwPs-sQz=qGjlmmz{rcg^Y*cy9RXpQ^ZPVOS z-FwAAK^|xPV!o(=>jgFz?rqd>XrOWS(6}NapIyJU5ZB=+DeTp&x*Et*Rku!&*Ahbl zJ*78qZ9ebv>B@(S0P26v8IjqrNlr|emu~7?ZYj4Co{~9yyzqt+3UQ6@RQqVk1$tLd zfVBb5U4CCIN^Se1aP(3o9f7)Z0F;Esr!SY~hb}@O+ognB5i%0D0rc45d!-g7dMi0d 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

    uY&ZtBEexd8HriLM1$`iy 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 literal 0 HcmV?d00001 From b5c1829583bd188fc5f034ca4ac35674bdf8c455 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 28 Jan 2013 21:12:29 -0800 Subject: [PATCH 041/487] * update index, emphasize required assignments and attendance in the assessment portion * update outline with full week 05 reading. * update week04 presentation with Dan's suggestions * push forward on week 05 presentation --- source/main/index.rst | 7 +- source/main/outline.rst | 39 ++++++++- source/presentations/week04.rst | 87 +++++++++++++++---- source/presentations/week05.rst | 145 +++++++++++++++++++++++++++++++- 4 files changed, 252 insertions(+), 26 deletions(-) diff --git a/source/main/index.rst b/source/main/index.rst index bf2225d2..75d85a83 100644 --- a/source/main/index.rst +++ b/source/main/index.rst @@ -56,9 +56,10 @@ Minutiae :Assessment: - The course is graded Pass/Fail, based on satisfactory completion of - required programming assignments and classroom presentations. Attendance - is required; more than two unexcused absences will result in a Fail. + The course is graded Pass/Fail, based on **satisfactory completion of + required programming assignments** and classroom presentations. + **Attendance is required**; more than two unexcused absences will result + in a Fail. :Accommodation: diff --git a/source/main/outline.rst b/source/main/outline.rst index c9829bc4..d4eefef1 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -281,6 +281,8 @@ Services Gateway Interface). We'll see the ways in which WSGI is similar to CGI, and look at the ways in which it differs. We'll create a simple interaction using WSGI and see what benefits and drawbacks it confers. +`Week 4 Presentation `_ + Reading ******* @@ -359,10 +361,45 @@ framework. We will have the chance to repeat the class lab, or create another dynamic system using one of the many other python web frameworks available to us. +Reading +******* + +* `Web Application Frameworks + `_ +* `Flask Documentation `_ - Read the Foreward, + Installation and Quickstart sections. +* `Unittest - Unit Testing Framework + `_ - We will be writing + tests from here forward. Start learning how. + +Before Class +************ + +* Install Flask in a virtualenv on your local machine. +* Walk through the examples in the Quickstart section. +* You can play with the tutorial if you want. We'll be doing this in class as + our lab work + +Reference +********* + +* `Bottle: Python Web Framework `_ +* `CherryPy: A Minimalize Python Web Framework `_ +* `Web.py: Think about the ideal way to write a web app. Write the code to + make it happen. `_ + +These are only a few of the many python web frameworks available in the +'microframework' class. I offer these resources as a starting point. For your +assignment, pick one of these to work with, or select one from the list at the +python wiki below. **Do Not Use Django or Pyramid**. We will be covering those +specifically in class. + +* `Python Web Frameworks `_ + Assignment ********** -To Be Decided +Coming soon Week 6 - Django --------------- diff --git a/source/presentations/week04.rst b/source/presentations/week04.rst index 1d6cdb96..cc1ecdf3 100644 --- a/source/presentations/week04.rst +++ b/source/presentations/week04.rst @@ -209,6 +209,7 @@ You have a couple of options: * Python Standard Library CGIHTTPServer * Apache +* IIS (on Windows) * Some other HTTP server that implements CGI (lighttpd, ...?) .. class:: incremental @@ -219,6 +220,19 @@ Let's start locally by using the Python module Again, Windows folks, this is going to be most easily done on your VM +Running CGI - Preparations +-------------------------- + +If you are running this on your VM (*Windows users, this means **you***) and +you **do not already have the class repo on your vm**, here's the steps to get +it:: + + $ cd + $ mkdir git + $ cd git + $ git clone https://github.com/cewing/training.python_web.git + $ cd training.python_web + Running CGI - First Test ------------------------ @@ -229,7 +243,8 @@ Make sure you have the latest source of the class documentation, then: * Open *two* terminal windows and in both, ``cd`` to the ``assignments/week04/lab`` directory * In the first terminal, run ``python -m CGIHTTPServer`` -* Open a web browser and load ``http://localhost:8000/`` +* Open a web browser and load ``http://localhost:8000/`` +* (if you're running on your VM, you'll open http://.blueboxgrid.com:8000/) * Click on *CGI Test 1* Did that work? @@ -242,6 +257,11 @@ Did that work? * The file must be executable, the directory needs to be readable *and* executable. + +.. class:: incremental + +Remember that you can use the bash ``chmod`` command to change permissions + Break It -------- @@ -264,7 +284,8 @@ Reload your web browser and see what happens. .. class:: incremental -Put the permissions back to how they were before. +| Put the permissions back to how they were before: +| $ chmod 755 cgi-bin/cgi_1.py Break It Differently -------------------- @@ -275,6 +296,7 @@ the script? What happens there? .. class:: incremental * Open ``assignments/week04/lab/cgi-bin/cgi_1.py`` in an editor +* if you're on your VM, use ``nano cgi-bin/cgi_1.py`` (ctrl-o, to save, ctrl-x to exit) * Before where it says ``cgi.test()``, add a single line: .. code-block:: python @@ -378,14 +400,21 @@ processes are run: More Permission Fun ------------------- -Let's interfere with this:: +Let's interfere with this: - $ ls -l /usr/bin/python - -rwxr-xr-x 2 root wheel ... /usr/bin/python - $ sudo chmod 750 /usr/bin/python - Password: - $ ls -l /usr/bin/python - -rwxr-x--- 2 root wheel ... /usr/bin/python +.. class:: small + +:: + + $ ls -l /usr/bin/python* + lrwxrwxrwx 1 root root 9 Oct 4 18:48 python -> python2.6 + lrwxrwxrwx 1 root root 9 Oct 4 18:48 python2 -> python2.6 + -rwxr-xr-x 1 root root 2288240 Apr 16 2010 python2.6 + $ sudo chmod 750 python + $ ls -l /usr/bin/python* + lrwxrwxrwx 1 root root 9 Oct 4 18:48 python -> python2.6 + lrwxrwxrwx 1 root root 9 Oct 4 18:48 python2 -> python2.6 + -rwxr-x--- 1 root root 2288240 Apr 16 2010 python2.6 .. class:: incremental @@ -395,12 +424,17 @@ tools. Enough of That -------------- -Okay, put the permissions back on your system python:: +Okay, put the permissions back on your system python: + +.. class:: small + +:: $ sudo chmod 755 /usr/bin/python - Password: - $ ls -l /usr/bin/python - -rwxr-xr-x 2 root wheel ... /usr/bin/python + $ ls -l /usr/bin/python* + lrwxrwxrwx 1 root root 9 Oct 4 18:48 python -> python2.6 + lrwxrwxrwx 1 root root 9 Oct 4 18:48 python2 -> python2.6 + -rwxr-xr-x 1 root root 2288240 Apr 16 2010 python2.6 The CGI Environment ------------------- @@ -423,13 +457,13 @@ Where do they come from? CGI Servers ----------- -Let's find 'em. In a terminal fire up python: +Let's find 'em. In a terminal (on your local machine, please) fire up python: .. code-block:: >>> import CGIHTTPServer >>> CGIHTTPServer.__file__ - '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/CGIHTTPServer.py' + '/big/giant/path/to/lib/python2.6/CGIHTTPServer.py' .. class:: incremental @@ -475,6 +509,11 @@ browser? A CGI Script must print it's results to stdout. +.. class:: incremental + +As a corollary to this, the ``test`` method of the cgi module has this line: +``sys.stderr = sys.stdout``. Why? + Recap: ------ @@ -504,7 +543,7 @@ Lab 1 You've seen the output from the ``cgi.test()`` method from the ``cgi`` module. Let's make our own version of this. -.. class:: incremental +.. class:: incremental small * In ``assignments/week04/lab/src`` you will find the file ``lab1_cgi_template.py``. @@ -513,6 +552,7 @@ Let's make our own version of this. * The script contains some html with text naming elements of the CGI environment. * Use elements of os.environ to fill in the blanks. +* view your work in a browser at localhost:8000 *or* .blueboxgrid.com:8000 .. class:: incremental center @@ -732,6 +772,7 @@ To get our script to run, we have to put it in the ``cgi-bin`` directory. * It is **not** world-writable * You'll need to put it somewhere you can write without using ``sudo`` * Put it in your home directory +* If you are already working on your VM, you can skip this part. .. class:: incremental @@ -854,7 +895,7 @@ A WSGI Appliction must: * Be a callable (function, method, class) * Take an environment and a ``start_response`` callable as arguments * Return an iterable of 0 or more strings, which are treated as the body of - the respponse. + the response. Flowcharts ---------- @@ -1275,6 +1316,11 @@ Open the file /etc/apache2/sites-available/default in a text editor: $ cd /etc/apache2 $ vi sites-available/default +.. class:: incremental + +You can also use ``nano`` or ``pico`` or ``joe`` or whatever simple text +editor you like. + Adding WSGIScriptAlias ---------------------- @@ -1343,6 +1389,10 @@ Okay, our syntax is good, no problems there. Let's restart: $ sudo /etc/init.d/apache2 graceful * Reloading web server config apache2 [ OK ] +.. class:: incremental + +Hit http://YOUR_VM.blueboxgrid.com/wsgi-bin/wsgi_test.py with your browser. + Looking at wsgi_test.py ----------------------- @@ -1388,7 +1438,8 @@ Let's repeat what we did for CGI with WSGI: * The script contains some html with text naming elements of the WSGI environment. * Use elements of ``environ`` to fill in the blanks. -* You can test and debug changes locally by running the script (``python lab2_wsgi_template.py``) +* You can test and debug changes *locally* by running the script (``python + lab2_wsgi.py``) and then pointing your browser to ``localhost:8080`` .. class:: incremental center diff --git a/source/presentations/week05.rst b/source/presentations/week05.rst index 4c43b4ca..1c9dd100 100644 --- a/source/presentations/week05.rst +++ b/source/presentations/week05.rst @@ -1,19 +1,22 @@ Internet Programming with Python ================================ -.. image:: img/gateway.jpg +.. image:: img/bike.jpg :align: left :width: 50% Week 5: Small Frameworks -.. class:: intro-blurb +.. class:: intro-blurb right -Wherein ... +| "Reinventing the wheel is great +| if your goal is to learn more about the wheel" +| +| -- James Tauber, PyCon 2007 .. class:: image-credit -image: The Wandering Angel http://www.flickr.com/photos/wandering_angel/1467802750/ - CC-BY +image: Britanglishman http://www.flickr.com/photos/britanglishman/5999131365/ - CC-BY But First --------- @@ -36,7 +39,141 @@ And Now... Small Frameworks +A Moment to Reflect +------------------- +We've been at this for a while now. We've learned a great deal: + +.. class:: incremental + +* Sockets, the TCP/IP Stack and Basic Mechanics +* Web Protocols and the Importance of Clear Communication +* APIs and Consuming Data from The Web +* CGI and WSGI and Getting Information to Your Dynamic Applications + +.. class:: incremental + +This concludes the foundational part of the course. + +.. class:: incremental + +Everything we do from here out will be based on tools built using what we've +learned these first four weeks. + +Onward +------ + +.. class:: big-centered + +We are moving up the stack + +We've built +----------- + +.. class:: big-centered + +A full-featured web server + +We've built +----------- + +.. class:: big-centered + +Data-driven applications using web-based APIs + +We've built +----------- + +.. class:: big-centered + +CGI web pages + +We've built +----------- + +.. class:: big-centered + +A simple wsgi application + +From Now On +----------- + +Think of everything we do as sitting on top of WSGI + +.. class:: incremental + +This may not *actually* be true + +.. class:: incremental + +But we will always be working at that level of abstraction. + +Frameworks +---------- + +From Wikipedia: + +.. class:: center incremental + +A web application framework (WAF) is a software framework that is designed to +support the development of dynamic websites, web applications and web +services. The framework aims to alleviate the overhead associated with common +activities performed in Web development. For example, many frameworks provide +libraries for database access, templating frameworks and session management, +and they often promote code reuse + +What Does That *Mean*? +---------------------- + +You use a framework to build an application. + +A framework allows you to build different kinds of applications. + +A framework abstracts what needs to be abstracted, and allows control of the +rest. + +.. class:: incremental + +Think back over the last four weeks. What were your pain points? Which bits do +you wish you didn't have to think about? + +Level of Abstraction +-------------------- + +This last part is important when it comes to choosing a framework + +.. class:: incremental + +* abstraction ∝ 1/freedom +* The more they choose, the less you can +* *Every* framework makes choices in what to abstract +* Pick a framework whose abstractions meet your needs + +.. class:: incremental + +Frameworks with a minimal level of abstraction are considered to be +*Microframeworks* + +.. class:: incremental center + +Where is the line between micro- and not? + +Python Web Frameworks +--------------------- + +There are scores of 'em. + +.. class:: incremental small + +Django Grok Pylons TurboGears web2py +Zope CubicWeb Enamel Gizmo(QP) Glashammer +Karrigell Nagare notmm Porcupine QP +SkunkWeb Spyce Tipfy Tornado WebCore +web.py Webware Werkzeug WHIFF XPRESS +AppWsgi Bobo Bo7le CherryPy circuits.web +Paste PyWebLib WebStack Albatross Aquarium +Divmod Nevow Flask JOTWeb2 Python Servlet +Engine Pyramid Quixote Spiked weblayer scraps ------ From 12a54c12fd63e754e5eaed6c2e1535ddc918698f Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 28 Jan 2013 23:11:13 -0800 Subject: [PATCH 042/487] * include notes from the homework in week 4 slides --- source/presentations/week04.rst | 82 +++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/source/presentations/week04.rst b/source/presentations/week04.rst index cc1ecdf3..3085e5bb 100644 --- a/source/presentations/week04.rst +++ b/source/presentations/week04.rst @@ -22,6 +22,88 @@ But First Review from the Assignment +Save Memory on Loading +---------------------- + +When you are loading data from an API, you can sometimes get more than you +bargained for. Both BeautifulSoup and the json library provide ways to help: + +.. code-block:: python + :class: incremental + + page = urllib2.urlopen(url) + json_string = page.read() + json.loads(json_string) + +.. code-block:: python + :class: incremental + + page = urllib2.urlopen(url) + json.loads(page) + +.. class:: incremental + +The second form will *buffer* the input as it is read, and minimize memory +consumption. If you've got really large data sets this can be very good. + +Protect Yourself From the Net +----------------------------- + +We learned in our last class that APIs can flake. Remember that. It's *vital*! + +.. code-block:: python + :class: incremental + + page = urllib2.urlopen(url) + parsed = BeautifulSoup(page) + +.. code-block:: python + :class: incremental + + page = urllib2.urlopen(url) + if page.code == 200: + parsed = BeautifulSoup(page) + else: + raise SomeExceptionYouCanCatch + +.. class:: incremental + +What happens if your desired API is offline when a user comes to see your +page? Make sure you give yourself a way to be kind to your users. 500 Internal +Server Errors suck! + +What You Made +------------- + +.. class:: incremental + +* geographic locations of our Bluebox VMs +* Visualization of the popularity of Facebook Friends' first names +* Restaurants near your location with recent Health Inspection data +* A Last-FM user's top artists, with lists of mixcloud mixes featuring each of + them +* A list of Craigslist apartments with the nearest bars, pizza and sushi + places and their Yelp ratings +* Geographic locations of the top 20 users returned for a twitter search, + along with other twitter data + +A Note on Homeworks +------------------- + +.. class:: incremental + +* I've been saying that only attendance counts for your grade. +* It was brought to my attention this week that my own syllabus says + differently +* The work we've done so far is all, in some sense, foundational. We will be + using tools starting next week that build upon the tools we've encountered. + +.. class:: incremental + +Homework from this point out should be considered required. We are now +reaching the level of tools you will use on a day to day basis. Mastery comes +with practice. + And Second ---------- From b41c8ba4d8491cefe18f0cd97cbe1bbf9d129a97 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 28 Jan 2013 23:35:45 -0800 Subject: [PATCH 043/487] * add a tool to create exertped code samples * make an exertped code sample file for this week. --- assignments/week04/lab/type-along.txt | 654 ++++++++++++++++++++++++++ tools.py | 36 ++ 2 files changed, 690 insertions(+) create mode 100644 assignments/week04/lab/type-along.txt create mode 100644 tools.py diff --git a/assignments/week04/lab/type-along.txt b/assignments/week04/lab/type-along.txt new file mode 100644 index 00000000..a8a5915e --- /dev/null +++ b/assignments/week04/lab/type-along.txt @@ -0,0 +1,654 @@ +But First +--------- + +Save Memory on Loading +---------------------- + + page = urllib2.urlopen(url) + json_string = page.read() + json.loads(json_string) + + + page = urllib2.urlopen(url) + json.loads(page) + + +Protect Yourself From the Net +----------------------------- + + page = urllib2.urlopen(url) + parsed = BeautifulSoup(page) + + + page = urllib2.urlopen(url) + if page.code == 200: + parsed = BeautifulSoup(page) + else: + raise SomeExceptionYouCanCatch + + +What You Made +------------- + +A Note on Homeworks +------------------- + +And Second +---------- + +And Now... +---------- + +Think Back +---------- + +Stepping Away +------------- + + $ export VARIABLE='some_value' + $ echo this is the value: $VARIABLE + this is the value: some_value + + +Environment +----------- + + $ printenv + VARIABLE=some_value + TERM_PROGRAM=iTerm.app + TERM=xterm + SHELL=/bin/bash + ... + + +Environment in Python +--------------------- + + $ python + + + >>> import os + >>> print os.environ['VARIABLE'] + some_value + >>> print os.environ.keys() + ['VERSIONER_PYTHON_PREFER_32_BIT', 'VARIABLE', + 'LOGNAME', 'USER', 'PATH', ...] + + +Altering the Environment +------------------------ + + >>> os.environ['VARIABLE'] = 'new_value' + >>> print os.environ['VARIABLE'] + new_value + + + >>> ^D + $ echo this is the value: $VARIABLE + this is the value: some_value + + +Lessons Learned +--------------- + + subprocess.Popen(args, bufsize=0, executable=None, + stdin=None, stdout=None, stderr=None, + preexec_fn=None, close_fds=False, + shell=False, cwd=None, env=None, # <------- + universal_newlines=False, startupinfo=None, + creationflags=0) + + +Web Environment +--------------- + +RFC 3875 +-------- + +Meta-Variables +-------------- + + 4. The CGI Request . . . . . . . . . . . . . . . . . . . . . . . 10 + 4.1. Request Meta-Variables . . . . . . . . . . . . . . . . . 10 + 4.1.1. AUTH_TYPE. . . . . . . . . . . . . . . . . . . . 11 + 4.1.2. CONTENT_LENGTH . . . . . . . . . . . . . . . . . 12 + 4.1.3. CONTENT_TYPE . . . . . . . . . . . . . . . . . . 12 + 4.1.4. GATEWAY_INTERFACE. . . . . . . . . . . . . . . . 13 + 4.1.5. PATH_INFO. . . . . . . . . . . . . . . . . . . . 13 + 4.1.6. PATH_TRANSLATED. . . . . . . . . . . . . . . . . 14 + 4.1.7. QUERY_STRING . . . . . . . . . . . . . . . . . . 15 + 4.1.8. REMOTE_ADDR. . . . . . . . . . . . . . . . . . . 15 + 4.1.9. REMOTE_HOST. . . . . . . . . . . . . . . . . . . 16 + 4.1.10. REMOTE_IDENT . . . . . . . . . . . . . . . . . . 16 + 4.1.11. REMOTE_USER. . . . . . . . . . . . . . . . . . . 16 + 4.1.12. REQUEST_METHOD . . . . . . . . . . . . . . . . . 17 + 4.1.13. SCRIPT_NAME. . . . . . . . . . . . . . . . . . . 17 + 4.1.14. SERVER_NAME. . . . . . . . . . . . . . . . . . . 17 + 4.1.15. SERVER_PORT. . . . . . . . . . . . . . . . . . . 18 + 4.1.16. SERVER_PROTOCOL. . . . . . . . . . . . . . . . . 18 + 4.1.17. SERVER_SOFTWARE. . . . . . . . . . . . . . . . . 19 + + +Running CGI +----------- + +Running CGI - Preparations +-------------------------- + + $ cd + $ mkdir git + $ cd git + $ git clone https://github.com/cewing/training.python_web.git + $ cd training.python_web + + +Running CGI - First Test +------------------------ + +Did that work? +-------------- + +Break It +-------- + + $ ls -l cgi-bin/cgi_1.py + -rwxr-xr-x 1 cewing staff 42 Jan 17 22:30 cgi-bin/cgi_1.py + $ chmod 444 cgi-bin/cgi_1.py + $ ls -l cgi-bin/cgi_1.py + -r--r--r-- 1 cewing staff 42 Jan 17 22:35 cgi-bin/cgi_1.py + + +Break It Differently +-------------------- + + 1 / 0 + + +Errors in CGI +------------- + +Viewing Errors in Python CGI +---------------------------- + + import cgitb + cgitb.enable() + + +cgitb Output +------------ + +Another Way to Break It +----------------------- + + #!/usr/bin/python + import cgi + import cgitb + + + cgitb.enable() + + + cgi.test() + + +CGI Process Execution +--------------------- + + $ ./path/to/cgi_1.py + + +CGI Process Execution +--------------------- + +More Permission Fun +------------------- + + $ ls -l /usr/bin/python* + lrwxrwxrwx 1 root root 9 Oct 4 18:48 python -> python2.6 + lrwxrwxrwx 1 root root 9 Oct 4 18:48 python2 -> python2.6 + -rwxr-xr-x 1 root root 2288240 Apr 16 2010 python2.6 + $ sudo chmod 750 python + $ ls -l /usr/bin/python* + lrwxrwxrwx 1 root root 9 Oct 4 18:48 python -> python2.6 + lrwxrwxrwx 1 root root 9 Oct 4 18:48 python2 -> python2.6 + -rwxr-x--- 1 root root 2288240 Apr 16 2010 python2.6 + + +Enough of That +-------------- + + $ sudo chmod 755 /usr/bin/python + $ ls -l /usr/bin/python* + lrwxrwxrwx 1 root root 9 Oct 4 18:48 python -> python2.6 + lrwxrwxrwx 1 root root 9 Oct 4 18:48 python2 -> python2.6 + -rwxr-xr-x 1 root root 2288240 Apr 16 2010 python2.6 + + +The CGI Environment +------------------- + +CGI Servers +----------- + + >>> import CGIHTTPServer + >>> CGIHTTPServer.__file__ + '/big/giant/path/to/lib/python2.6/CGIHTTPServer.py' + + +Environmental Set Up +-------------------- + + # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html + # XXX Much of the following could be prepared ahead of time! + env = {} + env['SERVER_SOFTWARE'] = self.version_string() + env['SERVER_NAME'] = self.server.server_name + env['GATEWAY_INTERFACE'] = 'CGI/1.1' + env['SERVER_PROTOCOL'] = self.protocol_version + env['SERVER_PORT'] = str(self.server.server_port) + env['REQUEST_METHOD'] = self.command + ... + ua = self.headers.getheader('user-agent') + if ua: + env['HTTP_USER_AGENT'] = ua + ... + os.environ.update(env) + ... + + +CGI Scripts +----------- + +Recap: +------ + +Lab 1 +----- + +Putting CGI Online +------------------ + +A Word About Our VMs +-------------------- + +Apache +------ + +Managing Server Processes +------------------------- + + $ sudo /etc/init.d/nginx stop + Stopping nginx: nginx. + $ sudo /etc/init.d/apache2 start + * Starting web server apache2 [ OK ] + + +Check Your Work +--------------- + +Default Site +------------ + + $ cd /etc/apache2/ + $ ls sites-available/ + default default-ssl + $ ls -l sites-enabled/ + total 0 + ... 000-default -> ../sites-available/default + + +Apache Configuration +-------------------- + + $ less sites-available/default + + + + ServerAdmin webmaster@localhost + + + DocumentRoot /var/www + + Options FollowSymLinks + AllowOverride None + + + Options Indexes FollowSymLinks MultiViews + AllowOverride None + Order allow,deny + allow from all + + + +More Apache Configuration +------------------------- + + ErrorLog /var/log/apache2/error.log + # Possible values include: debug, info, notice, warn, error, crit, + # alert, emerg. + LogLevel warn + CustomLog /var/log/apache2/access.log combined + + Alias /doc/ "/usr/share/doc/" + + Options Indexes MultiViews FollowSymLinks + AllowOverride None + Order deny,allow + Deny from all + Allow from 127.0.0.0/255.0.0.0 ::1/128 + + + + + +Apache CGI Configuration +------------------------ + + ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ + + AllowOverride None + Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch + Order allow,deny + Allow from all + + + +Setting up Our Script +--------------------- + + $ ls -la /usr/lib/cgi-bin/ + total 24 + drwxr-xr-x 2 root root 4096 Apr 13 2010 . + drwxr-xr-x 66 root root 20480 Nov 23 2011 .. + + +No Directory Listing +-------------------- + +Copy CGI To The Server +---------------------- + + $ cd /path/to/training.python_web + $ scp assignments/week04/lab/cgi-bin/cgi_1.py uw@:~/ + + +Move it to cgi-bin +------------------ + + $ sudo mv ~/cgi_1.py /usr/lib/cgi-bin/ + $ ls -l /usr/lib/cgi-bin + total 4 + -rwxr-xr-x 1 uw uw 42 Jan 20 04:34 cgi_1.py + + +Do it again +----------- + +And Now +------- + +CGI Problems +------------ + +Alternatives to CGI +------------------- + +WSGI +---- + +WSGI: Apps and Servers +---------------------- + +Flowcharts +---------- + +The Whole Enchilada +------------------- + +Using wsgiref +------------- + +Apache mod_wsgi +--------------- + +Proxied WSGI Servers +-------------------- + +WSGI Middleware +--------------- + +Simplified WSGI Server +---------------------- + + from some_application import simple_app + + def build_env(request): + # put together some environment info from the reqeuest + return env + + def handle_request(request, app): + environ = build_env(request) + iterable = app(environ, start_response) + for data in iterable: + # send data to client here + + def start_response(status, headers): + # start an HTTP response, sending status and headers + + # listen for HTTP requests and pass on to handle_request() + serve(simple_app) + + +WSGI Environment +---------------- + +WSGI Environment +---------------- + +WSGI Environment +---------------- + +Simple WSGI Application +----------------------- + + def application(environ, start_response) + status = "200 OK" + body = "Hello World\n" + response_headers = [('Content-type', 'text/plain', + 'Content-length', len(body))] + start_response(status, response_headers) + return [body] + + +Simple WSGI Middleware +---------------------- + + class Upperware: + def __init__(self, app) + self.wrapped_app = app + + def __call__(self, environ, start_response) + for data in self.wrapped_app(environ, start_response): + return data.upper() + + +A Word on Middleware +-------------------- + +Interesting Middleware Uses +--------------------------- + +WSGI on our VMs +--------------- + +Apache Modules +-------------- + + $ which apache2ctl + /usr/sbin/apache2ctl + $ apache2ctl -M + Loaded Modules: + ... + alias_module (shared) + auth_basic_module (shared) + authn_file_module (shared) + authz_default_module (shared) + ... + + +Another Way +----------- + + $ ls /etc/apache2/mods-enabled/ + alias.conf authz_user.load dir.load php5.load + alias.load autoindex.conf env.load reqtimeout.conf + auth_basic.load autoindex.load mime.conf reqtimeout.load + authn_file.load cgi.load mime.load setenvif.conf + authz_default.load deflate.conf negotiation.conf setenvif.load + authz_groupfile.load deflate.load negotiation.load status.conf + authz_host.load dir.conf php5.conf status.load + + +Available Modules +----------------- + + $ ls /etc/apache2/mods-available/ + actions.conf cern_meta.load ident.load proxy_http.load + actions.load cgi.load imagemap.load proxy_scgi.load + alias.conf cgid.conf include.load reqtimeout.conf + alias.load cgid.load info.conf reqtimeout.load + asis.load charset_lite.load info.load rewrite.load + auth_basic.load dav.load ldap.load setenvif.conf + auth_digest.load dav_fs.conf log_forensic.load setenvif.load + ... + + +Adding New Modules +------------------ + +Searching Using apt-cache +------------------------- + + $ apt-cache search mod_wsgi + + + $ apt-cache depends libapache2-mod-wsgi + libapache2-mod-wsgi + Depends: apache2 + apache2-mpm-itk + ... + + +Installing using apt-get +------------------------ + + $ sudo apt-get install libapache2-mod-wsgi + Reading package lists... Done + Building dependency tree + Reading state information... Done + ... + Get:1 http://us.archive.ubuntu.com/ubuntu/ lucid/universe libapache2-mod-wsgi 2.8-2ubuntu1 [63.5kB] + Fetched 63.5kB in 0s (197kB/s) + ... + Setting up libapache2-mod-wsgi (2.8-2ubuntu1) + * Restarting web server apache2 + ... waiting [ OK ] + + +Check Your Work +--------------- + + $ apache2ctl -M + Loaded Modules: + ... + alias_module (shared) + auth_basic_module (shared) + ... + status_module (shared) + wsgi_module (shared) + Syntax OK + + +Configure mod_wsgi +------------------ + + $ cd /etc/apache2 + $ vi sites-available/default + + +Adding WSGIScriptAlias +---------------------- + + ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ + + AllowOverride None + Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch + Order allow,deny + Allow from all + + + # Add this line to the file to expose a /wsgi-bin directory + WSGIScriptAlias /wsgi-bin/ /usr/lib/wsgi-bin/ + + +Give WSGI Something To Do +------------------------- + + $ sudo mkdir /usr/lib/wsgi-bin + + + $ sudo cp ~/wsgi_test.py /usr/lib/wsgi-bin/ + $ ls -l /usr/lib/wsgi-bin/ + total 4 + -rwxr-xr-x 1 root root 955 Jan 22 00:06 wsgi_test.py + + +Reload Apache +------------- + + $ apache2ctl configtest + Syntax OK + + + $ sudo /etc/init.d/apache2 graceful + * Reloading web server config apache2 [ OK ] + + +Looking at wsgi_test.py +----------------------- + + #!/usr/bin/python + + # This is our application object. It could have any name, + # except when using mod_wsgi where it must be "application" + def application(environ, start_response): + + # build the response body possibly using the environ dictionary + response_body = 'The request method was %s' % environ['REQUEST_METHOD'] + + # HTTP response code and message + status = '200 OK' + + # These are HTTP headers expected by the client. + # They must be wrapped as a list of tupled pairs: + # [(Header name, Header value)]. + response_headers = [('Content-Type', 'text/plain'), + ('Content-Length', str(len(response_body)))] + + # Send them to the server using the supplied function + start_response(status, response_headers) + + # Return the response body. + # Notice it is wrapped in a list although it could be any iterable. + return [response_body] + + +Lab 2 +----- + +Assignment +---------- + +Submitting the Assignment +------------------------- + diff --git a/tools.py b/tools.py new file mode 100644 index 00000000..fccb0578 --- /dev/null +++ b/tools.py @@ -0,0 +1,36 @@ +""" +Tools for manipulating documentation +""" + +def build_typealong(rstfile, outfile): + """extract indented code sample sections along with slide headers + + builds a type-along file that provides cut-and-paste for all code samples + in a slide presentation. + """ + in_lines = rstfile.readlines() + type_buffer = [] + prev_line = '' + + def get_header(cur, prev): + if cur.startswith('----'): + return (prev, cur, '\n') + return () + + for line in in_lines: + header = get_header(line, prev_line) + if header: + print "outputting a slide header" + outfile.writelines(header) + else: + if line.startswith(' '): + # omit ` :class: blah' type lines + if not line[4] == ':': + type_buffer.append(line) + elif line.startswith('\n'): + if type_buffer: + print "outputting a typeable section" + type_buffer.extend(['\n', '\n']) + outfile.writelines(type_buffer) + type_buffer = [] + prev_line = line \ No newline at end of file From 18da7dbd0805ae8e339eed1a3e0e31e37bbca739 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 28 Jan 2013 23:37:57 -0800 Subject: [PATCH 044/487] remove initial spaces to improve the cut-and-pastability of the samples --- assignments/week04/lab/type-along.txt | 592 +++++++++++++------------- 1 file changed, 296 insertions(+), 296 deletions(-) diff --git a/assignments/week04/lab/type-along.txt b/assignments/week04/lab/type-along.txt index a8a5915e..eeb2709b 100644 --- a/assignments/week04/lab/type-along.txt +++ b/assignments/week04/lab/type-along.txt @@ -4,27 +4,27 @@ But First Save Memory on Loading ---------------------- - page = urllib2.urlopen(url) - json_string = page.read() - json.loads(json_string) +page = urllib2.urlopen(url) +json_string = page.read() +json.loads(json_string) - page = urllib2.urlopen(url) - json.loads(page) +page = urllib2.urlopen(url) +json.loads(page) Protect Yourself From the Net ----------------------------- - page = urllib2.urlopen(url) - parsed = BeautifulSoup(page) +page = urllib2.urlopen(url) +parsed = BeautifulSoup(page) - page = urllib2.urlopen(url) - if page.code == 200: - parsed = BeautifulSoup(page) - else: - raise SomeExceptionYouCanCatch +page = urllib2.urlopen(url) +if page.code == 200: + parsed = BeautifulSoup(page) +else: + raise SomeExceptionYouCanCatch What You Made @@ -45,58 +45,58 @@ Think Back Stepping Away ------------- - $ export VARIABLE='some_value' - $ echo this is the value: $VARIABLE - this is the value: some_value +$ export VARIABLE='some_value' +$ echo this is the value: $VARIABLE +this is the value: some_value Environment ----------- - $ printenv - VARIABLE=some_value - TERM_PROGRAM=iTerm.app - TERM=xterm - SHELL=/bin/bash - ... +$ printenv +VARIABLE=some_value +TERM_PROGRAM=iTerm.app +TERM=xterm +SHELL=/bin/bash +... Environment in Python --------------------- - $ python +$ python - >>> import os - >>> print os.environ['VARIABLE'] - some_value - >>> print os.environ.keys() - ['VERSIONER_PYTHON_PREFER_32_BIT', 'VARIABLE', - 'LOGNAME', 'USER', 'PATH', ...] +>>> import os +>>> print os.environ['VARIABLE'] +some_value +>>> print os.environ.keys() +['VERSIONER_PYTHON_PREFER_32_BIT', 'VARIABLE', + 'LOGNAME', 'USER', 'PATH', ...] Altering the Environment ------------------------ - >>> os.environ['VARIABLE'] = 'new_value' - >>> print os.environ['VARIABLE'] - new_value +>>> os.environ['VARIABLE'] = 'new_value' +>>> print os.environ['VARIABLE'] +new_value - >>> ^D - $ echo this is the value: $VARIABLE - this is the value: some_value +>>> ^D +$ echo this is the value: $VARIABLE +this is the value: some_value Lessons Learned --------------- - subprocess.Popen(args, bufsize=0, executable=None, - stdin=None, stdout=None, stderr=None, - preexec_fn=None, close_fds=False, - shell=False, cwd=None, env=None, # <------- - universal_newlines=False, startupinfo=None, - creationflags=0) +subprocess.Popen(args, bufsize=0, executable=None, + stdin=None, stdout=None, stderr=None, + preexec_fn=None, close_fds=False, + shell=False, cwd=None, env=None, # <------- + universal_newlines=False, startupinfo=None, + creationflags=0) Web Environment @@ -108,25 +108,25 @@ RFC 3875 Meta-Variables -------------- - 4. The CGI Request . . . . . . . . . . . . . . . . . . . . . . . 10 - 4.1. Request Meta-Variables . . . . . . . . . . . . . . . . . 10 - 4.1.1. AUTH_TYPE. . . . . . . . . . . . . . . . . . . . 11 - 4.1.2. CONTENT_LENGTH . . . . . . . . . . . . . . . . . 12 - 4.1.3. CONTENT_TYPE . . . . . . . . . . . . . . . . . . 12 - 4.1.4. GATEWAY_INTERFACE. . . . . . . . . . . . . . . . 13 - 4.1.5. PATH_INFO. . . . . . . . . . . . . . . . . . . . 13 - 4.1.6. PATH_TRANSLATED. . . . . . . . . . . . . . . . . 14 - 4.1.7. QUERY_STRING . . . . . . . . . . . . . . . . . . 15 - 4.1.8. REMOTE_ADDR. . . . . . . . . . . . . . . . . . . 15 - 4.1.9. REMOTE_HOST. . . . . . . . . . . . . . . . . . . 16 - 4.1.10. REMOTE_IDENT . . . . . . . . . . . . . . . . . . 16 - 4.1.11. REMOTE_USER. . . . . . . . . . . . . . . . . . . 16 - 4.1.12. REQUEST_METHOD . . . . . . . . . . . . . . . . . 17 - 4.1.13. SCRIPT_NAME. . . . . . . . . . . . . . . . . . . 17 - 4.1.14. SERVER_NAME. . . . . . . . . . . . . . . . . . . 17 - 4.1.15. SERVER_PORT. . . . . . . . . . . . . . . . . . . 18 - 4.1.16. SERVER_PROTOCOL. . . . . . . . . . . . . . . . . 18 - 4.1.17. SERVER_SOFTWARE. . . . . . . . . . . . . . . . . 19 +4. The CGI Request . . . . . . . . . . . . . . . . . . . . . . . 10 + 4.1. Request Meta-Variables . . . . . . . . . . . . . . . . . 10 + 4.1.1. AUTH_TYPE. . . . . . . . . . . . . . . . . . . . 11 + 4.1.2. CONTENT_LENGTH . . . . . . . . . . . . . . . . . 12 + 4.1.3. CONTENT_TYPE . . . . . . . . . . . . . . . . . . 12 + 4.1.4. GATEWAY_INTERFACE. . . . . . . . . . . . . . . . 13 + 4.1.5. PATH_INFO. . . . . . . . . . . . . . . . . . . . 13 + 4.1.6. PATH_TRANSLATED. . . . . . . . . . . . . . . . . 14 + 4.1.7. QUERY_STRING . . . . . . . . . . . . . . . . . . 15 + 4.1.8. REMOTE_ADDR. . . . . . . . . . . . . . . . . . . 15 + 4.1.9. REMOTE_HOST. . . . . . . . . . . . . . . . . . . 16 + 4.1.10. REMOTE_IDENT . . . . . . . . . . . . . . . . . . 16 + 4.1.11. REMOTE_USER. . . . . . . . . . . . . . . . . . . 16 + 4.1.12. REQUEST_METHOD . . . . . . . . . . . . . . . . . 17 + 4.1.13. SCRIPT_NAME. . . . . . . . . . . . . . . . . . . 17 + 4.1.14. SERVER_NAME. . . . . . . . . . . . . . . . . . . 17 + 4.1.15. SERVER_PORT. . . . . . . . . . . . . . . . . . . 18 + 4.1.16. SERVER_PROTOCOL. . . . . . . . . . . . . . . . . 18 + 4.1.17. SERVER_SOFTWARE. . . . . . . . . . . . . . . . . 19 Running CGI @@ -135,11 +135,11 @@ Running CGI Running CGI - Preparations -------------------------- - $ cd - $ mkdir git - $ cd git - $ git clone https://github.com/cewing/training.python_web.git - $ cd training.python_web +$ cd +$ mkdir git +$ cd git +$ git clone https://github.com/cewing/training.python_web.git +$ cd training.python_web Running CGI - First Test @@ -151,17 +151,17 @@ Did that work? Break It -------- - $ ls -l cgi-bin/cgi_1.py - -rwxr-xr-x 1 cewing staff 42 Jan 17 22:30 cgi-bin/cgi_1.py - $ chmod 444 cgi-bin/cgi_1.py - $ ls -l cgi-bin/cgi_1.py - -r--r--r-- 1 cewing staff 42 Jan 17 22:35 cgi-bin/cgi_1.py +$ ls -l cgi-bin/cgi_1.py +-rwxr-xr-x 1 cewing staff 42 Jan 17 22:30 cgi-bin/cgi_1.py +$ chmod 444 cgi-bin/cgi_1.py +$ ls -l cgi-bin/cgi_1.py +-r--r--r-- 1 cewing staff 42 Jan 17 22:35 cgi-bin/cgi_1.py Break It Differently -------------------- - 1 / 0 +1 / 0 Errors in CGI @@ -170,8 +170,8 @@ Errors in CGI Viewing Errors in Python CGI ---------------------------- - import cgitb - cgitb.enable() +import cgitb +cgitb.enable() cgitb Output @@ -180,21 +180,21 @@ cgitb Output Another Way to Break It ----------------------- - #!/usr/bin/python - import cgi - import cgitb +#!/usr/bin/python +import cgi +import cgitb - cgitb.enable() +cgitb.enable() - cgi.test() +cgi.test() CGI Process Execution --------------------- - $ ./path/to/cgi_1.py +$ ./path/to/cgi_1.py CGI Process Execution @@ -203,25 +203,25 @@ CGI Process Execution More Permission Fun ------------------- - $ ls -l /usr/bin/python* - lrwxrwxrwx 1 root root 9 Oct 4 18:48 python -> python2.6 - lrwxrwxrwx 1 root root 9 Oct 4 18:48 python2 -> python2.6 - -rwxr-xr-x 1 root root 2288240 Apr 16 2010 python2.6 - $ sudo chmod 750 python - $ ls -l /usr/bin/python* - lrwxrwxrwx 1 root root 9 Oct 4 18:48 python -> python2.6 - lrwxrwxrwx 1 root root 9 Oct 4 18:48 python2 -> python2.6 - -rwxr-x--- 1 root root 2288240 Apr 16 2010 python2.6 +$ ls -l /usr/bin/python* +lrwxrwxrwx 1 root root 9 Oct 4 18:48 python -> python2.6 +lrwxrwxrwx 1 root root 9 Oct 4 18:48 python2 -> python2.6 +-rwxr-xr-x 1 root root 2288240 Apr 16 2010 python2.6 +$ sudo chmod 750 python +$ ls -l /usr/bin/python* +lrwxrwxrwx 1 root root 9 Oct 4 18:48 python -> python2.6 +lrwxrwxrwx 1 root root 9 Oct 4 18:48 python2 -> python2.6 +-rwxr-x--- 1 root root 2288240 Apr 16 2010 python2.6 Enough of That -------------- - $ sudo chmod 755 /usr/bin/python - $ ls -l /usr/bin/python* - lrwxrwxrwx 1 root root 9 Oct 4 18:48 python -> python2.6 - lrwxrwxrwx 1 root root 9 Oct 4 18:48 python2 -> python2.6 - -rwxr-xr-x 1 root root 2288240 Apr 16 2010 python2.6 +$ sudo chmod 755 /usr/bin/python +$ ls -l /usr/bin/python* +lrwxrwxrwx 1 root root 9 Oct 4 18:48 python -> python2.6 +lrwxrwxrwx 1 root root 9 Oct 4 18:48 python2 -> python2.6 +-rwxr-xr-x 1 root root 2288240 Apr 16 2010 python2.6 The CGI Environment @@ -230,30 +230,30 @@ The CGI Environment CGI Servers ----------- - >>> import CGIHTTPServer - >>> CGIHTTPServer.__file__ - '/big/giant/path/to/lib/python2.6/CGIHTTPServer.py' +>>> import CGIHTTPServer +>>> CGIHTTPServer.__file__ +'/big/giant/path/to/lib/python2.6/CGIHTTPServer.py' Environmental Set Up -------------------- - # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html - # XXX Much of the following could be prepared ahead of time! - env = {} - env['SERVER_SOFTWARE'] = self.version_string() - env['SERVER_NAME'] = self.server.server_name - env['GATEWAY_INTERFACE'] = 'CGI/1.1' - env['SERVER_PROTOCOL'] = self.protocol_version - env['SERVER_PORT'] = str(self.server.server_port) - env['REQUEST_METHOD'] = self.command - ... - ua = self.headers.getheader('user-agent') - if ua: - env['HTTP_USER_AGENT'] = ua - ... - os.environ.update(env) - ... +# Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html +# XXX Much of the following could be prepared ahead of time! +env = {} +env['SERVER_SOFTWARE'] = self.version_string() +env['SERVER_NAME'] = self.server.server_name +env['GATEWAY_INTERFACE'] = 'CGI/1.1' +env['SERVER_PROTOCOL'] = self.protocol_version +env['SERVER_PORT'] = str(self.server.server_port) +env['REQUEST_METHOD'] = self.command +... +ua = self.headers.getheader('user-agent') +if ua: + env['HTTP_USER_AGENT'] = ua +... +os.environ.update(env) +... CGI Scripts @@ -277,10 +277,10 @@ Apache Managing Server Processes ------------------------- - $ sudo /etc/init.d/nginx stop - Stopping nginx: nginx. - $ sudo /etc/init.d/apache2 start - * Starting web server apache2 [ OK ] +$ sudo /etc/init.d/nginx stop +Stopping nginx: nginx. +$ sudo /etc/init.d/apache2 start + * Starting web server apache2 [ OK ] Check Your Work @@ -289,77 +289,77 @@ Check Your Work Default Site ------------ - $ cd /etc/apache2/ - $ ls sites-available/ - default default-ssl - $ ls -l sites-enabled/ - total 0 - ... 000-default -> ../sites-available/default +$ cd /etc/apache2/ +$ ls sites-available/ +default default-ssl +$ ls -l sites-enabled/ +total 0 +... 000-default -> ../sites-available/default Apache Configuration -------------------- - $ less sites-available/default +$ less sites-available/default - - ServerAdmin webmaster@localhost + + ServerAdmin webmaster@localhost - DocumentRoot /var/www - - Options FollowSymLinks - AllowOverride None - - - Options Indexes FollowSymLinks MultiViews - AllowOverride None - Order allow,deny - allow from all - + DocumentRoot /var/www + + Options FollowSymLinks + AllowOverride None + + + Options Indexes FollowSymLinks MultiViews + AllowOverride None + Order allow,deny + allow from all + More Apache Configuration ------------------------- - ErrorLog /var/log/apache2/error.log - # Possible values include: debug, info, notice, warn, error, crit, - # alert, emerg. - LogLevel warn - CustomLog /var/log/apache2/access.log combined - - Alias /doc/ "/usr/share/doc/" - - Options Indexes MultiViews FollowSymLinks - AllowOverride None - Order deny,allow - Deny from all - Allow from 127.0.0.0/255.0.0.0 ::1/128 - - - + ErrorLog /var/log/apache2/error.log + # Possible values include: debug, info, notice, warn, error, crit, + # alert, emerg. + LogLevel warn + CustomLog /var/log/apache2/access.log combined + + Alias /doc/ "/usr/share/doc/" + + Options Indexes MultiViews FollowSymLinks + AllowOverride None + Order deny,allow + Deny from all + Allow from 127.0.0.0/255.0.0.0 ::1/128 + + + Apache CGI Configuration ------------------------ - ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ - - AllowOverride None - Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch - Order allow,deny - Allow from all - +ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ + + AllowOverride None + Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch + Order allow,deny + Allow from all + Setting up Our Script --------------------- - $ ls -la /usr/lib/cgi-bin/ - total 24 - drwxr-xr-x 2 root root 4096 Apr 13 2010 . - drwxr-xr-x 66 root root 20480 Nov 23 2011 .. +$ ls -la /usr/lib/cgi-bin/ +total 24 +drwxr-xr-x 2 root root 4096 Apr 13 2010 . +drwxr-xr-x 66 root root 20480 Nov 23 2011 .. No Directory Listing @@ -368,17 +368,17 @@ No Directory Listing Copy CGI To The Server ---------------------- - $ cd /path/to/training.python_web - $ scp assignments/week04/lab/cgi-bin/cgi_1.py uw@:~/ +$ cd /path/to/training.python_web +$ scp assignments/week04/lab/cgi-bin/cgi_1.py uw@:~/ Move it to cgi-bin ------------------ - $ sudo mv ~/cgi_1.py /usr/lib/cgi-bin/ - $ ls -l /usr/lib/cgi-bin - total 4 - -rwxr-xr-x 1 uw uw 42 Jan 20 04:34 cgi_1.py +$ sudo mv ~/cgi_1.py /usr/lib/cgi-bin/ +$ ls -l /usr/lib/cgi-bin +total 4 +-rwxr-xr-x 1 uw uw 42 Jan 20 04:34 cgi_1.py Do it again @@ -420,23 +420,23 @@ WSGI Middleware Simplified WSGI Server ---------------------- - from some_application import simple_app - - def build_env(request): - # put together some environment info from the reqeuest - return env - - def handle_request(request, app): - environ = build_env(request) - iterable = app(environ, start_response) - for data in iterable: - # send data to client here - - def start_response(status, headers): - # start an HTTP response, sending status and headers - - # listen for HTTP requests and pass on to handle_request() - serve(simple_app) +from some_application import simple_app + +def build_env(request): + # put together some environment info from the reqeuest + return env + +def handle_request(request, app): + environ = build_env(request) + iterable = app(environ, start_response) + for data in iterable: + # send data to client here + +def start_response(status, headers): + # start an HTTP response, sending status and headers + +# listen for HTTP requests and pass on to handle_request() +serve(simple_app) WSGI Environment @@ -451,25 +451,25 @@ WSGI Environment Simple WSGI Application ----------------------- - def application(environ, start_response) - status = "200 OK" - body = "Hello World\n" - response_headers = [('Content-type', 'text/plain', - 'Content-length', len(body))] - start_response(status, response_headers) - return [body] +def application(environ, start_response) + status = "200 OK" + body = "Hello World\n" + response_headers = [('Content-type', 'text/plain', + 'Content-length', len(body))] + start_response(status, response_headers) + return [body] Simple WSGI Middleware ---------------------- - class Upperware: - def __init__(self, app) - self.wrapped_app = app - - def __call__(self, environ, start_response) - for data in self.wrapped_app(environ, start_response): - return data.upper() +class Upperware: + def __init__(self, app) + self.wrapped_app = app + + def __call__(self, environ, start_response) + for data in self.wrapped_app(environ, start_response): + return data.upper() A Word on Middleware @@ -484,43 +484,43 @@ WSGI on our VMs Apache Modules -------------- - $ which apache2ctl - /usr/sbin/apache2ctl - $ apache2ctl -M - Loaded Modules: - ... - alias_module (shared) - auth_basic_module (shared) - authn_file_module (shared) - authz_default_module (shared) - ... +$ which apache2ctl +/usr/sbin/apache2ctl +$ apache2ctl -M +Loaded Modules: + ... + alias_module (shared) + auth_basic_module (shared) + authn_file_module (shared) + authz_default_module (shared) + ... Another Way ----------- - $ ls /etc/apache2/mods-enabled/ - alias.conf authz_user.load dir.load php5.load - alias.load autoindex.conf env.load reqtimeout.conf - auth_basic.load autoindex.load mime.conf reqtimeout.load - authn_file.load cgi.load mime.load setenvif.conf - authz_default.load deflate.conf negotiation.conf setenvif.load - authz_groupfile.load deflate.load negotiation.load status.conf - authz_host.load dir.conf php5.conf status.load +$ ls /etc/apache2/mods-enabled/ +alias.conf authz_user.load dir.load php5.load +alias.load autoindex.conf env.load reqtimeout.conf +auth_basic.load autoindex.load mime.conf reqtimeout.load +authn_file.load cgi.load mime.load setenvif.conf +authz_default.load deflate.conf negotiation.conf setenvif.load +authz_groupfile.load deflate.load negotiation.load status.conf +authz_host.load dir.conf php5.conf status.load Available Modules ----------------- - $ ls /etc/apache2/mods-available/ - actions.conf cern_meta.load ident.load proxy_http.load - actions.load cgi.load imagemap.load proxy_scgi.load - alias.conf cgid.conf include.load reqtimeout.conf - alias.load cgid.load info.conf reqtimeout.load - asis.load charset_lite.load info.load rewrite.load - auth_basic.load dav.load ldap.load setenvif.conf - auth_digest.load dav_fs.conf log_forensic.load setenvif.load - ... +$ ls /etc/apache2/mods-available/ +actions.conf cern_meta.load ident.load proxy_http.load +actions.load cgi.load imagemap.load proxy_scgi.load +alias.conf cgid.conf include.load reqtimeout.conf +alias.load cgid.load info.conf reqtimeout.load +asis.load charset_lite.load info.load rewrite.load +auth_basic.load dav.load ldap.load setenvif.conf +auth_digest.load dav_fs.conf log_forensic.load setenvif.load +... Adding New Modules @@ -529,118 +529,118 @@ Adding New Modules Searching Using apt-cache ------------------------- - $ apt-cache search mod_wsgi +$ apt-cache search mod_wsgi - $ apt-cache depends libapache2-mod-wsgi - libapache2-mod-wsgi - Depends: apache2 - apache2-mpm-itk - ... +$ apt-cache depends libapache2-mod-wsgi +libapache2-mod-wsgi + Depends: apache2 + apache2-mpm-itk +... Installing using apt-get ------------------------ - $ sudo apt-get install libapache2-mod-wsgi - Reading package lists... Done - Building dependency tree - Reading state information... Done - ... - Get:1 http://us.archive.ubuntu.com/ubuntu/ lucid/universe libapache2-mod-wsgi 2.8-2ubuntu1 [63.5kB] - Fetched 63.5kB in 0s (197kB/s) - ... - Setting up libapache2-mod-wsgi (2.8-2ubuntu1) - * Restarting web server apache2 - ... waiting [ OK ] +$ sudo apt-get install libapache2-mod-wsgi +Reading package lists... Done +Building dependency tree +Reading state information... Done +... +Get:1 http://us.archive.ubuntu.com/ubuntu/ lucid/universe libapache2-mod-wsgi 2.8-2ubuntu1 [63.5kB] +Fetched 63.5kB in 0s (197kB/s) +... +Setting up libapache2-mod-wsgi (2.8-2ubuntu1) + * Restarting web server apache2 + ... waiting [ OK ] Check Your Work --------------- - $ apache2ctl -M - Loaded Modules: - ... - alias_module (shared) - auth_basic_module (shared) - ... - status_module (shared) - wsgi_module (shared) - Syntax OK +$ apache2ctl -M +Loaded Modules: + ... + alias_module (shared) + auth_basic_module (shared) + ... + status_module (shared) + wsgi_module (shared) +Syntax OK Configure mod_wsgi ------------------ - $ cd /etc/apache2 - $ vi sites-available/default +$ cd /etc/apache2 +$ vi sites-available/default Adding WSGIScriptAlias ---------------------- - ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ - - AllowOverride None - Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch - Order allow,deny - Allow from all - - - # Add this line to the file to expose a /wsgi-bin directory - WSGIScriptAlias /wsgi-bin/ /usr/lib/wsgi-bin/ +ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ + + AllowOverride None + Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch + Order allow,deny + Allow from all + + +# Add this line to the file to expose a /wsgi-bin directory +WSGIScriptAlias /wsgi-bin/ /usr/lib/wsgi-bin/ Give WSGI Something To Do ------------------------- - $ sudo mkdir /usr/lib/wsgi-bin +$ sudo mkdir /usr/lib/wsgi-bin - $ sudo cp ~/wsgi_test.py /usr/lib/wsgi-bin/ - $ ls -l /usr/lib/wsgi-bin/ - total 4 - -rwxr-xr-x 1 root root 955 Jan 22 00:06 wsgi_test.py +$ sudo cp ~/wsgi_test.py /usr/lib/wsgi-bin/ +$ ls -l /usr/lib/wsgi-bin/ +total 4 +-rwxr-xr-x 1 root root 955 Jan 22 00:06 wsgi_test.py Reload Apache ------------- - $ apache2ctl configtest - Syntax OK +$ apache2ctl configtest +Syntax OK - $ sudo /etc/init.d/apache2 graceful - * Reloading web server config apache2 [ OK ] +$ sudo /etc/init.d/apache2 graceful +* Reloading web server config apache2 [ OK ] Looking at wsgi_test.py ----------------------- - #!/usr/bin/python +#!/usr/bin/python + +# This is our application object. It could have any name, +# except when using mod_wsgi where it must be "application" +def application(environ, start_response): + + # build the response body possibly using the environ dictionary + response_body = 'The request method was %s' % environ['REQUEST_METHOD'] + + # HTTP response code and message + status = '200 OK' + + # These are HTTP headers expected by the client. + # They must be wrapped as a list of tupled pairs: + # [(Header name, Header value)]. + response_headers = [('Content-Type', 'text/plain'), + ('Content-Length', str(len(response_body)))] + + # Send them to the server using the supplied function + start_response(status, response_headers) - # This is our application object. It could have any name, - # except when using mod_wsgi where it must be "application" - def application(environ, start_response): - - # build the response body possibly using the environ dictionary - response_body = 'The request method was %s' % environ['REQUEST_METHOD'] - - # HTTP response code and message - status = '200 OK' - - # These are HTTP headers expected by the client. - # They must be wrapped as a list of tupled pairs: - # [(Header name, Header value)]. - response_headers = [('Content-Type', 'text/plain'), - ('Content-Length', str(len(response_body)))] - - # Send them to the server using the supplied function - start_response(status, response_headers) - - # Return the response body. - # Notice it is wrapped in a list although it could be any iterable. - return [response_body] + # Return the response body. + # Notice it is wrapped in a list although it could be any iterable. + return [response_body] Lab 2 From 3b20be2080f367cb2f7f4f9f7bdf165584bc55b2 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 28 Jan 2013 23:40:20 -0800 Subject: [PATCH 045/487] add notes on type-along.txt --- source/presentations/week04.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/source/presentations/week04.rst b/source/presentations/week04.rst index 3085e5bb..da441bc4 100644 --- a/source/presentations/week04.rst +++ b/source/presentations/week04.rst @@ -111,6 +111,17 @@ And Second Questions from the Reading? +And Third +--------- + +Open ``assignments/week04/lab/type-along.txt`` + +.. class:: incremental + +This contains all the code examples from today's lecture. It's meant to help +you with keeping up when we are moving quickly through sample slides. I hope +it is of some use. + And Now... ---------- From 8b933833b90a0e26ed86bedd0aa86067aeb51eda Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 1 Feb 2013 00:00:06 -0800 Subject: [PATCH 046/487] * add css rules for invisible tables * push into flask intro slides --- source/presentations/week05.rst | 268 ++++++++++++++++++++++++++---- source/ui/uw_pce_theme/pretty.css | 13 ++ 2 files changed, 252 insertions(+), 29 deletions(-) diff --git a/source/presentations/week05.rst b/source/presentations/week05.rst index 1c9dd100..35a9c255 100644 --- a/source/presentations/week05.rst +++ b/source/presentations/week05.rst @@ -60,13 +60,6 @@ This concludes the foundational part of the course. Everything we do from here out will be based on tools built using what we've learned these first four weeks. -Onward ------- - -.. class:: big-centered - -We are moving up the stack - We've built ----------- @@ -95,6 +88,13 @@ We've built A simple wsgi application +Onward +------ + +.. class:: big-centered + +We are moving up the stack + From Now On ----------- @@ -108,6 +108,122 @@ This may not *actually* be true But we will always be working at that level of abstraction. +The Abstraction Stack +--------------------- + +You can think of the libraries we use to write web applications as belonging +to one of several levels: + +.. class:: incremental center + +plumbing + +.. class:: incremental center + +tools + +.. class:: incremental center + +small frameworks + +.. class:: incremental center + +full-stack frameworks + +.. class:: incremental center + +systems + +Plumbing +-------- + +We've done this part already: + +.. class:: center + +Sockets + +.. class:: center + +Protocols + +.. class:: center + +CGI/WSGI + +Tools +----- + +We've started to talk about these, we'll see more soon: + +.. class:: center + +cgitb + +.. class:: center + +wsgi middleware + +.. class:: center + +werkzeug tools + +.. class:: center + +WebOb + +Small Frameworks +---------------- + +We're here today: + +.. class:: center + +Flask + +.. class:: center + +Bottle + +.. class:: center + +CherryPy + +.. class:: center + +Web.py + +.. class:: center + +and many many more... + +Full Stack Frameworks +--------------------- + +We will visit this level next: + +.. class:: center + +Django + +.. class:: center + +Pyramid + +.. class:: center + +web2py + +Systems +------- + +We'll finish up here + +.. class:: center + +Plone + + Frameworks ---------- @@ -127,8 +243,12 @@ What Does That *Mean*? You use a framework to build an application. +.. class:: incremental + A framework allows you to build different kinds of applications. +.. class:: incremental + A framework abstracts what needs to be abstracted, and allows control of the rest. @@ -147,42 +267,132 @@ This last part is important when it comes to choosing a framework * abstraction ∝ 1/freedom * The more they choose, the less you can * *Every* framework makes choices in what to abstract -* Pick a framework whose abstractions meet your needs +* *Every* framework makes *different* choices + +Python Web Frameworks +--------------------- + +There are scores of 'em (this is a partial list). + +.. class:: incremental invisible small center + +========= ======== ======== ========== ============== +Django Grok Pylons TurboGears web2py +Zope CubicWeb Enamel Gizmo(QP) Glashammer +Karrigell Nagare notmm Porcupine QP +SkunkWeb Spyce Tipfy Tornado WebCore +web.py Webware Werkzeug WHIFF XPRESS +AppWsgi Bobo Bo7le CherryPy circuits.web +Paste PyWebLib WebStack Albatross Aquarium +Divmod Nevow Flask JOTWeb2 Python Servlet +Engine Pyramid Quixote Spiked weblayer +========= ======== ======== ========== ============== + +Choosing a Framework +-------------------- + +Many folks will tell you " is the **best** framework". + +.. class:: incremental + +In most cases, what they really mean is "I know how to use " + +.. class:: incremental + +In some cases, what they really mean is " fits my brain the best" + +.. class:: incremental + +What they usually forget is that everyone's brain (and everyone's use-case) is +different. + +Cris' First Law of Frameworks +----------------------------- + +.. class:: center + +**Pick the Right Tool for the Job** .. class:: incremental -Frameworks with a minimal level of abstraction are considered to be -*Microframeworks* +First Corollary .. class:: incremental center -Where is the line between micro- and not? +The right tool is the tool that allows you to finish the job quickly and +correctly. -Python Web Frameworks ---------------------- +.. class:: incremental center -There are scores of 'em. +But how do you know which that one is? -.. class:: incremental small +Cris' Second Law of Frameworks +------------------------------ -Django Grok Pylons TurboGears web2py -Zope CubicWeb Enamel Gizmo(QP) Glashammer -Karrigell Nagare notmm Porcupine QP -SkunkWeb Spyce Tipfy Tornado WebCore -web.py Webware Werkzeug WHIFF XPRESS -AppWsgi Bobo Bo7le CherryPy circuits.web -Paste PyWebLib WebStack Albatross Aquarium -Divmod Nevow Flask JOTWeb2 Python Servlet -Engine Pyramid Quixote Spiked weblayer +.. class:: big-centered -scraps ------- +You can't know unless you try + +.. class:: incremental center + +so let's try + +Preparation +----------- + +We proceed under the assumption that you have installed Flask into a +virtualenv, either on your laptop or on your VM. + +.. class:: incremental + +Start by activating the virtualenv with Flask installed + +.. class:: incremental -What is a Framework? +Next, create a new python source file: `flask_intro.py` -What types of frameworks are there? +.. class:: incremental + +Finally, open that file in your text editor + +Flask +----- + +Getting started with Flask is pretty straightforward. Here's a complete, +simple app. Type it into `flask_intro.py`: + +.. code-block:: python + :class: small + + from flask import Flask + app = Flask(__name__) + + @app.route('/') + def hello_world(): + return 'Hello World!' + + if __name__ == '__main__': + app.run() + +.. class:: incremental + +Load http://localhost:5000 in your browser to see it in action. -Why choose one over another? +What's Happening Here? +---------------------- + +Flask the framework provides a Python class called `Flask`. This class +represents a single *application* in the WSGI sense. + +.. class:: incremental + +* You instantiate a `Flask` app with a name that represents the package or + module containing the app. +* If your application is a single module, this should be `__name__` +* This is used to help the `Flask` app figure out where to look for resources + +scraps +------ Intro to Flask diff --git a/source/ui/uw_pce_theme/pretty.css b/source/ui/uw_pce_theme/pretty.css index 3a6191ec..a0e0d862 100644 --- a/source/ui/uw_pce_theme/pretty.css +++ b/source/ui/uw_pce_theme/pretty.css @@ -169,6 +169,19 @@ p.image-credit { z-index: 10; } +table.invisible { + border: none; + border-collapse: collapse; +} +table.invisible tr, +table.invisible td { + border: none; +} +table.invisible td { + text-align: center; + padding: 5px; +} + /* Pygments 'colorful' colorization */ .code { background-color: #ffffcc} .current .c, .c { color: #888888 } /* Comment */ From c661b74ac60ce32d339fddd4a2b654bbeffffabd Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 3 Feb 2013 06:51:24 -0800 Subject: [PATCH 047/487] update to use db api as provided --- .../teachers/week04/answers/homework.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/assignments/teachers/week04/answers/homework.py b/assignments/teachers/week04/answers/homework.py index cc20cf38..a72d308b 100644 --- a/assignments/teachers/week04/answers/homework.py +++ b/assignments/teachers/week04/answers/homework.py @@ -19,6 +19,7 @@ def __init__(self, db, urls): def __call__(self, environ, start_response): headers = [('Content-type', 'text/html')] + import pdb; pdb.set_trace( ) try: path = environ.get('PATH_INFO', None) if path is None: @@ -44,9 +45,9 @@ def __call__(self, environ, start_response): def books(self): core = ['

    Book Database

    ', '
      '] - tmpl = '
    • %s
    • ' - for book_id, book_data in self.db.items(): - core.append(tmpl % (book_id, book_data['title'])) + tmpl = '
    • %(title)s
    • ' + for data in self.db.titles(): + core.append(tmpl % data) core.append('
    ') body = "\n".join(core) context = {'page_title': "Book Database", @@ -66,9 +67,10 @@ def book(self, id):

    More Books

    """ - book = self.db.get(id, None) - if book is None: - raise NameError + try: + book = self.db.title_info(id) + except KeyError: + raise NameError('book not found') title = "Book Database: %s" % book['isbn'] context = {'page_title': title, 'page_body': tmpl % book} @@ -99,7 +101,7 @@ def _get_callable(self, path): # this block will be called when the script is run directly from wsgiref.simple_server import make_server import bookdb - application = MyApplication(bookdb.database, URLS) + application = MyApplication(bookdb.BookDB(), URLS) srv = make_server('localhost', 8080, application) srv.serve_forever() else: @@ -114,4 +116,4 @@ def _get_callable(self, path): import sys sys.path.append('/path/to/directory/containing/bookdb/on/server') import bookdb - application = MyApplication(bookdb.database, URLS) + application = MyApplication(bookdb.BookDB(), URLS) From 4789368c48ee1eb87c784227b06c09ee169d1ec2 Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 3 Feb 2013 06:51:50 -0800 Subject: [PATCH 048/487] * add reading notes for week05 --- source/main/outline.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/source/main/outline.rst b/source/main/outline.rst index d4eefef1..5054e3fa 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -372,6 +372,14 @@ Reading `_ - We will be writing tests from here forward. Start learning how. +Please also skim this: + +* `sqlite3 - DB API for sqlite3 + `_ - We'll need a bit + of familiarity with the sqlite3 module. How to open connections, execute + queries, and read the results from a cursor. Just read the first two + sections ('Creating a Database' and 'Retrieving Data'). + Before Class ************ @@ -396,6 +404,11 @@ specifically in class. * `Python Web Frameworks `_ +You may also want to do more reading on the unittest module: + +* `PyMOTW - unittest + `_ + Assignment ********** From 472549939ac4bb23d6f26bcdef328e729518ab85 Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 3 Feb 2013 06:52:12 -0800 Subject: [PATCH 049/487] finish week5 slides --- source/presentations/week05.rst | 1285 ++++++++++++++++++++++++++++++- 1 file changed, 1274 insertions(+), 11 deletions(-) diff --git a/source/presentations/week05.rst b/source/presentations/week05.rst index 35a9c255..2b53687c 100644 --- a/source/presentations/week05.rst +++ b/source/presentations/week05.rst @@ -345,11 +345,11 @@ virtualenv, either on your laptop or on your VM. .. class:: incremental -Start by activating the virtualenv with Flask installed +Start by activating the virtualenv with Flask installed. Mine is 'flaskenv'. .. class:: incremental -Next, create a new python source file: `flask_intro.py` +Next, create a new python source file: ``flask_intro.py`` .. class:: incremental @@ -374,9 +374,41 @@ simple app. Type it into `flask_intro.py`: if __name__ == '__main__': app.run() + +Running our App +--------------- + +As you might expect by now, the last block in our ``flask_intro.py`` file +allows us to run this as a python program. Save your file, and in your +terminal try this:: + + (flaskenv)$ python flask_intro.py + .. class:: incremental -Load http://localhost:5000 in your browser to see it in action. +Load ``http://localhost:5000`` in your browser to see it in action. + +Debugging our App +----------------- + +Last week, ``cgitb`` provided us with useful feedback when building an app. +Flask has a similar tool. Make the following changes to your +``flask_intro.py`` file: + +.. code-block:: python + :class: small + + @app.route('/') + def hello_world(): + bar = 1 / 0 + return 'Hello World!' + + if __name__ == '__main__': + app.run(debug=True) + +In your terminal, quit the app with ``^C`` and then restart it. Then reload +your browser and see what happens. + What's Happening Here? ---------------------- @@ -389,18 +421,1249 @@ represents a single *application* in the WSGI sense. * You instantiate a `Flask` app with a name that represents the package or module containing the app. * If your application is a single module, this should be `__name__` -* This is used to help the `Flask` app figure out where to look for resources +* This is used to help the `Flask` app figure out where to look for + *resources* +* *Resources* can be static files (css, images, javascript), templates, or + additional python modules you create and need to import. +* You define a function and route a URL to call it -scraps ------- +URL Routing +----------- + +Remember our bookdb homework? How did you end up solving the problem of +mapping an HTTP request to the right function? + +.. class:: incremental + +Flask solves this problem by using the `route` decorator from your app. + +.. class:: incremental + +A 'route' takes a URL rule (more on that in a minute) and maps it to an +*endpoint* and a *function*. + +.. class:: incremental + +When a request arrives at a URL that matches a known rule, the function is +called. + +Routes Can Be Dynamic +--------------------- + +You can provide *placeholders* in dynamic urls. Each *placeholder* is then a +named arg to your function (add these to ``flask_intro.py``): + +.. code-block:: python + :class: incremental small + + @app.route('/profile/') + def show_profile(username): + return "My username is %s" % username + +.. class:: incremental + +These *placeholders* can also include *converters* that will ensure the +incoming argument is of the correct type. + +.. code-block:: python + :class: incremental small + + @app.route('/div//') + def divide(val): + return "%0.2f divided by 2 is %0.2f" % (val, val / 2) + +Routes Can Be Filtered +---------------------- + +You can also determine which HTTP *methods* a given route will accept: + +.. code-block:: python + :class: small + + @app.route('/blog/entry//', methods=['GET',]) + def read_entry(id): + return "reading entry %d" % id + + @app.route('/blog/entry//', methods=['POST', ]) + def write_entry(id): + return 'writing entry %d' % id + +.. class:: incremental + +After adding that to ``flask_intro.py`` and saving, try loading +``http://localhost:5000/blog/entry/23/`` into your browser. Which was called? + +Routes Can Be Reversed +---------------------- + +Reversing a URL means the ability to generating the url that would result in a +given endpoint being called. + +.. class:: incremental + +This means *you don't have to hard-code your URLs when building links* + +.. class:: incremental + +That means *you can change the URLs for your app without changing code or +templates* + +.. class:: incremental + +This is called **decoupling** and it is a good thing + +Reversing URLs in Flask +----------------------- + +In Flask, you reverse a url with the ``url_for`` function. + +.. class:: incremental + +* ``url_for`` requires an HTTP request context to work +* You can fake an HTTP request when working in a terminal (or testing) +* Use the ``test_request_context`` method of your app object +* This is a great chance to learn about the Python ``with`` statement +* **Don't type this** + +.. code-block:: python + :class: small incremental + + from flask import url_for + with app.test_request_context(): + print url_for('endpoint', **kwargs) + +Reversing in Action +------------------- + +Quit your Flask app with ``^C``. Then start a python interpreter in that same +terminal and import your ``flask_intro.py`` module: + +.. code-block:: python + + import flask_intro + from flask_intro import app + from flask import url_for + with app.test_request_context(): + print url_for('show_profile', username="cris") + print url_for('divide', val=23.7) + + '/profile/cris/' + '/div/23.7/' + +Generating HTML +--------------- + +.. class:: big-centered + +I enjoy writing building HTML in Python strings + +.. class:: incremental right + +-- nobody, ever + +Templating +---------- + +A good framework will provide some way of generating HTML with a templating +system. + +.. class:: incremental + +There are nearly as many templating systems as there are frameworks + +.. class:: incremental + +Each has advantages and disadvantages + +.. class:: incremental + +Flask includes the *Jinja2* templating system (perhaps because it's built by +the same folks) + +Jinja2 Template Basics +---------------------- + +There are a few basic things to know: + +.. class:: incremental + +* Variables in templates can be printed by surrounding the variable name with + double curly braces: ``{{ name }}``. +* If a variable points to something like a dictionary or object, you can use + *either* dot or subscription notation: ``{{ obj[attr] }}``, ``{{ dict.key + }}``. +* Variables in templates can be *filtered*: ``{{ name|capitalize }}``. There + is a list of builtin filters. +* Logic can be put into templates using the processor marker: ``{% for x in y + %}{{ x }}{% endfor %}`` +* Logic comes in pairs. Any start *must* have an explicit end. + +Advanced Jinja2 +--------------- + +There is *way* too much about writing templates in Jinja2 for us to cover here +today. Read more here: + +.. class:: center + +http://jinja.pocoo.org/docs/templates/ + +Templates in Flask +------------------ + +Use the ``render_template`` function: + +.. code-block:: python + :class: small + + from flask import render_template + + @app.route('/hello/') + @app.route('/hello/') + def hello(name=None): + return render_template('hello.html', name=name) + +.. class:: incremental + +Flask looks for a ``templates`` directory in the same location as your app +module (remember ``app = Flask(__name__)``?). + +.. class:: incremental + +Any extra variables you want to pass to the template should be keyword +arguments to ``render_template`` + +Flask Template Context +---------------------- + +Flask adds a few things to the context of templates. You can use these + +.. class:: incremental + +* **config**: contains the current configuration object +* **request**: contains the current request object +* **session**: any session data that might be available +* **g**: the request-local object to which global variables are bound +* **get_flashed_messages**: a function that returns messages you flash to your + users (more on this later). +* **url_for**: so you can easily *reverse* urls from within your templates + +Lab 1 +----- + +Open a terminal, change directories to the class repository, then to +``assignments/week05/lab/book_app``. + +.. class:: incremental + +* You'll find a file ``book_app.py`` which is all set up and ready to go +* You'll also find a ``templates`` directory with some templates +* Complete the functions to provide the right stuff to the templates +* Complete the templates to display the data to the end-user +* At the end you should have a reproduced version of last week's homework + +.. class:: incremental center + +**GO** + +Lab 2 - Part 1 +-------------- + +The rest of class today will be devoted to building and deploying a simple +micro-blog app using flask. + +.. class:: incremental + +This is based almost entirely on the `Flaskr tutorial +`_ from the Flask website. + +Data Persistence +---------------- + +There are many models for persistance of data. + +.. class:: incremental + +* Flat files +* Relational Database (SQL RDBMs like PostgreSQL, MySQL, SQLServer, Oracle) +* Object Stores (Pickle, ZODB) +* NoSQL Databases (CouchDB, MongoDB, etc) + +.. class:: incremental + +It's also one of the most contentious issues in app design. + +.. class:: incremental + +For this reason, it's one of the things that most Small Frameworks leave +undecided. + +Simple SQL +---------- + +For our second lab exercise today, we're going to use a simple SQL database. + +.. class:: incremental + +Python `PEP 249 `_ describes a +common API for database connections called DB API. + +.. class:: incremental + +The Python Standard Library comes with an implementation of this for a common, +light-weight sql database, sqlite3 + +.. class:: incremental + +I am *not* going to talk a lot about SQL. It's too deep a pool for us to get +into. We'll concentrate only on those bits we need to get along. + +Our Database +------------ + +We're going to keep this really really simple. + +.. class:: incremental + +In ``assignments/week05/lab/`` find the ``flaskr_1`` directory and open the +``schema.sql`` file in your editor. Add the following and save the file: + +.. code-block:: sql + :class: incremental + + drop table if exists entries; + create table entries ( + id integer primary key autoincrement, + title string not null, + text string not null + ); + +Our App +------- + +We'll also need to do some configuration for our app. + +.. class:: incremental + +In that same directory, find the file ``flaskr.py`` and open it in your +editor. Add the following and save the file: + +.. code-block:: python + :class: incremental + + # configuration goes here + DATABASE = '/tmp/flaskr.db' + SECRET_KEY = 'development key' + + app = Flask(__name__) # this is already in the file + app.config.from_object(__name__) + + +Creating the Database +--------------------- + +Still in ``flaskr.py`` let's add a function that will connect to our database: + +.. code-block:: python + :class: incremental + + # add this at the very top + import sqlite3 + + # add the rest of this below the app.config statement + def connect_db(): + return sqlite3.connect(app.config['DATABASE']) + +.. class:: incremental -Intro to Flask +This will be a convenience to us later on, and it will allow us to write our +very first test. -Lab 1 create simple multi-page app with flask (redo week 4 homework in class) +Tests and TDD +------------- -templating (jinja2 in flask) +.. class:: center + +**If it isn't tested, it's broken** + +.. class:: incremental + +Test-Driven Development means writing the tests before writing the functions. +As your tests pass, you know you're building what you want. + +.. class:: incremental + +We are going to write tests at every step of this lab. Along the way, we'll +learn a bit about the Python Standard Library module ``unittest``. + +.. class:: incremental + +You'll want to read more about this module. See our outline for reading +suggestions. + +Testing Setup +------------- + +In the same ``flaskr_1`` directory, find and open the ``flaskr_tests.py`` file +in your editor. Edit it to look like this: + +.. code-block:: python + :class: small + + import os + import flaskr + import unittest + import tempfile + + class FlaskrTestCase(unittest.TestCase): + + def setUp(self): + db_fd = tempfile.mkstemp() + self.db_fd, flaskr.app.config['DATABASE'] = db_fd + flaskr.app.config['TESTING'] = True + self.client = flaskr.app.test_client() + self.app = flaskr.app + +Testing Teardown +---------------- + +Add the following method to your test class: + +.. code-block:: python + + class FlaskrTestCase(unittest.TestCase): + ... + + def tearDown(self): + os.close(self.db_fd) + os.unlink(flaskr.app.config['DATABASE']) + +Make Tests Runnable +------------------- + +And finally, add the following at the bottom of your ``flaskr_tests.py`` file: + +.. code-block:: python + + if __name__ == '__main__': + unittest.main() + +.. class:: incremental + +Now, we're ready to add our first method. + +Test Databse Setup +------------------ + +We'd like to test that our database is correctly initialized. The schema has +one table with three columns. Let's test that. + +Add the following method to your test class in ``flaskr_tests.py``: + +.. code-block:: python + + def test_database_setup(self): + con = flaskr.connect_db() + cur = con.execute('PRAGMA table_info(entries);') + rows = cur.fetchall() + self.assertEquals(len(rows), 3) + +Run the Tests +------------- + +Since we added that ``if __name__ == '__main__'`` block, we can simply run our +tests with a flask-aware python executable: + +.. class:: small + +:: + + (flaskenv)$ python flaskr_tests.py + F + ====================================================================== + FAIL: test_database_setup (__main__.FlaskrTestCase) + ---------------------------------------------------------------------- + Traceback (most recent call last): + File "flaskr_tests.py", line 23, in test_database_setup + self.assertTrue(len(rows) == 3) + AssertionError: False is not True + + ---------------------------------------------------------------------- + Ran 1 test in 0.011s + + FAILED (failures=1) + +Make the Test Pass +------------------ + +Our database hasn't actually be properly created. We have no table and so no +rows are returned when we try to describe it. Let's fix that. Add the +following to ``flaskr.py``: + +.. code-block:: python + + # add this import at the top + from contextlib import closing + + # add this function after the connect_db function + def init_db(): + with closing(connect_db()) as db: + with app.open_resource('schema.sql') as f: + db.cursor().executescript(f.read()) + db.commit() + +Initialize the DB in Tests +-------------------------- + +We also need to call that function in our ``flaskr_tests.py``, in the +``setUp`` method of our test case. + +Add the following line at the end of that ``setUp`` method: + +.. code-block:: python + + def setUp(self): + ... + flaskr.init_db() # <- add this at the end + +.. class:: incremental + +Then, re-run the tests (``python flaskr_tests.py``) and see what you get. + +.. class:: incremental center -Deploying to webserver (virtualenv and mod_wsgi) +**Wahoooo!** -Lab 2 create a simple app with flask part 2 +Initialize the DB IRL +--------------------- + +Okay, so we know the ``init_db`` function we added sets up the database +properly. + +.. class:: incremental + +We still need to do this in real life, so that we can work against the +database. + +.. class:: incremental + +Start up a python interpreter in your ``flaskr_1`` folder and do the +following: + +.. code-block:: python + :class: incremental + + import flaskr + flaskr.init_db() + ^D + +Lab 2 - Part 2 +-------------- + +Okay, we have a database. Now it's time to write stuff into it, and read it +back. + +.. class:: incremental + +Once again, we're going to start by writing tests. + +.. class:: incremental + +If you've fallen behind, or if you just want to start fresh, you can find the +base of what we've done so far in the ``flaskr_2`` folder. + +Managing DB Connections +----------------------- + +Database connections should be bound to the borders of a request/response. + +.. class:: incremental + +Flask provides decorators that mark functions to be run at these borders: + +.. class:: incremental + +* ``@before_request``: any method decorated by this will be called before the + cycle begins +* ``@after_request``: any method decorated by this will be called after the + cycle is complete. If an unhandled exception occurs, these functions are + skipped. +* ``@teardown_request``: any method decorated by this will be called at the + end of the cycle, even if an unhandled exception occurs. + +Manage our DB +------------- + +Add the following code to our app (``flaskr.py``): + +.. code-block:: python + :class: small + + # add this import at the top: + from flask import g + + # add these function after init_db + @app.before_request + def before_request(): + g.db = connect_db() + + @app.teardown_request + def teardown_request(exception): + g.db.close() + +.. class:: incremental + +We bind our db connection to the 'g' object, which is a global context flask +supplies to each request. + +Test Writing Entries +-------------------- + +We want to test that we can write an entry by providing a title and text. Add +the following method to ``flaskr_tests.py``: + +.. code-block:: python + :class: small + + def test_write_entry(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.write_entry(*expected) + con = flaskr.connect_db() + cur = con.execute("select * from entries;") + rows = cur.fetchall() + self.assertEquals(len(rows), 1) + for val in expected: + self.assertTrue(val in rows[0]) + +.. class:: incremental + +Note that we have to set up a request context, and preprocess it to get our +@before_request method run. + +Write an Entry +-------------- + +Now we are ready to write an entry to our database. Add this function to +``flaskr.py``: + +.. code-block:: python + + def write_entry(title, text): + g.db.execute('insert into entries (title, text) values (?, ?)', + [title, text]) + g.db.commit() + +.. class:: incremental + +When you're done, re-run your tests. You should now be two for two. + +Test Reading Entries +-------------------- + +.. code-block:: python + :class: small + + def test_get_all_entries_empty(self): + with self.app.test_request_context('/'): + self.app.preprocess_request() + entries = flaskr.get_all_entries() + self.assertEquals(len(entries), 0) + + def test_get_all_entries(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.write_entry(*expected) + entries = flaskr.get_all_entries() + self.assertEquals(len(entries), 1) + for entry in entries: + self.assertEquals(expected[0], entry['title']) + self.assertEquals(expected[1], entry['text']) + +Read Entries +------------ + +Okay, so now we have 4 tests, and two fail, add this function to ``flaskr.py``: + +.. code-block:: python + :class: small + + def get_all_entries(): + cur = g.db.execute('select title, text from entries order by id desc') + entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()] + return entries + +.. class:: incremental + +Re-run your tests. You should now have four passing tests. Great Job! + +Lab 2 - Part 3 +-------------- + +Now we can read and write blog entries, let's add views so we can see what +we're doing. + +.. class:: incremental + +Again. Tests come first. + +.. class:: incremental + +And again, if you've fallen behind or want to start clean, the completed code +from our last step is in ``flaskr_3`` + +Test the Front Page +------------------- + +Add the following tests to ``flaskr_tests.py``: + +.. code-block:: + + def test_empty_listing(self): + rv = self.client.get('/') + assert 'No entries here so far' in rv.data + + def test_listing(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.write_entry(*expected) + rv = self.client.get('/') + for value in expected: + assert value in rv.data + +Template Inheritance +-------------------- + +One aspect of Jinja2 templates we haven't seen yet is that templates can +inherit structure from other templates. + +.. class:: incremental + +* you can make replaceable blocks in templates with blocks: ``{% block foo + %}{% endblock %}``. +* you can build on a template in a second template by extending: ``{% extends + "layout.html" %}`` (this *must* be first) + +.. class:: incremental + +We want the parts of our app to look alike, so let's create a basic layout +first. Create a file ``layout.html`` in the ``templates`` directory. + +Creating Layout +--------------- + +.. code-block:: jinja + + + + + Flaskr + + +

    Flaskr

    +
    + {% block body %}{% endblock %} +
    + + + +Extending Layout +---------------- + +Create a new file, ``show_entries.html`` in ``templates``: + +.. code-block:: jinja + :class: small + + {% extends "layout.html" %} + {% block body %} +

    Posts

    +
      + {% for entry in entries %} +
    • +

      {{ entry.title }}

      +
      + {{ entry.text|safe }} +
      +
    • + {% else %} +
    • No entries here so far
    • + {% endfor %} +
    + {% endblock %} + +Creating a View +--------------- + +Now, we just need to hook up our entries to that template. In ``flaskr.py`` +add the following code: + +.. code-block:: python + + # at the top, import + from flask import render_template + + # and after our last functions: + @app.route('/') + def show_entries(): + entries = get_all_entries() + return render_template('show_entries.html', entries=entries) + +.. class:: incremental + +Run our tests. Should be 6 for 6 now. + +Authentication +-------------- + +We don't want just anyone to be able to add new entries. So we want to be able +to authenticate a user. + +.. class:: incremental + +We'll be using built-in functionality of Flask to do this, but this +simplest-possible implementation should serve only as a guide. + +.. class:: incremental + +We'll start with the tests, of course. + +Test Authentication +------------------- + +Back in ``flaskr_tests.py`` add new test methods: + +.. code-block:: python + :class: small + + def test_login_passes(self): + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.do_login(flaskr.app.config['USERNAME'], + flaskr.app.config['PASSWORD']) + self.assertTrue(session.get('logged_in', False)) + + def test_login_fails(self): + with self.app.test_request_context('/'): + self.app.preprocess_request() + self.assertRaises(ValueError, flaskr.do_login, + flaskr.app.config['USERNAME'], + 'incorrectpassword') + +Set Up Authentication +--------------------- + +Now, let's add the code in ``flaskr.py`` to support this: + +.. code-block:: python + :class: small + + # add an import + from flask import session + + # and configuration + USERNAME = 'admin' + PASSWORD = 'default' + + # and a function + def do_login(usr, pwd): + if usr != app.config['USERNAME']: + raise ValueError + elif pwd != app.config['PASSWORD']: + raise ValueError + else: + session['logged_in'] = True + +Login/Logout in Tests +--------------------- + +Let's add tests for a view. We'll set up a form that redirects back to the +main view on success. First, methods to actually do the login/logout (in +``flaskr_tests.py``): + +.. code-block:: python + + def login(self, username, password): + return self.client.post('/login', data=dict( + username=username, + password=password + ), follow_redirects=True) + + def logout(self): + return self.client.get('/logout', + follow_redirects=True) + +Test Authentication +------------------- + +And now the test itself (again, ``flaskr_tests.py``): + +.. code-block:: python + + def test_login_logout(self): + rv = self.login('admin', 'default') + assert 'You were logged in' in rv.data + rv = self.logout() + assert 'You were logged out' in rv.data + rv = self.login('adminx', 'default') + assert 'Invalid username' in rv.data + rv = self.login('admin', 'defaultx') + assert 'Invalid password' in rv.data + +.. class:: incremental + +We should be up to 9 tests, one failing + +Add Login Template +------------------ + +Add ``login.html`` to ``templates``: + +.. code-block:: jinja + :class: tiny + + {% extends "layout.html" %} + {% block body %} +

    Login

    + {% if error -%} +

    Error {{ error }} + {%- endif %} +

    +
    + + +
    +
    + + +
    +
    + +
    +
    + {% endblock %} + +Add Login/Logout Views +---------------------- + +And back in ``flaskr.py`` add new code. Let's start with imports: + +.. code-block:: python + + # at the top, new imports + from flask import request + from flask import redirect + from flask import flash + from flask import url_for + +And the View Code +----------------- + +.. code-block:: python + :class: small + + @app.route('/login', methods=['GET', 'POST']) + def login(): + error = None + if request.method == 'POST': + try: + do_login(request.form['username'], + request.form['password']) + except ValueError: + error = "Invalid Login" + else: + flash('You were logged in') + return redirect(url_for('show_entries')) + return render_template('login.html', error=error) + + @app.route('/logout') + def logout(): + session.pop('logged_in', None) + flash('You were logged out') + return redirect(url_for('show_entries')) + +About Flash +----------- + +.. class:: small + +Flask provides ``flash`` as a way of sending messages to the user from view +code. We need a place to show these messages. Add it to ``layout.html`` (along +with links to log in and out) + +.. code-block:: jinja + :class: small + +

    Flaskr

    +
    + {% if not session.logged_in %} + log in + {% else %} + log_out + {% endif %} +
    + {% for message in get_flashed_messages() %} +
    {{ message }}
    + {% endfor %} +
    + +Adding an Entry +--------------- + +We still lack a way to add an entry. We need a view to do that. Again, tests +first (in ``flaskr_tests.py``): + +.. code-block:: python + + def test_add_entries(self): + self.login('admin', 'default') + rv = self.client.post('/add', data=dict( + title='Hello', + text='This is a post' + ), follow_redirects=True) + assert 'No entries here so far' not in rv.data + assert 'Hello' in rv.data + assert 'This is a post' in rv.data + +Add the View +------------ + +We've already got all the stuff we need to write entries, we just need an +endpoint that will do it via the web (in ``flaskr.py``): + +.. code-block:: python + :class: small + + # add an import + from flask import abort + + @app.route('/add', methods=['POST']) + def add_entry(): + if not session.get('logged_in'): + abort(401) + try: + write_entry(request.form['title'], request.form['text']) + flash('New entry was successfully posted') + except sqlite3.Error as e: + flash('There was an error: %s' % e.args[0]) + return redirect(url_for('show_entries')) + +Where do Entries Come From +-------------------------- + +Finally, we're almost done. We can log in and log out. We can add entries and +view them. But look at that last view. Do you see a call to +``render_template`` in there at all? + +.. class:: incremental + +There isn't one. That's because that view is never meant to be be visible. +Look carefully at the logic. What happens? + +.. class:: incremental + +So where do the form values come from? + +.. class:: incremental + +Let's add a form to the main view. Open ``show_entries.html`` + +Provide a Form +-------------- + +.. code-block:: jinja + :class: small + + {% block body %} + {% if session.logged_in %} +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + {% endif %} +

    Posts

    + +All Done +-------- + +Okay. That's it. We've got an app all written. + +.. class:: incremental + +So far, we haven't actually touched our browsers at all, but we have +reasonable certainty that this works because of our tests. Let's try it. + + +.. class:: incremental + +In the terminal where you've been running tests, run our flaskr app: + +.. class:: incremental + +:: + + (flaskenv)$ python flaskr.py + * Running on http://127.0.0.1:5000/ + * Restarting with reloader + +The Big Payoff +-------------- + +Now load ``http://localhost:5000/`` in your browser and enjoy your reward. + +Lab 2 - Part 4 +-------------- + +On the other hand, what we've got here is pretty ugly. We could prettify it. + +.. class:: incremental + +Again, if you want to start fresh or you fell behind you can find code +completed to this point in ``flaskr_4``. + +.. class:: incremental + +In that directory inside the ``static`` directory you will find +``styles.css``. Open it in your editor. It contains basic CSS for this app. + +.. class:: incremental + +We'll need to include this file in our ``layout.html``. + +Static Files +------------ + +Like page templates, Flask locates static resources like images, css and +javascript by looking for a ``static`` directory next to the app module. + +.. class:: incremental + +You can use the special url endpoint ``static`` to build urls that point here. +Open ``layout.html`` and add the following: + +.. code-block:: jinja + :class: small incremental + + + Flaskr + + + + +Deploying +--------- + +First, move the source code to your VM:: + + (flaskenv)$ cd ../ + (flaskenv)$ tar -czvf flaskr.tgz flaskr + (flaskenv)$ scp flaskr.tgz :~/ + (flaskenv)$ ssh + $ tar -zxvf flaskr.tgz + +Then, on your VM, set up a virtualenv with Flask installed + +Deploying +--------- + +You'll need to make some changes to mod_wsgi configuration. + +* Open ``/etc/apache2/sites-available/default`` in an editor (on the VM) + +* Add the following line at the top (outside the VirtualHost block): + ``WSGIPythonHome /path/to/flaskenv`` + +* Delete all other lines refering to mod_wsgi configuration +* Add the following in the VirtualHost block: + +:: + + WSGIScriptAlias / /var/www/flaskr.wsgi + +Deploying +--------- + +Finally, you'll need to add the named wsgi file and edit it to match:: + + $ sudo touch /var/www/flaskr.wsgi + $ sudo vi /var/www/flasrk.wsgi + + + import sys + sys.path.insert(0, 'path/to/flaskr') # the flaskr app you uploaded + + from flaskr import app as application + +Deploying +--------- + +Finally, restart apache and bask in the glow:: + + $ sudo apache2ctl configtest + $ sudo /etc/init.d/apache2 graceful + +Load http://your_vm/ + +Wheeee! + +Going Further +------------- + +It's not too hard to see ways you could improve this. + +.. class:: incremental + +* For my part, I made a version using Bootstrap.js. +* You could limit the number of posts shown on the front page. +* You could add dates to the posts and provide archived views for older posts. +* You could add the ability to edit existing posts (and add an updated date to the schema) +* ... + +But Instead +----------- + +Instead of doing any of that, this week's assignment is a bit different. + +.. class:: incremental + +You've implemented an app in one Small Framework. I want you to do it all +again, in a different Small Framework. + +.. class:: incremental + +While you're working on it, think about the differences between your new +Framework and Flask. What do you like more? What do you like less? How might +this influence your choice of Frameworks in the future? + +Assignment +---------- +* Re-implement the Flaskr app we built in class in a different Small + Framework. +* There are several named in the class outline, and in this presentation. +* Pick one of them, or a different one of your choice. It must be Python. +* When you are finished, add your source code and a README that talks about + your experience to the ``athome`` folder of week05. +* Tell me about your new Framework. Discuss the points above regarding + differences. + +Submitting The Assignment +------------------------- + +* Try to get your code running on your VM +* Add your source code, in it's entirety, to the ``athome`` folder for week 5 +* Add a README.txt file that discusses the experience. +* Commit your changes to your fork of the class repository and send me a pull + request From 73cd2428369b091e26e74bb63588db3736894a62 Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 3 Feb 2013 06:53:03 -0800 Subject: [PATCH 050/487] * add completed flaskr app w/ bootstrappy goodness --- .../week05/answers/book_app/book_app.py | 24 +++++ .../week05/answers/book_app/bookdb.py | 39 ++++++++ .../book_app/templates/book_detail.html | 15 +++ .../answers/book_app/templates/book_list.html | 16 +++ .../teachers/week05/answers/flaskr/flaskr.py | 93 ++++++++++++++++++ .../week05/answers/flaskr/flaskr_tests.py | 40 ++++++++ .../teachers/week05/answers/flaskr/schema.sql | 6 ++ .../flaskr/static/css/bootstrap.min.css | 9 ++ .../static/img/glyphicons-halflings-white.png | Bin 0 -> 8777 bytes .../static/img/glyphicons-halflings.png | Bin 0 -> 12799 bytes .../answers/flaskr/static/js/bootstrap.min.js | 6 ++ .../answers/flaskr/templates/layout.html | 55 +++++++++++ .../answers/flaskr/templates/login.html | 32 ++++++ .../flaskr/templates/show_entries.html | 49 +++++++++ 14 files changed, 384 insertions(+) create mode 100644 assignments/teachers/week05/answers/book_app/book_app.py create mode 100644 assignments/teachers/week05/answers/book_app/bookdb.py create mode 100644 assignments/teachers/week05/answers/book_app/templates/book_detail.html create mode 100644 assignments/teachers/week05/answers/book_app/templates/book_list.html create mode 100644 assignments/teachers/week05/answers/flaskr/flaskr.py create mode 100644 assignments/teachers/week05/answers/flaskr/flaskr_tests.py create mode 100644 assignments/teachers/week05/answers/flaskr/schema.sql create mode 100644 assignments/teachers/week05/answers/flaskr/static/css/bootstrap.min.css create mode 100644 assignments/teachers/week05/answers/flaskr/static/img/glyphicons-halflings-white.png create mode 100644 assignments/teachers/week05/answers/flaskr/static/img/glyphicons-halflings.png create mode 100644 assignments/teachers/week05/answers/flaskr/static/js/bootstrap.min.js create mode 100644 assignments/teachers/week05/answers/flaskr/templates/layout.html create mode 100644 assignments/teachers/week05/answers/flaskr/templates/login.html create mode 100644 assignments/teachers/week05/answers/flaskr/templates/show_entries.html diff --git a/assignments/teachers/week05/answers/book_app/book_app.py b/assignments/teachers/week05/answers/book_app/book_app.py new file mode 100644 index 00000000..21c83725 --- /dev/null +++ b/assignments/teachers/week05/answers/book_app/book_app.py @@ -0,0 +1,24 @@ +from flask import Flask +from flask import render_template + +import bookdb + +app = Flask(__name__) + +db = bookdb.BookDB() + + +@app.route('/') +def books(): + books = db.titles() + return render_template('book_list.html', books=books) + + +@app.route('/book//') +def book(book_id): + book = db.title_info(book_id) + return render_template('book_detail.html', book=book) + + +if __name__ == '__main__': + app.run(debug=True) diff --git a/assignments/teachers/week05/answers/book_app/bookdb.py b/assignments/teachers/week05/answers/book_app/bookdb.py new file mode 100644 index 00000000..49769f37 --- /dev/null +++ b/assignments/teachers/week05/answers/book_app/bookdb.py @@ -0,0 +1,39 @@ + + +class BookDB(): + def titles(self): + titles = [dict(id=id, title=database[id]['title']) for id in database.keys()] + return titles + + def title_info(self, id): + return database[id] + + +# let's pretend we're getting this information from a database somewhere +database = { + 'id1' : {'title' : 'CherryPy Essentials: Rapid Python Web Application Development', + 'isbn' : '978-1904811848', + 'publisher' : 'Packt Publishing (March 31, 2007)', + 'author' : 'Sylvain Hellegouarch', + }, + 'id2' : {'title' : 'Python for Software Design: How to Think Like a Computer Scientist', + 'isbn' : '978-0521725965', + 'publisher' : 'Cambridge University Press; 1 edition (March 16, 2009)', + 'author' : 'Allen B. Downey', + }, + 'id3' : {'title' : 'Foundations of Python Network Programming', + 'isbn' : '978-1430230038', + 'publisher' : 'Apress; 2 edition (December 21, 2010)', + 'author' : 'John Goerzen', + }, + 'id4' : {'title' : 'Python Cookbook, Second Edition', + 'isbn' : '978-0-596-00797-3', + 'publisher' : 'O''Reilly Media', + 'author' : 'Alex Martelli, Anna Ravenscroft, David Ascher', + }, + 'id5' : {'title' : 'The Pragmatic Programmer: From Journeyman to Master', + 'isbn' : '978-0201616224', + 'publisher' : 'Addison-Wesley Professional (October 30, 1999)', + 'author' : 'Andrew Hunt, David Thomas', + }, +} diff --git a/assignments/teachers/week05/answers/book_app/templates/book_detail.html b/assignments/teachers/week05/answers/book_app/templates/book_detail.html new file mode 100644 index 00000000..33a690a4 --- /dev/null +++ b/assignments/teachers/week05/answers/book_app/templates/book_detail.html @@ -0,0 +1,15 @@ + + + + {{ book.title }} + + +

    {{ book.title }}

    +
    +
    Author
    {{ book.author }}
    +
    Publisher
    {{ book.publisher }}
    +
    ISBN
    {{ book.isbn }}
    +
    +

    Back to the list

    + + diff --git a/assignments/teachers/week05/answers/book_app/templates/book_list.html b/assignments/teachers/week05/answers/book_app/templates/book_list.html new file mode 100644 index 00000000..25b0b5ab --- /dev/null +++ b/assignments/teachers/week05/answers/book_app/templates/book_list.html @@ -0,0 +1,16 @@ + + + + Python Books + + +

    Summer Reading

    +

    Here's a list of books you might enjoy. Click a title to read more + about that book.

    + + + diff --git a/assignments/teachers/week05/answers/flaskr/flaskr.py b/assignments/teachers/week05/answers/flaskr/flaskr.py new file mode 100644 index 00000000..335efe65 --- /dev/null +++ b/assignments/teachers/week05/answers/flaskr/flaskr.py @@ -0,0 +1,93 @@ +import sqlite3 +from contextlib import closing + +from flask import Flask +from flask import request +from flask import session +from flask import g +from flask import redirect +from flask import url_for +from flask import abort +from flask import render_template +from flask import flash + +# configuration +DATABASE = '/tmp/flaskr.db' +DEBUG = True +SECRET_KEY = 'devkey' +USERNAME = 'admin' +PASSWORD = 'default' + + +app = Flask(__name__) +app.config.from_object(__name__) + +def connect_db(): + return sqlite3.connect(app.config['DATABASE']) + + +def init_db(): + with closing(connect_db()) as db: + with app.open_resource('schema.sql') as f: + db.cursor().executescript(f.read()) + db.commit() + + +@app.before_request +def before_request(): + g.db = connect_db() + + +@app.teardown_request +def teardown_request(exception): + g.db.close() + + +def get_all_entries(): + cur = g.db.execute('select title, text from entries order by id desc') + entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()] + return entries + + +@app.route('/') +def show_entries(): + entries = get_all_entries() + return render_template('show_entries.html', entries=entries) + + +@app.route('/add', methods=['POST']) +def add_entry(): + if not session.get('logged_in'): + abort(401) + g.db.execute('insert into entries (title, text) values (?, ?)', + [request.form['title'], request.form['text']]) + g.db.commit() + flash('New entry was successfully posted') + return redirect(url_for('show_entries')) + + +@app.route('/login', methods=['GET', 'POST']) +def login(): + error = None + if request.method == 'POST': + if request.form['username'] != app.config['USERNAME']: + error = 'Invalid Username' + elif request.form['password'] != app.config['PASSWORD']: + error = 'Invalid Password' + else: + session['logged_in'] = True + flash('You are logged in') + return redirect(url_for('show_entries')) + return render_template('login.html', error=error) + + +@app.route('/logout') +def logout(): + session.pop('logged_in', None) + flash('You are now logged out') + return redirect(url_for('show_entries')) + + +if __name__ == '__main__': + app.run() + diff --git a/assignments/teachers/week05/answers/flaskr/flaskr_tests.py b/assignments/teachers/week05/answers/flaskr/flaskr_tests.py new file mode 100644 index 00000000..f5d93417 --- /dev/null +++ b/assignments/teachers/week05/answers/flaskr/flaskr_tests.py @@ -0,0 +1,40 @@ +import os +import flaskr +import unittest +import tempfile + + +class FlaskrTestCase(unittest.TestCase): + + def setUp(self): + self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp() + flaskr.app.config['TESTING'] = True + self.app = flaskr.app.test_client() + flaskr.init_db() + + def tearDown(self): + os.close(self.db_fd) + os.unlink(flaskr.app.config['DATABASE']) + + + def login(self, username, password): + return self.app.post('/login', data=dict( + username=username, + password=password + ), follow_redirects=True) + + + def logout(self): + return self.app.get('/logout', follow_redirects=True) + + + def test_get_all_entries_empty(self): + with self.app.test_request_context('/'): + self.app.preprocess_request() + entries = flaskr.get_all_entries() + self.assertEquals(entries, []) + + +if __name__ == '__main__': + unittest.main() + diff --git a/assignments/teachers/week05/answers/flaskr/schema.sql b/assignments/teachers/week05/answers/flaskr/schema.sql new file mode 100644 index 00000000..71fe0588 --- /dev/null +++ b/assignments/teachers/week05/answers/flaskr/schema.sql @@ -0,0 +1,6 @@ +drop table if exists entries; +create table entries ( + id integer primary key autoincrement, + title string not null, + text string not null +); diff --git a/assignments/teachers/week05/answers/flaskr/static/css/bootstrap.min.css b/assignments/teachers/week05/answers/flaskr/static/css/bootstrap.min.css new file mode 100644 index 00000000..140f731d --- /dev/null +++ b/assignments/teachers/week05/answers/flaskr/static/css/bootstrap.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap v2.2.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{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}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,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}.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}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .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;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.127659574468085%;*margin-left:2.074468085106383%;-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 .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:hover{color:#808080}.text-warning{color:#c09853}a.text-warning:hover{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover{color:#2d6987}.text-success{color:#468847}a.text-success:hover{color:#356635}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;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}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-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 .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-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)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-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)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.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-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[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-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)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),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 .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-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)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),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 .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-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)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),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}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-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)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus: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:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{margin-bottom:5px;font-size:0;white-space:nowrap}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 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 input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 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;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{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-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.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 #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.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-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover td,.table-hover tbody tr:hover th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success td{background-color:#dff0d8}.table tbody tr.error td{background-color:#f2dede}.table tbody tr.warning td{background-color:#fcf8e3}.table tbody tr.info td{background-color:#d9edf7}.table-hover tbody tr.success:hover td{background-color:#d0e9c6}.table-hover tbody tr.error:hover td{background-color:#ebcccc}.table-hover tbody tr.warning:hover td{background-color:#faf2cc}.table-hover tbody tr.info:hover td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("http://github.com/img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:url("http://github.com/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{width:16px;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{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.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-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-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}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu li>a:hover,.dropdown-menu li>a:focus,.dropdown-submenu:hover>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .disabled>a,.dropdown-menu .disabled>a:hover{color:#999}.dropdown-menu .disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;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 #e3e3e3;-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{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #bbb;*border: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);border-bottom-color:#a2a2a2;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-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)}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .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;outline:0;-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)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.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{border-color:#c5c5c5;border-color:rgba(0,0,0,0.15) rgba(0,0,0,0.15) rgba(0,0,0,0.25)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #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(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-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(to bottom,#fbb450,#f89406);background-repeat:repeat-x;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(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-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(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;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(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-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(to bottom,#62c462,#51a351);background-repeat:repeat-x;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(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-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(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;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(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;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(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}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-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright: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>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left: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)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{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)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-mini .caret,.btn-small .caret,.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;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}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success h4{color:#468847}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info h4{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-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-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:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;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:20px;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:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.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:#fff;background-color:#08c}.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-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.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-top-color:#ddd;border-bottom-color:transparent}.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:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.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:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:hover{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;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,.navbar-form .btn{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:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius: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-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #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(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);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)}.navbar .btn-navbar:hover,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .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}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret{border-top-color:#555;border-bottom-color:#555}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover{color:#fff}.navbar-inverse .brand{color:#999}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline: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)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;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(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-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 ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{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 li>a:hover{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;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;outline:0;-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{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-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}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.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;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{margin-top:-3px}.tooltip.right{margin-left:3px}.tooltip.bottom{margin-top:3px}.tooltip.left{margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;width:236px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-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}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover{border-color:#08c;-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-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media .pull-left{margin-right:10px}.media .pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-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(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',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)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;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:-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(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',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;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.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:-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;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-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(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{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:-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,.progress .bar-success{background-color:#5eb95e;background-image:-moz-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(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{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:-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,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-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(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{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:-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,.progress .bar-warning{background-color:#faa732;background-image:-moz-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(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{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:-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:20px}.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-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.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:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed} diff --git a/assignments/teachers/week05/answers/flaskr/static/img/glyphicons-halflings-white.png b/assignments/teachers/week05/answers/flaskr/static/img/glyphicons-halflings-white.png new file mode 100644 index 0000000000000000000000000000000000000000..3bf6484a29d8da269f9bc874b25493a45fae3bae GIT binary patch literal 8777 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 B7G?kd literal 0 HcmV?d00001 diff --git a/assignments/teachers/week05/answers/flaskr/static/img/glyphicons-halflings.png b/assignments/teachers/week05/answers/flaskr/static/img/glyphicons-halflings.png new file mode 100644 index 0000000000000000000000000000000000000000..a9969993201f9cee63cf9f49217646347297b643 GIT binary patch literal 12799 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 literal 0 HcmV?d00001 diff --git a/assignments/teachers/week05/answers/flaskr/static/js/bootstrap.min.js b/assignments/teachers/week05/answers/flaskr/static/js/bootstrap.min.js new file mode 100644 index 00000000..6eeb15ce --- /dev/null +++ b/assignments/teachers/week05/answers/flaskr/static/js/bootstrap.min.js @@ -0,0 +1,6 @@ +/*! +* Bootstrap.js by @fat & @mdo +* Copyright 2012 Twitter, Inc. +* http://www.apache.org/licenses/LICENSE-2.0.txt +*/ +!function($){"use strict";$(function(){$.support.transition=function(){var transitionEnd=function(){var name,el=document.createElement("bootstrap"),transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(name in transEndEventNames)if(void 0!==el.style[name])return transEndEventNames[name]}();return transitionEnd&&{end:transitionEnd}}()})}(window.jQuery),!function($){"use strict";var dismiss='[data-dismiss="alert"]',Alert=function(el){$(el).on("click",dismiss,this.close)};Alert.prototype.close=function(e){function removeElement(){$parent.trigger("closed").remove()}var $parent,$this=$(this),selector=$this.attr("data-target");selector||(selector=$this.attr("href"),selector=selector&&selector.replace(/.*(?=#[^\s]*$)/,"")),$parent=$(selector),e&&e.preventDefault(),$parent.length||($parent=$this.hasClass("alert")?$this:$this.parent()),$parent.trigger(e=$.Event("close")),e.isDefaultPrevented()||($parent.removeClass("in"),$.support.transition&&$parent.hasClass("fade")?$parent.on($.support.transition.end,removeElement):removeElement())};var old=$.fn.alert;$.fn.alert=function(option){return this.each(function(){var $this=$(this),data=$this.data("alert");data||$this.data("alert",data=new Alert(this)),"string"==typeof option&&data[option].call($this)})},$.fn.alert.Constructor=Alert,$.fn.alert.noConflict=function(){return $.fn.alert=old,this},$(document).on("click.alert.data-api",dismiss,Alert.prototype.close)}(window.jQuery),!function($){"use strict";var Button=function(element,options){this.$element=$(element),this.options=$.extend({},$.fn.button.defaults,options)};Button.prototype.setState=function(state){var d="disabled",$el=this.$element,data=$el.data(),val=$el.is("input")?"val":"html";state+="Text",data.resetText||$el.data("resetText",$el[val]()),$el[val](data[state]||this.options[state]),setTimeout(function(){"loadingText"==state?$el.addClass(d).attr(d,d):$el.removeClass(d).removeAttr(d)},0)},Button.prototype.toggle=function(){var $parent=this.$element.closest('[data-toggle="buttons-radio"]');$parent&&$parent.find(".active").removeClass("active"),this.$element.toggleClass("active")};var old=$.fn.button;$.fn.button=function(option){return this.each(function(){var $this=$(this),data=$this.data("button"),options="object"==typeof option&&option;data||$this.data("button",data=new Button(this,options)),"toggle"==option?data.toggle():option&&data.setState(option)})},$.fn.button.defaults={loadingText:"loading..."},$.fn.button.Constructor=Button,$.fn.button.noConflict=function(){return $.fn.button=old,this},$(document).on("click.button.data-api","[data-toggle^=button]",function(e){var $btn=$(e.target);$btn.hasClass("btn")||($btn=$btn.closest(".btn")),$btn.button("toggle")})}(window.jQuery),!function($){"use strict";var Carousel=function(element,options){this.$element=$(element),this.options=options,"hover"==this.options.pause&&this.$element.on("mouseenter",$.proxy(this.pause,this)).on("mouseleave",$.proxy(this.cycle,this))};Carousel.prototype={cycle:function(e){return e||(this.paused=!1),this.options.interval&&!this.paused&&(this.interval=setInterval($.proxy(this.next,this),this.options.interval)),this},to:function(pos){var $active=this.$element.find(".item.active"),children=$active.parent().children(),activePos=children.index($active),that=this;if(!(pos>children.length-1||0>pos))return this.sliding?this.$element.one("slid",function(){that.to(pos)}):activePos==pos?this.pause().cycle():this.slide(pos>activePos?"next":"prev",$(children[pos]))},pause:function(e){return e||(this.paused=!0),this.$element.find(".next, .prev").length&&$.support.transition.end&&(this.$element.trigger($.support.transition.end),this.cycle()),clearInterval(this.interval),this.interval=null,this},next:function(){return this.sliding?void 0:this.slide("next")},prev:function(){return this.sliding?void 0:this.slide("prev")},slide:function(type,next){var e,$active=this.$element.find(".item.active"),$next=next||$active[type](),isCycling=this.interval,direction="next"==type?"left":"right",fallback="next"==type?"first":"last",that=this;if(this.sliding=!0,isCycling&&this.pause(),$next=$next.length?$next:this.$element.find(".item")[fallback](),e=$.Event("slide",{relatedTarget:$next[0]}),!$next.hasClass("active")){if($.support.transition&&this.$element.hasClass("slide")){if(this.$element.trigger(e),e.isDefaultPrevented())return;$next.addClass(type),$next[0].offsetWidth,$active.addClass(direction),$next.addClass(direction),this.$element.one($.support.transition.end,function(){$next.removeClass([type,direction].join(" ")).addClass("active"),$active.removeClass(["active",direction].join(" ")),that.sliding=!1,setTimeout(function(){that.$element.trigger("slid")},0)})}else{if(this.$element.trigger(e),e.isDefaultPrevented())return;$active.removeClass("active"),$next.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return isCycling&&this.cycle(),this}}};var old=$.fn.carousel;$.fn.carousel=function(option){return this.each(function(){var $this=$(this),data=$this.data("carousel"),options=$.extend({},$.fn.carousel.defaults,"object"==typeof option&&option),action="http://github.com/string"==typeof option?option:options.slide;data||$this.data("carousel",data=new Carousel(this,options)),"number"==typeof option?data.to(option):action?data[action]():options.interval&&data.cycle()})},$.fn.carousel.defaults={interval:5e3,pause:"hover"},$.fn.carousel.Constructor=Carousel,$.fn.carousel.noConflict=function(){return $.fn.carousel=old,this},$(document).on("click.carousel.data-api","[data-slide]",function(e){var href,$this=$(this),$target=$($this.attr("data-target")||(href=$this.attr("href"))&&href.replace(/.*(?=#[^\s]+$)/,"")),options=$.extend({},$target.data(),$this.data());$target.carousel(options),e.preventDefault()})}(window.jQuery),!function($){"use strict";var Collapse=function(element,options){this.$element=$(element),this.options=$.extend({},$.fn.collapse.defaults,options),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,scroll,actives,hasData;if(!this.transitioning){if(dimension=this.dimension(),scroll=$.camelCase(["scroll",dimension].join("-")),actives=this.$parent&&this.$parent.find("> .accordion-group > .in"),actives&&actives.length){if(hasData=actives.data("collapse"),hasData&&hasData.transitioning)return;actives.collapse("hide"),hasData||actives.data("collapse",null)}this.$element[dimension](0),this.transition("addClass",$.Event("show"),"shown"),$.support.transition&&this.$element[dimension](this.$element[0][scroll])}},hide:function(){var dimension;this.transitioning||(dimension=this.dimension(),this.reset(this.$element[dimension]()),this.transition("removeClass",$.Event("hide"),"hidden"),this.$element[dimension](0))},reset:function(size){var dimension=this.dimension();return this.$element.removeClass("collapse")[dimension](size||"auto")[0].offsetWidth,this.$element[null!==size?"addClass":"removeClass"]("collapse"),this},transition:function(method,startEvent,completeEvent){var that=this,complete=function(){"show"==startEvent.type&&that.reset(),that.transitioning=0,that.$element.trigger(completeEvent)};this.$element.trigger(startEvent),startEvent.isDefaultPrevented()||(this.transitioning=1,this.$element[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"]()}};var old=$.fn.collapse;$.fn.collapse=function(option){return this.each(function(){var $this=$(this),data=$this.data("collapse"),options="object"==typeof option&&option;data||$this.data("collapse",data=new Collapse(this,options)),"string"==typeof option&&data[option]()})},$.fn.collapse.defaults={toggle:!0},$.fn.collapse.Constructor=Collapse,$.fn.collapse.noConflict=function(){return $.fn.collapse=old,this},$(document).on("click.collapse.data-api","[data-toggle=collapse]",function(e){var href,$this=$(this),target=$this.attr("data-target")||e.preventDefault()||(href=$this.attr("href"))&&href.replace(/.*(?=#[^\s]+$)/,""),option=$(target).data("collapse")?"toggle":$this.data();$this[$(target).hasClass("in")?"addClass":"removeClass"]("collapsed"),$(target).collapse(option)})}(window.jQuery),!function($){"use strict";function clearMenus(){$(toggle).each(function(){getParent($(this)).removeClass("open")})}function getParent($this){var $parent,selector=$this.attr("data-target");return selector||(selector=$this.attr("href"),selector=selector&&/#/.test(selector)&&selector.replace(/.*(?=#[^\s]*$)/,"")),$parent=$(selector),$parent.length||($parent=$this.parent()),$parent}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(){var $parent,isActive,$this=$(this);if(!$this.is(".disabled, :disabled"))return $parent=getParent($this),isActive=$parent.hasClass("open"),clearMenus(),isActive||$parent.toggleClass("open"),$this.focus(),!1},keydown:function(e){var $this,$items,$parent,isActive,index;if(/(38|40|27)/.test(e.keyCode)&&($this=$(this),e.preventDefault(),e.stopPropagation(),!$this.is(".disabled, :disabled"))){if($parent=getParent($this),isActive=$parent.hasClass("open"),!isActive||isActive&&27==e.keyCode)return $this.click();$items=$("[role=menu] li:not(.divider):visible a",$parent),$items.length&&(index=$items.index($items.filter(":focus")),38==e.keyCode&&index>0&&index--,40==e.keyCode&&$items.length-1>index&&index++,~index||(index=0),$items.eq(index).focus())}}};var old=$.fn.dropdown;$.fn.dropdown=function(option){return this.each(function(){var $this=$(this),data=$this.data("dropdown");data||$this.data("dropdown",data=new Dropdown(this)),"string"==typeof option&&data[option].call($this)})},$.fn.dropdown.Constructor=Dropdown,$.fn.dropdown.noConflict=function(){return $.fn.dropdown=old,this},$(document).on("click.dropdown.data-api touchstart.dropdown.data-api",clearMenus).on("click.dropdown touchstart.dropdown.data-api",".dropdown form",function(e){e.stopPropagation()}).on("touchstart.dropdown.data-api",".dropdown-menu",function(e){e.stopPropagation()}).on("click.dropdown.data-api touchstart.dropdown.data-api",toggle,Dropdown.prototype.toggle).on("keydown.dropdown.data-api touchstart.dropdown.data-api",toggle+", [role=menu]",Dropdown.prototype.keydown)}(window.jQuery),!function($){"use strict";var Modal=function(element,options){this.options=options,this.$element=$(element).delegate('[data-dismiss="modal"]',"click.dismiss.modal",$.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};Modal.prototype={constructor:Modal,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var that=this,e=$.Event("show");this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.escape(),this.backdrop(function(){var transition=$.support.transition&&that.$element.hasClass("fade");that.$element.parent().length||that.$element.appendTo(document.body),that.$element.show(),transition&&that.$element[0].offsetWidth,that.$element.addClass("in").attr("aria-hidden",!1),that.enforceFocus(),transition?that.$element.one($.support.transition.end,function(){that.$element.focus().trigger("shown")}):that.$element.focus().trigger("shown")}))},hide:function(e){e&&e.preventDefault(),e=$.Event("hide"),this.$element.trigger(e),this.isShown&&!e.isDefaultPrevented()&&(this.isShown=!1,this.escape(),$(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),$.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal())},enforceFocus:function(){var that=this;$(document).on("focusin.modal",function(e){that.$element[0]===e.target||that.$element.has(e.target).length||that.$element.focus()})},escape:function(){var that=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(e){27==e.which&&that.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var that=this,timeout=setTimeout(function(){that.$element.off($.support.transition.end),that.hideModal()},500);this.$element.one($.support.transition.end,function(){clearTimeout(timeout),that.hideModal()})},hideModal:function(){this.$element.hide().trigger("hidden"),this.backdrop()},removeBackdrop:function(){this.$backdrop.remove(),this.$backdrop=null},backdrop:function(callback){var animate=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var doAnimate=$.support.transition&&animate;this.$backdrop=$(' + {% for message in get_flashed_messages() %} +
    {{ message }}
    + {% endfor %} +
    + {% block body %}{% endblock %} +
    + + \ No newline at end of file diff --git a/assignments/week05/lab/flaskr_4/templates/login.html b/assignments/week05/lab/flaskr_4/templates/login.html new file mode 100644 index 00000000..ed4554db --- /dev/null +++ b/assignments/week05/lab/flaskr_4/templates/login.html @@ -0,0 +1,20 @@ +{% extends "layout.html" %} +{% block body %} +

    Login

    + {% if error -%} +

    Error {{ error }} + {%- endif %} +

    +
    + + +
    +
    + + +
    +
    + +
    +
    +{% endblock %} diff --git a/assignments/week05/lab/flaskr_4/templates/show_entries.html b/assignments/week05/lab/flaskr_4/templates/show_entries.html new file mode 100644 index 00000000..f44fd92b --- /dev/null +++ b/assignments/week05/lab/flaskr_4/templates/show_entries.html @@ -0,0 +1,31 @@ +{% extends "layout.html" %} +{% block body %} + {% if session.logged_in %} +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + {% endif %} +

    Posts

    +
      + {% for entry in entries %} +
    • +

      {{ entry.title }}

      +
      + {{ entry.text|safe }} +
      +
    • + {% else %} +
    • No entries here so far
    • + {% endfor %} +
    +{% endblock %} \ No newline at end of file From ea87a017f73cc98ee3ddae8c45e0d112050ed87a Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 3 Feb 2013 07:01:32 -0800 Subject: [PATCH 052/487] * add type-along for week 5 --- assignments/week05/lab/type-along.txt | 761 ++++++++++++++++++++++++++ 1 file changed, 761 insertions(+) create mode 100644 assignments/week05/lab/type-along.txt diff --git a/assignments/week05/lab/type-along.txt b/assignments/week05/lab/type-along.txt new file mode 100644 index 00000000..e8d4c740 --- /dev/null +++ b/assignments/week05/lab/type-along.txt @@ -0,0 +1,761 @@ +But First +--------- + +And Second +---------- + +And Now... +---------- + +A Moment to Reflect +------------------- + +We've built +----------- + +We've built +----------- + +We've built +----------- + +We've built +----------- + +Onward +------ + +From Now On +----------- + +The Abstraction Stack +--------------------- + +Plumbing +-------- + +Tools +----- + +Small Frameworks +---------------- + +Full Stack Frameworks +--------------------- + +Systems +------- + +Frameworks +---------- + +What Does That *Mean*? +---------------------- + +Level of Abstraction +-------------------- + +Python Web Frameworks +--------------------- + +Choosing a Framework +-------------------- + +Cris' First Law of Frameworks +----------------------------- + +Cris' Second Law of Frameworks +------------------------------ + +Preparation +----------- + +Flask +----- + + from flask import Flask + app = Flask(__name__) + + @app.route('/') + def hello_world(): + return 'Hello World!' + + if __name__ == '__main__': + app.run() + + +Running our App +--------------- + + (flaskenv)$ python flask_intro.py + + +Debugging our App +----------------- + + @app.route('/') + def hello_world(): + bar = 1 / 0 + return 'Hello World!' + + if __name__ == '__main__': + app.run(debug=True) + + +What's Happening Here? +---------------------- + +URL Routing +----------- + +Routes Can Be Dynamic +--------------------- + + @app.route('/profile/') + def show_profile(username): + return "My username is %s" % username + + + @app.route('/div//') + def divide(val): + return "%0.2f divided by 2 is %0.2f" % (val, val / 2) + + +Routes Can Be Filtered +---------------------- + + @app.route('/blog/entry//', methods=['GET',]) + def read_entry(id): + return "reading entry %d" % id + + @app.route('/blog/entry//', methods=['POST', ]) + def write_entry(id): + return 'writing entry %d' % id + + +Routes Can Be Reversed +---------------------- + +Reversing URLs in Flask +----------------------- + + from flask import url_for + with app.test_request_context(): + print url_for('endpoint', **kwargs) + + +Reversing in Action +------------------- + + import flask_intro + from flask_intro import app + from flask import url_for + with app.test_request_context(): + print url_for('show_profile', username="cris") + print url_for('divide', val=23.7) + + '/profile/cris/' + '/div/23.7/' + + +Generating HTML +--------------- + +Templating +---------- + +Jinja2 Template Basics +---------------------- + +Advanced Jinja2 +--------------- + +Templates in Flask +------------------ + + from flask import render_template + + @app.route('/hello/') + @app.route('/hello/') + def hello(name=None): + return render_template('hello.html', name=name) + + +Flask Template Context +---------------------- + +Lab 1 +----- + +Lab 2 - Part 1 +-------------- + +Data Persistence +---------------- + +Simple SQL +---------- + +Our Database +------------ + + drop table if exists entries; + create table entries ( + id integer primary key autoincrement, + title string not null, + text string not null + ); + + +Our App +------- + + # configuration goes here + DATABASE = '/tmp/flaskr.db' + SECRET_KEY = 'development key' + + app = Flask(__name__) # this is already in the file + app.config.from_object(__name__) + + +Creating the Database +--------------------- + + # add this at the very top + import sqlite3 + + # add the rest of this below the app.config statement + def connect_db(): + return sqlite3.connect(app.config['DATABASE']) + + +Tests and TDD +------------- + +Testing Setup +------------- + + import os + import flaskr + import unittest + import tempfile + + class FlaskrTestCase(unittest.TestCase): + + def setUp(self): + db_fd = tempfile.mkstemp() + self.db_fd, flaskr.app.config['DATABASE'] = db_fd + flaskr.app.config['TESTING'] = True + self.client = flaskr.app.test_client() + self.app = flaskr.app + + +Testing Teardown +---------------- + + class FlaskrTestCase(unittest.TestCase): + ... + + def tearDown(self): + os.close(self.db_fd) + os.unlink(flaskr.app.config['DATABASE']) + + +Make Tests Runnable +------------------- + + if __name__ == '__main__': + unittest.main() + + +Test Databse Setup +------------------ + + def test_database_setup(self): + con = flaskr.connect_db() + cur = con.execute('PRAGMA table_info(entries);') + rows = cur.fetchall() + self.assertEquals(len(rows), 3) + + +Run the Tests +------------- + + (flaskenv)$ python flaskr_tests.py + F + ====================================================================== + FAIL: test_database_setup (__main__.FlaskrTestCase) + ---------------------------------------------------------------------- + Traceback (most recent call last): + File "flaskr_tests.py", line 23, in test_database_setup + self.assertTrue(len(rows) == 3) + AssertionError: False is not True + + + ---------------------------------------------------------------------- + Ran 1 test in 0.011s + + + FAILED (failures=1) + + +Make the Test Pass +------------------ + + # add this import at the top + from contextlib import closing + + # add this function after the connect_db function + def init_db(): + with closing(connect_db()) as db: + with app.open_resource('schema.sql') as f: + db.cursor().executescript(f.read()) + db.commit() + + +Initialize the DB in Tests +-------------------------- + + def setUp(self): + ... + flaskr.init_db() # <- add this at the end + + +Initialize the DB IRL +--------------------- + + import flaskr + flaskr.init_db() + ^D + + +Lab 2 - Part 2 +-------------- + +Managing DB Connections +----------------------- + +Manage our DB +------------- + + # add this import at the top: + from flask import g + + # add these function after init_db + @app.before_request + def before_request(): + g.db = connect_db() + + @app.teardown_request + def teardown_request(exception): + g.db.close() + + +Test Writing Entries +-------------------- + + def test_write_entry(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.write_entry(*expected) + con = flaskr.connect_db() + cur = con.execute("select * from entries;") + rows = cur.fetchall() + self.assertEquals(len(rows), 1) + for val in expected: + self.assertTrue(val in rows[0]) + + +Write an Entry +-------------- + + def write_entry(title, text): + g.db.execute('insert into entries (title, text) values (?, ?)', + [title, text]) + g.db.commit() + + +Test Reading Entries +-------------------- + + def test_get_all_entries_empty(self): + with self.app.test_request_context('/'): + self.app.preprocess_request() + entries = flaskr.get_all_entries() + self.assertEquals(len(entries), 0) + + + def test_get_all_entries(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.write_entry(*expected) + entries = flaskr.get_all_entries() + self.assertEquals(len(entries), 1) + for entry in entries: + self.assertEquals(expected[0], entry['title']) + self.assertEquals(expected[1], entry['text']) + + +Read Entries +------------ + + def get_all_entries(): + cur = g.db.execute('select title, text from entries order by id desc') + entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()] + return entries + + +Lab 2 - Part 3 +-------------- + +Test the Front Page +------------------- + + def test_empty_listing(self): + rv = self.client.get('/') + assert 'No entries here so far' in rv.data + + + def test_listing(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.write_entry(*expected) + rv = self.client.get('/') + for value in expected: + assert value in rv.data + + +Template Inheritance +-------------------- + +Creating Layout +--------------- + + + + + Flaskr + + +

    Flaskr

    +
    + {% block body %}{% endblock %} +
    + + + + +Extending Layout +---------------- + + {% extends "layout.html" %} + {% block body %} +

    Posts

    +
      + {% for entry in entries %} +
    • +

      {{ entry.title }}

      +
      + {{ entry.text|safe }} +
      +
    • + {% else %} +
    • No entries here so far
    • + {% endfor %} +
    + {% endblock %} + + +Creating a View +--------------- + + # at the top, import + from flask import render_template + + # and after our last functions: + @app.route('/') + def show_entries(): + entries = get_all_entries() + return render_template('show_entries.html', entries=entries) + + +Authentication +-------------- + +Test Authentication +------------------- + + def test_login_passes(self): + with self.app.test_request_context('/'): + self.app.preprocess_request() + flaskr.do_login(flaskr.app.config['USERNAME'], + flaskr.app.config['PASSWORD']) + self.assertTrue(session.get('logged_in', False)) + + + def test_login_fails(self): + with self.app.test_request_context('/'): + self.app.preprocess_request() + self.assertRaises(ValueError, flaskr.do_login, + flaskr.app.config['USERNAME'], + 'incorrectpassword') + + +Set Up Authentication +--------------------- + + # add an import + from flask import session + + # and configuration + USERNAME = 'admin' + PASSWORD = 'default' + + # and a function + def do_login(usr, pwd): + if usr != app.config['USERNAME']: + raise ValueError + elif pwd != app.config['PASSWORD']: + raise ValueError + else: + session['logged_in'] = True + + +Login/Logout in Tests +--------------------- + + def login(self, username, password): + return self.client.post('/login', data=dict( + username=username, + password=password + ), follow_redirects=True) + + + def logout(self): + return self.client.get('/logout', + follow_redirects=True) + + +Test Authentication +------------------- + + def test_login_logout(self): + rv = self.login('admin', 'default') + assert 'You were logged in' in rv.data + rv = self.logout() + assert 'You were logged out' in rv.data + rv = self.login('adminx', 'default') + assert 'Invalid username' in rv.data + rv = self.login('admin', 'defaultx') + assert 'Invalid password' in rv.data + + +Add Login Template +------------------ + + {% extends "layout.html" %} + {% block body %} +

    Login

    + {% if error -%} +

    Error {{ error }} + {%- endif %} +

    +
    + + +
    +
    + + +
    +
    + +
    +
    + {% endblock %} + + +Add Login/Logout Views +---------------------- + + # at the top, new imports + from flask import request + from flask import redirect + from flask import flash + from flask import url_for + + +And the View Code +----------------- + + @app.route('/login', methods=['GET', 'POST']) + def login(): + error = None + if request.method == 'POST': + try: + do_login(request.form['username'], + request.form['password']) + except ValueError: + error = "Invalid Login" + else: + flash('You were logged in') + return redirect(url_for('show_entries')) + return render_template('login.html', error=error) + + + @app.route('/logout') + def logout(): + session.pop('logged_in', None) + flash('You were logged out') + return redirect(url_for('show_entries')) + + +About Flash +----------- + +

    Flaskr

    +
    + {% if not session.logged_in %} + log in + {% else %} + log_out + {% endif %} +
    + {% for message in get_flashed_messages() %} +
    {{ message }}
    + {% endfor %} +
    + + +Adding an Entry +--------------- + + def test_add_entries(self): + self.login('admin', 'default') + rv = self.client.post('/add', data=dict( + title='Hello', + text='This is a post' + ), follow_redirects=True) + assert 'No entries here so far' not in rv.data + assert 'Hello' in rv.data + assert 'This is a post' in rv.data + + +Add the View +------------ + + # add an import + from flask import abort + + + @app.route('/add', methods=['POST']) + def add_entry(): + if not session.get('logged_in'): + abort(401) + try: + write_entry(request.form['title'], request.form['text']) + flash('New entry was successfully posted') + except sqlite3.Error as e: + flash('There was an error: %s' % e.args[0]) + return redirect(url_for('show_entries')) + + +Where do Entries Come From +-------------------------- + +Provide a Form +-------------- + + {% block body %} + {% if session.logged_in %} +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + {% endif %} +

    Posts

    + + +All Done +-------- + + (flaskenv)$ python flaskr.py + * Running on http://127.0.0.1:5000/ + * Restarting with reloader + + +The Big Payoff +-------------- + +Lab 2 - Part 4 +-------------- + +Static Files +------------ + + + Flaskr + + + + +Deploying +--------- + + (flaskenv)$ cd ../ + (flaskenv)$ tar -czvf flaskr.tgz flaskr + (flaskenv)$ scp flaskr.tgz :~/ + (flaskenv)$ ssh + $ tar -zxvf flaskr.tgz + + +Deploying +--------- + + WSGIScriptAlias / /var/www/flaskr.wsgi + + +Deploying +--------- + + $ sudo touch /var/www/flaskr.wsgi + $ sudo vi /var/www/flasrk.wsgi + + + import sys + sys.path.insert(0, 'path/to/flaskr') # the flaskr app you uploaded + + from flaskr import app as application + + +Deploying +--------- + + $ sudo apache2ctl configtest + $ sudo /etc/init.d/apache2 graceful + + +Going Further +------------- + +But Instead +----------- + +Assignment +---------- + +Submitting The Assignment +------------------------- + From 7260a350824653b6286853e1ad73adfef5558621 Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 3 Feb 2013 07:05:25 -0800 Subject: [PATCH 053/487] * update outline with links to assignment and presentation * add assignment file for this week --- assignments/week05/athome/assignment.txt | 23 +++++++++++++++++++++++ source/main/outline.rst | 8 +++++++- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 assignments/week05/athome/assignment.txt diff --git a/assignments/week05/athome/assignment.txt b/assignments/week05/athome/assignment.txt new file mode 100644 index 00000000..c0a8963a --- /dev/null +++ b/assignments/week05/athome/assignment.txt @@ -0,0 +1,23 @@ +* Re-implement the Flaskr app we built in class in a different Small + Framework. + +* There are several named in the class outline, and in this presentation. + +* Pick one of them, or a different one of your choice. It must be Python. + +* When you are finished, add your source code and a README that talks about + your experience to the ``athome`` folder of week05. + +* Tell me about your new Framework. Discuss the points above regarding + differences. + +Submittin Your Work + +* Try to get your code running on your VM + +* Add your source code, in it's entirety, to the ``athome`` folder for week 5 + +* Add a README.txt file that discusses the experience. + +* Commit your changes to your fork of the class repository and send me a pull + request diff --git a/source/main/outline.rst b/source/main/outline.rst index 5054e3fa..20327c36 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -361,6 +361,8 @@ framework. We will have the chance to repeat the class lab, or create another dynamic system using one of the many other python web frameworks available to us. +`Week 5 Presentation `_ + Reading ******* @@ -412,7 +414,11 @@ You may also want to do more reading on the unittest module: Assignment ********** -Coming soon +You can read the assignment at + +http://github.com/cewing/training.python_web/blob/master/assignments/week05/athome/assignment.txt + +Please complete the assignment by noon on Sunday, February 10, 2013. Week 6 - Django --------------- From 79ad59e1532eb735405f4e2ff63618fd78469250 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 4 Feb 2013 22:37:25 -0800 Subject: [PATCH 054/487] first set of typo fixes from Dan. --- source/presentations/week05.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/presentations/week05.rst b/source/presentations/week05.rst index 2b53687c..4d5dd294 100644 --- a/source/presentations/week05.rst +++ b/source/presentations/week05.rst @@ -451,7 +451,8 @@ Routes Can Be Dynamic --------------------- You can provide *placeholders* in dynamic urls. Each *placeholder* is then a -named arg to your function (add these to ``flask_intro.py``): +named arg to your function (add these to ``flask_intro.py`` (and delete the +1/0 bit)): .. code-block:: python :class: incremental small @@ -496,7 +497,7 @@ After adding that to ``flask_intro.py`` and saving, try loading Routes Can Be Reversed ---------------------- -Reversing a URL means the ability to generating the url that would result in a +Reversing a URL means the ability to generate the url that would result in a given endpoint being called. .. class:: incremental @@ -590,7 +591,7 @@ There are a few basic things to know: * Variables in templates can be printed by surrounding the variable name with double curly braces: ``{{ name }}``. * If a variable points to something like a dictionary or object, you can use - *either* dot or subscription notation: ``{{ obj[attr] }}``, ``{{ dict.key + *either* dot or subscript notation: ``{{ obj[attr] }}``, ``{{ dict.key }}``. * Variables in templates can be *filtered*: ``{{ name|capitalize }}``. There is a list of builtin filters. From 5fcea554e3155374ec1b856337a93fb4e928c9bd Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 5 Feb 2013 00:59:15 -0800 Subject: [PATCH 055/487] * Update outline with readings, preparations and references for Django week 1 * Add homework review slides and Final assignment slide. --- source/main/outline.rst | 58 ++++++++- source/presentations/week05.rst | 205 +++++++++++++++++++++++++------- 2 files changed, 219 insertions(+), 44 deletions(-) diff --git a/source/main/outline.rst b/source/main/outline.rst index 20327c36..e3353146 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -423,9 +423,59 @@ Please complete the assignment by noon on Sunday, February 10, 2013. Week 6 - Django --------------- -**Date**: Feb. 19, 2013 +**Date**: Feb. 12, 2013 + +In this class we'll get introduced to arguably the most popular full-stack +Python web framework, Django. We'll build a simple application that introduces +us to the basics of Models, Views and Templates. We'll also learn about the +Django admin and how it can help us rapidly develop effective applications. + +We'll cover basic relational modeling and talk about how to create effective +database schemas to model real-world problems. We'll take a look at how the +Django ORM (and ORMs in general) can help shield Python developers from SQL. + +For our homework, we'll take a look at a set of specifications for a project +and create a set of Django Models that will fulfill the specification. + +Reading +******* + +* `Django at a Glance + `_ - introduction to + the concepts and execution of Django + +* `Quick Install Guide + `_ - lightweight + instructions on installing Django. Use Python 2.6, not 2.5. + +* `Django Tutorial, part 1 + `_ - as noted + below, please actually follow the steps in the tutorial up until you reach + *Creating Models* + +Before Class +************ + +* Install Django 1.4.3. Use a Virtualenv and pip or easy_install. (see the + installation quick-start above, and the more in-depth guide below) + +* Install an RDBMS (I personally recommend PostgreSQL, but MySQL or any other + will do. We can even live with sqlite3, so long as you understand it is + **not for production**) + +* Set up a Django project. Walk through the first part of the tutorial above + until you reach *Creating Models*. **Do Not** create models) + +Reference +********* +* `Using Django `_ - far more + in-depth information about core topics in Django. Pay particular attention + to the installation documentation here. +* `Django Design Philosophies + `_ - some + well-considered words on why Django is the way it is. Assignment ********** @@ -435,7 +485,7 @@ To Be Decided Week 7 - Django --------------- -**Date**: Feb. 26, 2013 +**Date**: Feb. 19, 2013 Assignment ********** @@ -445,7 +495,7 @@ To Be Decided Week 8 - Pyramid ---------------- -**Date**: Mar. 5, 2013 +**Date**: Feb. 26, 2013 Assignment ********** @@ -455,7 +505,7 @@ To Be Decided Week 9 - The Cloud ------------------ -**Date**: Feb. 12, 2013 +**Date**: Mar. 5, 2013 Assignment ********** diff --git a/source/presentations/week05.rst b/source/presentations/week05.rst index 4d5dd294..dab15362 100644 --- a/source/presentations/week05.rst +++ b/source/presentations/week05.rst @@ -9,9 +9,9 @@ Week 5: Small Frameworks .. class:: intro-blurb right -| "Reinventing the wheel is great -| if your goal is to learn more about the wheel" -| +| "Reinventing the wheel is great +| if your goal is to learn more about the wheel" +| | -- James Tauber, PyCon 2007 .. class:: image-credit @@ -25,6 +25,111 @@ But First Review from the Assignment +URL Mapping +----------- + +Two basic approaches to solving the problem:: + + /books?id=id1 + /books/id1 + +.. class:: incremental + +The first generally used ``environ['QUERY_STRING']``. The second used +``environ['PATH_INFO']`` + +.. class:: incremental + +Both are fine. Largely a matter of taste. I find the latter more common in +daily work. + +Regular Expressions +------------------- + +My personal approach to the url mapping problem was the second, which relies +on regular expression mapping: + +.. code-block:: python + + URLS = [(r'^$', 'books'), + (r'^book/(id[\d]{1,2})$', 'book'), ] + +.. class:: incremental + +Regular expressions should be as tight as possible, it's easy to over-match + +.. class:: incremental + +Read the `Python Regexp How-to `_ +and find a good `Regular Expression Tester `_ + +String Formatting +----------------- + +This is awkward: + +.. code-block:: python + + bob = {'a': 'things', 'b': 'stuff'} + "I have lots of " + bob['a'] + " and " + bob['b'] + "." + +.. class:: incremental + +This is much less so: + +.. code-block:: python + :class: incremental + + bob = {'a': 'things', 'b': 'stuff'} + "I have lots of %(a)s and %(b)s." % bob + +.. class:: incremental + +I am chastened. string.format() is the best (most flexible) + +WSGIScriptAlias +--------------- + +CGI required a cgi directory. WSGI makes no such requirement. + +.. class:: incremental + +You can use WSGIScriptAlias to point to a single file + +.. class:: incremental + +Since a single file can often provide the entry point to an entire app, this +allows you to mount entire apps at arbitrary path locations: + +.. class:: incremental + +:: + + WSGIScriptAlias / /path/to/main/app/wsgi_app.py + WSGIScriptAlias /blog /path/to/blog/app/wsgi_app.py + WSGIScriptAlias /forum /path/to/forum/app/wsgi_app.py + +Bad HTML +-------- + +I know that web browsers are forgiving, but you should be less so. + +These are *not* good HTML:: + +

    foobar

    +

    foobar

    + +.. class:: incremental + +This is: `

    foobar

    ` + +.. class:: incremental + +The `Mozilla Developer Network +`_ is a great resource for +proper HTML. It also has great reference information on JavaScript. Shun the +`w3schools`. + And Second ---------- @@ -32,6 +137,26 @@ And Second Questions from the Reading? +And Third +--------- + +.. class:: center incremental + +**Class Project** + +.. class:: incremental + +* Create a Website +* It can do anything you want it to. +* It should have some user interactions (forms users complete). +* It should look nice-ish +* It should show off some aspect of what you've learned +* It should take you about 15-20 hours to create (so small) +* It will be due on the last day of class (March 10) +* We will spend half of each of the last two class session working on it in + class. +* **Questions?** + And Now... ---------- @@ -277,13 +402,13 @@ There are scores of 'em (this is a partial list). .. class:: incremental invisible small center ========= ======== ======== ========== ============== -Django Grok Pylons TurboGears web2py -Zope CubicWeb Enamel Gizmo(QP) Glashammer -Karrigell Nagare notmm Porcupine QP -SkunkWeb Spyce Tipfy Tornado WebCore -web.py Webware Werkzeug WHIFF XPRESS -AppWsgi Bobo Bo7le CherryPy circuits.web -Paste PyWebLib WebStack Albatross Aquarium +Django Grok Pylons TurboGears web2py +Zope CubicWeb Enamel Gizmo(QP) Glashammer +Karrigell Nagare notmm Porcupine QP +SkunkWeb Spyce Tipfy Tornado WebCore +web.py Webware Werkzeug WHIFF XPRESS +AppWsgi Bobo Bo7le CherryPy circuits.web +Paste PyWebLib WebStack Albatross Aquarium Divmod Nevow Flask JOTWeb2 Python Servlet Engine Pyramid Quixote Spiked weblayer ========= ======== ======== ========== ============== @@ -366,11 +491,11 @@ simple app. Type it into `flask_intro.py`: from flask import Flask app = Flask(__name__) - + @app.route('/') def hello_world(): return 'Hello World!' - + if __name__ == '__main__': app.run() @@ -402,7 +527,7 @@ Flask has a similar tool. Make the following changes to your def hello_world(): bar = 1 / 0 return 'Hello World!' - + if __name__ == '__main__': app.run(debug=True) @@ -419,7 +544,7 @@ represents a single *application* in the WSGI sense. .. class:: incremental * You instantiate a `Flask` app with a name that represents the package or - module containing the app. + module containing the app. * If your application is a single module, this should be `__name__` * This is used to help the `Flask` app figure out where to look for *resources* @@ -484,7 +609,7 @@ You can also determine which HTTP *methods* a given route will accept: @app.route('/blog/entry//', methods=['GET',]) def read_entry(id): return "reading entry %d" % id - + @app.route('/blog/entry//', methods=['POST', ]) def write_entry(id): return 'writing entry %d' % id @@ -547,7 +672,7 @@ terminal and import your ``flask_intro.py`` module: with app.test_request_context(): print url_for('show_profile', username="cris") print url_for('divide', val=23.7) - + '/profile/cris/' '/div/23.7/' @@ -618,7 +743,7 @@ Use the ``render_template`` function: :class: small from flask import render_template - + @app.route('/hello/') @app.route('/hello/') def hello(name=None): @@ -671,7 +796,7 @@ Lab 2 - Part 1 -------------- The rest of class today will be devoted to building and deploying a simple -micro-blog app using flask. +micro-blog app using flask. .. class:: incremental @@ -755,7 +880,7 @@ editor. Add the following and save the file: # configuration goes here DATABASE = '/tmp/flaskr.db' SECRET_KEY = 'development key' - + app = Flask(__name__) # this is already in the file app.config.from_object(__name__) @@ -770,14 +895,14 @@ Still in ``flaskr.py`` let's add a function that will connect to our database: # add this at the very top import sqlite3 - + # add the rest of this below the app.config statement def connect_db(): return sqlite3.connect(app.config['DATABASE']) .. class:: incremental -This will be a convenience to us later on, and it will allow us to write our +This will be a convenience to us later on, and it will allow us to write our very first test. Tests and TDD @@ -815,9 +940,9 @@ in your editor. Edit it to look like this: import flaskr import unittest import tempfile - + class FlaskrTestCase(unittest.TestCase): - + def setUp(self): db_fd = tempfile.mkstemp() self.db_fd, flaskr.app.config['DATABASE'] = db_fd @@ -834,7 +959,7 @@ Add the following method to your test class: class FlaskrTestCase(unittest.TestCase): ... - + def tearDown(self): os.close(self.db_fd) os.unlink(flaskr.app.config['DATABASE']) @@ -905,7 +1030,7 @@ following to ``flaskr.py``: # add this import at the top from contextlib import closing - + # add this function after the connect_db function def init_db(): with closing(connect_db()) as db: @@ -939,7 +1064,7 @@ Initialize the DB IRL --------------------- Okay, so we know the ``init_db`` function we added sets up the database -properly. +properly. .. class:: incremental @@ -1002,12 +1127,12 @@ Add the following code to our app (``flaskr.py``): # add this import at the top: from flask import g - + # add these function after init_db @app.before_request def before_request(): g.db = connect_db() - + @app.teardown_request def teardown_request(exception): g.db.close() @@ -1103,7 +1228,7 @@ Re-run your tests. You should now have four passing tests. Great Job! Lab 2 - Part 3 -------------- -Now we can read and write blog entries, let's add views so we can see what +Now we can read and write blog entries, let's add views so we can see what we're doing. .. class:: incremental @@ -1138,7 +1263,7 @@ Add the following tests to ``flaskr_tests.py``: Template Inheritance -------------------- -One aspect of Jinja2 templates we haven't seen yet is that templates can +One aspect of Jinja2 templates we haven't seen yet is that templates can inherit structure from other templates. .. class:: incremental @@ -1206,7 +1331,7 @@ add the following code: # at the top, import from flask import render_template - + # and after our last functions: @app.route('/') def show_entries(): @@ -1250,7 +1375,7 @@ Back in ``flaskr_tests.py`` add new test methods: def test_login_fails(self): with self.app.test_request_context('/'): self.app.preprocess_request() - self.assertRaises(ValueError, flaskr.do_login, + self.assertRaises(ValueError, flaskr.do_login, flaskr.app.config['USERNAME'], 'incorrectpassword') @@ -1264,11 +1389,11 @@ Now, let's add the code in ``flaskr.py`` to support this: # add an import from flask import session - + # and configuration USERNAME = 'admin' PASSWORD = 'default' - + # and a function def do_login(usr, pwd): if usr != app.config['USERNAME']: @@ -1579,7 +1704,7 @@ Then, on your VM, set up a virtualenv with Flask installed Deploying --------- -You'll need to make some changes to mod_wsgi configuration. +You'll need to make some changes to mod_wsgi configuration. * Open ``/etc/apache2/sites-available/default`` in an editor (on the VM) @@ -1600,11 +1725,11 @@ Finally, you'll need to add the named wsgi file and edit it to match:: $ sudo touch /var/www/flaskr.wsgi $ sudo vi /var/www/flasrk.wsgi - - + + import sys sys.path.insert(0, 'path/to/flaskr') # the flaskr app you uploaded - + from flaskr import app as application Deploying @@ -1622,11 +1747,11 @@ Wheeee! Going Further ------------- -It's not too hard to see ways you could improve this. +It's not too hard to see ways you could improve this. .. class:: incremental -* For my part, I made a version using Bootstrap.js. +* For my part, I made a version using Bootstrap.js. * You could limit the number of posts shown on the front page. * You could add dates to the posts and provide archived views for older posts. * You could add the ability to edit existing posts (and add an updated date to the schema) From 801d2c87728c0cbd0f3fd27ea90ba46ac21f619b Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 5 Feb 2013 17:43:48 -0800 Subject: [PATCH 056/487] fix error in step 2 test setUp --- assignments/week05/lab/flaskr_2/flaskr_tests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assignments/week05/lab/flaskr_2/flaskr_tests.py b/assignments/week05/lab/flaskr_2/flaskr_tests.py index 38d88b93..50fef94d 100644 --- a/assignments/week05/lab/flaskr_2/flaskr_tests.py +++ b/assignments/week05/lab/flaskr_2/flaskr_tests.py @@ -9,7 +9,8 @@ class FlaskrTestCase(unittest.TestCase): def setUp(self): self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp() flaskr.app.config['TESTING'] = True - self.app = flaskr.app.test_client() + self.client = flaskr.app.test_client() + self.app = flaskr.app flaskr.init_db() def tearDown(self): From 4d48f2caf4f32c33dac15ddfdd1c5a1f599898d2 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 5 Feb 2013 17:45:00 -0800 Subject: [PATCH 057/487] add note for windows users regarding tmp --- source/presentations/week05.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/presentations/week05.rst b/source/presentations/week05.rst index dab15362..e4f1e087 100644 --- a/source/presentations/week05.rst +++ b/source/presentations/week05.rst @@ -152,7 +152,7 @@ And Third * It should look nice-ish * It should show off some aspect of what you've learned * It should take you about 15-20 hours to create (so small) -* It will be due on the last day of class (March 10) +* It will be due Friday following the last day of class (March 15) * We will spend half of each of the last two class session working on it in class. * **Questions?** @@ -884,6 +884,10 @@ editor. Add the following and save the file: app = Flask(__name__) # this is already in the file app.config.from_object(__name__) +.. class:: incremental small + +**Windows users, you will need to create C:\\tmp or change the pathname for +DATABASE** Creating the Database --------------------- From 0d91102c9207e82ed25aac9d6aa68d841c179d7e Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 5 Feb 2013 17:49:43 -0800 Subject: [PATCH 058/487] fix error in login tests, thanks cqoverly --- source/presentations/week05.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/presentations/week05.rst b/source/presentations/week05.rst index e4f1e087..171a9d2b 100644 --- a/source/presentations/week05.rst +++ b/source/presentations/week05.rst @@ -1439,9 +1439,9 @@ And now the test itself (again, ``flaskr_tests.py``): rv = self.logout() assert 'You were logged out' in rv.data rv = self.login('adminx', 'default') - assert 'Invalid username' in rv.data + assert 'Invalid Login' in rv.data rv = self.login('admin', 'defaultx') - assert 'Invalid password' in rv.data + assert 'Invalid Login' in rv.data .. class:: incremental From 6c00b658511d5fffbf8195c2ca1a46d0abfd389f Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 9 Feb 2013 23:40:11 -0800 Subject: [PATCH 059/487] * update outline with readings for week 7 * work on week 6 presentation --- source/main/outline.rst | 73 +++++++ source/presentations/week06.rst | 371 +++++++++++++++++++++++++++++++- 2 files changed, 442 insertions(+), 2 deletions(-) diff --git a/source/main/outline.rst b/source/main/outline.rst index e3353146..724b9403 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -487,6 +487,79 @@ Week 7 - Django **Date**: Feb. 19, 2013 +In this class we'll dive a bit further into Django. We'll take the +specifications from week 6 and the models we created from them to set up a +simple application. Along the way we'll learn a bit more about the Django +admin, generic views, and templates. + +We'll also discuss extending the functionality of our application using +existing Django **apps**. We'll see how these add-ons can help us to solve +common problems like user registration and database schema management. + +Finally, we'll discuss some of the strengths and weaknesses of Django. What +makes it a good choice for some projects but not for others. + +Our assignment for the week will be to enhance the application we build in +class with some additional functionality. + +Reading +******* + +* `Using Django `_ - far more + in-depth information about core topics in Django. Pay attention specifically + to the following topics (you'll want to follow links in these documents): + + * `Models `_ - + details of the django modelling system. How to represent data for, + relationships between and the presentation of your objects. + + * `Queries `_ - + basic information about the Django ORM and how to use it to create, + retrieve, update and delete objects. + + * `Working with Forms + `_ - how to create, + display, and process forms in Django, including forms that are associated + with a given model. + + * `The Django Template Language + `_ - learn + template basics like variables, filters, tags and blocks, and learn about + template inheritance. + + * `Class-based Generic Views + `_ - an + introduction to the simplest way to present your objects to your adoring + public. + + * `Testing Django Applications + `_ - learn + different approaches to testing Django applications, including unit + testing and doctests. + +Before Class +************ + +We'll be adding a new bit of functionality to our app, and we'll do this not +by developing it ourselves, but by *integrating* an existing add-on. Before +class begins, please install `django-south +`_ and `django-registration +`_ into your Django +virtualenv. + +Reference +********* + +* `SQLAlchemy and You `_ + - A really in-depth look at the differences between the Django ORM and the + reigning king of Python database integration, SQLAlchemy. + +* `About Django from the Pyramid Guy + `_ - a talk given at + DjangoCon 2012 by Chris McDonough, one of the driving forces behind the + Pyramid framework. Also available in `video form + `_. + Assignment ********** diff --git a/source/presentations/week06.rst b/source/presentations/week06.rst index e6943ef9..5add580d 100644 --- a/source/presentations/week06.rst +++ b/source/presentations/week06.rst @@ -1,2 +1,369 @@ -This is Week 6 --------------- \ No newline at end of file +Internet Programming with Python +================================ + +.. image:: img/django-pony.png + :align: left + :width: 50% + +Week 6: Django - Part 1 + +.. class:: intro-blurb right + +Wherein we become 'perfectionists with deadlines' + +.. class:: image-credit + +image: http://djangopony.com/ + +But First +--------- + +.. class:: big-centered + +Review from the Assignment + +And Second +---------- + +.. class:: big-centered + +Questions from the Reading? + +And Now +------- + +.. image:: img/django_lead.png + :align: center + :width: 79% + + +Full Stack Framework +-------------------- + +Django is **One Big Package** + +.. class:: incremental + +When you installed Flask, you also installed *werkzeug* and *jinja2*, a total +of 1.85MB + +.. class:: incremental + +Django 1.4.3 weighs in at 7.7MB (4 times the size of Flask) + +.. class:: incremental + +So what do you get? + +Full Stack Framework +-------------------- + +Django comes with: + +.. class:: incremental + +* Persistence via the *Django ORM* +* CRUD content editing via the automatic *Django Admin* +* URL Mapping via *urlpatterns* +* Templating via the *Django Template Language* +* Caching with levels of configurability +* Internationalization via i18n hooks +* Form rendering and handling + +.. class:: incremental + +Pretty much everything you need to make a solid website quickly + +What Sets it Apart? +------------------- + +Lots of frameworks offer some of these features, if not all. + +.. class:: incremental + +What is Django's *killer feature* + +.. class:: incremental center + +**The Django Admin** + +The Django Admin +---------------- + +Works in concert with the Django ORM to provide automatic CRUD functionality + +.. class:: incremental + +You write the models, it provides the UI + +.. class:: incremental center + +**Really** + +The Pareto Principle +-------------------- + +The Django Admin is a perfect embodiment of the Pareto Priciple, a.k.a. the +80/20 rule: + +.. class:: incremental center + +80% of the problems can be solved by 20% of the effort + +.. class:: incremental + +The converse also holds true: + +.. class:: incremental center + +Fixing the last 20% of the problems will take the remaining 80% of the effort. + +Other Django Advantages +----------------------- + +Clearly the most popular Python web framework at this time + +.. class:: incremental + +Popularity translates into: + +.. class:: incremental + +* Active, present community +* Plethora of good examples to be found online +* Rich ecosystem of *apps* (encapsulated add-on functionality) + +.. class:: incremental center + +**Jobs** + +Active Development +------------------ + +Popular frameworks tend to be actively developed. + +.. class:: incremental + +Django releases in the last 12 months: + +.. class:: incremental + +* 1.5 (any day now) +* 1.4.3 (December 2012) +* 1.3.5 (December 2012) +* 1.4.2 (November 2012) +* 1.3.3 (August 2012) +* 1.4.1 (July 2012) +* 1.3.2 (July 2012) +* 1.4 (March 2012) + +Great Documentation +------------------- + +Thorough, readable, and discoverable. + +.. class:: incremental + +Led the way to better documentation for all Python + +.. class:: incremental + +`Read The Docs `_ - built in connection with +Django, sponsored by the Django Software Foundation. + +.. class:: incremental + +Write documentation as part of your python package, and render new versions of +that documentation for every commit + +.. class:: incremental center + +**this is awesome** + +History +------- + +Django was created to power the website of the Lawrence Journal-World +newspaper, Lawrence, KS + +.. class:: incremental + +This birth in practicality is reflected in the design of the system. + +.. class:: incremental + +Pretty much every design decision was made to solve a real problem. + +.. class:: incremental + +You can read more in `this Quora post +`_ + +Django Organization +------------------- + +Django is organized into *projects* and *apps* + +.. class:: incremental + +A Django *project* represents the totality of a website, all the pages it +will contain and all the functionality it supports + +.. class:: incremental + +A Django *app* represents an individual unit of functionality: a blog, a +forum, a registration system, a content tagging system, etc. + +.. class:: incremental + +One *project* can (and likely will) consist of many *apps* + +Starting a Project +------------------ + +You should already have done this at home, but we'll look at it together in +case: + +.. class:: incremental + +* Set up a Django virtualenv +* Activate that env and ``pip install django`` +* Create a new Django project: + +.. code-block:: + :class: incremental + + (djangoenv)$ django-admin.py startproject mysite + +.. class:: incremental + +This will create a folder called 'mysite'. Let's take a look at it: + +Project Layout +-------------- + +The folder created by *django-admin.py* contains the following structure: + +.. code-block:: + + mysite/ + manage.py + mysite/ + __init__.py + settings.py + urls.py + wsgi.py + +.. class:: incremental + +If what you see doesn't match that, you're using an older version of Django. +Make sure you've installed 1.4.3. + +*django-admin.py* and *manage.py* +--------------------------------- + +*django-admin.py* provides a hook for administrative tasks and abilities: + +.. class:: incremental + +* creating a new project or app +* running the development server +* executing tests +* entering a python interpreter +* entering a database shell session with your database +* much much more (run ``django-admin.py`` without an argument) + +.. class:: incremental + +*manage.py* wraps this functionality, adding the full environment of your +project. + +Development Server +------------------ + +At this point, you should be ready to use the development server:: + + (djangoenv)$ cd mysite + (djangoenv)$ python manage.py runserver + ... + +.. class:: incremental + +Load ``http://localhost:8000`` in your browser. + +A Blank Slate +------------- + +You should see this: + +.. image:: img/django-start.png + :align: center + :width: 98% + +.. class:: incremental center + +**Do you?** + +Connecting A Database +--------------------- + +Django comes with its own ORM (Object-Relational Mapper) + +.. class:: incremental + +The first step in working with Django is to connect it to your database (this +is set in ``settings.py``) + +.. code-block:: python + :class: small incremental + + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.', + 'NAME': '', + 'USER': '', + 'PASSWORD': '', + 'HOST': '', + 'PORT': '', + } + } + +Building DB Tables +------------------ + +The Django ORM builds tables. Django models describe the objects you want, the +ORM does the rest. + +.. class:: incremental + +Django comes with some *apps* set up and ready to use. These define models, +and need tables to power them. You create the tables by running the management +command *syncdb*: + +.. class:: incremental + +:: + + (djangoenv)$ python manage.py syncdb + +.. class:: incremental + +Add your first admin user when prompted (remember the password) + +scraps +------ + +- manage.py startproject + +- manage.py startapp + +connecting to a database + +writing models + +writing views + +writing tests + +what next? + From c491f42e8ac9965a230b0a182de130f18b5a644c Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 9 Feb 2013 23:40:56 -0800 Subject: [PATCH 060/487] add images for week 6 presentation --- source/img/django-pony.png | Bin 0 -> 63811 bytes source/img/django-start.png | Bin 0 -> 31371 bytes source/img/django_lead.png | Bin 0 -> 50583 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 source/img/django-pony.png create mode 100644 source/img/django-start.png create mode 100644 source/img/django_lead.png diff --git a/source/img/django-pony.png b/source/img/django-pony.png new file mode 100644 index 0000000000000000000000000000000000000000..b1b58ab7a00f259b76cb5f70a344394d34d9a565 GIT binary patch literal 63811 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

    QOERmOdXqT_+)d282e2c1WG)twCD*o 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

  • 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 literal 0 HcmV?d00001 diff --git a/source/img/django_lead.png b/source/img/django_lead.png new file mode 100644 index 0000000000000000000000000000000000000000..b962c25702628fa4523a5d49851af29552ba3e23 GIT binary patch literal 50583 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 v-D4r%Te|fvWdUPs^!JfusGt5 Date: Tue, 12 Feb 2013 01:57:55 -0800 Subject: [PATCH 061/487] * complete the week06 slides * add images to support --- source/img/admin_index.png | Bin 0 -> 18633 bytes source/img/django-admin-login.png | Bin 0 -> 7749 bytes source/presentations/week06.rst | 1258 ++++++++++++++++++++++++++++- 3 files changed, 1250 insertions(+), 8 deletions(-) create mode 100644 source/img/admin_index.png create mode 100644 source/img/django-admin-login.png diff --git a/source/img/admin_index.png b/source/img/admin_index.png new file mode 100644 index 0000000000000000000000000000000000000000..55a8919f5fb77f12d5af16b607a08229fd637def GIT binary patch literal 18633 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 TaXvnw00000NkvXXu0mjfP)V4v literal 0 HcmV?d00001 diff --git a/source/img/django-admin-login.png b/source/img/django-admin-login.png new file mode 100644 index 0000000000000000000000000000000000000000..4ceb5f54b92922f5f82b8896c8dccfbcd1ad6bdf GIT binary patch literal 7749 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, with some minor +adjustments. + +Lab - Step One +-------------- + +We are going to create an *app* to add to our *project*. This app will: + +.. class:: incremental + +* Allow a user to create poll questions +* Allow a user to provide choices for these questions +* Allow visitors to a site to see these questions and vote for an answer +* Allow the total vote tallies for the answers to a poll question to be + displayed. + +.. class:: incremental + +As stated above, an *app* should represent a unit of functionality within a +larger system, the *project*. We have a project, we need to create an *app* + +Create an App +------------- + +This is accomplished using ``manage.py``. + +.. class:: incremental + +In your terminal, make sure you are in the *outer* mysite directory, where the +file ``manage.py`` is located. Then: + +.. class:: incremental + +:: + + (djangoenv)$ python manage.py startapp polls + +What is Created +--------------- + +This should leave you with the following structure: + +.. class:: small + +:: + + mysite/ + manage.py + mysite/ + ... + polls/ + __init__.py + models.py + tests.py + views.py + +.. class:: incremental + +We'll start by defining the objects we will work with: poll questions and +choices. + +Models +------ + +Open the file ``models.py`` in your editor, and add the following code: + +.. code-block:: python + + from django.db import models + + class Poll(models.Model): + question = models.CharField(max_length=200) + pub_date = models.DateTimeField('date published') + + class Choice(models.Model): + poll = models.ForeignKey(Poll) + choice = models.CharField(max_length=200) + votes = models.IntegerField(default=0) + +Model Details +------------- + +Let's look at that a bit more closely: + +.. code-block:: python + :class: small incrmental + + class Poll(models.Model): + +.. class: incremental small + +* Our Models are Python classes that inherit from the Model class +* The ``Model`` class provides a standard API for interacting with a database, + centered on the object defined by the model. +* You can add functionality to your object by adding methods to these models. +* Consider methods added to a model to be row-level operations. They will work + on a single record from the database, not on entire tables +* You can read much more about the `Model API + `_ + +Field Details +------------- + +A model has attributes defined by ``Fields``: + +.. code-block:: python + :class: small + + question = models.CharField(max_length=200) + pub_date = models.DateTimeField('date published') + poll = models.ForeignKey(Poll) + votes = models.IntegerField(default=0) + +.. class:: incremental small + +* Fields map to columns in a database table +* Note there are no explicit primary key fields. Django does this + automatically +* Different field types map to different SQL column types, the ORM handles + this. +* Django fields can handle complex relationships between objects. +* Field constructors take arguments, some are common to all Fields, others + particular to a given Field type. +* **ALL** Django model fields default to being NOT NULL (required). You change + this with the ``blank`` and ``null`` constructor arguments +* You can read much more about `Model Fields + `_ + +Hooking it Up +------------- + +Okay, we've got a couple of models, now we need to add our *app* to our +project. + +.. class:: incremental + +In Django, this is accomplished by configuration. + +.. class:: incremental + +Configuration takes place in the project ``settings.py`` file. + +.. class:: incremental + +Open that file now, in your editor. + +Installing Apps +--------------- + +You extend Django functionality by *installing apps*. Find the following block +in ``settings.py`` and edit it like so: + +.. code-block:: python + :class: small + + INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + # Uncomment the next line to enable the admin: + # 'django.contrib.admin', + # Uncomment the next line to enable admin documentation: + # 'django.contrib.admindocs', + 'polls', # <- YOU ADD THIS PART + ) + +Setting Up the Database +----------------------- + +By now, we should have some guess as to what the next step will be + +.. code-block:: + :class: incremental + + (djangoenv)$ python manage.py syncdb + +.. class:: incremental + +This will execute the SQL commands needed to create the new tables in your +database. + +A Word About Development +------------------------ + +These models we've created are not going to change. This is unusual for a +development cycle. + +.. class:: incremental + +The ``syncdb`` management command only creates tables that *do not yet exist*. +It **does not update tables**. + +.. class:: incremental + +It is easy to get your model definitions out of sync with your database. + +.. class:: incremental + +Django provides the management command ``sqlclear`` to handle this. It drops +all tables, so you can run ``syncdb`` again. + +ACK!!! ------ -- manage.py startproject +.. class:: center + +That doesn't sound very nice, does it? + +.. class:: big-centered incremental + +We'll learn a better way next week + +The Django Shell +---------------- + +Django provides a management command ``shell``: + +.. class:: incremental + +* Shares the same ``sys.path`` as your project, so all installed python + packages are present. +* Imports the ``settings.py`` file from your project, and so shares all + installed apps and other settings. +* Handles connections to your database, so you can interact with live data + directly. + +.. class:: incremental + +Let's explore the Model Instance API directly using this shell + +Model Instance API +------------------ + +:: + + (djangoenv)$ python manage.py shell + +.. code-block:: python + + >>> from polls.models import Poll + >>> Poll.objects.count() + 0 + >>> p1 = Poll(question="What is your name?") + >>> p1.full_clean() + Traceback (most recent call last): + ... + >>> from django.utils import timezone + >>> p1.pub_date = timezone.now() + >>> p1.full_clean() + >>> p1.save() + >>> Poll.objects.count() + 1 + +More API +-------- + +.. code-block:: python + :class: small + + >>> Poll.objects.filter(id=1) + [] + >>> what_polls = Poll.objects.filter(question__startswith="What") + [] + >>> mypoll = Poll.objects.get(pk=1) + >>> mypoll.choice_set.all() + [] + >>> from polls.models import Choice + >>> c1 = Choice(choice="King Arthur of the Britons", poll=mypoll) + >>> c1.save + >>> mypoll.choice_set.all() + [] + >>> mypoll.choice_set.create(choice="Lancelot of Camelot") + >>> mypoll.choice_set.all() + [, ] + +Enhancing Models +---------------- + +It's clear that the representation of our objects leaves something to be +desired. Django can help + +.. class:: incremental + +Back in ``models.py``, add these methods: + +.. code-block:: python + :class: small incremental + + class Poll(models.Model): + # ... + def __unicode__(self): + return self.question + + class Choice(models.Model): + # ... + def __unicode__(self): + return self.choice + +Model Methods +------------- + +This ``__unicode__`` method is a normal python instance method. You can add +other methods, too (still ``models.py``): + +.. code-block:: python + :class: small incremental + + from django.utils import timezone + + class Poll(models.Model): + # ... + def published_today(self): + now = timezone.now() + time_delta = now - self.pub_date + return time_delta.days == 0 + +.. class:: incremental + +Save that, then start up the Django shell again (``python manage.py shell``) + +Check Custom Methods +-------------------- + +.. code-block:: python + + >>> from polls.models import Poll + >>> mypoll = Poll.objects.get(pk=1) + >>> mypoll + + >>> mypoll.choice_set.all() + [, + , + ] + >>> mypoll.published_today() + True + +Testing Our Models +------------------ + +As with any project, we want to test our work. Django provides a testing +framework to allow this. + +.. class:: incremental + +Django supports both *unit tests* and *doctests*. I strongly suggest using +*unit tests*. + +.. class:: incremental + +You add tests for your *app* to the file ``tests.py``, which should be at the +same package level as ``models.py``. + +.. class:: incremental + +Locate and open this file in your editor. We are going to add a few tests for +the models we've just written. + +Testing Setup +------------- + +.. code-block:: python + :class: small + + from datetime import timedelta + + from django.test import TestCase + from django.utils import timezone + + from polls.models import Poll + + class PollTest(TestCase): + def setUp(self): + self.expected_question = "what is the question?" + self.expected_choice = "do you like spongecake?" + self.poll = Poll.objects.create( + question=self.expected_question, + pub_date=timezone.now()) + self.choice = self.poll.choice_set.create( + choice=self.expected_choice) + +Writing Tests +------------- + +.. code-block:: python + :class: small + + def test_poll_display(self): + self.assertEquals(unicode(self.poll), self.expected_question) + new_question = "What is the answer?" + self.poll.question = new_question + self.assertEquals(unicode(self.poll), new_question) + + def test_choice_display(self): + self.assertEquals(unicode(self.choice), self.expected_choice) + new_choice = "is left better than right?" + self.choice.choice = new_choice + self.assertEquals(unicode(self.choice), new_choice) + + def test_published_today(self): + self.assertTrue(self.poll.published_today()) + delta = timedelta(hours=26) + self.poll.pub_date = self.poll.pub_date - delta + self.assertFalse(self.poll.published_today()) + +Running Tests +------------- + +You can run your tests using a management command provided by Django:: + + (djangoenv)$ python manage.py test polls + +.. class:: incremental + +* This will run the tests for the ``polls`` app +* You can provide the name of any installed app +* If you provide no name, the tests for *all* installed apps will run +* You can run subsets by providing dotted names: ``polls.PollTest``, + ``polls.PollTest.test_poll_display`` + +.. class:: incremental + +There is a lot more to know about `Testing Django applications +`_ + +What to Test +------------ + +In any framework, the question arises of what exactly to test. Much of the +functioning of your app is provided by framework tools. Do you need to test +that stuff? + +.. class:: incremental + +I *usually* don't write tests covering features provided directly by the +framework. + +.. class:: incremental + +I *do* write tests for functionality I add, and for places where I make +changes to how the default functionality works. + +.. class:: incremental + +This is largely a matter of style and taste (and of how much development time +you have). + + +Lab - Part Two +-------------- + +In this part, we'll be adding our app to the Django Admin. This will allow +us to add, edit and delete objects with a minimum of work. + +We'll focus instead on how to customize the admin to get the best results we +can. + +Install the Admin +----------------- + +The Django Admin is, itself, an *app*. It is not installed by default. + +.. class:: incremental + +Open the ``settings.py`` file from our ``mysite`` project package and uncomment +the admin bit: + +.. code-block:: python + :class: incremental small + + INSTALLED_APPS = ( + # ... + 'django.contrib.staticfiles', + # Uncomment the next line to enable the admin: + 'django.contrib.admin', # <- THIS LINE HERE + # Uncomment the next line to enable admin documentation: + # 'django.contrib.admindocs', + 'polls', + ) + +Add the Admin Tables +-------------------- + +As you might expect, enabling the admin alters our DB. We'll need to run +the ``syncdb`` management command:: + + (djangoenv)$ python manage.py syncdb + Creating tables ... + Creating table django_admin_log + Installing custom SQL ... + Installing indexes ... + Installed 0 object(s) from 0 fixture(s) + +.. class:: incremental + +All set. Let's add URLs next + +Django URL Resolution +--------------------- + +Like Flas, Django has a system for routing URLs to code: the *urlconf*. + +.. class:: incremental + +* a urlconf is a list of mappings +* each mapping has a regexp *rule*, representing the URL +* each mapping names or provides the ``callable`` to be invoked +* each mapping can have a *name*, used to *reverse* the URL +* a urlconf should be created using functions from the ``django.conf.urls`` + module +* django will load the urlconf named ``urlpatterns`` that it finds in the file + named in ``settings.ROOT_URLCONF``. +* That urlconf must include any others it requires + +Django URL Patterns +------------------- + +Open the file ``urls.py`` from your ``mysite`` project package: + +.. code-block:: python + + from django.conf.urls import patterns, include, url + ... + urlpatterns = patterns('', + # list of url patterns + ) + +.. class:: incremental + +You can include lists of urls from installed apps by using the ``include`` +function as the callable in a url pattern: + +.. code-block:: python + :class: incremental + + url(http://github.com/r'%5Eblog/',%20include('my.blog.app.urls')) + +Including the Admin +------------------- + +Using this knowledge, we can add *all* the URLs provided by the Django admin +in one stroke. Edit ``urls.py``, which is open in your editor, and uncomment +three lines: + +.. code-block:: python + :class: incremental + + from django.contrib import admin #<- Uncomment these two + admin.autodiscover() + + urlpatterns = patterns('', + + # Uncomment the next line to enable the admin: + url(http://github.com/r'%5Eadmin/',%20include(admin.site.urls)), #<- and this + ) + +Using the Development Server +---------------------------- + +We can now view the admin. We'll use the Django development server. + +.. class:: incremental + +In your terminal, use the ``runserver`` management command to start the +development server: + +.. class:: incremental + +:: + + (djangoenv)$ python manage.py runserver + Validating models... + + 0 errors found + Django version 1.4.3, using settings 'mysite.settings' + Development server is running at http://127.0.0.1:8000/ + Quit the server with CONTROL-C. + +Viewing the Admin +----------------- + +Load ``http://localhost:8000/``. You should see this: + +.. image:: img/django-admin-login.png + :align: center + :width: 50% + +.. class:: incremental + +Login with the name and password you created before. + +The Admin Index +--------------- + +The index will provide a list of all the installed *apps* and each model +registered. You should see this: + +.. image:: img/admin_index.png + :align: center + :width: 90% + +.. class:: incremental + +Click on ``Users``. Find yourself? Edit yourself, but **don't** uncheck +``superuser``. + +Add Polls to the Admin +---------------------- + +Okay, let's add our app, and the models therein, to the admin. + +.. class:: incremental + +Add a new file to the ``polls`` app package: ``admin.py``. Edit it and add the +following: + +.. code-block:: python + :class: incremental + + from django.contrib import admin + from polls.models import Poll, Choice + + admin.site.register(Poll) + admin.site.register(Choice) + +.. class:: incremental + +Restart your Development server and reload the admin index + +Customized Admin +---------------- + +The Django Admin displays ``ModelAdmin`` instances for any models that are +registered + +.. class:: incremental + +* The object ``admin.site`` is a global instance of the ``Admin`` class. +* Each call to ``admin.site.register`` adds a new model to the global *site* +* ``register`` takes two args: a *Model* subclass and a *ModelAdmin* subclass +* If you call it with only the *Model* subclass, the *ModelAdmin* is + automatically generated. +* You can create, and customize, a *ModelAdmin* subclass for your models. + +Create a PollAdmin +------------------ + +In ``admin.py`` add the following code (above the calls to ``register``): + +.. code-block:: python + + class PollAdmin(admin.ModelAdmin): + list_display = ('pub_date', 'question', + 'published_today') + list_filter = ('pub_date', ) + ordering = ('pub_date', ) + +.. class:: incremental + +Then add this new class to the ``register`` call for our ``Poll``: + +.. code-block:: python + :class: incremental + + admin.site.register(Poll, PollAdmin) + +More Convenient Relations +------------------------- + +In our Admin site, you can see the ``Poll`` to which a ``Choice`` belongs. + +.. class:: incremental + +It'd be a lot nicer to be able to manage the ``Choices`` for a ``Poll`` from +the poll admin page, wouldn't it? + +.. class:: incremental + +The Django Admin provides a special type of ``ModelAdmin`` for just this +purpose: The ``InlineModelAdmin``. + +.. class:: incremental + +There are two flavors, *stacked* and *tabular*. The *tabular* version is more +compact as it displays each related object in a single table row. + +Create a Choice Inline +---------------------- + +Add the following code *above* our ``PollAdmin`` class in ``admin.py``: + +.. code-block:: python + + class ChoiceInline(admin.TabularInline): + model = Choice + extra = 3 + ordering = ('choice', ) + +Then, add the inline to ``PollAdmin``: + +.. code-block:: python + + class PollAdmin(admin.ModelAdmin): + # ... + inlines = (ChoiceInline, ) + +Method Attributes for the Admin +------------------------------- + +For example, methods of a class you use in the admin can have special +attributes that alter how it works. Make these changes to ``models.py`` + +.. code-block:: python + + class Poll(models.Model): + ... + def published_today(self): + now = timezone.now() + time_delta = now - self.pub_date + return time_delta.days == 0 + published_today.boolean = True + published_today.short_description = "Published Today?" + + +Reap the Rewards +---------------- + +Good work. You've set up a fully functional CRUD admin interface for your +application database in about 25 lines of code. + +.. class:: incremental + +Play with it for a bit. + +Lab - Part 3 +------------ + +In this part, we'll add public views and set up a way for visitors to vote +in our poll. + +Along the way, we'll learn a bit about Django's *Generic Views* and the +*Django Templating Language* + +Django Views +------------ + +Django views are callables that take a request and return a response. + +.. class:: incremental + +From the beginning, these have been functions. They still can be. + +.. class:: incremental + +Version 1.3 added support for Class-based Views. + +.. class:: incremental + +Really, they've always been there implicitly. The Admin is just a big +class-based view. + +Generic Views +------------- + +One of the most common uses for Class-based Views is in creating Generic Views. + +.. class:: incremental + +Some public views are so common that providing a simple and generic interface +for making them is a big win. + +.. class:: incremental + +* Showing a list of objects of some type. +* Showing the details of a single object of some type. +* Displaying a static HTML template (or a template with some dynamic context) +* Displaying and processing a simple HTML form. + +Our Application +--------------- + +We'd like to be able to add some views that show our polls to the public. + +.. class:: incremental + +What views would we like to have? + +.. class:: incremental + +* A list of all polls, perhaps ordered by publication date +* A display of a single poll, showing each choice and allowing a vote +* A view that processes a vote +* A view that shows the poll results after you vote. + +.. class:: incremental + +I start by configuring my URLs, it helps me think about the app API. + +Configure URLs +-------------- + +In your ``polls`` app package, add a new file: ``urls.py``. Open it in an +editor: + +.. code-block:: python + :class: incremental small + + from django.conf.urls import patterns, url + from django.http import HttpResponse + + def stub(request, *args, **kwargs): + return HttpResponse('stub view', mimetype="text/plain") + + urlpatterns = patterns('', + url(http://github.com/r'%5E"),%20stub,%20name=%22poll_list"), + url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/$', stub, name="poll_detail"), + url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/vote/$' stub, name="poll_vote"), + url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/result/$', stub, name="poll_result"), + ) + +Hook URLs to the Root +--------------------- + +Like with the Django Admin, we can now add all the urls for our poll app at +once. + +.. class:: incremental + +In the ``urls.py`` in our ``mysite`` project package, add the following: + +.. code-block:: python + :class: incremental small + + urlpatterns = patterns('', + url(http://github.com/r'%5Eadmin/',%20include(admin.site.urls)), + url(http://github.com/r'%5Epolls/',%20include('polls.urls')), # ADD + ) + +.. class:: incremental + +Restart the development server and load ``http://localhost:8000/polls/`` + +Generic Poll List +----------------- + +Django's Generic Views allow you to do quite a lot with just a little code. +Edit ``urls.py``: + +.. code-block:: python + :class: incremental small + + # add this import + from django.views.generic import ListView + + # edit the url pattern for the poll list: + url(r'^$', + ListView.as_view( + queryset=Poll.objects.order_by('-pub_date')[:5], + context_object_name='polls', + template_name="polls/list.html" + ), + name="poll_list"), + +.. class:: incremental + +Now, we just need to make that template + +Django Templates +---------------- + +The `Django Template Language +`_ looks a *lot* like +Jinja2. It is, however, quite a bit more limited. + +.. class:: incremental + +* variables available in context may be printed with ``{{ name }}`` +* variables that are objects or dictionaries may be addressed with dots: ``{{ + name.attr }}`` +* *filters* are available and look the same ``{{ name|upper }}`` +* logical *tags*: ``{% for x in y %}{{ x }}{% endfor %}`` +* available filters and tags may be extended with custom code +* templates can be *extended* and *included* +* you may define *blocks* in templates to be filled by other templates. +* you **may not** execute arbitrary python or assign variables and use them + +Setting Up +---------- + +In ``assignments/week06/lab/source`` you'll find a file ``base.html``. + +.. class:: incremental + +Create a new directory, ``templates`` in your ``polls`` app package. + +.. class:: incremental + +Copy the ``base.html`` file into that new directory. + +.. class:: incremental + +Next, create a folder ``polls`` *inside* that new templates directory. We'll +add our individual templates here. + +List Template +------------- + +Add ``list.html`` inside ``templates/polls``: + +.. code-block:: django + :class: small + + {% extends "base.html" %} + + {% block content %} +

    Latest Polls

    + {% for poll in polls %} + + {% endfor %} + {% endblock %} + +.. class:: incremental + +Now, load ``http://localhost:8000/polls/`` again. + +Detail View +----------- + +Back in our ``polls`` app, let's edit ``urls.py`` again: + +.. code-block:: python + :class: incremental small + + # add this import + from django.views.generic import ListView + + # and edit the detail url like so: + url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/$', + DetailView.as_view( + model=Poll, + template_name="polls/detail.html" + ), + name="poll_detail"), + +.. class:: incremental + +Again, we only need to add a template. + +Forms in Django +--------------- + +We want to be able to vote on a poll. + +.. class:: incremental + +Because doing so involves changing data on the server, we should do this with +a POST request. + +.. class:: incremental + +An html form is a simple way to allow us to force a POST request. + +.. class:: incremental + +Data-altering requests are vulnerable to Cross-Site Request Forgery, a common +attack vector. + +Danger: CSRF +------------ + +Django not only provides a convenient system to fight this, it *requires* it +for any POST requests. + +.. class:: incremental + +The Django middleware that does this is enabled by default. All you need to do +is include the {% csrf_token %} tag in your form template. + +.. class:: incremental + +Create a new file ``detail.html`` in your ``templates/polls`` directory + +Detail Template +--------------- + +.. code-block:: django + :class: small + + {% extends "base.html" %} + {% block content %} +

    {{ poll }}

    + {% if poll.choice_set.count > 0 %} +
    + {% csrf_token %} + {% for choice in poll.choice_set.all %} +
    +
    + {% endfor %} + +
    + {% else %} +

    No choices are available for this poll

    + {% endif %} + {% endblock %} + +Processing The Vote +------------------- + +We can now submit a form to the ``poll_vote`` url. We need to process that +vote + +.. class:: incremental + +Here, a class-based generic view is just going to get in our way. Let's use +an old-fashioned view function. + +.. class:: incremental + +How is our user's vote reaching the server? + +.. class:: incremental + +It gets there as POST data, the value for the key 'choice'. + +Django GET and POST Data +------------------------ + +Django provides the same type of Request/Response based interaction model that +most frameworks are based on. Views are called with the first argument being a +``request`` object. + +.. class:: incremental + +request.GET and request.POST are dictionary-like objects containing data +parsed from incoming HTTP request. + +.. class:: incremental + +You can use normal dictionary syntax to read values from these: + +.. code-block:: python + :class: incremental small + + bar = request.POST['bucko'] + foo = request.GET.get('somevar', None) + +Vote View Skeleton +------------------ + +In ``views.py`` from our ``polls`` app package: + +.. code-block:: python + :class: small + + from django.core.urlresolvers import reverse + from django.http import HttpResponseRedirect + + def vote_view(request, pk): + if request.method == "POST": + try: + # attempt to get a choice + except NoGoodChoice: # send back to detail + url = reverse('poll_detail', args=[pk, ]) + else: # vote and send to result + url = reverse('poll_result', args=[pk]) + else: # submitted via GET, ignore it + url = reverse('poll_detail', args=[pk, ]) + + return HttpResponseRedirect(url) + +Get the Choice +-------------- + +Let's start by filling out the process of getting the choice: + +.. code-block:: python + :class: small + + # add imports + from django.shortcuts import get_object_or_404 + from django.contrib import messages + from polls.models import Poll, Choice + # and edit our skeleton + def vote_view(request, pk): + poll = get_object_or_404(Poll, pk=pk) + if request.method == "POST": + try: + choice = poll.choice_set.get( + pk=request.POST.get('choice', 0)) + except Choice.DoesNotExist: + msg = "Ooops, pick a choice that exists, please" + messages.add_message(request, messages.ERROR, msg) + url = reverse('poll_detail', args=[pk, ]) + +Add a Vote +---------- + +Next, let's record a vote on our choice: + +.. code-block:: python + :class: small + + def vote_view(request, pk): + ... + try: + # choice = ... + except Choice.DoesNotExist: + # ... + else: + choice.votes += 1 + choice.save() + messages.add_message(request, messages.INFO, + "You voted for %s" % choice) + url = reverse('poll_result', args=[pk]) + +Add the URL +----------- + +Finally, we need to add this view to our urlconf. Back in ``urls.py`` in the +``polls`` app package, edit the url for the voting view like so: + +.. code-block:: python + :class: small + + url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/vote/$', + 'polls.views.vote_view', + name="poll_vote"), + +.. class:: incremental + +Notice that the 'callable' in this pattern is a string. Django allows you to +use this sort of *dotted name* reference. It will resolve it (or throw an +error if it can't) + +Display Result +-------------- + +The last view we need is the poll result. This can simply be a different +version of the Generic DetailView. Still in ``urls.py`` edit the pattern for +the results view: + +.. code-block:: python + :class: small + + url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/result/$', + DetailView.as_view( + model=Poll, + template_name="polls/result.html"), + name="poll_result") + +.. class:: incremental + +And, of course, we will need to create that final template + +Result Template +--------------- + +In ``templates/polls`` create a new file, ``result.html``: + +.. code-block:: django + :class: small + + {% extends "base.html" %} + + {% block content %} +

    {{ poll }}

    +
      + {% for choice in poll.choice_set.all %} +
    • {{ choice }} ({{choice.votes}} votes)
    • + {% endfor %} +
    + Back to the polls, please + {% endblock %} + +Play a Bit +---------- + +Alright. You've done it. + +Take a few minutes to add some polls in the Admin. + +Then return to the public side and vote. See how it goes. + +Assignment +---------- + +* Review the data structure and views required for the Flaskr app. + +* Start a new *app* in your same `mysite` project. Call it `djangor` -- manage.py startapp +* Build the required models to represent the data. Make two enhancements: + + * Add a column for 'pub_date' to the entry model + + * Allow each entry to be 'owned' by a User. Add a relation field to + represent this. + + * *HINT* ``django.contrib.auth.models`` defines a ``User`` model. -connecting to a database +* Build the urlconf required to present an entry list and a view for posting a + new entry. Add two new urls: + * One should show the archive of all posts from a given month and year + * One should show all the posts by a single user -writing models +* Build views for each URL -writing views +Submitting the Assignment +------------------------- -writing tests +* place your *app* package into the `athome` folder in ``assignments/week06/`` -what next? +* Add any notes, comments or questions in the form of a README file in that + same folder +* Commit your changes to your fork and make a pull request. From 030c30ad22816834ae8a2019b4c01c93ce69ef08 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 12 Feb 2013 02:04:47 -0800 Subject: [PATCH 062/487] update the outline to improve the description of week 7 --- source/main/outline.rst | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/source/main/outline.rst b/source/main/outline.rst index 724b9403..4447a86e 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -480,17 +480,24 @@ Reference Assignment ********** -To Be Decided +Assignment +********** + +You can read the assignment at + +http://github.com/cewing/training.python_web/blob/master/assignments/week06/athome/assignment.txt + +Please complete the assignment by noon on Sunday, February 17, 2013. Week 7 - Django --------------- **Date**: Feb. 19, 2013 -In this class we'll dive a bit further into Django. We'll take the -specifications from week 6 and the models we created from them to set up a -simple application. Along the way we'll learn a bit more about the Django -admin, generic views, and templates. +In this class we'll dive a bit further into Django. We'll take the app we +build for our week 6 homework and add style and security features. Along the +way we'll have a chance to learn more about Django's templates, models, views +and forms. We'll also discuss extending the functionality of our application using existing Django **apps**. We'll see how these add-ons can help us to solve From e3f8d65959291402bf47c91f3cbfa4ef53b26dce Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 12 Feb 2013 02:10:10 -0800 Subject: [PATCH 063/487] add lab files and teacher answer files for week 6 --- .../teachers/week06/answers/mysite/manage.py | 10 ++ .../week06/answers/mysite/mysite/__init__.py | 0 .../week06/answers/mysite/mysite/settings.py | 152 ++++++++++++++++++ .../week06/answers/mysite/mysite/urls.py | 18 +++ .../week06/answers/mysite/mysite/wsgi.py | 28 ++++ .../week06/answers/mysite/polls/__init__.py | 0 .../week06/answers/mysite/polls/admin.py | 20 +++ .../week06/answers/mysite/polls/models.py | 32 ++++ .../answers/mysite/polls/templates/base.html | 20 +++ .../mysite/polls/templates/polls/detail.html | 21 +++ .../mysite/polls/templates/polls/list.html | 11 ++ .../mysite/polls/templates/polls/result.html | 11 ++ .../week06/answers/mysite/polls/tests.py | 40 +++++ .../week06/answers/mysite/polls/urls.py | 34 ++++ .../week06/answers/mysite/polls/views.py | 26 +++ assignments/week06/athome/assignment.txt | 33 ++++ assignments/week06/lab/src/base.html | 20 +++ 17 files changed, 476 insertions(+) create mode 100644 assignments/teachers/week06/answers/mysite/manage.py create mode 100644 assignments/teachers/week06/answers/mysite/mysite/__init__.py create mode 100644 assignments/teachers/week06/answers/mysite/mysite/settings.py create mode 100644 assignments/teachers/week06/answers/mysite/mysite/urls.py create mode 100644 assignments/teachers/week06/answers/mysite/mysite/wsgi.py create mode 100644 assignments/teachers/week06/answers/mysite/polls/__init__.py create mode 100644 assignments/teachers/week06/answers/mysite/polls/admin.py create mode 100644 assignments/teachers/week06/answers/mysite/polls/models.py create mode 100644 assignments/teachers/week06/answers/mysite/polls/templates/base.html create mode 100644 assignments/teachers/week06/answers/mysite/polls/templates/polls/detail.html create mode 100644 assignments/teachers/week06/answers/mysite/polls/templates/polls/list.html create mode 100644 assignments/teachers/week06/answers/mysite/polls/templates/polls/result.html create mode 100644 assignments/teachers/week06/answers/mysite/polls/tests.py create mode 100644 assignments/teachers/week06/answers/mysite/polls/urls.py create mode 100644 assignments/teachers/week06/answers/mysite/polls/views.py create mode 100644 assignments/week06/athome/assignment.txt create mode 100644 assignments/week06/lab/src/base.html diff --git a/assignments/teachers/week06/answers/mysite/manage.py b/assignments/teachers/week06/answers/mysite/manage.py new file mode 100644 index 00000000..8a50ec04 --- /dev/null +++ b/assignments/teachers/week06/answers/mysite/manage.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) diff --git a/assignments/teachers/week06/answers/mysite/mysite/__init__.py b/assignments/teachers/week06/answers/mysite/mysite/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/assignments/teachers/week06/answers/mysite/mysite/settings.py b/assignments/teachers/week06/answers/mysite/mysite/settings.py new file mode 100644 index 00000000..405f36e7 --- /dev/null +++ b/assignments/teachers/week06/answers/mysite/mysite/settings.py @@ -0,0 +1,152 @@ +# Django settings for mysite project. + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +ADMINS = ( + # ('Your Name', 'your_email@example.com'), +) + +MANAGERS = ADMINS + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + 'NAME': 'mysite.db', # Or path to database file if using sqlite3. + 'USER': '', # Not used with sqlite3. + 'PASSWORD': '', # Not used with sqlite3. + 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. + 'PORT': '', # Set to empty string for default. Not used with sqlite3. + } +} + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# In a Windows environment this must be set to your system time zone. +TIME_ZONE = 'America/Chicago' + +# Language code for this installation. All choices can be found here: +# http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGE_CODE = 'en-us' + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + +# If you set this to False, Django will not format dates, numbers and +# calendars according to the current locale. +USE_L10N = True + +# If you set this to False, Django will not use timezone-aware datetimes. +USE_TZ = True + +# Absolute filesystem path to the directory that will hold user-uploaded files. +# Example: "/home/media/media.lawrence.com/media/" +MEDIA_ROOT = '' + +# URL that handles the media served from MEDIA_ROOT. Make sure to use a +# trailing slash. +# Examples: "http://media.lawrence.com/media/", "http://example.com/media/" +MEDIA_URL = '' + +# Absolute path to the directory static files should be collected to. +# Don't put anything in this directory yourself; store your static files +# in apps' "static/" subdirectories and in STATICFILES_DIRS. +# Example: "/home/media/media.lawrence.com/static/" +STATIC_ROOT = '' + +# URL prefix for static files. +# Example: "http://media.lawrence.com/static/" +STATIC_URL = '/static/' + +# Additional locations of static files +STATICFILES_DIRS = ( + # Put strings here, like "/home/html/static" or "C:/www/django/static". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +# List of finder classes that know how to find static files in +# various locations. +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', +# 'django.contrib.staticfiles.finders.DefaultStorageFinder', +) + +# Make this unique, and don't share it with anybody. +SECRET_KEY = ')-z(0n-exq%$(^6*sunt1b7q#zo!hy$f(-p#2@q1pjcsvc0y@)' + +# List of callables that know how to import templates from various sources. +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', +# 'django.template.loaders.eggs.Loader', +) + +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + # Uncomment the next line for simple clickjacking protection: + # 'django.middleware.clickjacking.XFrameOptionsMiddleware', +) + +ROOT_URLCONF = 'mysite.urls' + +# Python dotted path to the WSGI application used by Django's runserver. +WSGI_APPLICATION = 'mysite.wsgi.application' + +TEMPLATE_DIRS = ( + # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + # Uncomment the next line to enable the admin: + 'django.contrib.admin', + # Uncomment the next line to enable admin documentation: + # 'django.contrib.admindocs', + 'polls', +) + +# A sample logging configuration. The only tangible logging +# performed by this configuration is to send an email to +# the site admins on every HTTP 500 error when DEBUG=False. +# See http://docs.djangoproject.com/en/dev/topics/logging for +# more details on how to customize your logging configuration. +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse' + } + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler' + } + }, + 'loggers': { + 'django.request': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': True, + }, + } +} diff --git a/assignments/teachers/week06/answers/mysite/mysite/urls.py b/assignments/teachers/week06/answers/mysite/mysite/urls.py new file mode 100644 index 00000000..94976a0a --- /dev/null +++ b/assignments/teachers/week06/answers/mysite/mysite/urls.py @@ -0,0 +1,18 @@ +from django.conf.urls import patterns, include, url + +# Uncomment the next two lines to enable the admin: +from django.contrib import admin +admin.autodiscover() + +urlpatterns = patterns('', + # Examples: + # url(http://github.com/r'%5E'),%20'mysite.views.home',%20name='home'), + # url(http://github.com/r'%5Emysite/',%20include('mysite.foo.urls')), + + # Uncomment the admin/doc line below to enable admin documentation: + # url(http://github.com/r'%5Eadmin/doc/',%20include('django.contrib.admindocs.urls')), + + # Uncomment the next line to enable the admin: + url(http://github.com/r'%5Eadmin/',%20include(admin.site.urls)), + url(http://github.com/r'%5Epolls/',%20include('polls.urls')) +) diff --git a/assignments/teachers/week06/answers/mysite/mysite/wsgi.py b/assignments/teachers/week06/answers/mysite/mysite/wsgi.py new file mode 100644 index 00000000..4169f1ec --- /dev/null +++ b/assignments/teachers/week06/answers/mysite/mysite/wsgi.py @@ -0,0 +1,28 @@ +""" +WSGI config for mysite project. + +This module contains the WSGI application used by Django's development server +and any production WSGI deployments. It should expose a module-level variable +named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover +this application via the ``WSGI_APPLICATION`` setting. + +Usually you will have the standard Django WSGI application here, but it also +might make sense to replace the whole Django WSGI application with a custom one +that later delegates to the Django one. For example, you could introduce WSGI +middleware here, or combine a Django application with an application of another +framework. + +""" +import os + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + +# This application object is used by any WSGI server configured to use this +# file. This includes Django's development server, if the WSGI_APPLICATION +# setting points here. +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() + +# Apply WSGI middleware here. +# from helloworld.wsgi import HelloWorldApplication +# application = HelloWorldApplication(application) diff --git a/assignments/teachers/week06/answers/mysite/polls/__init__.py b/assignments/teachers/week06/answers/mysite/polls/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/assignments/teachers/week06/answers/mysite/polls/admin.py b/assignments/teachers/week06/answers/mysite/polls/admin.py new file mode 100644 index 00000000..33331596 --- /dev/null +++ b/assignments/teachers/week06/answers/mysite/polls/admin.py @@ -0,0 +1,20 @@ +from django.contrib import admin +from polls.models import Poll, Choice + + +class ChoiceInline(admin.TabularInline): + model = Choice + extra = 3 + ordering = ('choice', ) + + +class PollAdmin(admin.ModelAdmin): + list_display = ('pub_date', 'question', + 'published_today') + list_filter = ('pub_date', ) + ordering = ('pub_date', ) + inlines = (ChoiceInline, ) + + +admin.site.register(Poll, PollAdmin) +admin.site.register(Choice) diff --git a/assignments/teachers/week06/answers/mysite/polls/models.py b/assignments/teachers/week06/answers/mysite/polls/models.py new file mode 100644 index 00000000..a32765c7 --- /dev/null +++ b/assignments/teachers/week06/answers/mysite/polls/models.py @@ -0,0 +1,32 @@ +from django.db import models +from django.utils import timezone + + +class Poll(models.Model): + question = models.CharField(max_length=200) + pub_date = models.DateTimeField('date published') + + def __unicode__(self): + return self.question + + def published_today(self): + now = timezone.now() + time_delta = now - self.pub_date + return time_delta.days == 0 + published_today.boolean = True + published_today.short_description = "Published Today?" + + def total_votes(self): + total = 0 + for choice in self.choice_set.all(): + total += choice.votes + return total + + +class Choice(models.Model): + poll = models.ForeignKey(Poll) + choice = models.CharField(max_length=200) + votes = models.IntegerField(default=0) + + def __unicode__(self): + return self.choice diff --git a/assignments/teachers/week06/answers/mysite/polls/templates/base.html b/assignments/teachers/week06/answers/mysite/polls/templates/base.html new file mode 100644 index 00000000..268c42bf --- /dev/null +++ b/assignments/teachers/week06/answers/mysite/polls/templates/base.html @@ -0,0 +1,20 @@ + + + + My Site + + +
    +
    + {% if messages %} + {% for message in messages %} +

    + {{ message }}

    + {% endfor %} + {% endif %} + {% block content %} + {% endblock %} +
    +
    + + \ No newline at end of file diff --git a/assignments/teachers/week06/answers/mysite/polls/templates/polls/detail.html b/assignments/teachers/week06/answers/mysite/polls/templates/polls/detail.html new file mode 100644 index 00000000..a842f41c --- /dev/null +++ b/assignments/teachers/week06/answers/mysite/polls/templates/polls/detail.html @@ -0,0 +1,21 @@ +{% extends "base.html" %} + +{% block content %} +

    {{ poll }}

    +{% if poll.choice_set.count > 0 %} +
    + {% csrf_token %} + {% for choice in poll.choice_set.all %} +
    + +
    + {% endfor %} + +
    +{% else %} +

    No choices are available for this poll

    +{% endif %} +{% endblock %} \ No newline at end of file diff --git a/assignments/teachers/week06/answers/mysite/polls/templates/polls/list.html b/assignments/teachers/week06/answers/mysite/polls/templates/polls/list.html new file mode 100644 index 00000000..2aeb2773 --- /dev/null +++ b/assignments/teachers/week06/answers/mysite/polls/templates/polls/list.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} + +{% block content %} +

    Latest Polls

    +{% for poll in polls %} +
    +

    {{ poll }}

    +

    Total Votes: {{ poll.total_votes }}

    +
    +{% endfor %} +{% endblock %} diff --git a/assignments/teachers/week06/answers/mysite/polls/templates/polls/result.html b/assignments/teachers/week06/answers/mysite/polls/templates/polls/result.html new file mode 100644 index 00000000..8937985a --- /dev/null +++ b/assignments/teachers/week06/answers/mysite/polls/templates/polls/result.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} + +{% block content %} +

    {{ poll }}

    +
      + {% for choice in poll.choice_set.all %} +
    • {{ choice }} ({{choice.votes}} votes)
    • + {% endfor %} +
    +Back to the polls, please +{% endblock %} \ No newline at end of file diff --git a/assignments/teachers/week06/answers/mysite/polls/tests.py b/assignments/teachers/week06/answers/mysite/polls/tests.py new file mode 100644 index 00000000..dd007626 --- /dev/null +++ b/assignments/teachers/week06/answers/mysite/polls/tests.py @@ -0,0 +1,40 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" +from datetime import timedelta + +from django.test import TestCase +from django.utils import timezone + +from polls.models import Poll + + +class PollTest(TestCase): + def setUp(self): + self.expected_question = "what is the question?" + self.expected_choice = "do you like spongecake?" + self.poll = Poll.objects.create(question=self.expected_question, + pub_date=timezone.now()) + self.choice = self.poll.choice_set.create( + choice=self.expected_choice) + + def test_published_today(self): + self.assertTrue(self.poll.published_today()) + delta = timedelta(hours=26) + self.poll.pub_date = self.poll.pub_date - delta + self.assertFalse(self.poll.published_today()) + + def test_poll_display(self): + self.assertEquals(unicode(self.poll), self.expected_question) + new_question = "What is the answer?" + self.poll.question = new_question + self.assertEquals(unicode(self.poll), new_question) + + def test_choice_display(self): + self.assertEquals(unicode(self.choice), self.expected_choice) + new_choice = "is left better than right?" + self.choice.choice = new_choice + self.assertEquals(unicode(self.choice), new_choice) \ No newline at end of file diff --git a/assignments/teachers/week06/answers/mysite/polls/urls.py b/assignments/teachers/week06/answers/mysite/polls/urls.py new file mode 100644 index 00000000..32da9a8d --- /dev/null +++ b/assignments/teachers/week06/answers/mysite/polls/urls.py @@ -0,0 +1,34 @@ +from django.conf.urls import patterns, url +from django.views.generic import DetailView, ListView +from django.http import HttpResponse + +from polls.models import Poll + + +def stub(request, *args, **kwargs): + return HttpResponse('stub view', mimetype="text/plain") + + +urlpatterns = patterns('', + url(r'^$', + ListView.as_view( + queryset=Poll.objects.order_by('-pub_date')[:5], + context_object_name='polls', + template_name="polls/list.html" + ), + name="poll_list"), + url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/$', + DetailView.as_view( + model=Poll, + template_name="polls/detail.html" + ), + name="poll_detail"), + url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/vote/$', + 'polls.views.vote_view', + name="poll_vote"), + url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/result/$', + DetailView.as_view( + model=Poll, + template_name="polls/result.html"), + name="poll_result") +) \ No newline at end of file diff --git a/assignments/teachers/week06/answers/mysite/polls/views.py b/assignments/teachers/week06/answers/mysite/polls/views.py new file mode 100644 index 00000000..d069db6b --- /dev/null +++ b/assignments/teachers/week06/answers/mysite/polls/views.py @@ -0,0 +1,26 @@ +from django.shortcuts import get_object_or_404 +from django.core.urlresolvers import reverse +from django.contrib import messages +from django.http import HttpResponseRedirect +from polls.models import Poll, Choice + + +def vote_view(request, pk): + poll = get_object_or_404(Poll, pk=pk) + if request.method == "POST": + try: + choice = poll.choice_set.get(pk=request.POST.get('choice', 0)) + except Choice.DoesNotExist: + msg = "Ooops, pick a choice that exists, please" + messages.add_message(request, messages.ERROR, msg) + url = reverse('poll_detail', args=[pk, ]) + else: + choice.votes += 1 + choice.save() + messages.add_message(request, messages.INFO, + "You voted for %s" % choice) + url = reverse('poll_result', args=[pk]) + else: + url = reverse('poll_detail', args=[pk, ]) + + return HttpResponseRedirect(url) \ No newline at end of file diff --git a/assignments/week06/athome/assignment.txt b/assignments/week06/athome/assignment.txt new file mode 100644 index 00000000..bca15cec --- /dev/null +++ b/assignments/week06/athome/assignment.txt @@ -0,0 +1,33 @@ +Assignment + +* Review the data structure and views required for the Flaskr app. + +* Start a new *app* in your same `mysite` project. Call it `djangor` + +* Build the required models to represent the data. Make two enhancements: + + * Add a column for 'pub_date' to the entry model + + * Allow each entry to be 'owned' by a User. Add a relation field to + represent this. + + * *HINT* ``django.contrib.auth.models`` defines a ``User`` model. + +* Build the urlconf required to present an entry list and a view for posting a + new entry. Add two new urls: + + * One should show the archive of all posts from a given month and year + + * One should show all the posts by a single user + +* Build views for each URL + +Submitting the Assignment +------------------------- + +* place your *app* package into the `athome` folder in ``assignments/week06/`` + +* Add any notes, comments or questions in the form of a README file in that + same folder + +* Commit your changes to your fork and make a pull request. diff --git a/assignments/week06/lab/src/base.html b/assignments/week06/lab/src/base.html new file mode 100644 index 00000000..f89925eb --- /dev/null +++ b/assignments/week06/lab/src/base.html @@ -0,0 +1,20 @@ + + + + My Site + + +
    +
    + {% if messages %} + {% for message in messages %} +

    + {{ message }}

    + {% endfor %} + {% endif %} + {% block content %} + {% endblock %} +
    +
    + + From 47e3db575262fca8ebef4450154e4350724f4e80 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 12 Feb 2013 02:14:23 -0800 Subject: [PATCH 064/487] update, trim a bit --- source/presentations/week06.rst | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/source/presentations/week06.rst b/source/presentations/week06.rst index 9e2f4ad6..98b7c4c6 100644 --- a/source/presentations/week06.rst +++ b/source/presentations/week06.rst @@ -36,25 +36,6 @@ And Now :align: center :width: 79% - -Full Stack Framework --------------------- - -Django is **One Big Package** - -.. class:: incremental - -When you installed Flask, you also installed *werkzeug* and *jinja2*, a total -of 1.85MB - -.. class:: incremental - -Django 1.4.3 weighs in at 7.7MB (4 times the size of Flask) - -.. class:: incremental - -So what do you get? - Full Stack Framework -------------------- @@ -221,7 +202,7 @@ One *project* can (and likely will) consist of many *apps* Starting a Project ------------------ -You should already have done this at home, but we'll look at it together in +You should already have done this at home, but we'll look at it together quickly, in case: .. class:: incremental From 061715a4bf43965bdf51d9e241cc7e0eedded894 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 12 Feb 2013 02:17:25 -0800 Subject: [PATCH 065/487] consistency. for hobgoblins --- source/presentations/week06.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/presentations/week06.rst b/source/presentations/week06.rst index 98b7c4c6..4c29ca1a 100644 --- a/source/presentations/week06.rst +++ b/source/presentations/week06.rst @@ -202,8 +202,8 @@ One *project* can (and likely will) consist of many *apps* Starting a Project ------------------ -You should already have done this at home, but we'll look at it together quickly, in -case: +You should already have done this at home, but we'll look at it together +quickly, in case: .. class:: incremental @@ -371,7 +371,7 @@ Todays lab is drawn from the `Django Tutorial `_, with some minor adjustments. -Lab - Step One +Lab - Part One -------------- We are going to create an *app* to add to our *project*. This app will: @@ -1104,8 +1104,8 @@ application database in about 25 lines of code. Play with it for a bit. -Lab - Part 3 ------------- +Lab - Part Three +---------------- In this part, we'll add public views and set up a way for visitors to vote in our poll. From dffa7a68bac35e936d5bc4a20d23a5184ef10d23 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 12 Feb 2013 02:24:21 -0800 Subject: [PATCH 066/487] updates to the outline, link presentation for week 6 --- source/main/outline.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/main/outline.rst b/source/main/outline.rst index 4447a86e..82d8b657 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -437,6 +437,8 @@ Django ORM (and ORMs in general) can help shield Python developers from SQL. For our homework, we'll take a look at a set of specifications for a project and create a set of Django Models that will fulfill the specification. +`Week 6 Presentation `_ + Reading ******* From 0b5169f0591bc85b34cf642cdc87b5a187518a15 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 12 Feb 2013 17:59:50 -0800 Subject: [PATCH 067/487] update assignment portion --- source/presentations/week06.rst | 72 ++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/source/presentations/week06.rst b/source/presentations/week06.rst index 4c29ca1a..3e491a8e 100644 --- a/source/presentations/week06.rst +++ b/source/presentations/week06.rst @@ -1558,35 +1558,69 @@ Take a few minutes to add some polls in the Admin. Then return to the public side and vote. See how it goes. +Next Week +--------- + +We are going to mix it up quite a bit this week. + +.. class:: incremental + +I would like you all to divide into teams. Each team should have 4-6 people. +Each team should have both experienced and inexperienced members. Try to match +up with people whose strengths are different from your own. + +.. class:: incremental + +Now, each team, pick a 'facilitator'. This person will be responsible for +managing the operation of the team. This person will help to ensure that each +team member has a task. This should be a more experienced team member. + Assignment ---------- -* Review the data structure and views required for the Flaskr app. +During this week, each **non-leader member** will duplicate the Flaskr app +using Django. + +.. class:: incremental -* Start a new *app* in your same `mysite` project. Call it `djangor` +* Create a new *app* which will hold all the code required. +* Define the model for the 'entry' object. +* Extend that model with two additional fields: ``publication_date`` + (DateTimeField), and ``author`` (ForeignKey to + ``django.contrib.auth.models.User``) +* Define the URLs you'll need (an entry list, a form processor) +* Define the Views you'll need (see the two above). -* Build the required models to represent the data. Make two enhancements: - - * Add a column for 'pub_date' to the entry model - - * Allow each entry to be 'owned' by a User. Add a relation field to - represent this. - - * *HINT* ``django.contrib.auth.models`` defines a ``User`` model. +Assignment +---------- -* Build the urlconf required to present an entry list and a view for posting a - new entry. Add two new urls: - * One should show the archive of all posts from a given month and year - * One should show all the posts by a single user +During this week, each **team leader** will communicate with me to build a +plan for implementing a new feature for the Django flaskr app. + +.. class:: incremental -* Build views for each URL +* User Registration +* 'Archive' views based on date or author +* WYSIWYG visual editor for entry posts. +* Tagging +* Theme (make it beautiful) +* Search (this is a bigger one than you might think) Submitting the Assignment ------------------------- -* place your *app* package into the `athome` folder in ``assignments/week06/`` +Leaders, you will communicate with me to make a plan + +Members, you will do the usual submission of your code. + +DO NOT ATTEMPT TO GET YOUR CODE RUNNING ON A VM + +Next Week +--------- + +Our class next week will be a little different. Each team will be implementing +a new feature for our micro-blog application. -* Add any notes, comments or questions in the form of a README file in that - same folder +We will work in teams for the entire class up until 8:30, when we will show +off our results. -* Commit your changes to your fork and make a pull request. From 49ae2eed27fcb2dd67e3d767d87e997cb9e562ee Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 17 Feb 2013 15:50:34 -0800 Subject: [PATCH 068/487] update linked assignment text to match the actual assignment in the slides. --- assignments/week06/athome/assignment.txt | 40 +++++++++++++++++++----- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/assignments/week06/athome/assignment.txt b/assignments/week06/athome/assignment.txt index bca15cec..bf7b9f6f 100644 --- a/assignments/week06/athome/assignment.txt +++ b/assignments/week06/athome/assignment.txt @@ -1,4 +1,34 @@ Assignment +---------- + +As described in class, we've divided into teams for Week 07. Our assignment +for week six is also divided. Each team has a team leader, they have one +assignment, described below. The remaining members of each team have a second +assignment, also described below. + +Team Leader Assignment +---------------------- + +If you are a team leader, your assignment is to formulate a plan to implement +one of the following features as an extension to the djangor micro-blog app +your team members are building. Please pick one feature and communicate your +plan to me before the start of class on Tuesday, Feb. 19: + +* User Registration (django-registration) +* 'Archive' views based on date or author (generic date-based views) +* WYSIWYG visual editor for entry posts. (django-ckeditor) +* Tagging (django-taggit) +* Theme (make it beautiful) + +Submitting the Team Leader Assignment +------------------------------------- + +Communicate with your team to decide a feature. Formulate a plan to implement +that feature. Research the tools you'll need to accomplish the job. +Communicate your plan to Cris (cris@crisewing.com) + +Team Member Assignment +---------------------- * Review the data structure and views required for the Flaskr app. @@ -14,16 +44,12 @@ Assignment * *HINT* ``django.contrib.auth.models`` defines a ``User`` model. * Build the urlconf required to present an entry list and a view for posting a - new entry. Add two new urls: - - * One should show the archive of all posts from a given month and year - - * One should show all the posts by a single user + new entry. * Build views for each URL -Submitting the Assignment -------------------------- +Submitting the Team Member Assignment +------------------------------------- * place your *app* package into the `athome` folder in ``assignments/week06/`` From 0fbfe5ab08b43d8bca7f41518f85d9edc272c277 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 18 Feb 2013 23:35:03 -0800 Subject: [PATCH 069/487] * add assignment instructions for week 7 --- assignments/week07/athome/assignment.txt | 129 +++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 assignments/week07/athome/assignment.txt diff --git a/assignments/week07/athome/assignment.txt b/assignments/week07/athome/assignment.txt new file mode 100644 index 00000000..6d02ac8c --- /dev/null +++ b/assignments/week07/athome/assignment.txt @@ -0,0 +1,129 @@ +Assignment - Prep +----------------- + +For this week, you have *no* code assignment. + +Instead I want you to focus on installing software and reading for next week. +Software we'll be installing uses C extensions, and so installing it on OS X +or Linux requires a compiler and python's development headers. + +**Ubuntu** (our vms): + + $ sudo apt-get install python-dev + +**OS X**: Ensure that you have XCode installed. It's free, but *big* expect it +to take a while if you don't already have it. + +**Windows**: You all are safe for the time being. + +Assignment - Virtualenv +----------------------- + +With that prep work out of the way, you're ready to start. First, set up a +virtualenv: + + $ python2.6 virtualenv.py --distribute pyramidenv + ... + $ source pyramidenv/bin/activate + (pyramidenv)$ + +Remeber, Windows users: ``> pyramidenv\Scripts\activate`` + +Assignment - Install Pyramid +---------------------------- + +Once you've got a virtualenv set up and ready to go, install Pyramid: + + (pyramidenv)$ easy_install pyramid + +This will install a number of dependency packages, do not be alarmed. + +Next, we'll install a different kind of Database, the ZODB. + +Assignment - Install ZODB +------------------------- + +If you're on OS X or Linux: + + (pyramidenv)$ easy_install ZODB3==3.10.5 + +This will take some time. If you get errors, contact me directly or via the +Google Group. + +Windows users, you'll have it a bit easier here. You have to install a binary +egg: + + [pyramidenv]> pip install --egg ZODB3==3.10.5 + +Pause for Self Evaluation +------------------------- + +At this point, you can check your work. Fire up a python interpreter in your +virtualenv: + + (pyramidenv)$ python + >>> import ZODB + >>> ^D + (pyramidenv)$ + +If you get an ImportError when you try that, you're not done. Contact me. + +Assignment - Extras +------------------- + +Next, we'll need to finish installing the bits we need for our work next +week: + + (pyramidenv)$ easy_install docutils nose coverage + ... + (pyramidenv)$ easy_install pyramid_zodbconn pyramid_tm + ... + (pyramidenv)$ easy_install pyramid_debugtoolbar + +These tools will allow us to manage ZODB connections, debug our app, and run +cool tests. + +Assignment - Set Up Project +--------------------------- + +And finally, we'll set up a project for ourselves. This is like running +'startproject' for django in a way: + + (pyramidenv)$ pcreate -s zodb wikitutorial + +Do not be alarmed by the 'sorry for the convenience' message. + +You get a folder called ``wikitutorial``. In it you should see files like +``setup.py`` and ``development.ini`` among others. + +This is an installable ``package``. You can install this package with +easy_install. + +Final Self Evaluation +--------------------- + +In fact, let's do that now, so we can prove to ourselves this all worked: + + (pyramidenv)$ cd wikitutorial + (pyramidenv)$ python setup.py develop + ... + +You'll see a bunch of output. When it's over, run tests: + + (pyramidenv)$ python setup.py test -q + +Congratulations +--------------- + +When you've made it this far, and you see 1 test run successfully, you're +done. + +If you like, you can see your work by running the new project:: + + (pyramidenv)$ pserve development.ini + Starting server in PID 3056. + serving on http://0.0.0.0:6543 + +Visit that url to see your work in action. then go grab a beer and curl up +with the reading for the week. There's a lot. + From 57b66820c18edda484dfc939175a15555d37b1a6 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 18 Feb 2013 23:36:12 -0800 Subject: [PATCH 070/487] rename this to pick up automatic formatting --- assignments/week07/athome/{assignment.txt => assignment.rst} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename assignments/week07/athome/{assignment.txt => assignment.rst} (100%) diff --git a/assignments/week07/athome/assignment.txt b/assignments/week07/athome/assignment.rst similarity index 100% rename from assignments/week07/athome/assignment.txt rename to assignments/week07/athome/assignment.rst From f0524a20f0c0fd7f121e0c7a7642dc0fadfee12b Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 18 Feb 2013 23:38:49 -0800 Subject: [PATCH 071/487] fix header formatting --- assignments/week07/athome/assignment.rst | 27 +++++++++++++----------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/assignments/week07/athome/assignment.rst b/assignments/week07/athome/assignment.rst index 6d02ac8c..7652170f 100644 --- a/assignments/week07/athome/assignment.rst +++ b/assignments/week07/athome/assignment.rst @@ -1,5 +1,8 @@ -Assignment - Prep ------------------ +Week 7 Assignment Instructions +============================== + +Prep +---- For this week, you have *no* code assignment. @@ -16,8 +19,8 @@ to take a while if you don't already have it. **Windows**: You all are safe for the time being. -Assignment - Virtualenv ------------------------ +Virtualenv +---------- With that prep work out of the way, you're ready to start. First, set up a virtualenv: @@ -29,8 +32,8 @@ virtualenv: Remeber, Windows users: ``> pyramidenv\Scripts\activate`` -Assignment - Install Pyramid ----------------------------- +Install Pyramid +--------------- Once you've got a virtualenv set up and ready to go, install Pyramid: @@ -40,8 +43,8 @@ This will install a number of dependency packages, do not be alarmed. Next, we'll install a different kind of Database, the ZODB. -Assignment - Install ZODB -------------------------- +Install ZODB +------------ If you're on OS X or Linux: @@ -68,8 +71,8 @@ virtualenv: If you get an ImportError when you try that, you're not done. Contact me. -Assignment - Extras -------------------- +Extras +------ Next, we'll need to finish installing the bits we need for our work next week: @@ -83,8 +86,8 @@ week: These tools will allow us to manage ZODB connections, debug our app, and run cool tests. -Assignment - Set Up Project ---------------------------- +Set Up Project +-------------- And finally, we'll set up a project for ourselves. This is like running 'startproject' for django in a way: From 776b43e16a791748a632cbdccd9487433b45809b Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 18 Feb 2013 23:40:37 -0800 Subject: [PATCH 072/487] tweaks to assignment wording fix up outline for week7-8 finalize week 7 presentation start week 8 slides --- assignments/week07/athome/assignment.rst | 4 +- source/main/outline.rst | 117 +++++-- source/presentations/week07.rst | 420 ++++++++++++++++++++++- source/presentations/week08.rst | 36 +- 4 files changed, 551 insertions(+), 26 deletions(-) diff --git a/assignments/week07/athome/assignment.rst b/assignments/week07/athome/assignment.rst index 7652170f..d95d5160 100644 --- a/assignments/week07/athome/assignment.rst +++ b/assignments/week07/athome/assignment.rst @@ -127,6 +127,6 @@ If you like, you can see your work by running the new project:: Starting server in PID 3056. serving on http://0.0.0.0:6543 -Visit that url to see your work in action. then go grab a beer and curl up -with the reading for the week. There's a lot. +Visit ``http://localhost:6543`` to see your work in action. then go grab a +beer and curl up with the reading for the week. There's a lot. diff --git a/source/main/outline.rst b/source/main/outline.rst index 82d8b657..51a60f6e 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -496,20 +496,18 @@ Week 7 - Django **Date**: Feb. 19, 2013 -In this class we'll dive a bit further into Django. We'll take the app we -build for our week 6 homework and add style and security features. Along the -way we'll have a chance to learn more about Django's templates, models, views -and forms. - -We'll also discuss extending the functionality of our application using -existing Django **apps**. We'll see how these add-ons can help us to solve -common problems like user registration and database schema management. +In this class we'll dive a bit further into Django. We'll start with a +duplicate of the micro-blog we built in week 5 and work in teams to extend the +functionality by integrating existing apps. Along the way, we'll have a chance +to explore team-based development workflow. Finally, we'll discuss some of the strengths and weaknesses of Django. What makes it a good choice for some projects but not for others. -Our assignment for the week will be to enhance the application we build in -class with some additional functionality. +Our assignment for the week will be to prepare for working with Pyramid in +Week 8. + +`Week 7 Presentation `_ Reading ******* @@ -546,16 +544,6 @@ Reading different approaches to testing Django applications, including unit testing and doctests. -Before Class -************ - -We'll be adding a new bit of functionality to our app, and we'll do this not -by developing it ourselves, but by *integrating* an existing add-on. Before -class begins, please install `django-south -`_ and `django-registration -`_ into your Django -virtualenv. - Reference ********* @@ -572,13 +560,100 @@ Reference Assignment ********** -To Be Decided +This week we will have no code assignment. Instead the assignment will be to +install Pyramid and the ZODB. + +**WARNING**: the ZODB is built with C-based extensions. Installing it requires +a c compiler. On linux, gcc will do nicely but you'll need to install python +development headers. If you are using Mac OS X, you'll need to install XCode. +This is not fast. Be sure to start early in the week to leave time for this. + +Read the `Instructions +`_ Week 8 - Pyramid ---------------- **Date**: Feb. 26, 2013 +This week we will look at a relative newcomer to the Python Web Framework +scene, Pyramid. Although the framework is a newcomer, it is represents a +combination of several projects, notably Repoze and Pylons, that have been +around for quite some time. In fact, the roots of Repoze go back to Zope, the +original Python web framework (and quite possibly the first web framework in +any language). + +We will talk a bit about what makes Pyramid different from other web +frameworks. We will look at the specific problems that the creators of Pyramid +are looking to solve, and we will investigate how those decisions have +influenced the design of the framework. + +We'll specifically look at two technologies that set the Pyramid framework +apart: the ZODB and URL Traversal. We'll do this by implementing a wiki using +these technologies and then discuss what might make such tools appealing to a +certain type of project. + +We'll also look at a very different templating system, Chameleon, which grew +out of Zope Page Templates and the Template Attribute Language. Chameleon +provides code structures via XML namespaces, allowing you to write templates +that will load in a browser looking like HTML without needing a framework to +render them. + +Reading +******* + +Why you should care about `Traversal +`_. + +Compare and contrast forms of dispatch in Pyramid: + +* `URL Route Dispatch + `_ +* `Object Traversal + `_ + +Learn a bit about the `ZODB `_ + +* Read the `tutorial `_ for a + quick overview of usage (don't actually do it, though). +* Read the `more complete walk-through here + `_ altough, again, do not + actually do the code examples. +* Learn about `object references in the ZODB + `_ + - one of its greatest strengths. + +Learn a bit about the Chameleon ZPT templating language: + +* Read about `Chameleon Templates in Pyramid + `_ +* A `Quick Intro to TAL `_ + +* `Chameleon Documentation `_ + +In particular, pay attention to: + +* `Basics (TAL) + `_ +* `Expressions (TALES) + `_ + + +References +********** + +* `The ZODB Book `_ - A work in + progress by Carlos De La Guardia. + +* The `ZPT Appendix `_ to + the Zope Book + +* Read `Defending Pyramid's Design + `_ + - an excellent point-by-point explanation of the design decisions that went + into creating this framework. + + Assignment ********** diff --git a/source/presentations/week07.rst b/source/presentations/week07.rst index e09f312f..7ef6e8e3 100644 --- a/source/presentations/week07.rst +++ b/source/presentations/week07.rst @@ -1,2 +1,418 @@ -This is Week 7 --------------- \ No newline at end of file +Internet Programming with Python +================================ + +.. image:: img/django-pony.png + :align: left + :width: 50% + +Week 7: Django - Part 2 + +.. class:: intro-blurb right + +Wherein we extend Django's built-in features + +.. class:: image-credit + +image: http://djangopony.com/ + +But First +--------- + +.. class:: big-centered + +Questions from the Reading? + +And Second +---------- + +A reminder of our task for today: + +.. class:: incremental + +Extend a basic micro-blog application with one of the following features: + +.. class:: incremental + +* User Registration +* 'Archive' views based on date or author +* WYSIWYG visual editor for entry posts. +* Tagging +* Theme (make it beautiful) + +Your Teams +---------- + +**Team 1**: + +.. class:: incremental + +**Leader**: Jon B + +.. class:: incremental + +**Members**: Tyler, Matt K, John C, Wilson, Divesh + +.. class:: incremental + +**Your Task**: User Registration with ``django-registration`` + +Your Teams +---------- + +**Team 2**: + +.. class:: incremental + +**Leader**: Matt O + +.. class:: incremental + +**Members**: David, Pho, Phil, Chris + +.. class:: incremental + +**Your Task**: Archive Views using Generic date-based views + +Your Teams +---------- + +**Team 3**: + +.. class:: incremental + +**Leader**: Austin + +.. class:: incremental + +**Members**: Edet, Eric, Allan + +.. class:: incremental + +**Your Task**: Content Tagging with ``django-taggit`` + +Your Teams +---------- + +**Team 4**: + +.. class:: incremental + +**Leader**: Jason + +.. class:: incremental + +**Members**: Daniel, Conor, Maria + +.. class:: incremental + +**Your Task**: WYSIWYG Editing with ``django-ckeditor`` + +My Guidelines +------------- + +Each team can work from a single *core* repository. + +.. class:: incremental + +Break the job into discreet tasks. + +.. class:: incremental + +Work in twos or threes, each small group take a task and complete it. + +.. class:: incremental + +Create a local branch. Complete your task then merge. + +.. class:: incremental + +Team leaders manage communications, keep an eye on the big picture. + +First Step - Setup +------------------ + +Get a 'core' repository (perhaps leaders fork mine):: + + https://github.com/cewing/training.django_microblog + +.. class:: incremental + +Add your teammates as **collaborators**: + +.. class:: incremental + +* In your browser, view the repo you'll be working from in github. +* Click on the 'settings' tab (in the grey bar below the repo name) +* Click on the 'collaborators' menu item on the left +* Add your teammates by github id to the list of collaborators + +.. class:: incremental + +Now you should **all** have read-write access to this *core* repo. + +Second Step - Workflow +---------------------- + +Each small group, pick a *driver* + +.. class:: incremental + +Each driver, clone the *core* repo to your local machine + +.. class:: incremental + +Pick a task. **Before** you start to work, make a local branch: + +.. class:: incremental + +:: + + $ git checkout -b + +.. class:: incremental + +Complete your task, making commits as you go (you're on a branch) + +Third Step - Cleanup +-------------------- + +When you're finished with a task, you'll merge your branch: + +.. class:: incremental small + +:: + + $ git branch + master + * + $ git checkout master + Switched to branch 'master' + $ git pull origin master + From ... + * branch master -> FETCH_HEAD + Already up-to-date. + $ git merge + $ git push origin master + +.. class:: incremental + +Rinse and repeat + +In The End +---------- + +Leaders, make a copy of the *core* repository on your machine + +.. class:: incremental + +When your team is done, set up your machine to show off your results + +.. class:: incremental + +At 8:30 we'll come together. Each team will have 5 minutes to show a quick +demo of their work, and say something about what they learned along the way. + +Almost There +------------ + +.. class:: big-centered + +Any Questions? + +And Now +------- + +.. class:: big-centered + +**begin** + +Reference +--------- + +A Few useful git commands: + +.. class:: small + +:: + + $ git clone # make a clone + $ git checkout -b # make a new local branch + $ git checkout master # return to the master + $ git branch # list branches (and show current) + $ git commit -m "message" # make a commit locally + $ git pull [origin [branch]] # pull recent changes from remote + $ git push [origin [branch]] # push committed changes to remote + $ git merge # merge changes from other to current + +Assignment - Prep +----------------- + +.. class:: small + +For this week, you have *no* code assignment. + +.. class:: small + +Instead I want you to focus on installing software and reading for next week. +Software we'll be installing uses C extensions, and so installing it on OS X +or Linux requires a compiler and python's development headers. + +.. class:: small + +**Ubuntu** (our vms): + +.. class:: small + +:: + + $ sudo apt-get install python-dev + +.. class:: small + +**OS X**: Ensure that you have XCode installed. It's free, but *big* expect it +to take a while if you don't already have it. + +.. class:: small + +**Windows**: You all are safe for the time being. + +Assignment - Virtualenv +----------------------- + +With that prep work out of the way, you're ready to start. First, set up a +virtualenv: + +.. class:: incremental + +:: + + $ python2.6 virtualenv.py --distribute pyramidenv + ... + $ source pyramidenv/bin/activate + (pyramidenv)$ + +.. class:: incremental + +Remeber, Windows users: ``> pyramidenv\Scripts\activate`` + +Assignment - Install Pyramid +---------------------------- + +Once you've got a virtualenv set up and ready to go, install Pyramid: + +.. class:: incremental + +:: + + (pyramidenv)$ easy_install pyramid + +.. class:: incremental + +This will install a number of dependency packages, do not be alarmed. + +.. class:: incremental + +Next, we'll install a different kind of Database, the ZODB. + +Assignment - Install ZODB +------------------------- + +If you're on OS X or Linux:: + + (pyramidenv)$ easy_install ZODB3==3.10.5 + +This will take some time. If you get errors, contact me directly or via the +Google Group. + +Windows users, you'll have it a bit easier here. You have to install a binary +egg:: + + [pyramidenv]> pip install --egg ZODB3==3.10.5 + +Pause for Self Evaluation +------------------------- + +At this point, you can check your work. Fire up a python interpreter in your +virtualenv:: + + (pyramidenv)$ python + >>> import ZODB + >>> ^D + (pyramidenv)$ + +If you get an ImportError when you try that, you're not done. Contact me. + +Assignment - Extras +------------------- + +Next, we'll need to finish installing the bits we need for our work next +week:: + + (pyramidenv)$ easy_install docutils nose coverage + ... + (pyramidenv)$ easy_install pyramid_zodbconn pyramid_tm + ... + (pyramidenv)$ easy_install pyramid_debugtoolbar + +.. class:: incremental + +These tools will allow us to manage ZODB connections, debug our app, and run +cool tests. + +Assignment - Set Up Project +--------------------------- + +And finally, we'll set up a project for ourselves. This is like running +'startproject' for django in a way: + +.. class:: incremental small + + (pyramidenv)$ pcreate -s zodb wikitutorial + +.. class:: incremental small center + +Do not be alarmed by the 'sorry for the convenience' message. + +.. class:: incremental + +You get a folder called ``wikitutorial``. In it you should see files like +``setup.py`` and ``development.ini`` among others. + +.. class:: incremental + +This is an installable ``package``. You can install this package with +easy_install. + +Final Self Evaluation +--------------------- + +In fact, let's do that now, so we can prove to ourselves this all worked:: + + (pyramidenv)$ cd wikitutorial + (pyramidenv)$ python setup.py develop + ... + +.. class:: incremental + +You'll see a bunch of output. When it's over, run tests: + +.. class:: incremental + +:: + + (pyramidenv)$ python setup.py test -q + +Congratulations +--------------- + +When you've made it this far, and you see 1 test run successfully, you're +done. + +If you like, you can see your work by running the new project:: + + (pyramidenv)$ pserve development.ini + Starting server in PID 3056. + serving on http://0.0.0.0:6543 + +Visit ``http://localhost:6543`` to see your work in action. then go grab a +beer and curl up with the reading for the week. There's a lot. diff --git a/source/presentations/week08.rst b/source/presentations/week08.rst index 5feffac1..4cd60ff3 100644 --- a/source/presentations/week08.rst +++ b/source/presentations/week08.rst @@ -1,2 +1,36 @@ This is Week 8 --------------- \ No newline at end of file +-------------- + + +scraps +------ + +Pyramid Intro + +- What is it +- Where does it come from +- What problem is it trying to solve? + +Things that make pyramid like other frameworks we've seen + +- uses request/response model +- can use url route dispatch +- can use sql-based persistence + +Things that make pyramid __unlike__ other frameworks we've seen + +- can also use traversal +- can work with Object persistence via the ZODB + +What is Traversal (as opposed to route dispatch?) + +What is the ZODB? + +Lab +--- + +work up the wiki tutorial +only go through views, then add tests + +add security as an at-home exercise + From 91592f3426eb1dd1663f1290aed6c74a83f3024b Mon Sep 17 00:00:00 2001 From: cewing Date: Wed, 20 Feb 2013 09:59:49 -0800 Subject: [PATCH 073/487] include windows instructions for installing VS2008Express --- assignments/week07/athome/assignment.rst | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/assignments/week07/athome/assignment.rst b/assignments/week07/athome/assignment.rst index d95d5160..8a4e3ea2 100644 --- a/assignments/week07/athome/assignment.rst +++ b/assignments/week07/athome/assignment.rst @@ -17,7 +17,25 @@ or Linux requires a compiler and python's development headers. **OS X**: Ensure that you have XCode installed. It's free, but *big* expect it to take a while if you don't already have it. -**Windows**: You all are safe for the time being. +**Windows**: See the next section + +Windows Prep +------------ + +Although there are pre-compiled binaries available for Windows, you'll need +one `.bat` file to get them to work properly. To get that file, you'll need to +install Visual Studio 2008 Express: + +* Download the installer (894MB): + http://download.microsoft.com/download/8/B/5/8B5804AD-4990-40D0-A6AA-CE894CBBB3DC/VS2008ExpressENUX1397868.iso +* Extract the files to a folder (call it VS2008ExpressENUX1397868—it will be + 2.68GB) using something like 7zip +* Inside that folder double-click on Setup.hta +* On the screen that comes up, click on the installer for Visual C++ 2008 + Express Edition and follow the instructions. **Note**: It does work if you + include the following two options which are pre-selected for you: (1) MSDN + Express Library for Visual Studio 2008, and (2) Microsoft SQL Server 2005 + Express Edition (x86). Virtualenv ---------- From aa1ffda8e7bff2efb406aa24adbd2de3b4b4acbf Mon Sep 17 00:00:00 2001 From: cewing Date: Wed, 20 Feb 2013 20:47:12 -0800 Subject: [PATCH 074/487] add Jon's suggestion about installing the command line tools, which are now optional. --- assignments/week07/athome/assignment.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/assignments/week07/athome/assignment.rst b/assignments/week07/athome/assignment.rst index 8a4e3ea2..8142b0f9 100644 --- a/assignments/week07/athome/assignment.rst +++ b/assignments/week07/athome/assignment.rst @@ -15,7 +15,14 @@ or Linux requires a compiler and python's development headers. $ sudo apt-get install python-dev **OS X**: Ensure that you have XCode installed. It's free, but *big* expect it -to take a while if you don't already have it. +to take a while if you don't already have it. Once you've downloaded it you'll +also need to install the command-line tools (Thanks to Jon Braam for this +pointer): + +* Open XCode +* Open the XCode menu, then click 'Preferences' > 'Downloads' > 'Install + Command Line Tools' +* Once this is done, you can close XCode again **Windows**: See the next section From 5d0bd2389bc236c8ff8a7631e7a0f5e03afe80b3 Mon Sep 17 00:00:00 2001 From: cewing Date: Wed, 20 Feb 2013 20:57:01 -0800 Subject: [PATCH 075/487] update slide instructions to match the ones in the homework folder. --- source/presentations/week07.rst | 54 +++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/source/presentations/week07.rst b/source/presentations/week07.rst index 7ef6e8e3..ab37cf89 100644 --- a/source/presentations/week07.rst +++ b/source/presentations/week07.rst @@ -244,37 +244,67 @@ A Few useful git commands: $ git push [origin [branch]] # push committed changes to remote $ git merge # merge changes from other to current -Assignment - Prep ------------------ - -.. class:: small +Assignment +---------- For this week, you have *no* code assignment. -.. class:: small +.. class:: incremental Instead I want you to focus on installing software and reading for next week. Software we'll be installing uses C extensions, and so installing it on OS X or Linux requires a compiler and python's development headers. -.. class:: small +.. class:: incremental -**Ubuntu** (our vms): +There are a few steps here, so follow along carefully. -.. class:: small +Assignment - Linux Prep +----------------------- + +For Linux machines, we'll need to have ``gcc`` (a c compiler) and python's +development headers in order to complete our tasks. The VMs we have access to +already have ``gcc`` installed, so all we need there is:: :: $ sudo apt-get install python-dev -.. class:: small +Assignment - OSX Prep +--------------------- + +OS X does not come with a c compiler installed. You'll need to have XCode +installed. It's free, but *big* expect it to take a while if you don't already +have it. + +Once it is installed, there's one more step, you have to install the +'optional' command line tools: + +* Launch XCode +* From the XCode menu, click 'preferences' > 'Downloads' > 'Install Command + Line Tools' +* Once it completes, you can quit XCode again. + +Assignment - Windows Prep +------------------------- -**OS X**: Ensure that you have XCode installed. It's free, but *big* expect it -to take a while if you don't already have it. +There are pre-compiled binaries available for Windows, but we need one +``.bat`` file in order to properly install them. We'll need to install Visual +Studio 2008 Express to get this file (if you already have another copy of VS, +you can probably skip this) .. class:: small -**Windows**: You all are safe for the time being. +* Download the installer (894MB): + http://download.microsoft.com/download/8/B/5/8B5804AD-4990-40D0-A6AA-CE894CBBB3DC/VS2008ExpressENUX1397868.iso +* Extract the files to a folder (call it VS2008ExpressENUX1397868—it will be + 2.68GB) using something like 7zip +* Inside that folder double-click on Setup.hta +* On the screen that comes up, click on the installer for Visual C++ 2008 + Express Edition and follow the instructions. **Note**: It does work if you + include the following two options which are pre-selected for you: (1) MSDN + Express Library for Visual Studio 2008, and (2) Microsoft SQL Server 2005 + Express Edition (x86). Assignment - Virtualenv ----------------------- From 93b024b6b3253e81353dbd91389c492f66e5a2a7 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 22 Feb 2013 00:39:19 -0800 Subject: [PATCH 076/487] update week 8 slides --- source/presentations/week08.rst | 351 +++++++++++++++++++++++++++++++- 1 file changed, 350 insertions(+), 1 deletion(-) diff --git a/source/presentations/week08.rst b/source/presentations/week08.rst index 4cd60ff3..aa31fd02 100644 --- a/source/presentations/week08.rst +++ b/source/presentations/week08.rst @@ -1,6 +1,355 @@ -This is Week 8 +Internet Programming with Python +================================ + +.. image:: img/pyramid-medium.png + :align: left + :width: 50% + +Week 8: Pyramid + +.. class:: intro-blurb right + +| Wherein we learn +| it's not built by aliens + +But First +--------- + +.. class:: big-centered + +Questions from the Reading? + +And Now +------- + + + + +Lab - Part One +-------------- + +.. class:: big-centered + +Getting To Know Pyramid + +Scaffolds and Opinions +---------------------- + +Pyramid uses what it calls *scaffolds* to get you started on a new project. + +.. class:: incremental + +When you ran ``pcreate -s zodb wikitutorial`` you were invoking the *zodb +scaffold* + +.. class:: incremental + +Pyramid the framework is highly un-opinionated. + +.. class:: incremental + +*Scaffolds*, conversely, can be quite opinionated. The one we used has chosen +our persistence mechanism (ZODB) and how we will reach our code (Traversal). + +Project Layout -------------- +Running ``pcreate`` has set up a file structure for us: + +.. class:: small + +:: + + wikitutorial/ + CHANGES.txt + development.ini + MANIFEST.in + production.ini + README.txt + setup.cfg + setup.py + wikitutorial/ + __init__.py + models.py + static/ + templates/ + tests.py + views.py + +Similarities to Django +---------------------- + +Our project is organized with an outer *project* folder and an inner *package* +folder (see the ``__init__.py``?) + +.. class:: incremental + +The name of that outer directory is not really important. + +.. class:: incremental + +Our inner *package* folder has a models.py, tests.py and views.py module + +.. class:: incremental + +Our inner *package* folder has a ``static/`` and ``templates/`` directory + +Differences from Django +----------------------- + +Our *outer* module has a ``setup.py`` file, which allows it to be installed +with ``pip`` or ``easy_install`` + +.. class:: incremental + +There is no ``manage.py`` file. Pyramid commands are console scripts. + +.. class:: incremental + +There is nothing magical in Pyramid about the name of the ``models.py`` +module. + +.. class:: incremental + +There is nothing magical in Pyramid about the names of the ``static/`` or +``templates/`` directories. + +Pyramid System Configuration +---------------------------- + +Pyramid keeps configuration intended for an entire installation in ``.ini`` +files at the top of a project. + +.. class:: incremental + +When you deploy an app to some wsgi server, you'll reference one of these files + +.. class:: incremental + +Settings there affect the environment of all apps that are running in that +wsgi server. + +.. class:: incremental + +It is much like Django's ``settings.py`` but is not a python module. + +Pyramid is Python +----------------- + +Running a Pyramid application is really just like running a Python module. In +the ``__init__.py`` file of your app *package*, you'll find a ``main`` +function: + +.. code-block:: python + :class: small incremental + + def main(global_config, **settings): + """ This function returns a Pyramid WSGI application. + """ + config = Configurator(root_factory=root_factory, + settings=settings) + config.add_static_view('static', 'static', cache_max_age=3600) + config.scan() + return config.make_wsgi_app() + +.. class:: incremental + +App-level configuration is done here. + +App Configuration +----------------- + +.. code-block:: python + :class: small + + def main(global_config, **settings): + +.. class:: incremental + +``global_config`` will be a dictionary of the settings from your ``.ini`` file +that come in the [DEFAULT] section (if there is one). These settings will be +shared across all apps that are involved in the system. + +.. class:: incremental + +The ``settings`` passed in here are the settings from your ``.ini`` file that +come in the section that corresponds to your application. They will be used +only by your app. + +App Configuration +----------------- + +.. code-block:: python + :class: small + + config = Configurator(root_factory=root_factory, + settings=settings) + config.add_static_view('static', 'static', cache_max_age=3600) + config.scan() + +.. class:: incremental + +Pyramid does configuration work when an app is run using the ``Configurator`` +class. + +.. class:: incremental + +The ``Configurator`` provides and extensible API for configuring just about +everything. + +.. class:: incremental + +You can read more in `the pyramid.config documentation +`_ + +The Application Root +-------------------- + +The ``Configurator`` constructor can take a ``root_factory`` keyword argument. + +.. class:: incremental + +The ``root_factory`` of your app is the router that determines how to dispatch +individual requests. + +.. class:: incremental + +If you do not provide this argument, the default root factory, which uses URL +Dispatch, will be used. + +.. class:: incremental + +In our case, we want to use Traversal for our app, so we have to provide a +custom ``root_factory``. + +Our Root Factory +---------------- + +.. code-block:: python + :class: small + + from pyramid_zodbconn import get_connection + from .models import appmaker + + def root_factory(request): + conn = get_connection(request) + return appmaker(conn.root()) + +.. class:: incremental + +In our root_factory method, we grab a connection to the ZODB and pass that into +a call to ``appmaker``, the result is returned (and becomes our app root). + +.. class:: incremental + +So what exactly does ``appmaker`` do? + +The appmaker +------------ + +.. code-block:: python + :class: small + + def appmaker(zodb_root): + if not 'app_root' in zodb_root: + app_root = MyModel() + zodb_root['app_root'] = app_root + import transaction + transaction.commit() + return zodb_root['app_root'] + +.. class:: incremental + +In essence, we are ensuring that there is an ``app_root`` object stored in the +ZODB, and then returning that. And that simple Python object will manage our +*Traversal* based application. + +Seeing It Live +-------------- + +You've done this at home, but let's repeat the exercise here. + +.. class:: incremental + +In a terminal, change directories into your ``wikitutorial`` *project* folder +(where you see ``development.ini``). Fire up your pyramid virtualenv and serve +our app: + +.. class:: incremental + +:: + + (pyramidenv)$ pserve development.ini + Starting server in PID 16698. + serving on http://0.0.0.0:6543 + +.. class:: incremental + +Load http://localhost:6543 and view your app root. + +Why is it Pretty? +----------------- + +If we understand correctly what is happening so far, we are looking at an +instance of ``MyModel``. + +.. class:: incremental + +What makes it look like this? + +.. class:: incremental + +The secret sauce lies in *view configuration* + +Pyramid Views +------------- + +.. code-block:: python + :class: small + + from pyramid.view import view_config + from .models import MyModel + + @view_config(context=MyModel, renderer='templates/mytemplate.pt') + def my_view(request): + return {'project': 'wikitutorial'} + +.. class:: incremental + +Pyramid views can be configured with the ``@view_config()`` decorator. + +.. class:: incremental + +Or call ``config.add_view()`` method in your app ``main``. + +.. class:: incremental + +``config.scan()`` in ``main`` picks up all config decorators. + +View Configuration +------------------ + +.. class:: small + +The ``view_config`` decorator (and the ``add_view`` method) take a number of +interesting arguments. In our case there are two. + +.. class:: incremental small + +``renderer`` is used to designate how the results returned by the view +callable will be handled. In our case, it's a template that will render + +.. class:: incremental small + +``context`` determines the *type* of object for which this view may be used. It +is an example of a ``predicate`` argument, which can be used to place +restrictions on when and how a view may be called. + +.. class:: incremental small + +Predicates are a very powerful system for choosing views. Read more about them +in `view configuration +`_ scraps ------ From 8bcca18464e2d43869414f5993c91f473aeb573b Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 22 Feb 2013 00:39:41 -0800 Subject: [PATCH 077/487] add pyramid logo image for week 8 presentation --- source/img/pyramid-medium.png | Bin 0 -> 9963 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 source/img/pyramid-medium.png diff --git a/source/img/pyramid-medium.png b/source/img/pyramid-medium.png new file mode 100644 index 0000000000000000000000000000000000000000..f6e85d79324e51b994058c2b9894d674f87a2cfd GIT binary patch literal 9963 zcmch7cQjmY_wVQl5B1ONb+4D_`v z001iT`JHot=A81D*Wc{?!4;%q7i0-_3kr1#fB-aHq0SHi179b1hy}#SHT-EmL!Ow@d$GG&cT!v-}G1{l5YST7~;VBrPC;(BJ@<^M!M} z@wX~}C9MF6QxG)33JUf4R}{@Wph3_;52(L@mZhA4v6G9Z-{13p@EaQ|8TbVTIr+Ij z4762+&JiR$JzbS_Wi{nwWwbRF?rAGZOY6wo*O8Xhm6O+$(pJ#b)lt0vFIjD1bWP6c28bIsb20M8JJt8M_)SKuEmD|!BVTNM8--alns|Gh05|5jG= z+!)Ef7xsT!=zo#Uv*+*Of2ZyFI!I)Lp89im<8UYn^)&$szr$<-lS}OA$B+~1u-J`5UDXOT={%G8dy)-ojJ21u0OU#l!hx2!U10C<`0Vr5 z)emMd&z>X0SX;`UdRSdBGq?0Jze60;pF~1?-Bed6ST?*rbxEoy6_>+R#$1Eq_Mf;~0j+i!3>YIr<9l(>?wW3R~%Qk3;q zr#b78LzimoCD3nwyLQy#j_+e7{boCB6P{~f+n#{qy0wgr^!=X(Mg%!-r(Qp7^;M`CvamE?r_iOuKschWjY*?opQDegb{^n+$Bz7d<__!y4%ZK^ND&*Ra000Cm4YW0^!sd4KnH;R9 z^M6nQYWHs+>_ zn$YJ@DV>?>9*e)}iT?x9rUH)o4Ejwwe~jKM^9(&zIZ!>7mXgupeTO<7H?@=qJTMwQ zrBDzQ#Z#F}qI5uKO)1*nEQLUIPz($}0^q4IG@A_nLBf9+{{L{|KjY4qOOx=gil4mD zf#6QRf_aCQ@-1p%_vn!_s^f3JtX=F2U4Cvuxd^?+O$xX#yT*B}04*zcf5ERj z`BGeeS@W+*DLQ5i(r^_&a;*ulS*b~NJpd10#@c#CM zo*mOVO&pLLf2w_#S*0Jk8=G5Hh+G|BeG#{e+!n9kqQ--xU6u*DIIueW4XOH zGCEmQG&zbbsukJRN`e-WM{0gzGp~)THNnsNcs?JMZ$nc{SAQb-BwFX!{KGZvEf%o~ zCP=ib+I&53bUe=`Ai9824P9lLVVWeX)Ly{0=fm}CTqhBVn5#hw&sksH3+h$cRxRME zr0{glp-#S0+9{F!(kH=R9uaLZ^~j}BGn>^1!5yks-(322X;Q1k^{tgc$EzyCIxyVR z(>%~KNvuWjM`nZ;cH=Zo>OF!`E&?QHr>#fILQ?@i%t%Vhn>jPkTd$b7XpbL>JJaB= znCv!(Ku3)l@T1|h@LhvqimQbY+*6X9LbaWif_8iy$>XeFCDoU6J zH@G34RwxS@RunBthhm?{(wzd?C!`YU=a;XMCRf;%=?jrLGTV;A^reNu^-MFV;^4OaIbE< zc^flNA9I`JO~I_@NV{Z3Z+L?{PDf;pe&Hl~18t(d>5+bwtU-mFwd3VWUM*vw;+QYy z2g}P!F)Kjcd9`71-}S~?@;v{ClU#DW>f5VLAuoD6k312p2^SDpg$l&2_%wH)(cd$& zclwtt49RMk`4K|fyqbbravcS!u;I0ok-=Ft5+<5PsN+i@kBym0(=n$XquyDr-U(>V zy6j0>vRAWNbtxc_bEHofLs2=9?_?1WZs}mj&ME4nX!Q4?z|3PU+)+WGO$RscK*6K3Z_o0n4lWL6Ea zabh6@^X-9;p4m{oT>lkG%Z||fep-^Am~XPjikM!rBvA^{AG$c!-rRV80iJ|xXKwDi zHRm$p11T?2GE7?YrG^vYg)`D}i|vLHunDtFlJ+s>;QqLY$G8;?^xQtpRul%=hQ z=kINW8r0|D*_GDzxo!f_wM?MXBobr*QyqA3vdw;{hC4) z(QA$rN_O^~uHbv?7*kyeBz>g)HK~>#=y$kHv2Jr@Fcm?wg7AAJH&R-a3K4U^D(d~c zx?^Hi>=sm9c2R=`Yj;q=*)hQ=c`d@~#c^g|mEf&2`f6A}6`2G3Xk-0pCq!vFhipS~ z{+i%x#!)SNtm}4V8|*aQ-PA_hBCNq!C_jwT$bT46#Pv`lq5e%hNm0@FWQkQzm+wY* z$}WEnOqxziacV$sanh@j^ngvdd3W2rsbVey)bF&(VLYAZZM^fb8=GXA(v&GLNQ)pd zmcng2KHmVhgZ)n4bi%`CZM*SH$S(j<0A zGK)#BMMb%$HRi0S*e0oNo$S|j+&w0hnGoo>y;9r@85b___(Wf6DUixa&JRJ=qANe$#$X7q1?q)gPAl#fOnWsn^%};{&t{X&B;N%- zvxa{x4K8QLHIBgH%uh!q;6{h94L~U|BA=$*s(4doo4ps_4rX&EA6kPR+Kyt)tMtIR z$`b=Po7}dwl@{W-1r|>{=P|_lEl?51`F&gY7xoK*B-%jQ1sN@LJpWx=uNOSwvdJ}AZS8@vsZy|}l z5|~0lUiGzjXNLm&>y3wqyIsH?OQaxe$bNr~HCC385j{+P$#EjmJv!_>_}|u_xVKiAo|$GhT{q&(|Gk+1!}aSF=%V7$$fmJd)a>QP4h$~k8F+869LDQ$3m*^ z!%V(*rgN5w=gN7G^)3&JF)@zFOEC5iF!F$4E15n^3F7-ho4dPVWqIU=?G1FW+si-_ z%kaIU45Wv+&UkY0^0EQkVFbo_F!Xb#!70MlVIfnDxUdKJHj=z+r$}6BFn|_3l!-|D z4V;BV&w?$pebHlo;FJ4~} z3U{8!{QS+)kw->JIl+Vm?Y=brz4TW})pR3;^dmO}zroYyp6Ma#c2gX7xUuU@z=&}T zI|`$GU{4F}>1b{v z+4yhmao2b8B3H2Nw~V%&j(6C+#o0k}@Z)j{(G)E4&Yq9-UHm4!pY$f>YA%_@m3!5+ zuAewr?SAW0{aqhsMTG*_5L?|JQ5h?_78D|^EpPU4S0M8bmpp4t6BA1l+4QgsN{Y)m z-L<7S7oq&S5H*}H;wh0qCLrD)N&P3G@m&Vb1O?ST&dsyk^uQjxQ@3l_xt(G9;QXz$ z++bwr06N#ch8z6L4d~-Fd@)$<=t4@YJ!XrNUS-rvT7Ab|Ov%Ubp<6WlL?%N?X!nL} zvd$E2L{@DxTMuQvBp`*~V&Ow$b3OV@m6Q~CQqYTFF^RC_kcwUF!Zyh_WI2Cp2LWVdLjE!+B+1~$lLu&;yYg>I6|L9>P+r> z%OW=V#hdajG8vhLzod8Y5ZXnKszgQYS0Q*LDzR5ye8lFVWbfp<}c16>N}2h6XPq*hYEbvPN%iw9L~ z+pXr#2{5%=kGHPkm1Xed8RY@vaX)7L^Xe7^vDH76&z_HV*(uJ5wtqP^LAO=QFmF5{ zZGRbtGLi5MQb3n5XjRz^;c!nix-)L@!T`P17E^1`BQ+!UbGang2pnnvk`k%8Ang@C2fsd!7Ix~#dghPOz2Y5eU(Zrw-tC- zZ>el2^)gwLR(@AOd4^lY5rSATh8JWoJI*ngAsl;pvsXv-gt8aiNWf@DXsiu%E(e8r zj^$-%C94@5YCI?bn*V{G>{KFV4C!n9CZ6R%k^F>a`i0IvcE(WW+91>24R#XOIKh<$ z5kHMZ%cQ=ZU3HRs5_go%Wr2)v@L7C)IJVRf7(YW@Hz0-R*q)c)C|jz9eY)hlh$sOr z2w($G<5__F57U4GeU1J7dcNp3UNO#rRr=dw0VG zd?yHd-07HX?09$SNrY}l9+vSP4C`Qw#G8!Ek??}X6ekmhh1#7`iu;F|W+2DOu_z1t zO6GQUKV`i})(T_*F9sEC0bj%6*i#F($V(c(7x{L!_G`BkWnR#J;q>_qk4-?zdl|yS zeK{+`D+}gFMn-=5*sF8_OC2cPm%29(-tpJ@qUlg8ikj~m{I zAl<;GFlQu*W(p{Z;n{6c1@O}?E+%F~>N;9Ji%A5@E0<+;7T0A-oOpR*MB#bFmxTev z;IikOCFHI6=%O8}@V`P*)$q#iNU4zyQiVTSi=I%Zf*kX84lnIG%BV<@!<*f+w$pFS-3I76^9;9hqtDJ3L#d%w~}b zAQ{7db3|w5!lkg~Hyv``hRUxloE@=WD=tnTtI2`~6jb^lRd{?T_4?TNa@19ebR*2* z^F!S;?gticp$^L(VZJPOl99rBj$0)ATI9n{Qx%PUKgM!*wc({8RPB1;H-y~#)1EsK z{*#t3zph4*QC{`^0Y6UfJ3^ z0}-xyUn%;R(S=DF@e%w{j z_|!9Ec?V9~nTLnj9uO*`%Rp*NX{!f@a93g{Q`1XMUdD_414=(GFv-$=q4DkdbnGhw z?#hE!;5#?7El*v?+)=D=-#bj7^n8!`sHGAUxG17~B$abN=Q@3+AI9wC$B&wtn)=(8 zgcmP@kfxaEfhx%_$ko#_#J#X437awn{zuIo*zHNdd(^v{e=5uT>i4a210Q(hg5|Xn=pt z)FiQP%~4j4aGVQEpi@r}1-LR3eNt>mSwo0j9awlZ#5LiviaHM>f&PG6OQ`N zw!2LWl7HGH@oHMf3>NT#_vs%bjk&v3BOy3`33gn|48{EJsh@odu=Wud041?~Ei_Zcyvmg;a&T654h6on9(5 zRL_x%nhDFAm$b{xE}!LW#ZSx~n4aj3iB#$pbo)EqJA%K&iQtg$3AWTRp|LWwuGbf4 z7k5gRWn1wPD?jX3cfw7PyRGF@mJnV}(0xv!(9!)N#zz=w$aZB^0bb}7?YdPiOSzX$ zEIuKWgJfVPnqNE7-;s5QQc8d{g^AKh-EhH7Q^32*z67}^gSrV`7#YWRU3(QxUW>6J z@4nifsHEbVt(@=W$K$i(X4>DKCTTBnj;lclGqwDqC-xY^(PxHHkciV#XZlx)@Feml zoEsoS9mbq+`$_s?cX{iS#mU|)vix{5QWLz9ST!PpbU)c0no-uG{)VdSmQ?sXFaMJE zMs+a9MRd(BdWaJZ<42s~Lh3z;6LY|=a##Tw0~PQkq5%TJF}g8q)GC+DK83USuFlt@ zF_-w;`li`I;>H6gw!b{*KPyT3Omy2e`Fj1_{-X^X)Y6Q;K_ZL=sbW3XI7<<=I9yel zFcO8I|0`t+u8VgkAua&8sXFQJUW3y_>Nj|pe?C91$5l2WJ+V5Y^%YXB_*bOW{r#H| zBjO75c->%pLfuiOkk=v|?qD>TG&IeK{24uW%1SCX#*=Q7_e34e58o9ycODr+9;a4U z0!Y&}aI0&^(0{QYr4@lA1wVC6y*_)~8WO%@YiA$5RWNg4kQ_}hE3~_pg=z?2PSuHj zmY}Pg^$~f;eLoo2yybF&UEPpHN)s5!C6b;*EM|i&*;Tm)%A>NeIcDo|iJ^;4ps~69 z*j|fx8Vnj~Xq=Ca5Q0Osop(>BxoP^W@RRQd_44#AhPm!^YN_tM6~}@SfA(KQJvyt5 z@&r%7O3~h@wxE2H4z7G0`Iurrwx?E4qvBu)-A&u8Q{FaQ5zB>Unj$$vbfCNMlvfjI zV=!|2axP$|KXf$5MZ;zDg7Kf!2Sl2>ZE(4;snf*1v|Dfhrd5_CM0x?QC8Gg_tgmg` zK3ep}2wr9c!@CYs_Zl0!7<_=Jj|-!fQX{AM>6n8(#qGrC&Y#J$66PFhIRQ7oZFtr`q_=P5rUdHj;0b^a$Y>2$k|joHOS!i-jYgbJ zQ>)ig^+}oa4@RDz+WxqlP>qD!Qcfwai<9?tbkrn??m5wq@H%@e6|fI*Re(0#AJ!ht zo~!h_yF1UIPeHuQ*)%FfPwUIObIwM*Tfoz({Z?2hQI<4>w4rjPy{+-v^fmzToJHaC zhK}^ljFKoXO7ia!LrVC$2PI%h$^`NPzy`3%9g_v%qKUW?qoK*%Y$drMi=!tz+Smv^ z%Eq%B;VUV^CDez2-TJOX&oodXEd519j~6L_7= z3OY8L)G|f_!7aciq^}guQGl0lj5gpR6*o=9)tDaHB&{Jt`u?R8o&EC-$(;BCZjJl| z_(N5w14yD`rAv6OZs^W6GQ@QHDr&J?pWFjM7LbJi-)Vcw0Q@v}FKA!C{hlheN2SK_ z%p;9sy)t6^@xVqK(2OMd4rT)=feQn)X^om#X#ap-QgOsd>@`g&Y@1%Jfjy*zlLtj( z^kO(@rqltkT70f*yXB>k1%!w-+c%&qcnCR@RV^1B`&=Cu;I4O1% z`tv;Ym@B`Z^{`zOD6IGv^(d7T{vk4n)U!2BO1g00luL0;g0ZJi+Cl;T_~*un97&XF z5|~>|7sE|ee8KJ;fcehGwY_)Ybp@r}y)bo*7<&u{Ac8jGx)ilFRe-NLSK!uCM>L#h zNb0-r+gbf0jojs)CmFAwjMY_g?i-&l)F2m2z-PA9>KCaFV~dp%6b2M#Pr*ojz@rP- z<9e7e%&8u-@0b_6BvAFM<@jrq2Y}mxzoEP_UwZD7t8#zpH$}rSt$N%BjaOLwF4(Y( z-m=}>Bk#1*#u(EI@cJe1cQ5RmkS0)mJhUMtF&ekVM6UY6h(P@Fw~y=LS7@6V`nvI5 zu)XM5R^;d#ab_|l-Cp?u+XII9*A|C@^!TFxZ(Zpa*nhO?{eN_&)j|KUF8K5}3X>FI ZhAu|%iml?^zkfe7&@s`j(|q#me*uC^&*=aF literal 0 HcmV?d00001 From fe1b59d5d28112ee2699dd7782eb81656586ed4c Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 23 Feb 2013 19:53:43 -0800 Subject: [PATCH 078/487] update outline update index page complete lab for week 8 --- source/main/index.rst | 1 + source/main/outline.rst | 10 +- source/presentations/week08.rst | 708 +++++++++++++++++++++++++++++++- 3 files changed, 707 insertions(+), 12 deletions(-) diff --git a/source/main/index.rst b/source/main/index.rst index 75d85a83..5535c193 100644 --- a/source/main/index.rst +++ b/source/main/index.rst @@ -16,6 +16,7 @@ Internet Programming with Python self outline assignments + project Winter Term, 2013 - (10 Sessions) diff --git a/source/main/outline.rst b/source/main/outline.rst index 51a60f6e..1b31ba8c 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -657,7 +657,15 @@ References Assignment ********** -To Be Decided +Begin work on your final project. You must communicate your plan with Dan and +I first to ensure it is of an appropriate scope. If you are having trouble +getting started, let us know. + +We will be spending most of the class over the next two weeks working. Be +prepared to take advantage of the time with Dan and me by getting started now. + +`Reread the project specification +`_ Week 9 - The Cloud ------------------ diff --git a/source/presentations/week08.rst b/source/presentations/week08.rst index aa31fd02..0ad12ae7 100644 --- a/source/presentations/week08.rst +++ b/source/presentations/week08.rst @@ -219,8 +219,8 @@ Dispatch, will be used. .. class:: incremental -In our case, we want to use Traversal for our app, so we have to provide a -custom ``root_factory``. +In our case, we want to use Traversal for our app, so we provide a custom +``root_factory``. Our Root Factory ---------------- @@ -337,7 +337,8 @@ interesting arguments. In our case there are two. .. class:: incremental small ``renderer`` is used to designate how the results returned by the view -callable will be handled. In our case, it's a template that will render +callable will be handled. In our case, it's a template that will render to an +HTML page. .. class:: incremental small @@ -351,6 +352,699 @@ Predicates are a very powerful system for choosing views. Read more about them in `view configuration `_ +Wiki Models +----------- + +Now that we have a basic idea of what's going on in the code generated for us, +it's time to build our wiki models. + +.. class:: incremental + +We'll need to have a Python class that corresponds to a *page* in our wiki. + +.. class:: incremental + +This will be the type of object we view when we are looking at the wiki. + +.. class:: incremental + +We'll also need to have a *root* object, which will be a container for all the +*pages* we create for the wiki. + +Persistence Magic +----------------- + +In an SQL database, data *about* an object is written to tables. In the ZODB, +the *object itself* is saved in the database. + +.. class:: incremental + +The ZODB provides *base classes* that will automatically save themselves. We +will use two of these: + +.. class:: incremental + +* **Persistent** - a class that automatically tracks changes to class + attributes and saves them. + +* **PersistenMapping** - roughly equivalent to a Python *dictionary*, this + class will save changes to itself *and its keys and values*. + +.. class:: incremental small + +The ZODB also provides lists and more complex persistent data structures like +BTrees. + +Traversal Magic +--------------- + +Traversal is supported by two object properties: ``__name__`` and +``__parent__``. + +.. class:: incremental + +Every object in a system which is going to use Traversal **must** provide +these two attributes. + +.. class:: incremental + +The *root* object in a Traversal system will have both of these attributes set +to ``None``. + +The Wiki Class +-------------- + +Open ``models.py`` from our ``wikitutorial`` *package* directory. + +.. class:: incremental + +First, delete the ``MyModel`` class. We won't need it. + +.. class:: incremental + +Add the following in its place: + +.. code-block:: python + :class: incremental + + class Wiki(PersistentMapping): + __name__ = None + __parent__ = None + +The Page Class +-------------- + +To that same file (models.py) add one import and a second class definition: + +.. code-block:: python + + from persistent import Persistent + + class Page(Persistent): + def __init__(self, data): + self.data = data + +.. class:: incremental + +What about ``__name__`` and ``__parent__``? + +.. class:: incremental + +We'll add those to each instance when we create it. + +Update Appmaker +--------------- + +The existing ``appmaker`` function needs to be updated for our new models: + +.. code-block:: python + + def appmaker(zodb_root): + if not 'app_root' in zodb_root: + app_root = Wiki() + frontpage = Page('This is the front page') + app_root['FrontPage'] = frontpage + frontpage.__name__ = 'FrontPage' + frontpage.__parent__ = app_root + zodb_root['app_root'] = app_root + import transaction + transaction.commit() + return zodb_root['app_root'] + +A Last Bit of Cleanup +--------------------- + +We've deleted the ``MyModel`` class. But we still have *views* that +reference the class. + +.. class:: incremental + +Open the ``views.py`` file in your *package* directory and delete everything +but the first line: + +.. code-block:: python + :class: incremental + + from pyramid.view import view_config + +.. class:: incremental + +Next, we'll test our models. + +Test the Wiki Model +------------------- + +Open ``tests.py`` from the *package* directory. Delete the ``ViewTests`` +class and replace it with the following: + +.. code-block:: python + :class: small + + class WikiModelTests(unittest.TestCase): + + def _getTargetClass(self): + from wikitutorial.models import Wiki + return Wiki + + def _makeOne(self): + return self._getTargetClass()() + + def test_it(self): + wiki = self._makeOne() + self.assertEqual(wiki.__parent__, None) + self.assertEqual(wiki.__name__, None) + +Test the Page Model +------------------- + +Add the following test class as well: + +.. code-block:: python + :class: small + + class PageModelTests(unittest.TestCase): + + def _getTargetClass(self): + from wikitutorial.models import Page + return Page + + def _makeOne(self, data=u'some data'): + return self._getTargetClass()(data=data) + + def test_constructor(self): + instance = self._makeOne() + self.assertEqual(instance.data, u'some data') + +Test Appmaker +------------- + +One more test class: + +.. code-block:: python + :class: small + + class AppmakerTests(unittest.TestCase): + + def _callFUT(self, zodb_root): + from .models import appmaker + return appmaker(zodb_root) + + def test_it(self): + root = {} + self._callFUT(root) + self.assertEqual(root['app_root']['FrontPage'].data, + 'This is the front page') + +A Quick Interlude +----------------- + +In your *package* directory you should see a file: ``Data.fs``. + +.. class:: incremental + +This is the ZODB. It contains references to a class that doesn't exist +anymore (MyModel). This means it is broken. + +.. class:: incremental + +Make sure Pyramid is not running. + +.. class:: incremental + +Delete Data.fs. It will be re-created as needed. + +Run our Tests +------------- + +Finally, let's run our tests:: + + (pyramidenv)$ python setup.py test + ... + Ran 2 tests in 0.000s + + OK + +.. class:: incremental + +We can also run tests to tell us our code-coverage: + +.. class:: incremental small + +:: + + (pyramidenv)$ nosetests --cover-package=tutorial --cover-erase --with-coverage + +Preparing for Views +------------------- + +Our ``Page`` model has a ``data`` attribute, which represents the text in the +page. + +.. class:: incremental + +Our pages will use ReStructuredText, a plain-text format that can be rendered +to HTML with a Python module called ``docutils``. + +.. class:: incremental + +Our project is installable as a python package. It declares its own +*dependencies* so that they will also be installed. + +.. class:: incremental + +We need to add the ``docutils`` package to this list. + +Package Dependencies +-------------------- + +Open the ``setup.py`` file from our *project* directory. Add ``docutils`` to +the list ``requires``: + +.. code-block:: python + + requires = [ + 'pyramid', + 'pyramid_zodbconn', + 'transaction', + 'pyramid_tm', + 'pyramid_debugtoolbar', + 'ZODB3', + 'waitress', + 'docutils', # <- ADD THIS + ] + +Complete the Change +------------------- + +Any time you make a change to ``setup.py`` for a package you are working on, +you need to re-install that package to pick up the changes:: + + (pyramidenv)$ python setup.py develop + +.. class:: incremental + +You'll see a whole bunch of stuff flicker by. In it will be a reference to +``Searching for docutils``. + +Adding Views +------------ + +Open ``views.py`` again. Add the following: + +.. code-block:: python + :class: small + + from docutils.core import publish_parts + import re + + from pyramid.httpexceptions import HTTPFound + from pyramid.view import view_config # <- ALREADY THERE + + from wikitutorial.models import Page + + # regular expression used to find WikiWords + wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") + + @view_config(context='.models.Wiki') + def view_wiki(context, request): + return HTTPFound(location=request.resource_url(context, + 'FrontPage')) + +Some Notes +---------- + +New pages in a typical wiki are added by writing *WikiWords* into the page. + +.. class:: incremental + +``r"\b([A-Z]\w+[A-Z]+\w+)"`` is a regular expression that will locate +WikiWords. + +.. class:: incremental + +Note that the ``@view_config`` for the ``view_wiki`` function has no +``renderer`` argument. It will never be *shown* + +.. class:: incremental + +Instead, it returns ``HTTPFound``, (``302 Found``). Calling +``request.resource_url`` provides a URL for the redirect. + +Add a Page View +--------------- + +.. code-block:: python + :class: small + + @view_config(context='.models.Page', renderer='templates/view.pt') + def view_page(context, request): + wiki = context.__parent__ + + def check(match): + word = match.group(1) + if word in wiki: + page = wiki[word] + view_url = request.resource_url(http://github.com/page) + return '%s' % (view_url, word) + else: + add_url = request.application_url + '/add_page/' + word + return '%s' % (add_url, word) + + content = publish_parts( + context.data, writer_name='html')['html_body'] + content = wikiwords.sub(check, content) + edit_url = request.resource_url(http://github.com/context,%20'edit_page') + return dict(page=context, content=content, edit_url=edit_url) + +Adding Templates +---------------- + +What will the page template for the ``view_page`` function need to be called? + +.. class:: incremental + +Go ahead and create ``view.pt`` in your ``templates`` directory. + +.. class:: incremental + +While you're there, also copy the file ``base.pt`` from +``assignments/week08/lab`` in the class repo. + +.. class:: incremental + +Like Django templates, Chameleon templates can extend other templates. Our +``base.pt`` template will be the master, and our ``view.pt`` and ``edit.pt`` +templates will extend it. + +The view.pt Template +-------------------- + +Type this code into your ``view.pt`` file: + +.. code-block:: xml + + + +
    + Page text goes here. +
    +

    + + Edit this page + +

    +
    +
    + +A Few Notes +----------- + +Chameleon page templates are valid XML. The templating language uses ``tal``/``metal`` +namespace XML tag attributes. + +.. class:: incremental + +```` tells us we will be using +``base.pt`` as our main template *macro*. + +.. class:: incremental + +Template *macros* can define one or more *slots*. These are like the *blocks* +in Jinja2 or Django templates. + +.. class:: incremental + +```` tells us that everything +here will go in the ``main-content`` slot. + +More Notes +---------- + +.. code-block:: xml + +
    + Page text goes here. +
    + +This uses the ``tal`` directive ``replace`` to completely replace the +``
    `` tag with whatever html is in ``content``. + +.. code-block:: xml + :class: incremental + + + Edit this page + + +.. class:: incremental + +Here, we use the ``tal`` directive ``attributes`` to set the ``href`` for our +anchor to the value passed into our template as ``edit_url``. + +View Your Work +-------------- + +We've created the following: + +.. class:: incremental small + +* A wiki view that redirects to the automatically-created FrontPage page +* A page view that will render the ``data`` from a page, along with a url for + editing that page +* A page template to show a wiki page. + +.. class:: incremental + +That's all we need to be able to see our work. Start Pyramid: + +.. class:: incremental small + +:: + + (pyramidenv)$ pserve development.ini + Starting server in PID 43925. + serving on http://0.0.0.0:6543 + +.. class:: incremental + +Load http://localhost:6543/ + +What You Should See +------------------- + +.. image:: img/wiki_frontpage.png + :align: center + :width: 95% + +Editing a Page +-------------- + +Back in ``views.py`` add the following: + +.. code-block:: python + :class: small + + @view_config(name='edit_page', context='.models.Page', + renderer='templates/edit.pt') + def edit_page(context, request): + if 'form.submitted' in request.params: + context.data = request.params['body'] + return HTTPFound(location = request.resource_url(http://github.com/context)) + + return dict(page=context, + save_url=request.resource_url(http://github.com/context,%20'edit_page')) + +The Edit Template +----------------- + +Create and fill ``edit.pt`` in ``templates``: + +.. code-block:: xml + :class: small + + + + Editing + Page Name Goes Here + + + +
    + +
    +
    + +
    + + {% endif %} +

    Posts

    + + +All Done +-------- + +Okay. That's it. We've got an app all written. + +.. class:: incremental + +So far, we haven't actually touched our browsers at all, but we have +reasonable certainty that this works because of our tests. Let's try it. + + +.. class:: incremental + +In the terminal where you've been running tests, run our microblog app: + +.. class:: incremental + +:: + + (flaskenv)$ python microblog.py + * Running on http://127.0.0.1:5000/ + * Restarting with reloader + + +The Big Payoff +-------------- + +Now load ``http://localhost:5000/`` in your browser and enjoy your reward. + + +Making It Pretty +---------------- + +What we've got here is pretty ugly. + +.. class:: incremental + +If you've fallen behind, or want to start fresh, you can find the finished +``microblog`` directory in the class resources. + +.. class:: incremental + +In that directory inside the ``static`` directory you will find +``styles.css``. Open it in your editor. It contains basic CSS for this app. + +.. class:: incremental + +We'll need to include this file in our ``layout.html``. + + +Static Files +------------ + +Like page templates, Flask locates static resources like images, css and +javascript by looking for a ``static`` directory relative to the app root. + +.. class:: incremental + +You can use the special url endpoint ``static`` to build urls that point here. +Open ``layout.html`` and add the following: + +.. code-block:: jinja + :class: small incremental + + + Flaskr + + + + +Going Further +------------- + +It's not too hard to see ways you could improve this. + +.. class:: incremental + +* For my part, I made a version with styles from Bootstrap.js. +* You could limit the number of posts shown on the front page and add + pagination. +* You could add *created date* to the entry schema and provide archived views + for older posts. +* You could add the ability to edit existing posts (and add a modified date to + the schema) +* You could support multi-user blogging by providing a more complex + authentication system and some more views. + + +Wrap-Up +------- + +For educational purposes you might try taking a look at the source code for +Flask and Werkzeug. Neither is too large a package. + +.. class:: incremental + +In particular seeing how Werkzeug sets up a Request and Response--and how +these relate to the WSGI specification--can be very enlightening. + +.. class:: incremental center + +**See You Tomorrow!** From aa4587016d10dff54a330e65a50fc4a9b85e5dbb Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 20 Jul 2013 14:51:58 -0700 Subject: [PATCH 123/487] complete the cannibalization of the week05 presentation --- source/presentations/week05.rst | 635 -------------------------------- 1 file changed, 635 deletions(-) diff --git a/source/presentations/week05.rst b/source/presentations/week05.rst index 29c91c30..e69de29b 100644 --- a/source/presentations/week05.rst +++ b/source/presentations/week05.rst @@ -1,635 +0,0 @@ -Internet Programming with Python -================================ - -blah blah blah - -Templates in Flask ------------------- - -Use the ``render_template`` function: - -.. code-block:: python - :class: small - - from flask import render_template - - @app.route('/hello/') - @app.route('/hello/') - def hello(name=None): - return render_template('hello.html', name=name) - -.. class:: incremental - -Flask looks for a ``templates`` directory in the same location as your app -module (remember ``app = Flask(__name__)``?). - -.. class:: incremental - -Any extra variables you want to pass to the template should be keyword -arguments to ``render_template`` - -Flask Template Context ----------------------- - -Flask adds a few things to the context of templates. You can use these - -.. class:: incremental - -* **config**: contains the current configuration object -* **request**: contains the current request object -* **session**: any session data that might be available -* **g**: the request-local object to which global variables are bound -* **get_flashed_messages**: a function that returns messages you flash to your - users (more on this later). -* **url_for**: so you can easily *reverse* urls from within your templates - -Lab 1 ------ - -Open a terminal, change directories to the class repository, then to -``assignments/week05/lab/book_app``. - -.. class:: incremental - -* You'll find a file ``book_app.py`` which is all set up and ready to go -* You'll also find a ``templates`` directory with some templates -* Complete the functions to provide the right stuff to the templates -* Complete the templates to display the data to the end-user -* At the end you should have a reproduced version of last week's homework - -.. class:: incremental center - -**GO** - - - - - -Lab 2 - Part 3 --------------- - -Now we can read and write blog entries, let's add views so we can see what -we're doing. - -.. class:: incremental - -Again. Tests come first. - -.. class:: incremental - -And again, if you've fallen behind or want to start clean, the completed code -from our last step is in ``flaskr_3`` - -Test the Front Page -------------------- - -Add the following tests to ``flaskr_tests.py``: - -.. code-block:: - - def test_empty_listing(self): - rv = self.client.get('/') - assert 'No entries here so far' in rv.data - - def test_listing(self): - expected = ("My Title", "My Text") - with self.app.test_request_context('/'): - self.app.preprocess_request() - flaskr.write_entry(*expected) - rv = self.client.get('/') - for value in expected: - assert value in rv.data - -Template Inheritance --------------------- - -One aspect of Jinja2 templates we haven't seen yet is that templates can -inherit structure from other templates. - -.. class:: incremental - -* you can make replaceable blocks in templates with blocks: ``{% block foo - %}{% endblock %}``. -* you can build on a template in a second template by extending: ``{% extends - "layout.html" %}`` (this *must* be first) - -.. class:: incremental - -We want the parts of our app to look alike, so let's create a basic layout -first. Create a file ``layout.html`` in the ``templates`` directory. - -Creating Layout ---------------- - -.. code-block:: jinja - - - - - Flaskr - - -

    Flaskr

    -
    - {% block body %}{% endblock %} -
    - - - -Extending Layout ----------------- - -Create a new file, ``show_entries.html`` in ``templates``: - -.. code-block:: jinja - :class: small - - {% extends "layout.html" %} - {% block body %} -

    Posts

    -
      - {% for entry in entries %} -
    • -

      {{ entry.title }}

      -
      - {{ entry.text|safe }} -
      -
    • - {% else %} -
    • No entries here so far
    • - {% endfor %} -
    - {% endblock %} - -Creating a View ---------------- - -Now, we just need to hook up our entries to that template. In ``flaskr.py`` -add the following code: - -.. code-block:: python - - # at the top, import - from flask import render_template - - # and after our last functions: - @app.route('/') - def show_entries(): - entries = get_all_entries() - return render_template('show_entries.html', entries=entries) - -.. class:: incremental - -Run our tests. Should be 6 for 6 now. - -Authentication --------------- - -We don't want just anyone to be able to add new entries. So we want to be able -to authenticate a user. - -.. class:: incremental - -We'll be using built-in functionality of Flask to do this, but this -simplest-possible implementation should serve only as a guide. - -.. class:: incremental - -We'll start with the tests, of course. - -Test Authentication -------------------- - -Back in ``flaskr_tests.py`` add new test methods: - -.. code-block:: python - :class: small - - def test_login_passes(self): - with self.app.test_request_context('/'): - self.app.preprocess_request() - flaskr.do_login(flaskr.app.config['USERNAME'], - flaskr.app.config['PASSWORD']) - self.assertTrue(session.get('logged_in', False)) - - def test_login_fails(self): - with self.app.test_request_context('/'): - self.app.preprocess_request() - self.assertRaises(ValueError, flaskr.do_login, - flaskr.app.config['USERNAME'], - 'incorrectpassword') - -Set Up Authentication ---------------------- - -Now, let's add the code in ``flaskr.py`` to support this: - -.. code-block:: python - :class: small - - # add an import - from flask import session - - # and configuration - USERNAME = 'admin' - PASSWORD = 'default' - - # and a function - def do_login(usr, pwd): - if usr != app.config['USERNAME']: - raise ValueError - elif pwd != app.config['PASSWORD']: - raise ValueError - else: - session['logged_in'] = True - -Login/Logout in Tests ---------------------- - -Let's add tests for a view. We'll set up a form that redirects back to the -main view on success. First, methods to actually do the login/logout (in -``flaskr_tests.py``): - -.. code-block:: python - - def login(self, username, password): - return self.client.post('/login', data=dict( - username=username, - password=password - ), follow_redirects=True) - - def logout(self): - return self.client.get('/logout', - follow_redirects=True) - -Test Authentication -------------------- - -And now the test itself (again, ``flaskr_tests.py``): - -.. code-block:: python - - def test_login_logout(self): - rv = self.login('admin', 'default') - assert 'You were logged in' in rv.data - rv = self.logout() - assert 'You were logged out' in rv.data - rv = self.login('adminx', 'default') - assert 'Invalid Login' in rv.data - rv = self.login('admin', 'defaultx') - assert 'Invalid Login' in rv.data - -.. class:: incremental - -We should be up to 9 tests, one failing - -Add Login Template ------------------- - -Add ``login.html`` to ``templates``: - -.. code-block:: jinja - :class: tiny - - {% extends "layout.html" %} - {% block body %} -

    Login

    - {% if error -%} -

    Error {{ error }} - {%- endif %} -

    -
    - - -
    -
    - - -
    -
    - -
    -
    - {% endblock %} - -Add Login/Logout Views ----------------------- - -And back in ``flaskr.py`` add new code. Let's start with imports: - -.. code-block:: python - - # at the top, new imports - from flask import request - from flask import redirect - from flask import flash - from flask import url_for - -And the View Code ------------------ - -.. code-block:: python - :class: small - - @app.route('/login', methods=['GET', 'POST']) - def login(): - error = None - if request.method == 'POST': - try: - do_login(request.form['username'], - request.form['password']) - except ValueError: - error = "Invalid Login" - else: - flash('You were logged in') - return redirect(url_for('show_entries')) - return render_template('login.html', error=error) - - @app.route('/logout') - def logout(): - session.pop('logged_in', None) - flash('You were logged out') - return redirect(url_for('show_entries')) - -About Flash ------------ - -.. class:: small - -Flask provides ``flash`` as a way of sending messages to the user from view -code. We need a place to show these messages. Add it to ``layout.html`` (along -with links to log in and out) - -.. code-block:: jinja - :class: small - -

    Flaskr

    -
    - {% if not session.logged_in %} - log in - {% else %} - log_out - {% endif %} -
    - {% for message in get_flashed_messages() %} -
    {{ message }}
    - {% endfor %} -
    - -Adding an Entry ---------------- - -We still lack a way to add an entry. We need a view to do that. Again, tests -first (in ``flaskr_tests.py``): - -.. code-block:: python - - def test_add_entries(self): - self.login('admin', 'default') - rv = self.client.post('/add', data=dict( - title='Hello', - text='This is a post' - ), follow_redirects=True) - assert 'No entries here so far' not in rv.data - assert 'Hello' in rv.data - assert 'This is a post' in rv.data - -Add the View ------------- - -We've already got all the stuff we need to write entries, we just need an -endpoint that will do it via the web (in ``flaskr.py``): - -.. code-block:: python - :class: small - - # add an import - from flask import abort - - @app.route('/add', methods=['POST']) - def add_entry(): - if not session.get('logged_in'): - abort(401) - try: - write_entry(request.form['title'], request.form['text']) - flash('New entry was successfully posted') - except sqlite3.Error as e: - flash('There was an error: %s' % e.args[0]) - return redirect(url_for('show_entries')) - -Where do Entries Come From --------------------------- - -Finally, we're almost done. We can log in and log out. We can add entries and -view them. But look at that last view. Do you see a call to -``render_template`` in there at all? - -.. class:: incremental - -There isn't one. That's because that view is never meant to be be visible. -Look carefully at the logic. What happens? - -.. class:: incremental - -So where do the form values come from? - -.. class:: incremental - -Let's add a form to the main view. Open ``show_entries.html`` - -Provide a Form --------------- - -.. code-block:: jinja - :class: small - - {% block body %} - {% if session.logged_in %} -
    -
    - - -
    -
    - - -
    -
    - -
    -
    - {% endif %} -

    Posts

    - -All Done --------- - -Okay. That's it. We've got an app all written. - -.. class:: incremental - -So far, we haven't actually touched our browsers at all, but we have -reasonable certainty that this works because of our tests. Let's try it. - - -.. class:: incremental - -In the terminal where you've been running tests, run our flaskr app: - -.. class:: incremental - -:: - - (flaskenv)$ python flaskr.py - * Running on http://127.0.0.1:5000/ - * Restarting with reloader - -The Big Payoff --------------- - -Now load ``http://localhost:5000/`` in your browser and enjoy your reward. - -Lab 2 - Part 4 --------------- - -On the other hand, what we've got here is pretty ugly. We could prettify it. - -.. class:: incremental - -Again, if you want to start fresh or you fell behind you can find code -completed to this point in ``flaskr_4``. - -.. class:: incremental - -In that directory inside the ``static`` directory you will find -``styles.css``. Open it in your editor. It contains basic CSS for this app. - -.. class:: incremental - -We'll need to include this file in our ``layout.html``. - -Static Files ------------- - -Like page templates, Flask locates static resources like images, css and -javascript by looking for a ``static`` directory next to the app module. - -.. class:: incremental - -You can use the special url endpoint ``static`` to build urls that point here. -Open ``layout.html`` and add the following: - -.. code-block:: jinja - :class: small incremental - - - Flaskr - - - - -Deploying ---------- - -First, move the source code to your VM:: - - (flaskenv)$ cd ../ - (flaskenv)$ tar -czvf flaskr.tgz flaskr - (flaskenv)$ scp flaskr.tgz :~/ - (flaskenv)$ ssh - $ tar -zxvf flaskr.tgz - -Then, on your VM, set up a virtualenv with Flask installed - -Deploying ---------- - -You'll need to make some changes to mod_wsgi configuration. - -* Open ``/etc/apache2/sites-available/default`` in an editor (on the VM) - -* Add the following line at the top (outside the VirtualHost block): - ``WSGIPythonHome /path/to/flaskenv`` - -* Delete all other lines refering to mod_wsgi configuration -* Add the following in the VirtualHost block: - -:: - - WSGIScriptAlias / /var/www/flaskr.wsgi - -Deploying ---------- - -Finally, you'll need to add the named wsgi file and edit it to match:: - - $ sudo touch /var/www/flaskr.wsgi - $ sudo vi /var/www/flasrk.wsgi - - - import sys - sys.path.insert(0, 'path/to/flaskr') # the flaskr app you uploaded - - from flaskr import app as application - -Deploying ---------- - -Finally, restart apache and bask in the glow:: - - $ sudo apache2ctl configtest - $ sudo /etc/init.d/apache2 graceful - -Load http://your_vm/ - -Wheeee! - -Going Further -------------- - -It's not too hard to see ways you could improve this. - -.. class:: incremental - -* For my part, I made a version using Bootstrap.js. -* You could limit the number of posts shown on the front page. -* You could add dates to the posts and provide archived views for older posts. -* You could add the ability to edit existing posts (and add an updated date to the schema) -* ... - -But Instead ------------ - -Instead of doing any of that, this week's assignment is a bit different. - -.. class:: incremental - -You've implemented an app in one Small Framework. I want you to do it all -again, in a different Small Framework. - -.. class:: incremental - -While you're working on it, think about the differences between your new -Framework and Flask. What do you like more? What do you like less? How might -this influence your choice of Frameworks in the future? - -Assignment ----------- - -* Re-implement the Flaskr app we built in class in a different Small - Framework. -* There are several named in the class outline, and in this presentation. -* Pick one of them, or a different one of your choice. It must be Python. -* When you are finished, add your source code and a README that talks about - your experience to the ``athome`` folder of week05. -* Tell me about your new Framework. Discuss the points above regarding - differences. - -Submitting The Assignment -------------------------- - -* Try to get your code running on your VM -* Add your source code, in it's entirety, to the ``athome`` folder for week 5 -* Add a README.txt file that discusses the experience. -* Commit your changes to your fork of the class repository and send me a pull - request From 7b1346845d26ae0140b01958875bc795ed4a8298 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 20 Jul 2013 22:10:03 -0700 Subject: [PATCH 124/487] push forward on session03 translations from week03 presentation --- source/presentations/session03.rst | 295 +++++++++++++++++++++++++---- source/presentations/week03.rst | 41 +--- 2 files changed, 262 insertions(+), 74 deletions(-) diff --git a/source/presentations/session03.rst b/source/presentations/session03.rst index 3c43705b..5a54ca95 100644 --- a/source/presentations/session03.rst +++ b/source/presentations/session03.rst @@ -301,6 +301,28 @@ BeautifulSoup will choose the best available, you don't need to worry about it (though you can specify). +Install Requests +---------------- + +Python provides tools for opening urls and communicating with servers. It's +spread across the ``urllib`` and ``urllib2`` packages. + +.. class:: incremental + +These packages have pretty unintuitive APIs. + +.. class:: incremental + +The ``requests`` library is becoming the de-facto standard for this type of +work. Let's install it too. + +.. class:: incremental + +:: + + (soupenv)$ pip install requests + + Our Class Mashup ---------------- @@ -342,59 +364,124 @@ formula for a search URL * price: ``minAsk=NNN maxAsk=NNN`` * bedrooms: ``bedrooms=N`` (N in range 1-8) +.. class:: incremental -Build a Search URL ------------------- +We can make a request with these parameters using the ``requests`` library we +installed a moment ago -First, let's build a function ``build_url`` that generates a good search url + +Opening URLs with Requests +-------------------------- + +Requests has a very nice API for doing HTTP requests. + +.. class:: incremental + +Each HTTP method is represented by a module-level function: .. class:: incremental -The standard library modules ``urllib`` and ``urllib2`` can help us +* ``GET`` == ``requests.get(url, **kwargs)`` +* ``POST`` == ``requests.post(url, **kwargs)`` +* ... + +.. class:: incremental + +Keyword arguments allow for other parts of an HTTP request: + +.. class:: incremental + +* ``params``: url parameters (?foo=bar&baz=bim) +* ``headers``: headers to send with the request +* ``data``: the body of the request, if any (form data for POST goes here) +* ... + + +Getting Responses with Requests +------------------------------- + +Once you've made a request using one of these methods, the return value is a +``response``. + +.. class:: incremental + +This object has a number of useful attributes: + +.. class:: incremental + +* ``response.status_code``: see the HTTP Status Code returned +* ``response.ok``: True if ``response.status_code`` is not an error code +* ``response.headers``: The headers sent in the response from the server +* ``response.text``: Body of the response, decoded to a unicode string +* ``response.encoding``: The encoding used to decode ``response.text`` +* ``response.content``: The original response body, not decoded (useful for + binary content) + +.. class:: incremental + +If an error status is returned, you can raise a Python error by calling +``response.raise_for_status``. + + +Fetch Search Results +-------------------- + +We can start our work by writing a function ``fetch_search_results`` .. class:: incremental * It will accept one keyword argument for each of the possible query values -* It will combine the values passed into an HTTP query -* It will combine that query with the base URL for the search and return the - result +* It will build a dictionary of request query parameters from incoming keywords +* It will make a request to the craigslist server using this query +* It will return the body of the response if there is no error +* It will raise an error if there is a problem with the response .. class:: incremental -Go ahead and write your version into ``mashup.py`` +Using what you've learned, take a stab at writing this function. Put it in +``mashup.py`` My Solution ----------- +Here's the one I created: + .. code-block:: python :class: small incremental - def build_url(http://github.com/**kwargs): + import requests + + def fetch_search_results(**kwargs): base = 'http://raleigh.craigslist.org/search/apa' valid_kws = ('query', 'minAsk', 'maxAsk', 'bedrooms') - use_kwargs = {} - for kw in valid_kws: - if kw in kwargs: - use_kwargs[key] = kwargs[key] + use_kwargs = dict( + [(key, val) for key, val in kwargs.items() if key in valid_kws]) if not use_kwargs: raise ValueError("No valid keywords") - query = urllib.urlencode(use_kwargs) - return '%s?%s' % (base, query) + resp = requests.get(base, params=use_kwargs, timeout=3) + if resp.ok: + return resp.text, resp.encoding + else: + resp.raise_for_status() -Grab and Parse a Page ---------------------- + +Parse the Results +----------------- Next, we need a function ``parse_source`` to set up HTML for scraping. It will need to: .. class:: incremental -* Take the constructed URL from before as an argument -* Open the url -* If appropriate, attempt to parse the page with BeautifulSoup -* Return the parsed HTML for processing +* Take the response body from the previous method (or some other source) +* Parse it using BeautifulSoup +* Return the parsed object for further processing + +.. class:: incremental + +Before you start, a word about parsing HTML with BeautifulSoup Parsing HTML with BeautifulSoup @@ -416,17 +503,26 @@ object as the sole argument: parsed = BeautifulSoup(page) +.. class:: incremental + +You might want to open the documentation as reference +(http://www.crummy.com/software/BeautifulSoup/bs4/doc) + + My Solution ----------- +Take a shot at writing this new function in ``mashup.py`` + .. code-block:: python - :class: incremental + :class: incremental small + + # add this import at the top + from bs4 import BeautifulSoup - def parse_source(url): - resp = urllib2.urlopen(url) - if resp.code != 200: - raise IOError("Error reading source URL") - parsed = BeautifulSoup(resp) + # then add this function lower down + def parse_source(html, encoding='utf-8'): + parsed = BeautifulSoup(html, from_encoding=encoding) return parsed @@ -439,10 +535,10 @@ To see how we're doing, we'll need to make our script do something when run. Add an ``if __name__ == '__main__`:`` block to the bottom of our library -.. class:: incremental small +.. class:: incremental -* Build a good search url -* Parse the resulting search page +* Fetch a search results page +* Parse the resulting HTML * For now, print out the results so we can see what we get .. container:: incremental small @@ -455,20 +551,27 @@ Add an ``if __name__ == '__main__`:`` block to the bottom of our library My Solution ----------- +Try to come up with the proper code on your own. Add it to ``mashup.py`` + .. code-block:: python :class: incremental if __name__ == '__main__': - url = build_url(http://github.com/minAsk=500,%20maxAsk=1000,%20bedrooms=2) - doc = parse_source(url) - print doc.prettify() + params = {'minAsk': 500, 'maxAsk': 1000, 'bedrooms': 2} + html, encoding = fetch_search_results(**params) + doc = parse_source(html, encoding) + print doc.prettify(encoding=encoding) Test Your Work -------------- Assuming your virtualenv is still active, you should be able to execute the -script:: +script. + +.. class:: incremental small + +:: (soupenv)$ python mashup.py @@ -479,4 +582,128 @@ script:: ... +.. container:: incremental + + Try it again, this time redirect the output to a local file, so we can use + it without needing to hit the craiglist servers each time: + + .. class:: small + + :: + + (soupenv)$ python mashup.py > craigslist_results.html + + +Finding The Needle +------------------ + +The next step is to find the bits of this pile of HTML that matter to us. + +.. class:: incremental + +We've got this HTML file, so let's open it in a browser and take a look + +.. class:: incremental + +We'll want to find: + +.. class:: incremental + +* The HTML element that contains a single listing +* The source of location data, listings without location should be abandoned +* The description of a listing +* The link to a full listing page on craigslist +* Relevant price or size data. + + +Pulling it Out +-------------- + +Now that we know what we are looking for, we can extract it. In BeautifulSoup: + +.. class:: incremental + +* All HTML elements (including the parsed document itself) act like ``tags`` +* A ``tag`` can be searched using the ``find_all`` method +* The ``find_all`` method searches the descendents of the tag on which it is + called. +* The ``find_all`` method takes arguments which act as *filters* on the search + results + +.. class:: incremental + +| like so: +| +| ``tag.find_all(name, attrs, recursive, text, limit, **kwargs)`` + + +Searching by CSS Class +---------------------- + +The items we are looking for are ``p`` tags which have the CSS class +``row``: + +.. class:: incremental + +``find_all`` supports keyword arguments. If the keyword you use isn't one of +the listed arguments, it is treated as an ``attribute`` + +.. class:: incremental + +In Python, ``class`` is a reserved word, so we can't use it as a keyword, but +you can use ``class_``! + +.. class:: incremental small + +:: + + parsed.find_all('p', class_='row') + + +Try It Out +---------- + +Let's fire up a python interpreter and get our hands dirty here:: + + (soupenv)$ python + +.. code-block:: python + :class: small incremental + + >>> html = open('craigslist_results.html', 'r').read() + >>> from bs4 import BeautifulSoup + >>> parsed = BeautifulSoup(html) + >>> listings = parsed.find_all('p', class_='row') + >>> len(entries) + 100 + + +.. class:: incremental + +That sounds about right. Let's see if we can get only those with location +data. + + +Filtering Tricks +---------------- + +Attribute filters given a ``True`` value match tags with that attribute + +.. class:: incremental + +Location data was in the ``data-latitude`` and ``data-longitude`` attributes. + +.. code-block:: python + :class: small incremental + + >>> location_attrs = { + ... 'data-longitude': True, + ... 'data-latitude': True} + >>> locatable = parsed.find_all( + ... 'p', class_='row', attrs=location_attrs) + >>> len(locatable) + 43 + +.. class:: incremental +Great. That worked nicely diff --git a/source/presentations/week03.rst b/source/presentations/week03.rst index 77cbcb6a..dda1908b 100644 --- a/source/presentations/week03.rst +++ b/source/presentations/week03.rst @@ -1,51 +1,12 @@ Internet Programming with Python ================================ +blah blah blah -Scraping HTML -------------- - -The next step is to figure out what it is from the HTML page that you want to -scrape. - -.. class:: incremental - -**Goal**: Sort the blog post titles and URLs into two lists, one for Django -and one for PostgreSQL - -.. class:: incremental - -What tools do we have to allow us to look at the source and find our targets? - -HTML Inspection Demo --------------------- -We can use the developer tools that come in Safari, Chrome and IE, or use the -Firebug extension to FireFox. -.. class:: incremental - -So, we need to find ``
    `` elements with the class ``feedEntry``. - -Searching Your Soup -------------------- - -BeautifulSoup has parsed our document -.. class:: incremental - -* A parsed document acts like a ``tag`` -* A ``tag`` can be searched using the ``find_all`` method -* The ``find_all`` method searches the descendents of the tag on which it is - called. -* The ``find_all`` method takes arguments which act as *filters* on the search - results -.. class:: incremental - -| like so: -| -| ``tag.find_all(name, attrs, recursive, text, limit, **kwargs)`` Searching by CSS Class ---------------------- From 430272cd8355a77db6d0a3a73ae7e95671f078f4 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 23 Jul 2013 00:34:10 -0700 Subject: [PATCH 125/487] complete the transfer of week03 to session03 --- source/presentations/session03.rst | 1447 ++++++++++++++++++++++++++++ source/presentations/week03.rst | 1075 --------------------- 2 files changed, 1447 insertions(+), 1075 deletions(-) diff --git a/source/presentations/session03.rst b/source/presentations/session03.rst index 5a54ca95..f4f25606 100644 --- a/source/presentations/session03.rst +++ b/source/presentations/session03.rst @@ -707,3 +707,1450 @@ Location data was in the ``data-latitude`` and ``data-longitude`` attributes. .. class:: incremental Great. That worked nicely + + +Parsing a Row +------------- + +Now that we have the rows we want, we need to parse them. We want to preserve: + +.. class:: incremental + +* Location data (latitude and longitude) +* Source link (to craiglist detailed listing) +* Description text +* Price and size data + +.. class:: incremental + +Which parts of a single row contain each of these elements? + + +Extracting Location +------------------- + +Location data is in the ``data-`` attributes we used to filter rows. + +.. container:: incremental + + We can read the HTML attributes of a 'tag' easily, using ``attrs``: + + .. code-block:: python + :class: small + + >>> row1 = locatable[0] + >>> row1.attrs + {u'data-pid': u'3949023084', u'data-latitude': u'35.8625743108992', + u'class': [u'row'], u'data-longitude': u'-78.6232739959049'} + >>> lat = row1.attrs.get('data-latitude', None) + >>> lon = row1.attrs.get('data-longitude', None) + >>> print lat, lon + 35.8625743108992 -78.6232739959049 + + +Extracting Description and Link +------------------------------- + +Where ``find_all`` will find many elements, ``find`` will only find the first +that matches the filters you provide. + +.. container:: incremental + + Our targets are in the first ``a`` tag in the ``pl`` span inside our row: + + .. code-block:: python + :class: small + + >>> link = row1.find('span', class_='pl').find('a') + +.. container:: incremental + + The link path will be in the attrs: + + .. code-block:: python + :class: small + + >>> path = link.attrs['href'] + +.. container:: incremental + + Text contained *inside* tags is in the ``string`` property: + + .. code-block:: python + :class: small + + >>> description = link.string.strip() + + +Extracting Price and Size +------------------------- + +Both price and size are held in the ``pnr`` span: + +.. code-block:: python + :class: small + + >>> pnr = row1.find('span', class_='pnr') + +.. container:: incremental + + Price, conveniently, is in it's own container: + + .. code-block:: python + :class: small + + >>> price_span = pnr.find('span', class_='price') + >>> price = price_span.string.strip() + +.. class:: incremental + +But the size element is not. It is a standalone *text node*. + +.. class:: incremental + +Try finding it by reading the ``string`` property of our `pnr` tag. + + +Simple Navigation and Text +-------------------------- + +We can get to a simple text node by navigating there. + +.. class:: incremental + +BeautifulSoup tags support navigation up, down and across document nodes. + +.. container:: incremental + + We already have the ``price`` span, the size text node is next at the same + level: + + .. code-block:: python + :class: small + + >>> size = price.next_sibling.strip(' \n-/') + u'2br - 1160ft\xb2' + +.. class:: incremental + +You may have noticed that we keep using ``strip``. There are two reasons for +this. + + +The NavigableString Element +--------------------------- + +The most obvious reason is that we don't really want all the extra whitespace. + +.. class:: incremental + +The second reason is more subtle. The values returned by ``string`` are +**not** simple unicode strings + +.. container:: incremental + + They are actually instances of a class called ``NavigableString``: + + .. code-block:: python + :class: small + + >>> price.next_sibling.__class__ + + +.. class:: incremental + +These things hold references to their surroundings. + +.. class:: incremental + +Calling ``strip`` or casting them to ``unicode`` converts them, saving memory + + +Put It All Together +------------------- + +Okay, a challenge. Combine everything we've done into a function that: + +.. class:: incremental + +* Extracts all the locatable listings from our html page +* Iterates over each of them, and builds a dictionary of data + * include ``location``, ``href``, ``description``, ``price`` and ``size`` + +* Returns a list of these dictionaries + +.. class:: incremental + +Call it ``extract_listings`` + +.. class:: incremental + +Put this new function into ``mashup.py`` and call it from ``__main__``, +printing the result + + +My Solution +----------- + +.. code-block:: python + :class: small incremental + + def extract_listings(doc): + location_attrs = {'data-latitude': True, + 'data-longitude': True} + for row in doc.find_all('p', class_='row', + attrs=location_attrs): + location = dict( + [(key, row.attrs.get(key)) for key in location_attrs]) + link = row.find('span', class_='pl').find('a') + price_span = row.find('span', class_='price') + listing = { + 'location': location, + 'href': link.attrs['href'], + 'description': link.string.strip(), + 'price': price_span.string.strip(), + 'size': price_span.next_sibling.strip(' \n-/') + } + yield listing + + +My Solution +----------- + +.. code-block:: python + :class: small + + if __name__ == '__main__': + params = {'minAsk': 500, 'maxAsk': 1000, 'bedrooms': 2} + html, encoding = fetch_search_results(**params) + doc = parse_source(html, encoding) + for listing in extract_listings(doc): + pprint.pprint(listing) + + +Another Approach +---------------- + +Scraping web pages is tedious and inherently brittle + +.. class:: incremental + +The owner of the website updates their layout, your code breaks + +.. class:: incremental + +But there is another way to get information from the web in a more normalized +fashion + +.. class:: incremental center + +**Web Services** + + +Web Services +------------ + +"a software system designed to support interoperable machine-to-machine +interaction over a network" - W3C + +.. class:: incremental + +* provides a defined set of calls +* returns structured data + + +Early Web Services +------------------ + +RSS is one of the earliest forms of Web Services + +* First known as ``RDF Site Summary`` +* Became ``Really Simple Syndication`` +* More at http://www.rss-specification.com/rss-specifications.htm + +.. class:: incremental + +A single web-based *endpoint* provides a dynamically updated listing of +content + +.. class:: incremental + +Implemented in pure HTTP. Returns XML + +.. class:: incremental + +**Atom** is a competing, but similar standard + + +RSS Document +------------ + +.. class:: tiny + +:: + + + + + RSS Title + This is an example of an RSS feed + http://www.someexamplerssdomain.com/main.html + Mon, 06 Sep 2010 00:01:00 +0000 + Mon, 06 Sep 2009 16:45:00 +0000 + 1800 + + + Example entry + Here is some text containing an interesting description. + http://www.wikipedia.org/ + unique string per item + Mon, 06 Sep 2009 16:45:00 +0000 + + ... + + + + +XML-RPC +------- + +RSS provides a pre-defined data set, can we also allow *calling procedures* to +get more dynamic data? + +.. class:: incremental + +We can! Enter XML-RPC (Remote Procedure Call) + +.. class:: incremental + +* Provides a set of defined procedures which can take arguments +* Calls are made via HTTP GET, by passing an XML document +* Returns from a call are sent to the client in XML + +.. class:: incremental + +There is an interactive example of this at the end of this session. We will +not go through it here, though. + + +Beyond XML-RPC +-------------- + +.. class:: incremental + +* XML-RPC allows introspection +* XML-RPC forces you to introspect to get information +* *Wouldn't it be nice to get that automatically?* +* XML-RPC provides data types +* XML-RPC provides only *certain* data types +* *Wouldn't it be nice to have an extensible system for types?* +* XML-RPC allows calling methods with parameters +* XML-RPC only allows calling methods, nothing else +* *wouldn't it be nice to have contextual data as well?* + +.. class:: incremental center + +**Enter SOAP: Simple Object Access Protocol** + + +SOAP +---- + +SOAP extends XML-RPC in a couple of useful ways: + +.. class:: incremental + +* It uses Web Services Description Language (WSDL) to provide meta-data about + an entire service in a machine-readable format (Automatic introspection) + +* It establishes a method for extending available data types using XML + namespaces + +* It provides a wrapper around method calls called the **envelope**, which + allows the inclusion of a **header** with system meta-data that can be used + by the application + + +SOAP in Python +-------------- + +There is no standard library module that supports SOAP directly. + +.. class:: incremental + +* The best-known and best-supported module available is **Suds** +* The homepage is https://fedorahosted.org/suds/ +* It can be installed using ``easy_install`` or ``pip install`` + +.. class:: incremental + +Again, there is a good example of using SOAP via the ``suds`` library at the +end of this session. + +.. class:: incremental + +But we're going to move on + + +Afterword +--------- + +SOAP (and XML-RPC) have some problems: + +.. class:: incremental + +* XML is pretty damned inefficient as a data transfer medium +* Why should I need to know method names? +* If I can discover method names at all, I have to read a WSDL to do it? + +.. class:: incremental + +Suds is the best we have, and it hasn't been updated since Sept. 2010. + +If Not XML, Then What? +---------------------- + +.. class:: big-centered incremental + +**JSON** + + +JSON +---- + +JavaScript Object Notation: + +.. class:: incremental + +* a lightweight data-interchange format +* easy for humans to read and write +* easy for machines to parse and generate + +.. class:: incremental + +Based on Two Structures: + +.. class:: incremental + +* object: ``{ string: value, ...}`` +* array: ``[value, value, ]`` + +.. class:: center incremental + +pythonic, no? + + +JSON Data Types +--------------- + +JSON provides a few basic data types (see http://json.org/): + +.. class:: incremental + +* string: unicode, anything but ", \\ and control characters +* number: any number, but json does not use octal or hexidecimal +* object, array (we've seen these above) +* true +* false +* null + +.. class:: incremental center + +**No date type? OMGWTF??!!1!1** + + +Dates in JSON +------------- + +.. class:: incremental + +Option 1 - Unix Epoch Time (number): + +.. code-block:: python + :class: small incremental + + >>> import time + >>> time.time() + 1358212616.7691269 + +.. class:: incremental + +Option 2 - ISO 8661 (string): + +.. code-block:: python + :class: small incremental + + >>> import datetime + >>> datetime.datetime.now().isoformat() + '2013-01-14T17:18:10.727240' + + +JSON in Python +-------------- + +You can encode python to json, and decode json back to python: + +.. code-block:: python + :class: small + + >>> import json + >>> array = [1,2,3] + >>> json.dumps(array) + >>> orig = {'foo': [1,2,3], 'bar': u'my resumé', 'baz': True} + >>> encoded = json.dumps(orig) + >>> encoded + '{"baz": true, "foo": [1, 2, 3], "bar": "my resum\\u00e9"}' + >>> decoded = json.loads(encoded) + >>> decoded == orig + True + +.. class:: incremental + +Customizing the encoder or decoder class allows for specialized serializations + + +JSON in Python +-------------- + +the json module also supports reading and writing to *file-like objects* via +``json.dump(fp)`` and ``json.load(fp)`` (note the missing 's') + +.. class:: incremental + +Remember duck-typing. Anything with a ``.write`` and a ``.read`` method is +*file-like* + +.. class:: incremental + +Have we seen any network-related classes recently that behave that way? + + +What about WSDL? +---------------- + +SOAP was invented in part to provide completely machine-readable +interoperability. + +.. class:: incremental + +Does that really work in real life? + +.. class:: incremental center + +Hardly ever + + +What about WSDL? +---------------- + +Another reason was to provide extensibility via custom types + +.. class:: incremental + +Does that really work in real life? + +.. class:: incremental center + +Hardly ever + + +Why Do All The Work? +-------------------- + +So, if neither of these goals is really achieved by using SOAP, why pay all +the overhead required to use the protocol? + +.. class:: incremental + +Enter REST + + +REST +---- + +.. class:: center + +Representational State Transfer + +.. class:: incremental + +* Originally described by Roy T. Fielding (did you read it?) +* Use HTTP for what it can do +* Read more in `this book + `_\* + +.. class:: image-credit incremental + +\* Seriously. Buy it and read +( HTTP/1.1 +* GET /comment HTTP/1.1 +* POST /comment HTTP/1.1 +* PUT /comment/ HTTP/1.1 +* DELETE /comment/ HTTP/1.1 + + +ROA +--- + +This is **Resource Oriented Architecture** + +.. class:: incremental + +The URL represents the *resource* we are working with + +.. class:: incremental + +The HTTP Verb represents the ``action`` to be taken + +.. class:: incremental + +The HTTP Code returned tells us the ``result`` (whether success or failure) + + +HTTP Codes Revisited +-------------------- + +.. class:: small + +POST /comment HTTP/1.1 (creating a new comment): + +.. class:: incremental small + +* Success: ``HTTP/1.1 201 Created`` +* Failure (unauthorized): ``HTTP/1.1 401 Unauthorized`` +* Failure (NotImplemented): ``HTTP/1.1 405 Not Allowed`` +* Failure (ValueError): ``HTTP/1.1 406 Not Acceptable`` + +.. class:: small incremental + +PUT /comment/ HTTP/1.1 (edit comment): + +.. class:: incremental small + +* Success: ``HTTP/1.1 200 OK`` +* Failure: ``HTTP/1.1 409 Conflict`` + +.. class:: small incremental + +DELETE /comment/ HTTP/1.1 (delete comment): + +.. class:: incremental small + +* Success: ``HTTP/1.1 204 No Content`` + + +HTTP Is Stateless +----------------- + +No individual request may be assumed to know anything about any other request. + +.. class:: incremental + +All the required information for to represent the possible actions to take +*should be present in either the request or the response*. + +.. class:: incremental big-centered + +Thus: HATEOAS + + +HATEOAS +------- + +.. class:: big-centered + +Hypermedia As The Engine Of Application State + + +Applications are State Engines +------------------------------ + +A State Engine is a machine that provides *states* for a resource to be in and +*transitions* to move resources between states. A Restful api should: + +.. class:: incremental + +* provide information about the current state of a resource +* provide information about available transitions for that resource (URIs) +* provide all this in *each* HTTP response + + +Playing With REST +----------------- + +Let's take a moment to play with REST. + +.. class:: incremental + +We'll use a common, public API provided by Google. + +.. class:: incremental center + +**Geocoding** + + +Geocoding with Google APIs +-------------------------- + +https://developers.google.com/maps/documentation/geocoding + +.. container:: incremental + + Open a python interpreter using our virtualenv: + + .. class:: small + + :: + + (soupenv)$ python + +.. code-block:: python + :class: small incremental + + >>> import requests + >>> import json + >>> from pprint import pprint + >>> url = 'http://maps.googleapis.com/maps/api/geocode/json' + >>> addr = '120 E. Cameron Avenue Chapel Hill, NC 27599' + >>> parameters = {'address': addr, 'sensor': 'false' } + >>> resp = requests.get(url, params=parameters) + >>> data = json.loads(resp.text) + >>> if data['status'] == 'OK': + ... pprint(data) + + + +Reverse Geocoding +----------------- + +You can do the same thing in reverse, supply latitude and longitude and get +back address information: + +.. code-block:: python + :class: small + + >>> location = lookup['results'][0]['geometry']['location'] + >>> latlng = '%f,%f' % (location['lat'], location['lng']) + >>> parameters = {'latlng': latlng, 'sensor': 'false'} + >>> resp = requests.get(url, params=paramters) + >>> data = json.loads(resp.text) + >>> if data['status'] == 'OK': + ... pprint(data) + +.. class:: incremental + +Notice that there are a number of results returned, ordered from most specific +to least. + + +Mash It Up +---------- + +Let's add a new function to ``mashup.py``. It will: + +.. class:: incremental + +* take a single listing from our craiglist work +* format the location data provided in that listing properly +* make a reverse geocoding lookup using the google api above +* add the best available address to the listing +* return the updated listing + +.. class:: incremental + +Call it ``add_address`` + + +My Solution +----------- + +.. code-block:: python + :class: small incremental + + # add an import + import json + + # and a function + def add_address(listing): + api_url = 'http://maps.googleapis.com/maps/api/geocode/json' + loc = listing['location'] + parameters = { + 'sensor': 'false', + 'latlng': "%s,%s" % (loc['data-latitude'], + loc['data-longitude']) + } + resp = requests.get(api_url, params=parameters) + data = json.loads(resp.text) + if data['status'] == 'OK': + best = data['results'][0] + listing['address'] = best['formatted_address'] + else: + listing['address'] = 'unavailable' + return listing + + +Add Address to Output +--------------------- + +Go ahead and bolt the new function into our ``__main__`` block: + +.. code-block:: python + :class: small incremental + + if __name__ == '__main__': + params = {'minAsk': 500, 'maxAsk': 1000, 'bedrooms': 2} + html, encoding = fetch_search_results(**params) + doc = parse_source(html, encoding) + for listing in extract_listings(doc): + listing = add_address(listing) + pprint.pprint(listing) + +.. container:: incremental + + And give the result a whirl: + + .. class:: small + + :: + + (soupenv)$ python mashup.py + {'address': u'800 Bethlehem Road, Knightdale, NC 27545, USA', + 'description': u'3 bedroom 2 bathroom unit is move in ready!' + ... + } + + +One More Step +------------- + +I'm a big fan of walking places. + +.. class:: incremental + +So I'd like to find an apartment that is located somewhere 'walkable' + +.. class:: incremental + +There's an API for that! + +.. class:: incremental + +http://www.walkscore.com/professional/api.php + +.. class:: incremental + +Take a second here and sign up for an api key. Use a real email address, +they'll email you an API key. + + +Getting a Walk Score +-------------------- + +The API documentation tells us we have to provide lat, lon and address to get +a walk score, along with our API key. + +.. class:: incremental + +It also tells us we have a choice of XML or JSON output. Let's use JSON + +.. class:: incremental + +Let's poke at it and see what we get back + +.. class:: incremental + +Fire up your virtualenv Python interpreter again + + +Making an API Call +------------------ + +:: + + (soupenv)$ python + +.. code-block:: python + :small: + + >>> import requests + >>> import json + >>> from pprint import pprint + >>> api_url = 'http://api.walkscore.com/score' + >>> lat, lon = 35.9108986, -79.053783 + >>> addr = '120 E. Cameron Avenue Chapel Hill, NC 27599' + >>> params = {'lat': lat, 'lon', lon, 'address': addr} + >>> params['wsapikey'] = '' + >>> params['format'] = 'json' + >>> resp = requests.get(api_url, params=params) + >>> data = json.loads(resp.text) + >>> if data['status'] == 1: + ... pprint(data) + + +Mash It Up +---------- + +Add a function to ``mashup.py`` that: + +.. class:: incremental + +* takes a single listing from our craigslist search +* uses the location and address to make a walkscore api call +* adds the description, walkscore and ws_link parameters to the listing +* returns the updated listing + +.. class:: incremental + +Call the function ``add_walkscore`` + +.. class:: incremental + +Bolt it into our script's ``__main__`` block where it fits best + + +My Solution +----------- + +.. code-block:: python + :class: small incremental + + def add_walkscore(listing): + api_url = 'http://api.walkscore.com/score' + apikey = '' + loc = listing['location'] + if listing['address'] == 'unavailable': + return listing + parameters = { + 'lat': loc['data-latitude'], 'lon': loc['data-longitude'], + 'address': listing['address'], 'wsapikey': apikey, + 'format': 'json' + } + resp = requests.get(api_url, params=parameters) + data = json.loads(resp.text) + if data['status'] == 1: + listing['ws_description'] = data['description'] + listing['ws_score'] = data['walkscore'] + listing['ws_link'] = data['ws_link'] + return listing + + +My Results +---------- + +.. code-block:: python + :class: small + + if __name__ == '__main__': + params = {'minAsk': 500, 'maxAsk': 1000, 'bedrooms': 2} + html, encoding = fetch_search_results(**params) + doc = parse_source(html, encoding) + for listing in extract_listings(doc): + listing = add_address(listing) + listing = add_walkscore(listing) + pprint.pprint(listing) + +.. class:: incremental + +Let's try it out:: + + (soupenv)$ python mashup.py + + +Wrap Up +------- + +We've built a simple mashup combining data from three different sources. + +.. class:: incremental + +As a result we can now make a listing of apartments ranked by the walkability +of their neighborhood. + +.. class:: incremental + +What other data sources might we use? Check out +http://www.programmableweb.com/apis/directory to see some of the possibilities + + +Next Steps +---------- + +We've spent this session consuming data produced by other people. + +.. class:: incremental + +In the next session we'll see how to take input from clients and use it to +create our own responses. + +.. class:: incremental + +See you back here soon! + + +Addenda +------- + +The following are provided as self-directed exercises. We just don't have the +time to cover them in depth in class. + + +XML-RPC +------- + +Examples of XML-RPC using the Python Standard Library + + +XML-RPC Example - Server +------------------------ + +xmlrpc_server.py: + +.. code-block:: python + :class: small + + from SimpleXMLRPCServer import SimpleXMLRPCServer + + server = SimpleXMLRPCServer(('localhost', 50000)) + + def multiply(a, b): + return a * b + server.register_function(multiply) + + try: + print "Use Ctrl-C to Exit" + server.serve_forever() + except KeyboardInterrupt: + print "Exiting" + + +XML-RPC Example - Client +------------------------ + +We can run a client from a terminal. First, open one terminal and run the +xmlrpc_server.py script: + + $ python xmlrcp_server.py + +Then, open another terminal and start up python: + +.. code-block:: python + :class: small + + >>> import xmlrpclib + >>> proxy = xmlrpclib.ServerProxy('http://localhost:50000/', verbose=True) + >>> proxy.multiply(3, 24) + ... + 72 + + +XML-RPC Request +--------------- + +``verbose=True`` allows us to see the request we sent: + +.. class:: tiny + +:: + + POST /RPC2 HTTP/1.0 + Host: localhost:50000 + User-Agent: xmlrpclib.py/1.0.1 (by www.pythonware.com) + Content-Type: text/xml + Content-Length: 192 + + + + multiply + + + 3 + + + 24 + + + + + +XML-RPC Response +---------------- + +and we can see the response, too: + +.. class:: tiny + +:: + + HTTP/1.0 200 OK + Server: BaseHTTP/0.3 Python/2.6.1 + Date: Sun, 13 Jan 2013 03:38:00 GMT + Content-type: text/xml + Content-length: 121 + + + + + + 72 + + + + + +More XML-RPC +------------ + +Register an entire Python class as a service, exposing class methods:: + + server.register_instance(MyClass()) + +Keep an instance method private : + +.. code-block:: python + :class: tiny + + class MyServiceClass(object): + ... + def public_method(self, arg1, arg2): + """this method is public""" + pass + + def _private_method(self): + """this method is private because it starts with '_' + """ + pass + + +XML-RPC Introspection +--------------------- + +First, implement required methods on your service class: + +.. code-block:: python + :class: tiny + + from SimpleXMLRPCServer import list_public_methods + + class MyServiceClass(object): + ... + def _listMethods(self): + """custom logic for presenting method names to users + + list_public_methods is a convenience function from the Python + library, but you can make your own logic if you wish. + """ + return list_public_methods(self) + + def _methodHelp(self, method): + """provide help text for an individual method + """ + f = getattr(self, method) + return f.__doc__ + + +XML-RPC Introspection +--------------------- + +Then enable introspection via the server instance: + +.. code-block:: python + :class: small + + server.register_introspection_functions() + +After this, a client proxy can call pre-defined methods to learn about what +your service offers: + +.. code-block:: python + :class: small + + >>> for name in proxy.system.listMethods(): + ... help = proxy.system.methodHelp(name) + ... print name + ... print "\t%s" % help + ... + public_method + this method is public + + +Introspection Question +---------------------- + +I told you when we added the ``_private_method`` that any method that any +method whose name starts with ``_`` would be **private**. + +.. class:: incremental + +But we also added a ``_listMethods`` method and a ``_methodHelp`` method and +*those* methods are listed when you run ``proxy.system.listMethods()`` + +.. class:: incremental + +Why is this? + +.. class:: incremental + +For a complete discussion of this, read `this MOTW post +`_ + + +SOAP +---- + +Example of Using SOAP via the ``suds`` package + + +Install Suds +------------ + +* Quit your python interpreter if you have it running. +* If you see (soupenv) at your command line prompt, cool. +* If you do not, type ``source /path/to/soupenv/bin/activate`` +* Windows folks: ``> \path\to\soupenv\Scripts\activate`` +* Once activated: ``pip install suds`` + + +Creating a Suds Client +---------------------- + +Suds allows us to create a SOAP client object. SOAP uses WSDL to define a +service. All we need to do to set this up in python is load the URL of the +WSDL for the service we want to use: + +.. code-block:: python + :class: small + + (soupenv)$ python + >>> from suds.client import Client + >>> geo_client = Client('https://geoservices.tamu.edu/Services/Geocode/WebService/GeocoderService_V03_01.asmx?wsdl') + >>> geo_client + + + +Peeking at the Service +---------------------- + +Suds allows us to visually scan the service. Simply print the client object to +see what the service has to offer: + +.. code-block:: python + :class: small + + >>> print geo_client + + Suds ( https://fedorahosted.org/suds/ ) version: 0.4 GA build: R699-20100913 + + Service ( GeocoderService_V03_01 ) tns="https://geoservices.tamu.edu/" + Prefixes (1) + ns0 = "https://geoservices.tamu.edu/" + Ports (2): + (GeocoderService_V03_01Soap) + Methods (4): + ... + Types (12): + ... + + +Debugging Suds +-------------- + +Suds uses python logging to deal with debug information, so if you want to see +what's going on under the hood, you configure it via the Python logging +module: + +.. code-block:: python + + >>> import logging + >>> logging.basicConfig(level=logging.INFO) + >>> logging.getLogger('suds.client').setLevel(logging.DEBUG) + +.. class:: incremental + +This will allow us to see the messages sent and received by our client. + + +Client Options +-------------- + +SOAP Servers can provide more than one *service* and each *service* might have +more than one *port*. Suds provides two ways to configure which *service* and +*port* you wish to use. + +Via subscription: + +.. code-block:: python + + client.service[''][''].method(args) + +Or the way we will do it, via configuration: + +.. code-block:: python + + geo_client.set_options(service='GeocoderService_V03_01', + port='GeocoderService_V03_01Soap') + + +Providing Arguments +------------------- + +Arguments to a method are set up as a dictionary. Although some may not be +required according to api documentation, it is safest to provide them all: + +.. code-block:: python + :class: small + + apiKey = '' + args = {'apiKey': apiKey, } + args['streetAddress'] = '1325 4th Avenue' + args['city'] = 'Seattle' + args['state'] = 'WA' + args['zip'] = '98101' + args['version'] = 3.01 + args['shouldReturnReferenceGeometry'] = True + args['shouldNotStoreTransactionDetails'] = True + args['shouldCalculateCensus'] = False + args['censusYear'] = "TwoThousandTen" + + +Making the Call +--------------- + +Finally, once we've got the arguments all ready we can go ahead and make a call +to the server: + +.. code-block:: python + :class: small + + >>> res = geo_client.service.GeocodeAddressNonParsed(**args) + DEBUG:suds.client:sending to + (https://geoservices.tamu.edu/Services/Geocode/WebService/GeocoderService_V03_01.asmx) + message: + ... + + +What does it look like? +----------------------- + +.. class:: tiny + +:: + + + + + + + 1325 4th Avenue + Seattle + WA + 98101 + a450a9181f85498598e21f8a39440e9a + 3.01 + false + TwoThousandTen + true + true + + + + + +And the Reply? +-------------- + +.. class:: tiny + +:: + + + + + + + 6ef9c110-994c-4142-93d5-a55173526b64 + 47.6084110119244 + -122.3351592971042 + 3.01 + QUALITY_ADDRESS_RANGE_INTERPOLATION + LOCATION_TYPE_STREET_ADDRESS + Exact + 1 + ... + 2910.69420560356 + Meters + 4269 + <?xml version="1.0" encoding="utf-8"?><LineString xmlns="http://www.opengis.net/gml"><posList>-122.334868 47.608226 -122.335777 47.609219</posList></LineString> + ... + + + + + + +And What of Our Result? +----------------------- + +The WSDL we started with should provide type definitions for both data we send +and results we receive. The ``res`` symbol we bound to our result earlier +should now be an instance of a *GeocodeAddressNonParsedResult*. Lets see what +that looks like: + +.. code-block:: python + + >>> type(res) + + >>> dir(res) + ['CensusTimeTaken', 'CensusYear', 'ErrorMessage', 'FArea', + 'FAreaType', 'FCity', 'FCounty', 'FCountySubRegion', + ...] + >>> res.Latitude, res.Longitude + (47.608411011924403, -122.3351592971042) + + +A Word on Debugging +------------------- + +.. class:: center + +**blerg** + +.. class:: incremental + +* Messages sent to the server are long XML strings +* Error messages are generally based on parsing errors in XML +* These error messages can be quite cryptic: +* "There is an error in XML document (1, 572). ---> The string '' is not a + valid Boolean value.' + +.. class:: incremental + +Try this: + +.. code-block:: python + :class: small incremental + + >>> geo_client.last_sent().str().replace(" ","")[:573] + '...\n' + diff --git a/source/presentations/week03.rst b/source/presentations/week03.rst index dda1908b..e69de29b 100644 --- a/source/presentations/week03.rst +++ b/source/presentations/week03.rst @@ -1,1075 +0,0 @@ -Internet Programming with Python -================================ - -blah blah blah - - - - - - -Searching by CSS Class ----------------------- - -The items we are looking for are ``div`` tags which have the CSS class -``feedEntry``: - -.. code-block:: python - - >>> entries = parsed.find_all('div', class_='feedEntry') - >>> len(entries) - 106 - -.. class:: incremental - -| If you pass a simple string as the sole value to the ``attrs`` argument, that - string is treated as a CSS class: -| -| ``parsed.find_all('div', 'feedEntry')`` - -Find a Single Match -------------------- - -What bits of an entry have the details we need to meet our goals? - -.. class:: incremental - -* A ``tag`` also has a ``find`` method which returns only the **first** match -* ``tag.find(name, attrs, recursive, text, **kwargs)`` -* In each entry, the first ```` has title and URL -* In each entry, the first ``

    `` with the class ``discreet`` has the source - of the feed (Planet Django or Planet PostgreSQL) - -Testing it out --------------- - -.. code-block:: python - - for e in entries: - anchor = e.find('a') - paragraph = e.find('p', 'discreet') - title = anchor.text.strip() - url = anchor.attrs['href'] - print title - print url - try: - print paragraph.text.strip() - except AttributeError: - print 'Uncategorized' - print - -.. class:: incremental - -Watch for unicode encoding errors, I don't get any, but you might. - -Lab 1 - 20 mins ---------------- - -* Write a function, take a BeautifulSoup object as the sole argument -* find all the 'feedEntry' divs in the page -* Get the title and url of the entry and put them in a dictionary -* Categorize an entry as ``pgsql``, ``django`` or ``other`` -* It should return three lists of categorized entries - -| Call it like so: -| -| ``pgsql, django, other = my_function(parsed_page)`` - -.. class:: incremental center - -**GO** - -Short Break ------------ - -While you are taking a short break, you might take a moment to sign up for -the geocoding service we'll use later: - -http://geoservices.tamu.edu/UserServices/Signup.aspx - -You can also view your profile once you've signed up: - -http://geoservices.tamu.edu/UserServices/Profile/ViewProfile.aspx - -Another Approach ----------------- - -Scraping web pages is inherently brittle - -.. class:: incremental - -The owner of the website updates their layout, your code breaks - -.. class:: incremental - -But there is another way to get information from the web in a more normalized -fashion - -.. class:: incremental center - -**Web Services** - -Web Services ------------- - -"a software system designed to support interoperable machine-to-machine -interaction over a network" - W3C - -.. class:: incremental - -* provides a defined set of calls -* returns structured data - -Classifying Web Services ------------------------- - -Web services can be classified in a couple of ways: - -.. class:: incremental - -* By how they are implemented (XML-RPC, SOAP, REST) - -* By what they return (XML, JSON) - -Early Web Services ------------------- - -RSS is one of the earliest forms of Web Services - -* First known as ``RDF Site Summary`` -* Became ``Really Simple Syndication`` -* More at http://www.rss-specification.com/rss-specifications.htm - -.. class:: incremental - -A single web-based *endpoint* provides a dynamically updated listing of -content - -.. class:: incremental - -Implemented in pure HTTP. Returns XML - -.. class:: incremental - -**Atom** is a competing, but similar standard - -RSS Document ------------- - -.. class:: tiny - -:: - - - - - RSS Title - This is an example of an RSS feed - http://www.someexamplerssdomain.com/main.html - Mon, 06 Sep 2010 00:01:00 +0000 - Mon, 06 Sep 2009 16:45:00 +0000 - 1800 - - - Example entry - Here is some text containing an interesting description. - http://www.wikipedia.org/ - unique string per item - Mon, 06 Sep 2009 16:45:00 +0000 - - ... - - - -XML-RPC -------- - -If we can provide a single endpoint that returns a single data set (RSS), can -we also allow *calling procedures* at an endpoint? - -.. class:: incremental - -We can! Enter XML-RPC (Remote Procedure Call) - -.. class:: incremental - -* Provides a set of defined procedures which can take arguments -* Calls are made via HTTP GET, by passing an XML document -* Returns from a call are sent to the client in XML - -.. class:: incremental - -Easier to demonstrate than explain - -XML-RPC Example - Server ------------------------- - -xmlrpc_server.py: - -.. code-block:: python - :class: small - - from SimpleXMLRPCServer import SimpleXMLRPCServer - - server = SimpleXMLRPCServer(('localhost', 50000)) - - def multiply(a, b): - return a * b - server.register_function(multiply) - - try: - print "Use Ctrl-C to Exit" - server.serve_forever() - except KeyboardInterrupt: - print "Exiting" - -XML-RPC Example - Client ------------------------- - -We can run a client from a terminal. First, open one terminal and run the -xmlrpc_server.py script: - - $ python xmlrcp_server.py - -Then, open another terminal and start up python: - -.. code-block:: python - :class: small - - >>> import xmlrpclib - >>> proxy = xmlrpclib.ServerProxy('http://localhost:50000/', verbose=True) - >>> proxy.multiply(3, 24) - ... - 72 - -XML-RPC Request ---------------- - -``verbose=True`` allows us to see the request we sent: - -.. class:: tiny - -:: - - POST /RPC2 HTTP/1.0 - Host: localhost:50000 - User-Agent: xmlrpclib.py/1.0.1 (by www.pythonware.com) - Content-Type: text/xml - Content-Length: 192 - - - - multiply - - - 3 - - - 24 - - - - -XML-RPC Response ----------------- - -and we can see the response, too: - -.. class:: tiny - -:: - - HTTP/1.0 200 OK - Server: BaseHTTP/0.3 Python/2.6.1 - Date: Sun, 13 Jan 2013 03:38:00 GMT - Content-type: text/xml - Content-length: 121 - - - - - - 72 - - - - - -More XML-RPC ------------- - -Register an entire Python class as a service, exposing class methods:: - - server.register_instance(MyClass()) - -Keep an instance method private : - -.. code-block:: python - :class: tiny - - class MyServiceClass(object): - ... - def public_method(self, arg1, arg2): - """this method is public""" - pass - - def _private_method(self): - """this method is private because it starts with '_' - """ - pass - -XML-RPC Introspection ---------------------- - -First, implement required methods on your service class: - -.. code-block:: python - :class: tiny - - from SimpleXMLRPCServer import list_public_methods - - class MyServiceClass(object): - ... - def _listMethods(self): - """custom logic for presenting method names to users - - list_public_methods is a convenience function from the Python - library, but you can make your own logic if you wish. - """ - return list_public_methods(self) - - def _methodHelp(self, method): - """provide help text for an individual method - """ - f = getattr(self, method) - return f.__doc__ - -XML-RPC Introspection ---------------------- - -Then enable introspection via the server instance: - -.. code-block:: python - :class: small - - server.register_introspection_functions() - -After this, a client proxy can call pre-defined methods to learn about what -your service offers: - -.. code-block:: python - :class: small - - >>> for name in proxy.system.listMethods(): - ... help = proxy.system.methodHelp(name) - ... print name - ... print "\t%s" % help - ... - public_method - this method is public - -Introspection Question ----------------------- - -I told you when we added the ``_private_method`` that any method that any -method whose name starts with ``_`` would be **private**. - -.. class:: incremental - -But we also added a ``_listMethods`` method and a ``_methodHelp`` method and -*those* methods are listed when you run ``proxy.system.listMethods()`` - -.. class:: incremental - -Why is this? - -.. class:: incremental - -For a complete discussion of this, read `this MOTW post`_ - -.. _this MOTW post: http://www.doughellmann.com/PyMOTW/SimpleXMLRPCServer/index.html#introspection-api - -Beyond XML-RPC --------------- - -.. class:: incremental - -* XML-RPC allows introspection -* XML-RPC forces you to introspect to get information -* *Wouldn't it be nice to get that automatically?* -* XML-RPC provides data types -* XML-RPC provides only *certain* data types -* *Wouldn't it be nice to have an extensible system for types?* -* XML-RPC allows calling methods with parameters -* XML-RPC only allows calling methods, nothing else -* *wouldn't it be nice to have contextual data as well?* - -.. class:: incremental center - -**Enter SOAP: Simple Object Access Protocol** - -SOAP ----- - -SOAP extends XML-RPC in a couple of useful ways: - -.. class:: incremental - -* It uses Web Services Description Language (WSDL) to provide meta-data about - an entire service in a machine-readable format (Automatic introspection) - -* It establishes a method for extending available data types using XML - namespaces - -* It provides a wrapper around method calls called the **envelope**, which - allows the inclusion of a **header** with system meta-data that can be used - by the application - -SOAP in Python --------------- - -There is no standard library module that supports SOAP directly. - -.. class:: incremental - -* The best-known and best-supported module available is **Suds** -* The homepage is https://fedorahosted.org/suds/ -* It can be installed using ``easy_install`` or ``pip install`` - -Install Suds ------------- - -* Quit your python interpreter if you have it running. -* If you see (soupenv) at your command line prompt, cool. -* If you do not, type ``source /path/to/soupenv/bin/activate`` -* Windows folks: ``> \path\to\soupenv\Scripts\activate`` -* Once activated: ``pip install suds`` - -Creating a Suds Client ----------------------- - -Suds allows us to create a SOAP client object. SOAP uses WSDL to define a -service. All we need to do to set this up in python is load the URL of the -WSDL for the service we want to use: - -.. code-block:: python - :class: small - - (soupenv)$ python - >>> from suds.client import Client - >>> geo_client = Client('https://geoservices.tamu.edu/Services/Geocode/WebService/GeocoderService_V03_01.asmx?wsdl') - >>> geo_client - - -Peeking at the Service ----------------------- - -Suds allows us to visually scan the service. Simply print the client object to -see what the service has to offer: - -.. code-block:: python - :class: small - - >>> print geo_client - - Suds ( https://fedorahosted.org/suds/ ) version: 0.4 GA build: R699-20100913 - - Service ( GeocoderService_V03_01 ) tns="https://geoservices.tamu.edu/" - Prefixes (1) - ns0 = "https://geoservices.tamu.edu/" - Ports (2): - (GeocoderService_V03_01Soap) - Methods (4): - ... - Types (12): - ... - -Debugging Suds --------------- - -Suds uses python logging to deal with debug information, so if you want to see -what's going on under the hood, you configure it via the Python logging -module: - -.. code-block:: python - - >>> import logging - >>> logging.basicConfig(level=logging.INFO) - >>> logging.getLogger('suds.client').setLevel(logging.DEBUG) - -.. class:: incremental - -This will allow us to see the messages sent and received by our client. - -Client Options --------------- - -SOAP Servers can provide more than one *service* and each *service* might have -more than one *port*. Suds provides two ways to configure which *service* and -*port* you wish to use. - -Via subscription: - -.. code-block:: python - - client.service[''][''].method(args) - -Or the way we will do it, via configuration: - -.. code-block:: python - - geo_client.set_options(service='GeocoderService_V03_01', - port='GeocoderService_V03_01Soap') - -Providing Arguments -------------------- - -Arguments to a method are set up as a dictionary. Although some may not be -required according to api documentation, it is safest to provide them all: - -.. code-block:: python - :class: small - - apiKey = '' - args = {'apiKey': apiKey, } - args['streetAddress'] = '1325 4th Avenue' - args['city'] = 'Seattle' - args['state'] = 'WA' - args['zip'] = '98101' - args['version'] = 3.01 - args['shouldReturnReferenceGeometry'] = True - args['shouldNotStoreTransactionDetails'] = True - args['shouldCalculateCensus'] = False - args['censusYear'] = "TwoThousandTen" - -Making the Call ---------------- - -Finally, once we've got the arguments all ready we can go ahead and make a call -to the server: - -.. code-block:: python - :class: small - - >>> res = geo_client.service.GeocodeAddressNonParsed(**args) - DEBUG:suds.client:sending to - (https://geoservices.tamu.edu/Services/Geocode/WebService/GeocoderService_V03_01.asmx) - message: - ... - -What does it look like? ------------------------ - -.. class:: tiny - -:: - - - - - - - 1325 4th Avenue - Seattle - WA - 98101 - a450a9181f85498598e21f8a39440e9a - 3.01 - false - TwoThousandTen - true - true - - - - -And the Reply? --------------- - -.. class:: tiny - -:: - - - - - - - 6ef9c110-994c-4142-93d5-a55173526b64 - 47.6084110119244 - -122.3351592971042 - 3.01 - QUALITY_ADDRESS_RANGE_INTERPOLATION - LOCATION_TYPE_STREET_ADDRESS - Exact - 1 - ... - 2910.69420560356 - Meters - 4269 - <?xml version="1.0" encoding="utf-8"?><LineString xmlns="http://www.opengis.net/gml"><posList>-122.334868 47.608226 -122.335777 47.609219</posList></LineString> - ... - - - - - -And What of Our Result? ------------------------ - -The WSDL we started with should provide type definitions for both data we send -and results we receive. The ``res`` symbol we bound to our result earlier -should now be an instance of a *GeocodeAddressNonParsedResult*. Lets see what -that looks like: - -.. code-block:: python - - >>> type(res) - - >>> dir(res) - ['CensusTimeTaken', 'CensusYear', 'ErrorMessage', 'FArea', - 'FAreaType', 'FCity', 'FCounty', 'FCountySubRegion', - ...] - >>> res.Latitude, res.Longitude - (47.608411011924403, -122.3351592971042) - -A Word on Debugging -------------------- - -.. class:: center - -**blerg** - -.. class:: incremental - -* Messages sent to the server are long XML strings -* Error messages are generally based on parsing errors in XML -* These error messages can be quite cryptic: -* "There is an error in XML document (1, 572). ---> The string '' is not a - valid Boolean value.' - -.. class:: incremental - -Try this: - -.. code-block:: python - :class: small incremental - - >>> geo_client.last_sent().str().replace(" ","")[:573] - '...\n' - - -Afterword ---------- - -SOAP (and XML-RPC) have some problems: - -.. class:: incremental - -* XML is pretty damned inefficient as a data transfer medium -* Why should I need to know method names? -* If I can discover method names at all, I have to read a WSDL to do it? - -.. class:: incremental - -Suds is the best we have, and it hasn't been updated since Sept. 2010. - -If Not XML, Then What? ----------------------- - -.. class:: big-centered incremental - -**JSON** - -JSON ----- - -JavaScript Object Notation: - -.. class:: incremental - -* a lightweight data-interchange format -* easy for humans to read and write -* easy for machines to parse and generate - -.. class:: incremental - -Based on Two Structures: - -.. class:: incremental - -* object: ``{ string: value, ...}`` -* array: ``[value, value, ]`` - -.. class:: center incremental - -pythonic, no? - -JSON Data Types ---------------- - -JSON provides a few basic data types (see http://json.org/): - -.. class:: incremental - -* string: unicode, anything but ", \\ and control characters -* number: any number, but json does not use octal or hexidecimal -* object, array (we've seen these above) -* true -* false -* null - -.. class:: incremental center - -**No date type? OMGWTF??!!1!1** - -Dates in JSON -------------- - -.. class:: incremental - -Option 1 - Unix Epoch Time (number): - -.. code-block:: python - :class: small incremental - - >>> import time - >>> time.time() - 1358212616.7691269 - -.. class:: incremental - -Option 2 - ISO 8661 (string): - -.. code-block:: python - :class: small incremental - - >>> import datetime - >>> datetime.datetime.now().isoformat() - '2013-01-14T17:18:10.727240' - -JSON in Python --------------- - -You can encode python to json, and decode json back to python: - -.. code-block:: python - :class: small - - >>> import json - >>> array = [1,2,3] - >>> json.dumps(array) - >>> orig = {'foo': [1,2,3], 'bar': u'my resumé', 'baz': True} - >>> encoded = json.dumps(orig) - >>> encoded - '{"baz": true, "foo": [1, 2, 3], "bar": "my resum\\u00e9"}' - >>> decoded = json.loads(encoded) - >>> decoded == orig - True - -.. class:: incremental - -Customizing the encoder or decoder class allows for specialized serializations - -JSON in Python --------------- - -the json module also supports reading and writing to *file-like objects* via -``json.dump(fp)`` and ``json.load(fp)`` (note the missing 's') - -.. class:: incremental - -Remember duck-typing. Anything with a ``.write`` and a ``.read`` method is -*file-like* - -.. class:: incremental - -Have we seen any network-related classes recently that behave that way? - -What about WSDL? ----------------- - -SOAP was invented in part to provide completely machine-readable -interoperability. - -.. class:: incremental - -Does that really work in real life? - -.. class:: incremental center - -Hardly ever - -What about WSDL? ----------------- - -Another reason was to provide extensibility via custom types - -.. class:: incremental - -Does that really work in real life? - -.. class:: incremental center - -Hardly ever - -Why Do All The Work? --------------------- - -So, if neither of these goals is really achieved by using SOAP, why pay all -the overhead required to use the protocol? - -.. class:: incremental - -Enter REST - -REST ----- - -.. class:: center - -Representational State Transfer - -.. class:: incremental - -* Originally described by Roy T. Fielding (did you read it?) -* Use HTTP for what it can do -* Read more in `this book - `_\* - -.. class:: image-credit incremental - -\* Seriously. Buy it and read -( HTTP/1.1 -* GET /comment HTTP/1.1 -* POST /comment HTTP/1.1 -* PUT /comment/ HTTP/1.1 -* DELETE /comment/ HTTP/1.1 - -ROA ---- - -This is **Resource Oriented Architecture** - -.. class:: incremental - -The URL represents the *resource* we are working with - -.. class:: incremental - -The HTTP Verb represents the ``action`` to be taken - -.. class:: incremental - -The HTTP Code returned tells us the ``result`` (whether success or failure) - -HTTP Codes Revisited --------------------- - -.. class:: small - -POST /comment HTTP/1.1 (creating a new comment): - -.. class:: incremental small - -* Success: ``HTTP/1.1 201 Created`` -* Failure (unauthorized): ``HTTP/1.1 401 Unauthorized`` -* Failure (NotImplemented): ``HTTP/1.1 405 Not Allowed`` -* Failure (ValueError): ``HTTP/1.1 406 Not Acceptable`` - -.. class:: small incremental - -PUT /comment/ HTTP/1.1 (edit comment): - -.. class:: incremental small - -* Success: ``HTTP/1.1 200 OK`` -* Failure: ``HTTP/1.1 409 Conflict`` - -.. class:: small incremental - -DELETE /comment/ HTTP/1.1 (delete comment): - -.. class:: incremental small - -* Success: ``HTTP/1.1 204 No Content`` - -HTTP Is Stateless ------------------ - -No individual request may be assumed to know anything about any other request. - -.. class:: incremental - -All the required information for to represent the possible actions to take -*should be present in either the request or the response*. - -.. class:: incremental big-centered - -Thus: HATEOAS - -HATEOAS -------- - -.. class:: big-centered - -Hypermedia As The Engine Of Application State - -Applications are State Engines ------------------------------- - -A State Engine is a machine that provides *states* for a resource to be in and -*transitions* to move resources between states. A Restful api should: - -.. class:: incremental - -* provide information about the current state of a resource -* provide information about available transitions for that resource (URIs) -* provide all this in each HTTP response - -Playing With REST ------------------ - -Let's take a moment to play with REST. - -.. class:: incremental - -We tried geocoding with SOAP. Let's repeat the exercise with a REST/JSON API - -.. class:: incremental center - -**Back to your interpreter** - -Geocoding with Google APIs --------------------------- - -https://developers.google.com/maps/documentation/geocoding - -.. code-block:: python - :class: small incremental - - >>> import urllib - >>> import urllib2 - >>> from pprint import pprint - >>> base = 'http://maps.googleapis.com/maps/api/geocode/json' - >>> addr = '1325 4th Ave, Seattle, WA 98101' - >>> data = {'address': addr, 'sensor': False } - >>> query = urllib.urlencode(data) - >>> res = urllib2.urlopen('?'.join([base, query])) - >>> response = json.load(res) - >>> pprint(response) - -RESTful Job Listings --------------------- - -https://github.com/mattnull/techsavvyapi - -.. code-block:: python - :class: small incremental - - >>> base = 'http://api.techsavvy.io/jobs' - >>> search = 'python+web' - >>> res = urllib2.urlopen('/'.join([base, search])) - >>> response = json.load(res) - >>> type(response) - - >>> response.keys() - [u'count', u'data'] - >>> response['count'] - 50 - >>> for post in response['data']: - ... for key in sorted(post.keys()): - ... print "%s:\n %s" % (key, post[key]) - ... print - ... - -Lab 2 - Mashup --------------- - -Some of the job postings from our TechSavvy api returned lat/lon pairs. - -Google provides a reverse address lookup service via the geocoding api -(https://developers.google.com/maps/documentation/geocoding/#ReverseGeocoding) - -Create a list of job postings, with an address for those postings that provide -the needed data - -.. class:: incremental center - -**GO** - -Assignment ----------- - -Using what you've learned this week, create a more complex mashup of some data -that interests you. Map the locations of the breweries near your house. Chart -a multi-axial graph of the popularity of various cities across several -categories. Visualize the most effective legislators in Congress. You have -interests, the Web has tools. Put them together to make something. - -Submitting the Assignment -------------------------- - -Place the following in the ``assignments/week03/athome`` directory and make a -pull request: - -.. class:: small - -A textual description of your mashup (README.txt). - What data sources did you scan, what tools did you use, what is the - outcome you wanted to create? - -.. class:: small - -Your source code (mashup.py). - Give me an executable python script that I can run to get output. - -.. class:: small - -Any instructions I need. - If I need instructions beyond 'python mashup.py' to get the right - output, let me know. - - - - - - - - - -What You Made -------------- - -.. class:: incremental - -* geographic locations of our Bluebox VMs -* Visualization of the popularity of Facebook Friends' first names -* Restaurants near your location with recent Health Inspection data -* A Last-FM user's top artists, with lists of mixcloud mixes featuring each of - them -* A list of Craigslist apartments with the nearest bars, pizza and sushi - places and their Yelp ratings -* Geographic locations of the top 20 users returned for a twitter search, - along with other twitter data \ No newline at end of file From 6b8aa612f8c3b352037b2c18e5e063042b95c551 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 23 Jul 2013 00:35:27 -0700 Subject: [PATCH 126/487] delete converted files --- source/presentations/week03.rst | 0 source/presentations/week05.rst | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 source/presentations/week03.rst delete mode 100644 source/presentations/week05.rst diff --git a/source/presentations/week03.rst b/source/presentations/week03.rst deleted file mode 100644 index e69de29b..00000000 diff --git a/source/presentations/week05.rst b/source/presentations/week05.rst deleted file mode 100644 index e69de29b..00000000 From 7756992095da3902907c052966c03e8c7c658f7c Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 23 Jul 2013 22:53:31 -0700 Subject: [PATCH 127/487] fix up session 7 references in outline --- source/main/outline.rst | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/source/main/outline.rst b/source/main/outline.rst index 29b6fa9b..072d1a81 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -152,16 +152,19 @@ Day 4 AM - Intro to Django -------------------------- In this class we'll get introduced to arguably the most popular full-stack -Python web framework, Django. We'll build a simple application that introduces -us to the basics of Models, Views and Templates. We'll also learn about the -Django admin and how it can help us rapidly develop effective applications. +Python web framework, Django. We'll install the framework, learn about how to +get it running and how to get started creating your very own app. -We'll cover basic relational modeling and talk about how to create effective -database schemas to model real-world problems. We'll take a look at how the -Django ORM (and ORMs in general) can help shield Python developers from SQL. +We'll be learning about the Django ORM and how Django Models can help shield +developers from much of the complexity of SQL. We'll learn how to use the tools +Django provides to explore and interact with your models while designing them. -For our homework, we'll take a look at a set of specifications for a project -and create a set of Django Models that will fulfill the specification. +Along the way, we'll continue our test-driven development style: writing tests +to demonstrate the functionality we desire and then implementing code to make +them pass. We'll get a chance to see how to build tests within the framework +offered by Django's testrunner. + +`Lecture Slides `_ From 6ea754a5abc1154a08426060b9054069efc82ac8 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 23 Jul 2013 22:53:55 -0700 Subject: [PATCH 128/487] point presentation index at session07 now that it exists. --- source/presentations/index.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/presentations/index.rst b/source/presentations/index.rst index b32be0b6..662633b8 100644 --- a/source/presentations/index.rst +++ b/source/presentations/index.rst @@ -8,13 +8,12 @@ Course Presentations * `Day 2 PM - CGI and WSGI `_ * `Day 3 AM - Frameworks and Flask `_ * `Day 3 PM - A Flask Application `_ -* `Week 7 - Django`_ +* `Day 4 AM - Introducing Django `_ * `Week 8 - Pyramid`_ * `Week 9 - The Cloud`_ * `Week 10 - Plone`_ -.. _Week 7 - Django: week07.html .. _Week 8 - Pyramid: week08.html .. _Week 9 - The Cloud: week09.html .. _Week 10 - Plone: week10.html From 3558a95c33b22cb7ec8f6f493456293d75cb3d89 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 23 Jul 2013 22:54:36 -0700 Subject: [PATCH 129/487] fix syntax error in session 03 --- source/presentations/session03.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/presentations/session03.rst b/source/presentations/session03.rst index f4f25606..4ca5bc9e 100644 --- a/source/presentations/session03.rst +++ b/source/presentations/session03.rst @@ -1592,7 +1592,7 @@ Making an API Call (soupenv)$ python .. code-block:: python - :small: + :class: small >>> import requests >>> import json From b9969c0a07954d922a965e768a266c3a9bfcfbdb Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 23 Jul 2013 22:55:10 -0700 Subject: [PATCH 130/487] begin converting week06 into session07 --- source/presentations/session07.rst | 490 +++++++++++++++++++++++++++++ source/presentations/week06.rst | 359 +-------------------- 2 files changed, 491 insertions(+), 358 deletions(-) create mode 100644 source/presentations/session07.rst diff --git a/source/presentations/session07.rst b/source/presentations/session07.rst new file mode 100644 index 00000000..14d671e1 --- /dev/null +++ b/source/presentations/session07.rst @@ -0,0 +1,490 @@ +Python Web Programming +====================== + +.. image:: img/django-pony.png + :align: left + :width: 50% + +Day 4 AM: Introducing Django + +.. class:: intro-blurb right + +Wherein we become 'perfectionists with deadlines' + +.. class:: image-credit + +image: http://djangopony.com/ + + +Full Stack Framework +-------------------- + +Django comes with: + +.. class:: incremental + +* Persistence via the *Django ORM* +* CRUD content editing via the automatic *Django Admin* +* URL Mapping via *urlpatterns* +* Templating via the *Django Template Language* +* Caching with levels of configurability +* Internationalization via i18n hooks +* Form rendering and handling +* User authentication and authorization + +.. class:: incremental + +Pretty much everything you need to make a solid website quickly + + +What Sets it Apart? +------------------- + +Lots of frameworks offer some of these features, if not all. + +.. class:: incremental + +What is Django's *killer feature* + +.. class:: incremental center + +**The Django Admin** + + +The Django Admin +---------------- + +Works in concert with the Django ORM to provide automatic CRUD functionality + +.. class:: incremental + +You write the models, it provides the UI + +.. class:: incremental center + +**Really** + + +The Pareto Principle +-------------------- + +The Django Admin is a great example of the Pareto Priciple, a.k.a. the 80/20 +rule: + +.. class:: incremental center + +**80% of the problems can be solved by 20% of the effort** + +.. class:: incremental + +The converse also holds true: + +.. class:: incremental center + +**Fixing the last 20% of the problems will take the remaining 80% of the +effort.** + + +Other Django Advantages +----------------------- + +Clearly the most popular full-stack Python web framework at this time + +.. class:: incremental + +Popularity translates into: + +.. class:: incremental + +* Active, present community +* Plethora of good examples to be found online +* Rich ecosystem of *apps* (encapsulated add-on functionality) + +.. class:: incremental center + +**Jobs** + + +Active Development +------------------ + +Django releases in the last 12+ months: + +.. class:: incremental + +* 1.5.1 (March 2013) +* 1.5 (February 2013) +* 1.4.5 (February 2013) +* 1.3.7 (February 2013) +* 1.4.3 (December 2012) +* 1.3.5 (December 2012) +* 1.4.2 (November 2012) +* 1.3.3 (August 2012) +* 1.4.1 (July 2012) +* 1.3.2 (July 2012) +* 1.4 (March 2012) + + +Great Documentation +------------------- + +Thorough, readable, and discoverable. + +.. class:: incremental + +Led the way to better documentation for all Python + +.. class:: incremental + +`Read The Docs `_ - built in connection with +Django, sponsored by the Django Software Foundation. + +.. class:: incremental + +Write documentation as part of your python package, and render new versions of +that documentation for every commit + +.. class:: incremental center + +**this is awesome** + + +Django Organization +------------------- + +A Django *project* represents a whole website: + +.. class:: incremental + +* global configuration settings +* inclusion points for additional functionality +* master list of URL endpoints + +.. class:: incremental + +A Django *app* encapsulates a unit of functionality: + +.. class:: incremental + +* A blog section +* A discussion forum +* A content tagging system + + +Apps Make Up a Project +---------------------- + +.. class:: big-centered + +One *project* can (and likely will) consist of many *apps* + + +Practice Safe Development +------------------------- + +We'll install Django and any other packages we use with it in a virtualenv. + +.. class:: incremental + +This will ensure that it is isolated from everything else we do in class (and +vice versa) + +.. container:: incremental + + Remember the basic format for creating a virtualenv: + + .. class:: small + + :: + + $ python virtualenv.py [options] + + $ virtualenv [options] + + +Set Up a VirtualEnv +------------------- + +Start by creating your virtualenv:: + + $ python virtualenv.py djangoenv + + $ virtualenv djangoenv + ... + +.. container:: incremental + + Then, activate it:: + + $ source djangoenv/bin/activate + + C:\> djangoenv\Scripts\activate + + +Install Django +-------------- + +Finally, install Django 1.5.1 using `setuptools` or `pip`: + +.. class:: small + +:: + + (djangoenv)$ pip install Django==1.5.1 + Downloading/unpacking Django==1.5.1 + Downloading Django-1.5.1.tar.gz (8.0MB): 8.0MB downloaded + Running setup.py egg_info for package Django + changing mode of /path/to/djangoenv/bin/django-admin.py to 755 + Successfully installed Django + Cleaning up... + (djangoenv)$ + + +Starting a Project +------------------ + +Everything in Django stems from the *project* + +.. class:: incremental + +To get started learning, we'll create one + +.. class:: incremental + +We'll use a script installed by Django, ``django-admin.py``: + +.. code-block:: + :class: incremental + + (djangoenv)$ django-admin.py startproject mysite + +.. class:: incremental + +This will create a folder called 'mysite'. Let's take a look at it: + + +Project Layout +-------------- + +The folder created by ``django-admin.py`` contains the following structure: + +.. code-block:: + + mysite/ + manage.py + mysite/ + __init__.py + settings.py + urls.py + wsgi.py + +.. class:: incremental + +If what you see doesn't match that, you're using an older version of Django. +Make sure you've installed 1.5.1. + + +What Got Created +---------------- + +.. class:: incremental + +* **outer *mysite* folder**: this is just a container and can be renamed or + moved at will +* **inner *mysite* folder**: this is your project directory. It should not be + renamed. +* **__init__.py**: magic file that makes *mysite* a python package. +* **settings.py**: file which holds configuration for your project, more soon. +* **urls.py**: file which holds top-level URL configuration for your project, + more soon. +* **wsgi.py**: binds a wsgi application created from your project to the + symbol ``application`` +* **manage.py**: a management control script. + + +*django-admin.py* and *manage.py* +--------------------------------- + +*django-admin.py* provides a hook for administrative tasks and abilities: + +.. class:: incremental + +* creating a new project or app +* running the development server +* executing tests +* entering a python interpreter +* entering a database shell session with your database +* much much more (run ``django-admin.py`` without an argument) + +.. class:: incremental + +*manage.py* wraps this functionality, adding the full environment of your +project. + + +Development Server +------------------ + +At this point, you should be ready to use the development server:: + + (djangoenv)$ cd mysite + (djangoenv)$ python manage.py runserver + ... + +.. class:: incremental + +Load ``http://localhost:8000`` in your browser. + + +A Blank Slate +------------- + +You should see this: + +.. image:: img/django-start.png + :align: center + :width: 98% + +.. class:: incremental center + +**Do you?** + + +Connecting A Database +--------------------- + +Django comes with its own ORM (Object-Relational Mapper) + +.. class:: incremental + +The first step in working with Django is to connect it to your database (this +is set in ``settings.py``) + +.. code-block:: python + :class: small incremental + + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.', + 'NAME': '', + 'USER': '', + 'PASSWORD': '', + 'HOST': '', + 'PORT': '', + } + } + + +A Quick Word about Databases +---------------------------- + +Sqlite3 is **not** a production-capable database. Do not attempt to use it as +such. + +.. class:: incremental + +Do not start a real project using sqlite3, expecting to move 'when you go to +production'. + +.. class:: incremental + +That being said, proper database administration is out-of-scope for this +class. + +.. class:: incremental + +So we'll be using sqlite3 for todays work. + + +Your Database Settings +---------------------- + +Edit ``settings.py`` in your project package to match: + +.. code-block:: python + :class: small + + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': 'mysite.db', + # The following settings are not used with sqlite3: + 'USER': '', + 'PASSWORD': '', + 'HOST': '', + 'PORT': '', + } + } + + +Django and Your Database +------------------------ + +Django interfaces with the database using an ORM (Object Relational Mapping) + +.. class:: incremental + +You write Python *models* describing the object that make up your system. + +.. class:: incremental + +The ORM handles converting data from these objects into SQL statements (and +back) + +.. class:: incremental + +We'll learn much more about this in a bit + + +Core Django *Apps* +------------------ + +Django already includes some *apps* for you. + +.. container:: incremental + + They're ``settings.py`` in the ``INSTALLED_APPS`` setting: + + .. code-block:: python + :class: small + + INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + # Uncomment the next line to enable the admin: + # 'django.contrib.admin', + # Uncomment the next line to enable admin documentation: + # 'django.contrib.admindocs', + ) + + +Creating the Database +--------------------- + +These *apps* define models of their own, tables must be created. + +.. container:: incremental + + You make them by running the ``syncdb`` management command: + + .. class:: small + + :: + + (djangoenv)$ python manage.py syncdb + Creating tables ... + Creating table auth_permission + Creating table auth_group_permissions + Creating table auth_group + ... + You just installed Django's auth system, ... + Would you like to create one now? (yes/no): + +.. class:: incremental + +Add your first user at this prompt (remember the password) + diff --git a/source/presentations/week06.rst b/source/presentations/week06.rst index 3e491a8e..7bb90e94 100644 --- a/source/presentations/week06.rst +++ b/source/presentations/week06.rst @@ -1,365 +1,8 @@ Internet Programming with Python ================================ -.. image:: img/django-pony.png - :align: left - :width: 50% - -Week 6: Django - Part 1 - -.. class:: intro-blurb right - -Wherein we become 'perfectionists with deadlines' - -.. class:: image-credit - -image: http://djangopony.com/ - -But First ---------- - -.. class:: big-centered - -Review from the Assignment - -And Second ----------- - -.. class:: big-centered - -Questions from the Reading? - -And Now -------- - -.. image:: img/django_lead.png - :align: center - :width: 79% - -Full Stack Framework --------------------- - -Django comes with: - -.. class:: incremental - -* Persistence via the *Django ORM* -* CRUD content editing via the automatic *Django Admin* -* URL Mapping via *urlpatterns* -* Templating via the *Django Template Language* -* Caching with levels of configurability -* Internationalization via i18n hooks -* Form rendering and handling - -.. class:: incremental - -Pretty much everything you need to make a solid website quickly - -What Sets it Apart? -------------------- - -Lots of frameworks offer some of these features, if not all. - -.. class:: incremental - -What is Django's *killer feature* - -.. class:: incremental center - -**The Django Admin** - -The Django Admin ----------------- - -Works in concert with the Django ORM to provide automatic CRUD functionality - -.. class:: incremental - -You write the models, it provides the UI - -.. class:: incremental center - -**Really** - -The Pareto Principle --------------------- - -The Django Admin is a perfect embodiment of the Pareto Priciple, a.k.a. the -80/20 rule: - -.. class:: incremental center - -80% of the problems can be solved by 20% of the effort - -.. class:: incremental - -The converse also holds true: - -.. class:: incremental center - -Fixing the last 20% of the problems will take the remaining 80% of the effort. - -Other Django Advantages ------------------------ - -Clearly the most popular Python web framework at this time - -.. class:: incremental - -Popularity translates into: - -.. class:: incremental - -* Active, present community -* Plethora of good examples to be found online -* Rich ecosystem of *apps* (encapsulated add-on functionality) - -.. class:: incremental center - -**Jobs** - -Active Development ------------------- - -Popular frameworks tend to be actively developed. - -.. class:: incremental - -Django releases in the last 12 months: - -.. class:: incremental - -* 1.5 (any day now) -* 1.4.3 (December 2012) -* 1.3.5 (December 2012) -* 1.4.2 (November 2012) -* 1.3.3 (August 2012) -* 1.4.1 (July 2012) -* 1.3.2 (July 2012) -* 1.4 (March 2012) - -Great Documentation -------------------- - -Thorough, readable, and discoverable. - -.. class:: incremental - -Led the way to better documentation for all Python - -.. class:: incremental - -`Read The Docs `_ - built in connection with -Django, sponsored by the Django Software Foundation. - -.. class:: incremental - -Write documentation as part of your python package, and render new versions of -that documentation for every commit - -.. class:: incremental center - -**this is awesome** - -History -------- - -Django was created to power the website of the Lawrence Journal-World -newspaper, Lawrence, KS - -.. class:: incremental - -This birth in practicality is reflected in the design of the system. - -.. class:: incremental - -Pretty much every design decision was made to solve a real problem. - -.. class:: incremental - -You can read more in `this Quora post -`_ - -Django Organization -------------------- - -Django is organized into *projects* and *apps* - -.. class:: incremental - -A Django *project* represents the totality of a website, all the pages it -will contain and all the functionality it supports - -.. class:: incremental - -A Django *app* represents an individual unit of functionality: a blog, a -forum, a registration system, a content tagging system, etc. - -.. class:: incremental - -One *project* can (and likely will) consist of many *apps* - -Starting a Project ------------------- - -You should already have done this at home, but we'll look at it together -quickly, in case: - -.. class:: incremental - -* Set up a Django virtualenv -* Activate that env and ``pip install django`` -* Create a new Django project: - -.. code-block:: - :class: incremental - - (djangoenv)$ django-admin.py startproject mysite - -.. class:: incremental - -This will create a folder called 'mysite'. Let's take a look at it: - -Project Layout --------------- - -The folder created by *django-admin.py* contains the following structure: - -.. code-block:: - - mysite/ - manage.py - mysite/ - __init__.py - settings.py - urls.py - wsgi.py - -.. class:: incremental - -If what you see doesn't match that, you're using an older version of Django. -Make sure you've installed 1.4.3. - -What Got Created ----------------- - -.. class:: incremental - -* **outer *mysite* folder**: this is just a container and can be renamed or - moved at will -* **inner *mysite* folder**: this is your project directory. It should not be - renamed. -* **__init__.py**: magic file that makes *mysite* a python package. -* **settings.py**: file which holds configuration for your project, more soon. -* **urls.py**: file which holds top-level URL configuration for your project, - more soon. -* **wsgi.py**: the .wsgi file which allows your project to be run in a wsgi - server, like mod_wsgi. -* **manage.py**: a management control script. - -*django-admin.py* and *manage.py* ---------------------------------- - -*django-admin.py* provides a hook for administrative tasks and abilities: - -.. class:: incremental - -* creating a new project or app -* running the development server -* executing tests -* entering a python interpreter -* entering a database shell session with your database -* much much more (run ``django-admin.py`` without an argument) - -.. class:: incremental - -*manage.py* wraps this functionality, adding the full environment of your -project. - -Development Server ------------------- - -At this point, you should be ready to use the development server:: - - (djangoenv)$ cd mysite - (djangoenv)$ python manage.py runserver - ... - -.. class:: incremental - -Load ``http://localhost:8000`` in your browser. - -A Blank Slate -------------- - -You should see this: - -.. image:: img/django-start.png - :align: center - :width: 98% - -.. class:: incremental center - -**Do you?** - -Connecting A Database ---------------------- - -Django comes with its own ORM (Object-Relational Mapper) - -.. class:: incremental - -The first step in working with Django is to connect it to your database (this -is set in ``settings.py``) - -.. code-block:: python - :class: small incremental - - DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.', - 'NAME': '', - 'USER': '', - 'PASSWORD': '', - 'HOST': '', - 'PORT': '', - } - } - -A Quick Word about Databases ----------------------------- - -Sqlite3 is **not** a production-capable database. Do not attempt to use it as -such. Do not start a real project using sqlite3, expecting to move 'when -you go to production'. - -.. class:: incremental - -That being said, proper database administration is out-of-scope for this -class. If you haven't already got a PostgreSQL or MySQL database set up and -ready to use, just use sqlite3 so we can get through this. - -Building DB Tables ------------------- - -The Django ORM builds tables. Django models describe the objects you want, the -ORM does the rest. - -.. class:: incremental - -Django comes with some *apps* set up and ready to use. These define models, -and need tables to power them. You create the tables by running the management -command *syncdb*: - -.. class:: incremental - -:: - - (djangoenv)$ python manage.py syncdb - -.. class:: incremental +blah blah blah -Add your first admin user when prompted (remember the password) Lab --- From 6efd00c9faa1f74c646ecefa17e533a347343482 Mon Sep 17 00:00:00 2001 From: cewing Date: Wed, 24 Jul 2013 23:54:01 -0700 Subject: [PATCH 131/487] continue on session07 translation from old week06 slides. --- source/presentations/session07.rst | 293 ++++++++++++++++++++++++++++- source/presentations/week06.rst | 132 ------------- 2 files changed, 292 insertions(+), 133 deletions(-) diff --git a/source/presentations/session07.rst b/source/presentations/session07.rst index 14d671e1..6ed4fd74 100644 --- a/source/presentations/session07.rst +++ b/source/presentations/session07.rst @@ -443,7 +443,7 @@ Django already includes some *apps* for you. .. container:: incremental - They're ``settings.py`` in the ``INSTALLED_APPS`` setting: + They're in ``settings.py`` in the ``INSTALLED_APPS`` setting: .. code-block:: python :class: small @@ -488,3 +488,294 @@ These *apps* define models of their own, tables must be created. Add your first user at this prompt (remember the password) + +Our Class App +------------- + +We are going to build an *app* to add to our *project*. To start with our app +will: + +.. class:: incremental + +* allow a user to create and edit blog posts +* allow a user to define categories +* allow a user to place a post in one or more categories + +.. class:: incremental + +As stated above, an *app* represents a unit within a system, the *project*. We +have a project, we need to create an *app* + + +Create an App +------------- + +This is accomplished using ``manage.py``. + +.. class:: incremental + +In your terminal, make sure you are in the *outer* mysite directory, where the +file ``manage.py`` is located. Then: + +.. class:: incremental + +:: + + (djangoenv)$ python manage.py startapp myblog + + +What is Created +--------------- + +This should leave you with the following structure: + +.. class:: small + +:: + + mysite/ + manage.py + mysite/ + ... + myblog/ + __init__.py + models.py + tests.py + views.py + +.. class:: incremental + +We'll start by defining the main Python class in our blog system, a ``Post``. + + +Django Models +------------- + +Any Python class in Django that is meant to be persisted *must* inherit from +the Django ``Model`` class. + +.. class:: incremental + +This base class provides all the functionality that connects the Python code +you write to your database. + +.. class:: incremental + +You can override methods from the base ``Model`` class to alter how this works. + +.. class:: incremental + +You can also write new methods on your class that provide new functionality. + + +Our Post Model +-------------- + +Open the ``models.py`` file created in our ``myblog`` package. Add the +following: + +.. code-block:: python + :class: small + + from django.db import models + from django.contrib.auth.models import User + + class Post(models.Model): + title = models.CharField(max_length=128) + text = models.TextField(blank=True) + author = models.ForeignKey(User) + created_date = models.DateTimeField(auto_now_add=True) + modified_date = models.DateTimeField(auto_now=True) + published_date = models.DateTimeField(blank=True, null=True) + + +Model Fields +------------ + +We've created a subclass of the Django ``Model`` class and added a bunch of +attributes. + +.. class:: incremental + +* These attributes are all instances of ``Field`` classes defined in Django +* Field attributes on a model map to columns in a database table +* The arguments you provide to each Field customize how it works + + * This means *both* how it operates in Django *and* how it is defined in SQL + +* There are arguments shared by all Field types +* There are also arguments specific to individual types + +.. class:: incremental + +You can read much more about `Model Fields and options +`_ + + +Field Details +------------- + +There are some features of our fields worth mentioning in specific: + +.. class:: incremental + +Notice we have no field that is designated as the *primary key* + +.. class:: incremental + +* You *can* make a field the primary key by adding ``primary_key=True`` in the + arguments +* If you do not, Django will automatically create one. This field is always + called ``id`` +* No matter what the primary key field is called, its value is always + available on a model instance as ``pk`` + + +Field Details +------------- + +.. code-block:: python + :class: small + + title = models.CharField(max_length=128) + +.. class:: incremental + +The required ``max_length`` argument is specific to ``CharField`` fields. + +.. class:: incremental + +It affects *both* the Python and SQL behavior of a field. + +.. class:: incremental + +In python, it is used to *validate* supplied values during *model validation* + +.. class:: incremental + +In SQL it is used in the column definition: ``VARCHAR(128)`` + + +Field Details +------------- + +.. code-block:: python + :class: small + + text = models.TextField(blank=True) + # ... + published_date = models.DateTimeField(blank=True, null=True) + +.. class:: incremental + +The argument ``blank`` is shared across all field types. The default is +``False`` + +.. class:: incremental + +This argument affects only the Python behavior of a field, determining if the +field is *required* + +.. class:: incremental + +The related ``null`` argument affects the SQL definition of a field: is the +column NULL or NOT NULL + + +Field Details +------------- + +.. code-block:: python + :class: small + + created_date = models.DateTimeField(auto_now_add=True) + modified_date = models.DateTimeField(auto_now=True) + +.. class:: incremental + +``auto_now_add`` is available on all date and time fields. It sets the value +of the field to *now* when an instance is first saved. + +.. class:: incremental + +``auto_now`` is similar, but sets the value anew each time an instance is +saved. + +.. class:: incremental + +Setting either of these will cause the ``editable`` attribute of a field to be +set to ``False``. + + +Field Details +------------- + +.. code-block:: python + :class: small + + author = models.ForeignKey(User) + +.. class:: incremental + +Django also models SQL *relationships* as specific field types. + +.. class:: incremental + +The required positional argument is the class of the related Model. + +.. class:: incremental + +By default, the reverse relation is implemented as the attribute +``_set``. + +.. class:: incremental + +You can override this by providing the ``related_name`` argument. + + +Our Category Model +------------------ + +Our app specification says that a user should be able to place a post in one +or more categories. + +.. class:: incremental + +We'll create a second Model to represent this. It should: + +.. class:: incremental + +* Have a unique name +* Have a description +* Be in a many-to-many relationship with our ``Post`` model +* Instances of ``Category`` should have a ``posts`` attribute that provides + access to all posts in that category +* Instances of ``Post`` should have a ``categories`` attribute that provides + access to all the categories it has been placed in. + + +My Solution +----------- + +Add this new Model class to ``models.py``. + +.. class:: incremental small + +https://docs.djangoproject.com/en/1.5/ref/models/fields/ + +.. container:: incremental + + Here's my model code: + + .. code-block:: python + :class: small + + class Category(models.Model): + name = models.CharField(max_length=128) + description = models.TextField(blank=True) + posts = models.ManyToManyField(Post, + blank=True, + null=True, + related_name='categories' + ) + diff --git a/source/presentations/week06.rst b/source/presentations/week06.rst index 7bb90e94..1a10cd73 100644 --- a/source/presentations/week06.rst +++ b/source/presentations/week06.rst @@ -4,140 +4,8 @@ Internet Programming with Python blah blah blah -Lab ---- -The remainder of our class today will be lab time. We'll be directly playing -with Django from here on out. -Todays lab is drawn from the `Django Tutorial -`_, with some minor -adjustments. - -Lab - Part One --------------- - -We are going to create an *app* to add to our *project*. This app will: - -.. class:: incremental - -* Allow a user to create poll questions -* Allow a user to provide choices for these questions -* Allow visitors to a site to see these questions and vote for an answer -* Allow the total vote tallies for the answers to a poll question to be - displayed. - -.. class:: incremental - -As stated above, an *app* should represent a unit of functionality within a -larger system, the *project*. We have a project, we need to create an *app* - -Create an App -------------- - -This is accomplished using ``manage.py``. - -.. class:: incremental - -In your terminal, make sure you are in the *outer* mysite directory, where the -file ``manage.py`` is located. Then: - -.. class:: incremental - -:: - - (djangoenv)$ python manage.py startapp polls - -What is Created ---------------- - -This should leave you with the following structure: - -.. class:: small - -:: - - mysite/ - manage.py - mysite/ - ... - polls/ - __init__.py - models.py - tests.py - views.py - -.. class:: incremental - -We'll start by defining the objects we will work with: poll questions and -choices. - -Models ------- - -Open the file ``models.py`` in your editor, and add the following code: - -.. code-block:: python - - from django.db import models - - class Poll(models.Model): - question = models.CharField(max_length=200) - pub_date = models.DateTimeField('date published') - - class Choice(models.Model): - poll = models.ForeignKey(Poll) - choice = models.CharField(max_length=200) - votes = models.IntegerField(default=0) - -Model Details -------------- - -Let's look at that a bit more closely: - -.. code-block:: python - :class: small incrmental - - class Poll(models.Model): - -.. class: incremental small - -* Our Models are Python classes that inherit from the Model class -* The ``Model`` class provides a standard API for interacting with a database, - centered on the object defined by the model. -* You can add functionality to your object by adding methods to these models. -* Consider methods added to a model to be row-level operations. They will work - on a single record from the database, not on entire tables -* You can read much more about the `Model API - `_ - -Field Details -------------- - -A model has attributes defined by ``Fields``: - -.. code-block:: python - :class: small - - question = models.CharField(max_length=200) - pub_date = models.DateTimeField('date published') - poll = models.ForeignKey(Poll) - votes = models.IntegerField(default=0) - -.. class:: incremental small - -* Fields map to columns in a database table -* Note there are no explicit primary key fields. Django does this - automatically -* Different field types map to different SQL column types, the ORM handles - this. -* Django fields can handle complex relationships between objects. -* Field constructors take arguments, some are common to all Fields, others - particular to a given Field type. -* **ALL** Django model fields default to being NOT NULL (required). You change - this with the ``blank`` and ``null`` constructor arguments -* You can read much more about `Model Fields - `_ Hooking it Up ------------- From 1837686a5a4cb9acefcb0041521d3b8f1c0dc277 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 26 Jul 2013 21:19:00 -0700 Subject: [PATCH 132/487] complete first Django session translated from old week06 presentation --- source/presentations/session07.rst | 1050 +++++++++++++++++++++++++++- source/presentations/week06.rst | 506 +------------- 2 files changed, 1051 insertions(+), 505 deletions(-) diff --git a/source/presentations/session07.rst b/source/presentations/session07.rst index 6ed4fd74..6e6d420d 100644 --- a/source/presentations/session07.rst +++ b/source/presentations/session07.rst @@ -302,6 +302,62 @@ What Got Created * **manage.py**: a management control script. +Django and WSGI +--------------- + +If you open ``wsgi.py``, you'll see the following: + +.. code-block:: python + :class: small + + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + + from django.core.wsgi import get_wsgi_application + application = get_wsgi_application() + +.. container:: incremental + + Django is pointing the python environment at your settings file and then + getting a wsgi application: + + .. code-block:: python + :class: small + + def get_wsgi_application(): + return WSGIHandler() + + +The Django WSGIHandler +---------------------- +.. code-block:: python + :class: tiny + + class WSGIHandler(base.BaseHandler): + #... + def __call__(self, environ, start_response): + if self._request_middleware is None: + #... set up django middleware + #... + try: + request = self.request_class(environ) + except UnicodeDecodeError: + #... + response = http.HttpResponseBadRequest() + else: + response = self.get_response(request) + #... + try: + status_text = STATUS_CODE_TEXT[response.status_code] + except KeyError: + status_text = 'UNKNOWN STATUS CODE' + status = '%s %s' % (response.status_code, status_text) + response_headers = [(str(k), str(v)) for k, v in response.items()] + for c in response.cookies.values(): + response_headers.append((str('Set-Cookie'), str(c.output(header='')))) + start_response(force_str(status), response_headers) + return response + + *django-admin.py* and *manage.py* --------------------------------- @@ -561,11 +617,13 @@ you write to your database. .. class:: incremental -You can override methods from the base ``Model`` class to alter how this works. +You can override methods from the base ``Model`` class to alter how this works +or write new methods to add functionality. .. class:: incremental -You can also write new methods on your class that provide new functionality. +Learn more about `models +`_ Our Post Model @@ -779,3 +837,991 @@ https://docs.djangoproject.com/en/1.5/ref/models/fields/ related_name='categories' ) + +Hooking it Up +------------- + +In order to use our new models, we need Django to know about our *app* + +.. class:: incremental + +This is accomplished by configuration in the ``settings.py`` file. + +.. class:: incremental + +Open that file now, in your editor, and find the INSTALLED_APPS setting. + + +Installing Apps +--------------- + +You extend Django functionality by *installing apps*. This is pretty simple: + +.. code-block:: python + :class: small + + INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + # Uncomment the next line to enable the admin: + # 'django.contrib.admin', + # Uncomment the next line to enable admin documentation: + # 'django.contrib.admindocs', + 'myblog', # <- YOU ADD THIS PART + ) + + +Setting Up the Database +----------------------- + +You know what the next step will be: + +.. code-block:: + :class: incremental + + (djangoenv)$ python manage.py syncdb + Creating tables ... + Creating table myblog_post + Creating table myblog_category_posts + Creating table myblog_category + Installing custom SQL ... + Installing indexes ... + Installed 0 object(s) from 0 fixture(s) + +.. class:: incremental + +Django has now created tables for our app. How many did it create? + + +ORM and SQL +----------- + +That third table is the SQL mechanism by which a ``Post`` is related to a +``Category``. + +.. class:: incremental + +The ORM shields us, as Python developers, from SQL intricacies. + +.. class:: incremental + +We don't need to know that a join table is needed for a ManyToMany relation. + +.. class:: incremental + +This is but one of the ways that the ORM helps us. More soon. + + +A Word About Development +------------------------ + +These models we've created are not going to change often. This is unusual for +a development cycle. + +.. class:: incremental + +The ``syncdb`` management command only creates tables that *do not yet exist*. +It **does not update tables**. + +.. class:: incremental + +The ``sqlclear `` command will print the ``DROP TABLE`` statements to +remove the tables for your app. + +.. class:: incremental + +Or ``sql `` will show the ``CREATE TABLE`` statements, and you can work +out the differences and update manually. + + +ACK!!! +------ + +That doesn't sound very nice, does it? + +.. class:: incremental + +Luckily, there is an app available for Django that helps with this: ``South`` + +.. class:: incremental + +South allows you to incrementally update your database in a simplified way. + +.. class:: incremental + +South supports forward, backward and data migrations. + +.. class:: incremental + +We'll learn a bit more about this in our next session. + + +Break Time +---------- + +.. class:: big-centered + +Let's take a break here and return in 10 minutes. + + +The Django Shell +---------------- + +Django provides a management command ``shell``: + +.. class:: incremental + +* Shares the same ``sys.path`` as your project, so all installed python + packages are present. +* Imports the ``settings.py`` file from your project, and so shares all + installed apps and other settings. +* Handles connections to your database, so you can interact with live data + directly. + +.. class:: incremental + +Let's explore the Model Instance API directly using this shell: + +.. class:: incremental + +:: + + (djangoenv)$ python manage.py shell + + +Creating Instances +------------------ + +Instances of our model can be created by simple instantiation: + +.. code-block:: python + :class: small + + >>> from myblog.models import Post + >>> p1 = Post(title="My first post", + ... text="This is the first post I've written") + >>> p1 + + +.. container:: incremental + + We can also validate that our new object is okay before we try to save it: + + .. code-block:: python + :class: small + + >>> p1.full_clean() + Traceback (most recent call last): + ... + ValidationError: {'author': [u'This field cannot be null.']} + + +Django Model Managers +--------------------- + +We have to hook our ``Post`` to an author, which must be a ``User``. + +.. class:: incremental + +To do this, we need to have an instance of the ``User`` class. + +.. class:: incremental + +We can use the ``User`` *model manager* to run table-level operations like +``SELECT``: + +.. class:: incremental + +All Django models have a *manager*. By default it is accessed through the +``objects`` class attribute. + + +Making a ForeignKey Relation +---------------------------- + +Let's use the *manager* to get an instance of the ``User`` class: + +.. code-block:: python + :class: small + + >>> from django.contrib.auth.models import User + >>> all_users = User.objects.all() + >>> all_users + [] + >>> u1 = all_users[0] + >>> p1.author = u1 + +.. container:: incremental + + And now our instance should validate properly: + + .. code-block:: python + :class: small + + >>> p1.full_clean() + >>> + + +Saving New Objects +------------------ + +Our model has three date fields, two of which are supposed to be +auto-populated: + +.. class:: python + :class: small + + >>> print(p1.created_date) + None + >>> print(p1.modified_date) + None + +.. container:: incremental + + When we save our post, these fields will get values assigned: + + .. code-block:: python + :class: small + + >>> p1.save() + >>> p1.created_date + datetime.datetime(2013, 7, 26, 20, 2, 38, 104217, tzinfo=) + >>> p1.modified_date + datetime.datetime(2013, 7, 26, 20, 2, 38, 104826, tzinfo=) + + +Updating An Instance +-------------------- + +Models operate much like 'normal' python objects. + +.. container:: incremental + + To change the value of a field, simply set the instance attribute to a new + value. Call ``save()`` to persist the change: + + .. code-block:: python + :class: small + + >>> p1.title = p1.title + " (updated)" + >>> p1.save() + >>> p1.title + 'My first post (updated)' + + +Create a Few Posts +------------------ + +Let's create a few more posts so we can explore the Django model manager query +API: + +.. code-block:: python + :class: small + + >>> p2 = Post(title="Another post", + ... text="The second one created", + ... author=u1).save() + >>> p3 = Post(title="The third one", + ... text="With the word 'heffalump'", + ... author=u1).save() + >>> p4 = Post(title="Posters are great decoration", + ... text="When you are a poor college student", + ... author=u1).save() + >>> Post.objects.count() + 4 + + +The Django Query API +-------------------- + +The *manager* on each model class supports a full-featured query API. + +.. class:: incremental + +API methods take keyword arguments, where the keywords are special +constructions combining field names with field *lookups*: + +.. class:: incremental small + +* title__exact="The exact title" +* text__contains="decoration" +* id__in=range(1,4) +* published_date__lte=datetime.datetime.now() + +.. class:: incremental + +Each keyword argument generates an SQL clause. + + +QuerySets +--------- + +API methods can be divided into two basic groups: methods that return +``QuerySets`` and those that do not. + +.. class:: incremental + +The former may be chained without hitting the database: + +.. code-block:: python + :class: small incremental + + >>> a = Post.objects.all() #<-- no query yet + >>> b = a.filter(title__icontains="post") #<-- not yet + >>> c = b.exclude(text__contains="created") #<-- nope + >>> [(p.title, p.text) for p in c] #<-- This will issue the query + +.. container:: incremental + + Conversely, the latter will issue an SQL query when executed. + + .. code-block:: python + :class: small + + >>> a.count() # immediately executes an SQL query + + +QuerySets and SQL +----------------- + +If you are curious, you can see the SQL that a given QuerySet will use: + +.. code-block:: python + :class: small incremental + + >>> print(c.query) + SELECT "myblog_post"."id", "myblog_post"."title", + "myblog_post"."text", "myblog_post"."author_id", + "myblog_post"."created_date", "myblog_post"."modified_date", + "myblog_post"."published_date" + FROM "myblog_post" + WHERE ("myblog_post"."title" LIKE %post% ESCAPE '\' + AND NOT ("myblog_post"."text" LIKE %created% ESCAPE '\' ) + ) + +.. class:: incremental + +The exact SQL will vary automatically depending on the database you are using. + + +Exploring the QuerySet API +-------------------------- + +See https://docs.djangoproject.com/en/1.5/ref/models/querysets + + +.. code-block:: python + :class: small + + >>> [p.pk for p in Post.objects.all().order_by('created_date')] + [1, 2, 3, 4] + >>> [p.pk for p in Post.objects.all().order_by('-created_date')] + [4, 3, 2, 1] + >>> [p.pk for p in Post.objects.filter(title__contains='post')] + [1, 2, 4] + >>> [p.pk for p in Post.objects.exclude(title__contains='post')] + [3] + >>> qs = Post.objects.exclude(title__contains='post') + >>> qs = qs.exclude(id__exact=3) + >>> [p.pk for p in qs] + [] + >>> qs = Post.objects.exclude(title__contains='post', id__exact=3) + >>> [p.pk for p in qs] + [1, 2, 3, 4] + + +Updating via QuerySets +---------------------- + +You can update all selected objects at the same time. + +.. class:: incremental + +Changes are persisted without needing to call ``save``. + +.. code-block:: python + :class: small incremental + + >>> qs = Post.objects.all() + >>> [p.published_date for p in qs] + [None, None, None, None] + >>> from datetime import datetime + >>> from django.utils.timezone import UTC + >>> utc = UTC() + >>> now = datetime.now(utc) + >>> qs.update(published_date=now) + 4 + >>> [p.published_date for p in qs] + [datetime.datetime(2013, 7, 27, 1, 20, 30, 505307, tzinfo=), + ...] + + +Testing Our Models +------------------ + +As with any project, we want to test our work. Django provides a testing +framework to allow this. + +.. class:: incremental + +Django supports both *unit tests* and *doctests*. I strongly suggest using +*unit tests*. + +.. class:: incremental + +You add tests for your *app* to the file ``tests.py``, which should be at the +same package level as ``models.py``. + +.. class:: incremental + +Locate and open this file in your editor. + + +Django TestCase Classes +----------------------- + +**SimpleTestCase** is for basic unit testing with no ORM requirements + +.. class:: incremental + +**TransactionTestCase** is useful if you need to test transactional +actions (commit and rollback) in the ORM + +.. class:: incremental + +**TestCase** is used when you require ORM access and a test client + +.. class:: incremental + +**LiveServerTestCase** launches the django server during test runs for +front-end acceptance tests. + + +Testing Data +------------ + +Sometimes testing requires base data to be present. We need a User for ours. + +.. class:: incremental + +Django provides *fixtures* to handle this need. + +.. class:: incremental + +Create a directory called ``fixtures`` inside your ``myblog`` app directory. + +.. class:: incremental + +Copy the file ``myblog_test_fixture.json`` from the class resources into this +directory, it contains a user for us. + + +Setting Up Our Tests +-------------------- + +Now that we have a fixture, we need to instruct our tests to use it. + +.. container:: incremental + + Edit ``tests.py`` (which comes with one test already) to look like this: + + .. code-block:: python + :class: small + + from django.test import TestCase + from django.contrib.auth.models import User + + class PostTestCase(TestCase): + fixtures = ['myblog_test_fixture.json', ] + + def setUp(self): + self.user = User.objects.get(pk=1) + + +Our First Enhancement +--------------------- + +Look at the way our Post represents itself in the Django shell: + +.. code-block:: python + :class: small + + >>> [p for p in Post.objects.all()] + [, , + , ] + +.. class:: incremental + +Wouldn't it be nice if the posts showed their titles instead? + +.. class:: incremental + +In Django, the ``__unicode__`` method is used to determine how a Model +instance represents itself. + +.. class:: incremental + +Then, calling ``unicode(instance)`` gives the desired result. + + +Write The Test +-------------- + +Let's write a test that demonstrates our desired outcome: + +.. code-block:: python + :class: small + + # add this import at the top + from myblog.models import Post + + # and this test method to the PostTestCase + test_unicode(self): + expected = "This is a title" + p1 = Post(title=expected) + actual = unicode(p1) + self.assertEqual(expected, actual) + + +Run The Test +------------ + +To run tests, use the ``test`` management command + +.. class:: incremental + +Without arguments, it will run all TestCases it finds in all installed *apps* + +.. class:: incremental + +You can pass the name of a single app to focus on those tests + +.. class:: incremental + +Quit your Django shell and in your terminal run the test we wrote: + +.. code-block:: bash + :class: small incremental + + (djangoenv)$ python manage.py test myblog + + +The Result +---------- + +We have yet to implement this enhancement, so our test should fail: + +.. class:: small + +:: + + Creating test database for alias 'default'... + F + ====================================================================== + FAIL: test_unicode (myblog.tests.PostTestCase) + ---------------------------------------------------------------------- + Traceback (most recent call last): + File "/Users/cewing/projects/training/uw_pce/training.python_web/scripts/session07/mysite/myblog/tests.py", line 15, in test_unicode + self.assertEqual(expected, actual) + AssertionError: 'This is a title' != u'Post object' + + ---------------------------------------------------------------------- + Ran 1 test in 0.007s + + FAILED (failures=1) + Destroying test database for alias 'default'... + + +Make it Pass +------------ + +Let's add an appropriate ``__unicode__`` method to our Post class + +.. class:: incremental + +It will take ``self`` as its only argument + +.. class:: incremental + +And it should return its own title as the result + +.. class:: incremental + +Go ahead and take a stab at this in ``models.py`` + +.. code-block:: python + :class: small incremental + + class Post(models.Model): + #... + + def __unicode__(self): + return self.title + + +Did It Work? +------------ + +Re-run the tests to see: + +.. code-block:: bash + :class: small + + (djangoenv)$ python manage.py test myblog + Creating test database for alias 'default'... + . + ---------------------------------------------------------------------- + Ran 1 test in 0.007s + + OK + Destroying test database for alias 'default'... + +.. class:: incremental center + +**YIPEEEE!** + + +Repeat the Exercise +------------------- + +Although we haven't played with it yet, our Category class could use the same +treatment, using the ``name`` field. + +.. class:: incremental + +Add a CategoryTestCase to ``tests.py`` with one test that shows this. + +.. class:: incremental + +Run the tests, demonstrating that you have two tests and one failure + +.. class:: incremental + +Add the appropriate method to the appropriate class in ``models.py`` and +re-run the tests. + + +My Test +------- + +.. code-block:: python + :class: incremental + + # another import + from myblog.models import Category + + # and the test case and test + class CategoryTestCase(TestCase): + + def test_unicode(self): + expected = "A Category" + c1 = Category(name=expected) + actual = unicode(c1) + self.assertEqual(expected, actual) + + +My Method +--------- + +.. code-block:: python + + class Category(models.Model): + #... + + def __unicode__(self): + return self.name + + +What to Test +------------ + +In any framework, the question arises of what to test. Much of your app's +functionality is provided by framework tools. Does that need testing? + +.. class:: incremental + +I *usually* don't write tests covering features provided directly by the +framework. + +.. class:: incremental + +I *do* write tests for functionality I add, and for places where I make +changes to how the default functionality works. + +.. class:: incremental + +This is largely a matter of style and taste (and of budget). + + +More Later +---------- + +We've only begun to test our blog app. + +.. class:: incremental + +We'll be adding many more tests later + +.. class:: incremental + +In between, you might want to take a look at the Django testing documentation: + +.. class:: incremental center + +https://docs.djangoproject.com/en/1.5/topics/testing/ + + +The Django Admin +---------------- + +As I stated earlier, the Django admin is really Django's *killer feature* + +.. class:: incremental + +To demonstrate this, we are going to set up the admin for our blog + + +Install the Admin +----------------- + +The Django Admin is, itself, an *app*. It is not installed by default. + +.. class:: incremental + +Open the ``settings.py`` file from our ``mysite`` project package and +uncomment the admin bit: + +.. code-block:: python + :class: incremental small + + INSTALLED_APPS = ( + # ... + 'django.contrib.staticfiles', + # Uncomment the next line to enable the admin: + 'django.contrib.admin', # <- THIS LINE HERE + # Uncomment the next line to enable admin documentation: + # 'django.contrib.admindocs', + 'myblog', + ) + + +Add the Admin Tables +-------------------- + +As you might expect, enabling the admin alters our DB. We'll need to run +the ``syncdb`` management command:: + + (djangoenv)$ python manage.py syncdb + Creating tables ... + Creating table django_admin_log + Installing custom SQL ... + Installing indexes ... + Installed 0 object(s) from 0 fixture(s) + +.. class:: incremental + +All set. Now let's make it visitable + + +Django URL Resolution +--------------------- + +Django too has a system for routing URLs to code: the *urlconf*. + +.. class:: incremental + +* A urlconf is a list of calls to the ``django.conf.urls.url`` function +* This function takes: + + * a regexp *rule*, representing the URL + + * a ``callable`` to be invoked (or a name identifying one) + + * an optional *name* kwarg, used to *reverse* the URL + + * other optional arguments we will skip for now + +* The function returns a *resolver* that matches the request path to the + callable +* django will load the urlconf named ``urlpatterns`` that it finds in the file + named in ``settings.ROOT_URLCONF``. + + +Including URLs +-------------- + +Many Django add-on *apps*, like the Django Admin, come with their own urlconf + +.. class:: incremental + +It is standard to include these urlconfs by rooting them at some path in your +site. + +.. container:: incremental + + You can do this by using the ``include`` function as the callable in a + ``url`` call: + + .. code-block:: python + :class: small + + url(http://github.com/r'%5Eforum/',%20include('random.forum.app.urls')) + + +Including the Admin +------------------- + +We can use this to add *all* the URLs provided by the Django admin in one +stroke. + +.. container:: incremental + + Uncomment three lines in ``urls.py``: + + .. code-block:: python + :class: small + + from django.contrib import admin #<- Uncomment these two + admin.autodiscover() #<- + + urlpatterns = patterns('', + + # Uncomment the next line to enable the admin: + url(http://github.com/r'%5Eadmin/',%20include(admin.site.urls)), #<- and this + ) + + +Using the Development Server +---------------------------- + +We can now view the admin. We'll use the Django development server. + +.. class:: incremental + +In your terminal, use the ``runserver`` management command to start the +development server: + +.. class:: incremental + +:: + + (djangoenv)$ python manage.py runserver + Validating models... + + 0 errors found + Django version 1.4.3, using settings 'mysite.settings' + Development server is running at http://127.0.0.1:8000/ + Quit the server with CONTROL-C. + + +Viewing the Admin +----------------- + +Load ``http://localhost:8000/``. You should see this: + +.. image:: img/django-admin-login.png + :align: center + :width: 50% + +.. class:: incremental + +Login with the name and password you created before. + + +The Admin Index +--------------- + +The index will provide a list of all the installed *apps* and each model +registered. You should see this: + +.. image:: img/admin_index.png + :align: center + :width: 90% + +.. class:: incremental + +Click on ``Users``. Find yourself? Edit yourself, but **don't** uncheck +``superuser``. + + +Add Posts to the Admin +---------------------- + +Okay, let's add our app models to the admin. + +.. class:: incremental + +Add a new file to the ``myblog`` app package: ``admin.py``. Open it and add +the following: + +.. code-block:: python + :class: incremental + + from django.contrib import admin + from myblog.models import Post, Category + + admin.site.register(Post) + admin.site.register(Category) + +.. class:: incremental + +Restart your Development server and reload the admin index + + +Play A Bit +---------- + +Visit the admin page for Posts. You should see the posts we created earlier in +the Django shell. + +.. class:: incremental + +Look at the listing of Posts. Because of our ``__unicode__`` method we see a +nice title. + +.. class:: incremental + +Are there other fields you'd like to see listed? + +.. class:: incremental + +Click on a Post, note what is and is not shown. + +.. class:: incremental + +Poke at the Category admin a bit too. + + +Next Steps +---------- + +We've learned a great deal about Django's ORM and Models. + +.. class:: incremental + +We've also spent some time getting to know the Query API provided by model +managers and QuerySets. + +.. class:: incremental + +We've also hooked up the Django Admin and noted some shortcomings. + +.. class:: incremental + +In our next session we'll improve how the admin works for us. + +.. class:: incremental + +Then we'll put a front-end on this blog. + + +Break Time +---------- + +.. class:: big-centered + +See you back soon. diff --git a/source/presentations/week06.rst b/source/presentations/week06.rst index 1a10cd73..78c7f8bd 100644 --- a/source/presentations/week06.rst +++ b/source/presentations/week06.rst @@ -7,509 +7,6 @@ blah blah blah -Hooking it Up -------------- - -Okay, we've got a couple of models, now we need to add our *app* to our -project. - -.. class:: incremental - -In Django, this is accomplished by configuration. - -.. class:: incremental - -Configuration takes place in the project ``settings.py`` file. - -.. class:: incremental - -Open that file now, in your editor. - -Installing Apps ---------------- - -You extend Django functionality by *installing apps*. Find the following block -in ``settings.py`` and edit it like so: - -.. code-block:: python - :class: small - - INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.messages', - 'django.contrib.staticfiles', - # Uncomment the next line to enable the admin: - # 'django.contrib.admin', - # Uncomment the next line to enable admin documentation: - # 'django.contrib.admindocs', - 'polls', # <- YOU ADD THIS PART - ) - -Setting Up the Database ------------------------ - -By now, we should have some guess as to what the next step will be - -.. code-block:: - :class: incremental - - (djangoenv)$ python manage.py syncdb - -.. class:: incremental - -This will execute the SQL commands needed to create the new tables in your -database. - -A Word About Development ------------------------- - -These models we've created are not going to change. This is unusual for a -development cycle. - -.. class:: incremental - -The ``syncdb`` management command only creates tables that *do not yet exist*. -It **does not update tables**. - -.. class:: incremental - -It is easy to get your model definitions out of sync with your database. - -.. class:: incremental - -Django provides the management command ``sqlclear`` to handle this. It drops -all tables, so you can run ``syncdb`` again. - -ACK!!! ------- - -.. class:: center - -That doesn't sound very nice, does it? - -.. class:: big-centered incremental - -We'll learn a better way next week - -The Django Shell ----------------- - -Django provides a management command ``shell``: - -.. class:: incremental - -* Shares the same ``sys.path`` as your project, so all installed python - packages are present. -* Imports the ``settings.py`` file from your project, and so shares all - installed apps and other settings. -* Handles connections to your database, so you can interact with live data - directly. - -.. class:: incremental - -Let's explore the Model Instance API directly using this shell - -Model Instance API ------------------- - -:: - - (djangoenv)$ python manage.py shell - -.. code-block:: python - - >>> from polls.models import Poll - >>> Poll.objects.count() - 0 - >>> p1 = Poll(question="What is your name?") - >>> p1.full_clean() - Traceback (most recent call last): - ... - >>> from django.utils import timezone - >>> p1.pub_date = timezone.now() - >>> p1.full_clean() - >>> p1.save() - >>> Poll.objects.count() - 1 - -More API --------- - -.. code-block:: python - :class: small - - >>> Poll.objects.filter(id=1) - [] - >>> what_polls = Poll.objects.filter(question__startswith="What") - [] - >>> mypoll = Poll.objects.get(pk=1) - >>> mypoll.choice_set.all() - [] - >>> from polls.models import Choice - >>> c1 = Choice(choice="King Arthur of the Britons", poll=mypoll) - >>> c1.save - >>> mypoll.choice_set.all() - [] - >>> mypoll.choice_set.create(choice="Lancelot of Camelot") - >>> mypoll.choice_set.all() - [, ] - -Enhancing Models ----------------- - -It's clear that the representation of our objects leaves something to be -desired. Django can help - -.. class:: incremental - -Back in ``models.py``, add these methods: - -.. code-block:: python - :class: small incremental - - class Poll(models.Model): - # ... - def __unicode__(self): - return self.question - - class Choice(models.Model): - # ... - def __unicode__(self): - return self.choice - -Model Methods -------------- - -This ``__unicode__`` method is a normal python instance method. You can add -other methods, too (still ``models.py``): - -.. code-block:: python - :class: small incremental - - from django.utils import timezone - - class Poll(models.Model): - # ... - def published_today(self): - now = timezone.now() - time_delta = now - self.pub_date - return time_delta.days == 0 - -.. class:: incremental - -Save that, then start up the Django shell again (``python manage.py shell``) - -Check Custom Methods --------------------- - -.. code-block:: python - - >>> from polls.models import Poll - >>> mypoll = Poll.objects.get(pk=1) - >>> mypoll - - >>> mypoll.choice_set.all() - [, - , - ] - >>> mypoll.published_today() - True - -Testing Our Models ------------------- - -As with any project, we want to test our work. Django provides a testing -framework to allow this. - -.. class:: incremental - -Django supports both *unit tests* and *doctests*. I strongly suggest using -*unit tests*. - -.. class:: incremental - -You add tests for your *app* to the file ``tests.py``, which should be at the -same package level as ``models.py``. - -.. class:: incremental - -Locate and open this file in your editor. We are going to add a few tests for -the models we've just written. - -Testing Setup -------------- - -.. code-block:: python - :class: small - - from datetime import timedelta - - from django.test import TestCase - from django.utils import timezone - - from polls.models import Poll - - class PollTest(TestCase): - def setUp(self): - self.expected_question = "what is the question?" - self.expected_choice = "do you like spongecake?" - self.poll = Poll.objects.create( - question=self.expected_question, - pub_date=timezone.now()) - self.choice = self.poll.choice_set.create( - choice=self.expected_choice) - -Writing Tests -------------- - -.. code-block:: python - :class: small - - def test_poll_display(self): - self.assertEquals(unicode(self.poll), self.expected_question) - new_question = "What is the answer?" - self.poll.question = new_question - self.assertEquals(unicode(self.poll), new_question) - - def test_choice_display(self): - self.assertEquals(unicode(self.choice), self.expected_choice) - new_choice = "is left better than right?" - self.choice.choice = new_choice - self.assertEquals(unicode(self.choice), new_choice) - - def test_published_today(self): - self.assertTrue(self.poll.published_today()) - delta = timedelta(hours=26) - self.poll.pub_date = self.poll.pub_date - delta - self.assertFalse(self.poll.published_today()) - -Running Tests -------------- - -You can run your tests using a management command provided by Django:: - - (djangoenv)$ python manage.py test polls - -.. class:: incremental - -* This will run the tests for the ``polls`` app -* You can provide the name of any installed app -* If you provide no name, the tests for *all* installed apps will run -* You can run subsets by providing dotted names: ``polls.PollTest``, - ``polls.PollTest.test_poll_display`` - -.. class:: incremental - -There is a lot more to know about `Testing Django applications -`_ - -What to Test ------------- - -In any framework, the question arises of what exactly to test. Much of the -functioning of your app is provided by framework tools. Do you need to test -that stuff? - -.. class:: incremental - -I *usually* don't write tests covering features provided directly by the -framework. - -.. class:: incremental - -I *do* write tests for functionality I add, and for places where I make -changes to how the default functionality works. - -.. class:: incremental - -This is largely a matter of style and taste (and of how much development time -you have). - - -Lab - Part Two --------------- - -In this part, we'll be adding our app to the Django Admin. This will allow -us to add, edit and delete objects with a minimum of work. - -We'll focus instead on how to customize the admin to get the best results we -can. - -Install the Admin ------------------ - -The Django Admin is, itself, an *app*. It is not installed by default. - -.. class:: incremental - -Open the ``settings.py`` file from our ``mysite`` project package and uncomment -the admin bit: - -.. code-block:: python - :class: incremental small - - INSTALLED_APPS = ( - # ... - 'django.contrib.staticfiles', - # Uncomment the next line to enable the admin: - 'django.contrib.admin', # <- THIS LINE HERE - # Uncomment the next line to enable admin documentation: - # 'django.contrib.admindocs', - 'polls', - ) - -Add the Admin Tables --------------------- - -As you might expect, enabling the admin alters our DB. We'll need to run -the ``syncdb`` management command:: - - (djangoenv)$ python manage.py syncdb - Creating tables ... - Creating table django_admin_log - Installing custom SQL ... - Installing indexes ... - Installed 0 object(s) from 0 fixture(s) - -.. class:: incremental - -All set. Let's add URLs next - -Django URL Resolution ---------------------- - -Like Flas, Django has a system for routing URLs to code: the *urlconf*. - -.. class:: incremental - -* a urlconf is a list of mappings -* each mapping has a regexp *rule*, representing the URL -* each mapping names or provides the ``callable`` to be invoked -* each mapping can have a *name*, used to *reverse* the URL -* a urlconf should be created using functions from the ``django.conf.urls`` - module -* django will load the urlconf named ``urlpatterns`` that it finds in the file - named in ``settings.ROOT_URLCONF``. -* That urlconf must include any others it requires - -Django URL Patterns -------------------- - -Open the file ``urls.py`` from your ``mysite`` project package: - -.. code-block:: python - - from django.conf.urls import patterns, include, url - ... - urlpatterns = patterns('', - # list of url patterns - ) - -.. class:: incremental - -You can include lists of urls from installed apps by using the ``include`` -function as the callable in a url pattern: - -.. code-block:: python - :class: incremental - - url(http://github.com/r'%5Eblog/',%20include('my.blog.app.urls')) - -Including the Admin -------------------- - -Using this knowledge, we can add *all* the URLs provided by the Django admin -in one stroke. Edit ``urls.py``, which is open in your editor, and uncomment -three lines: - -.. code-block:: python - :class: incremental - - from django.contrib import admin #<- Uncomment these two - admin.autodiscover() - - urlpatterns = patterns('', - - # Uncomment the next line to enable the admin: - url(http://github.com/r'%5Eadmin/',%20include(admin.site.urls)), #<- and this - ) - -Using the Development Server ----------------------------- - -We can now view the admin. We'll use the Django development server. - -.. class:: incremental - -In your terminal, use the ``runserver`` management command to start the -development server: - -.. class:: incremental - -:: - - (djangoenv)$ python manage.py runserver - Validating models... - - 0 errors found - Django version 1.4.3, using settings 'mysite.settings' - Development server is running at http://127.0.0.1:8000/ - Quit the server with CONTROL-C. - -Viewing the Admin ------------------ - -Load ``http://localhost:8000/``. You should see this: - -.. image:: img/django-admin-login.png - :align: center - :width: 50% - -.. class:: incremental - -Login with the name and password you created before. - -The Admin Index ---------------- - -The index will provide a list of all the installed *apps* and each model -registered. You should see this: - -.. image:: img/admin_index.png - :align: center - :width: 90% - -.. class:: incremental - -Click on ``Users``. Find yourself? Edit yourself, but **don't** uncheck -``superuser``. - -Add Polls to the Admin ----------------------- - -Okay, let's add our app, and the models therein, to the admin. - -.. class:: incremental - -Add a new file to the ``polls`` app package: ``admin.py``. Edit it and add the -following: - -.. code-block:: python - :class: incremental - - from django.contrib import admin - from polls.models import Poll, Choice - - admin.site.register(Poll) - admin.site.register(Choice) - -.. class:: incremental - -Restart your Development server and reload the admin index - Customized Admin ---------------- @@ -525,6 +22,9 @@ registered automatically generated. * You can create, and customize, a *ModelAdmin* subclass for your models. + + + Create a PollAdmin ------------------ From 3ae425352763594f35da3e5fb5958ae1833dd687 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 26 Jul 2013 22:41:26 -0700 Subject: [PATCH 133/487] complete outline and readings list reformat session names throughout to decrease specificity --- assignments/week07/athome/assignment.rst | 4 + source/main/outline.rst | 236 +++++------------------ source/main/readings.rst | 116 +++++++++-- source/presentations/index.rst | 25 +-- source/presentations/session01.rst | 2 +- source/presentations/session02.rst | 2 +- source/presentations/session03.rst | 2 +- source/presentations/session05.rst | 2 +- source/presentations/session06.rst | 2 +- source/presentations/session07.rst | 2 +- 10 files changed, 178 insertions(+), 215 deletions(-) diff --git a/assignments/week07/athome/assignment.rst b/assignments/week07/athome/assignment.rst index 8142b0f9..c26f0045 100644 --- a/assignments/week07/athome/assignment.rst +++ b/assignments/week07/athome/assignment.rst @@ -155,3 +155,7 @@ If you like, you can see your work by running the new project:: Visit ``http://localhost:6543`` to see your work in action. then go grab a beer and curl up with the reading for the week. There's a lot. + + + +http://wiki.cython.org/64BitCythonExtensionsOnWindows \ No newline at end of file diff --git a/source/main/outline.rst b/source/main/outline.rst index 072d1a81..d077b3d1 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -5,8 +5,8 @@ This course is five days long. Each day is split into morning and afternoon sessions. Each session will consist of three or so hours of instruction and exercises and a couple of short breaks. -Day 1 AM - TCP/IP and Sockets ------------------------------ +Session 1 - TCP/IP and Sockets +------------------------------ We will begin by covering basic front-matter for the course: daily schedule, class protocol, introductions and such. Next we will move into a disucssion of @@ -30,8 +30,8 @@ References * `Python Module of the Week - socket `_ -Day 1 PM - Web Protocols ------------------------- +Session 2 - Web Protocols +------------------------- Protocols are the languages of the Internet. They govern how machines speak to one-another. We will focus on finding both the similarities and differences @@ -62,8 +62,8 @@ clear and concise and have some great code examples. .. _Internet Protocols and Support: http://pymotw.com/2/internet_protocols.html -Day 2 AM - APIs and Mashups ---------------------------- +Session 3 - APIs and Mashups +---------------------------- The internet is a treasure trove of information. But meaning can be hard to find among all that data. Mashups offer a way to combine data from disparate @@ -91,8 +91,8 @@ References * `json `_ -Day 2 PM - CGI and WSGI ------------------------ +Session 4 - CGI and WSGI +------------------------ In this class we will explore ways of moving data from HTTP requests into the dynamic scripts that process data. We will begin by looking at the original @@ -108,8 +108,8 @@ using WSGI and see what benefits and drawbacks it confers. `Lecture Slides `_ -Day 3 AM - Frameworks and Flask -------------------------------- +Session 5 - Frameworks and Flask +-------------------------------- In this class we learn about using frameworks to help us reach our goals. We will learn what makes up a framework and some criteria for evaluating which is @@ -127,8 +127,8 @@ within Python. `Lecture Slides `_ -Day 3 PM - A Flask Application ------------------------------- +Session 6 - A Flask Application +------------------------------- In this class we will exercise our new-won knowledge by building a small application using Flask. We'll write templates and forms, persist data, @@ -148,136 +148,46 @@ of request and response. `Lecture Slides `_ -Day 4 AM - Intro to Django --------------------------- +Session 7 - Intro to Django +--------------------------- In this class we'll get introduced to arguably the most popular full-stack Python web framework, Django. We'll install the framework, learn about how to get it running and how to get started creating your very own app. We'll be learning about the Django ORM and how Django Models can help shield -developers from much of the complexity of SQL. We'll learn how to use the tools -Django provides to explore and interact with your models while designing them. +developers from much of the complexity of SQL. We'll learn how to use the +tools Django provides to explore and interact with your models while designing +them. We'll also get a brief introduction to the Django admin, Django's +*killer feature*. Along the way, we'll continue our test-driven development style: writing tests to demonstrate the functionality we desire and then implementing code to make them pass. We'll get a chance to see how to build tests within the framework -offered by Django's testrunner. +offered by Django's testrunner. `Lecture Slides `_ +Session 8 - A Django Application +-------------------------------- -Reading -******* - -* `Django at a Glance - `_ - introduction to - the concepts and execution of Django - -* `Quick Install Guide - `_ - lightweight - instructions on installing Django. Use Python 2.6, not 2.5. - -* `Django Tutorial, part 1 - `_ - as noted - below, please actually follow the steps in the tutorial up until you reach - *Creating Models* - -Before Class -************ - -* Install Django 1.4.3. Use a Virtualenv and pip or easy_install. (see the - installation quick-start above, and the more in-depth guide below) - -* Install an RDBMS (I personally recommend PostgreSQL, but MySQL or any other - will do. We can even live with sqlite3, so long as you understand it is - **not for production**) - -* Set up a Django project. Walk through the first part of the tutorial above - until you reach *Creating Models*. **Do Not** create models) - -Reference -********* - -* `Using Django `_ - far more - in-depth information about core topics in Django. Pay particular attention - to the installation documentation here. - -* `Django Design Philosophies - `_ - some - well-considered words on why Django is the way it is. - - -Day 4 PM - A Django Application -------------------------------- - -In this class we'll dive a bit further into Django. We'll start with a -duplicate of the micro-blog we built in week 5 and work in teams to extend the -functionality by integrating existing apps. Along the way, we'll have a chance -to explore team-based development workflow. +In this class we'll complete our exploration of Django. We'll customize the +Django admin to help us most efficiently administer our Blog application. +We'll create and test view functions that present our application to the world +and we'll provide front-end access to forms that allow us to create, edit and +publish blog entries without needing to use the admin. Finally, we'll discuss some of the strengths and weaknesses of Django. What makes it a good choice for some projects but not for others. -Our assignment for the week will be to prepare for working with Pyramid in -Week 8. - -`Week 7 Presentation `_ - -Reading -******* - -* `Using Django `_ - far more - in-depth information about core topics in Django. Pay attention specifically - to the following topics (you'll want to follow links in these documents): +`Lecture Slides `_ - * `Models `_ - - details of the django modelling system. How to represent data for, - relationships between and the presentation of your objects. - * `Queries `_ - - basic information about the Django ORM and how to use it to create, - retrieve, update and delete objects. +Session 9 - Intro to Pyramid +---------------------------- - * `Working with Forms - `_ - how to create, - display, and process forms in Django, including forms that are associated - with a given model. - - * `The Django Template Language - `_ - learn - template basics like variables, filters, tags and blocks, and learn about - template inheritance. - - * `Class-based Generic Views - `_ - an - introduction to the simplest way to present your objects to your adoring - public. - - * `Testing Django Applications - `_ - learn - different approaches to testing Django applications, including unit - testing and doctests. - -Reference -********* - -* `SQLAlchemy and You `_ - - A really in-depth look at the differences between the Django ORM and the - reigning king of Python database integration, SQLAlchemy. - -* `About Django from the Pyramid Guy - `_ - a talk given at - DjangoCon 2012 by Chris McDonough, one of the driving forces behind the - Pyramid framework. Also available in `video form - `_. - - -Day 5 AM - Intro to Pyramid ---------------------------- - -This week we will look at a relative newcomer to the Python Web Framework +In this class we will look at a relative newcomer to the Python Web Framework scene, Pyramid. Although the framework is a newcomer, it is represents a combination of several projects, notably Repoze and Pylons, that have been around for quite some time. In fact, the roots of Repoze go back to Zope, the @@ -289,74 +199,34 @@ frameworks. We will look at the specific problems that the creators of Pyramid are looking to solve, and we will investigate how those decisions have influenced the design of the framework. -We'll specifically look at two technologies that set the Pyramid framework -apart: the ZODB and URL Traversal. We'll do this by implementing a wiki using -these technologies and then discuss what might make such tools appealing to a -certain type of project. - -We'll also look at a very different templating system, Chameleon, which grew -out of Zope Page Templates and the Template Attribute Language. Chameleon -provides code structures via XML namespaces, allowing you to write templates -that will load in a browser looking like HTML without needing a framework to -render them. - -`Week 8 Presentation `_ - -Reading -******* +Along the way we'll be taking a good look at a very different templating +system, Chameleon. It grew out of Zope Page Templates (ZPT) and the Template +Attribute Language (TAL). It's chief advantage is that it provides structure +and variable interpolation via XML namespaced attributes. This allows you to +write templates that load in a browser and look 'right' without needing the +framework to render them. -Why you should care about `Traversal -`_. +We'll also take a good look at the ZODB, a venerable persistent object store +that was NoSQL before NoSQL was a thing. We'll see how objects in the ZODB can +be created, saved and connected to eachother in a number of ways. -Compare and contrast forms of dispatch in Pyramid: +`Lecture Slides `_ -* `URL Route Dispatch - `_ -* `Object Traversal - `_ -Learn a bit about the `ZODB `_ +Session 10 - A Pyramid Application +---------------------------------- -* Read the `tutorial `_ for a - quick overview of usage (don't actually do it, though). -* Read the `more complete walk-through here - `_ altough, again, do not - actually do the code examples. -* Learn about `object references in the ZODB - `_ - - one of its greatest strengths. +In this class we'll dive into building a real Pyramid application. We'll be +implementing a simple wiki, using traversal dispatch, ZODB persistence and +Chameleon templates. We'll get a chance to work with simple forms, see how +views work in Pyramid, and implement an ACL-based authorization scheme. -Learn a bit about the Chameleon ZPT templating language: +Along the way, we'll continue our drive for test-driven development by writing +tests that cover the functionality we want and then writing the code to make +them pass. -* Read about `Chameleon Templates in Pyramid - `_ -* A `Quick Intro to TAL `_ +By the end of the session, you'll have a fully functional wiki you can play +with. Maybe you'll use it to track the information you leared about Python +Web Development. -* `Chameleon Documentation `_ - -In particular, pay attention to: - -* `Basics (TAL) - `_ -* `Expressions (TALES) - `_ - - -References -********** - -* `The ZODB Book `_ - A work in - progress by Carlos De La Guardia. - -* The `ZPT Appendix `_ to - the Zope Book - -* Read `Defending Pyramid's Design - `_ - - an excellent point-by-point explanation of the design decisions that went - into creating this framework. - - - -Day 5 PM - A Pyramid Application --------------------------------- +`Lecture Slides `_ \ No newline at end of file diff --git a/source/main/readings.rst b/source/main/readings.rst index da9d5d07..e9935762 100644 --- a/source/main/readings.rst +++ b/source/main/readings.rst @@ -10,8 +10,8 @@ increase both the depth and breadth of your knowledge. The readings are organized like the class, by day, time and topic. -Day 1 AM - TCP/IP and Sockets ------------------------------ +Session 1 - TCP/IP and Sockets +------------------------------ * `Wikipedia - Internet Protocol Suite `_ @@ -31,8 +31,8 @@ networked computing in mind: * `ZeroMQ Guide, Chapter 1 `_ -Day 1 PM - Web Protocols ------------------------- +Session 2 - Web Protocols +------------------------- * `Python Standard Library Internet Protocols `_ @@ -69,8 +69,8 @@ remain unchanged) over time, skim these specifications for HTTP and SMTP: * `RFC 5321 - SMTP (latest) `_ -Day 2 AM - APIs and Mashups ---------------------------- +Session 3 - APIs and Mashups +---------------------------- * `Wikipedia's take on 'Web Services' `_ @@ -110,8 +110,8 @@ both from the side of production and consumption: .. _restkit: https://github.com/benoitc/restkit/ -Day 2 PM - CGI and WSGI ------------------------ +Session 4 - CGI and WSGI +------------------------ * `CGI tutorial`_ - Read the following sections: Hello World, Debugging, Form. Other sections optional. Follow along using CGIHTTPServer. @@ -143,8 +143,8 @@ more minimal and may be easier to comprehend off the bat. .. _Getting Started with WSGI: http://lucumr.pocoo.org/2007/5/21/getting-started-with-wsgi/ -Day 3 AM - Frameworks and Flask -------------------------------- +Sessions 4 & 5 - Flask +---------------------- * `Web Application Frameworks `_ @@ -179,4 +179,98 @@ pick the one that fits your brain best. * `Web.py `_: Think about the ideal way to write a web app. Write the code to make it happen. * `Aspen `_: A Python web framework that makes the most of - the filesystem. \ No newline at end of file + the filesystem. + + +Sessions 7 & 8 - Django +----------------------- + +Though it's way too much to read in any one sitting (or even in 10 or 20), the +Django documentation is excellent and thorough. As a start, take a look at +these sections: + +* `Django at a Glance + `_ - introduction to + the concepts and execution of Django + +* `Quick Install Guide + `_ - lightweight + instructions on installing Django. Use Python 2.6, or 2.7. + +* `Django Tutorial `_ + - The tutorial covers many of the same concepts we will in class. Go over it + to re-enforce the lessons you learn + +* `Using Django `_ - far more + in-depth information about core topics in Django. In particular, the + installation instructions here can be helpful when you run into trouble. + +Bookmark the `Django Documentation homepage +`_. It really is "everything you need +to know about Django" + +When you have some time, read `Django Design Philosophies +`_ - for some +well-considered words on why Django is the way it is. + +Conversely, for some well-considered criticisms of Django and the way it is, +read this in-depth comparison of SQLAlchemy and the Django ORM by the creator +of Flask: `SQLAlchemy and You `_ + +Or consider viewing `this video `_ +of a talk given at DjangoCon 2012 by Chris McDonough, one of the driving +forces behind the Pyramid framework. + + +Sessions 9 & 10 - Pyramid +------------------------- + +Why you should care about `Traversal +`_. + +Compare and contrast forms of dispatch in Pyramid: + +* `URL Route Dispatch + `_ +* `Object Traversal + `_ + +Learn a bit about the `ZODB `_ + +* Read the `tutorial `_ for a + quick overview of usage (don't actually do it, though). +* Read the `more complete walk-through here + `_ altough, again, do not + actually do the code examples. +* Learn about `object references in the ZODB + `_ + - one of its greatest strengths. + +Learn a bit about the Chameleon ZPT templating language: + +* Read about `Chameleon Templates in Pyramid + `_ +* A `Quick Intro to TAL `_ + +* `Chameleon Documentation `_ + +In particular, pay attention to: + +* `Basics (TAL) + `_ +* `Expressions (TALES) + `_ + +You might also consider keeping the following around for reference: + +* `The ZODB Book `_ - A work in + progress by Carlos De La Guardia. + +* The `ZPT Appendix `_ to + the Zope Book. It was written for ZPT, but applies also to Chameleon. + +Finally, if you are interested in such things, read this eloquent explanation +of the decisions that went into Pyramid's design: + +* `Defending Pyramid's Design + `_ diff --git a/source/presentations/index.rst b/source/presentations/index.rst index 662633b8..a40f49ca 100644 --- a/source/presentations/index.rst +++ b/source/presentations/index.rst @@ -2,18 +2,13 @@ Course Presentations ==================== .. _index: -* `Day 1 AM - Networking and Sockets `_ -* `Day 1 PM - Web Protocols `_ -* `Day 2 AM - APIs and Mashups `_ -* `Day 2 PM - CGI and WSGI `_ -* `Day 3 AM - Frameworks and Flask `_ -* `Day 3 PM - A Flask Application `_ -* `Day 4 AM - Introducing Django `_ -* `Week 8 - Pyramid`_ -* `Week 9 - The Cloud`_ -* `Week 10 - Plone`_ - - -.. _Week 8 - Pyramid: week08.html -.. _Week 9 - The Cloud: week09.html -.. _Week 10 - Plone: week10.html +* `Session 1 - Networking and Sockets `_ +* `Session 2 - Web Protocols `_ +* `Session 3 - APIs and Mashups `_ +* `Session 4 - CGI and WSGI `_ +* `Session 5 - Frameworks and Flask `_ +* `Session 6 - A Flask Application `_ +* `Session 7 - Introducing Django `_ +* `Session 8 - A Django Application `_ +* `Session 9 - Intro to Pyramid `_ +* `Session 10 - A Pyramid Application `_ diff --git a/source/presentations/session01.rst b/source/presentations/session01.rst index c067e856..7136827c 100644 --- a/source/presentations/session01.rst +++ b/source/presentations/session01.rst @@ -5,7 +5,7 @@ Python Web Programming :align: left :width: 33% -Day 1 AM: Networking and Sockets +Session 1: Networking and Sockets .. class:: intro-blurb diff --git a/source/presentations/session02.rst b/source/presentations/session02.rst index b2ab9278..a1f1d619 100644 --- a/source/presentations/session02.rst +++ b/source/presentations/session02.rst @@ -5,7 +5,7 @@ Python Web Programming :align: left :width: 45% -Day 2 PM: Web Protocols +Session 2: Web Protocols .. class:: intro-blurb diff --git a/source/presentations/session03.rst b/source/presentations/session03.rst index 4ca5bc9e..c7174f12 100644 --- a/source/presentations/session03.rst +++ b/source/presentations/session03.rst @@ -5,7 +5,7 @@ Python Web Programming :align: left :width: 50% -Week 3: Scraping, APIs and Mashups +Session 3: Scraping, APIs and Mashups .. class:: intro-blurb diff --git a/source/presentations/session05.rst b/source/presentations/session05.rst index 9e80cca6..7895ee66 100644 --- a/source/presentations/session05.rst +++ b/source/presentations/session05.rst @@ -5,7 +5,7 @@ Python Web Programming :align: left :width: 50% -Day 3 AM: Frameworks and Flask +Session 5: Frameworks and Flask .. class:: intro-blurb right diff --git a/source/presentations/session06.rst b/source/presentations/session06.rst index 513d9db2..0938dba3 100644 --- a/source/presentations/session06.rst +++ b/source/presentations/session06.rst @@ -5,7 +5,7 @@ Python Web Programming :align: left :width: 50% -Day 3 PM: A Flask Application +Session 6: A Flask Application .. class:: intro-blurb right diff --git a/source/presentations/session07.rst b/source/presentations/session07.rst index 6e6d420d..06095080 100644 --- a/source/presentations/session07.rst +++ b/source/presentations/session07.rst @@ -5,7 +5,7 @@ Python Web Programming :align: left :width: 50% -Day 4 AM: Introducing Django +Session 7: Introducing Django .. class:: intro-blurb right From 442b719b250b506cff4703705d5ccb9ea5a98d34 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 26 Jul 2013 22:44:32 -0700 Subject: [PATCH 134/487] refix this, hadn't saved it --- source/presentations/session04.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/presentations/session04.rst b/source/presentations/session04.rst index b0db86ff..d04b24c9 100644 --- a/source/presentations/session04.rst +++ b/source/presentations/session04.rst @@ -5,7 +5,7 @@ Python Web Programming :align: left :width: 50% -Day 2 PM: CGI, WSGI and Living Online +Session 4: CGI, WSGI and Living Online .. class:: intro-blurb From ef703ce24b98e8376789f344b494215c28a85a69 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 27 Jul 2013 17:55:30 -0700 Subject: [PATCH 135/487] push on --- source/main/outline.rst | 6 ++ source/presentations/session07.rst | 2 +- source/presentations/week06.rst | 116 ----------------------------- 3 files changed, 7 insertions(+), 117 deletions(-) diff --git a/source/main/outline.rst b/source/main/outline.rst index d077b3d1..f52859e3 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -178,6 +178,12 @@ We'll create and test view functions that present our application to the world and we'll provide front-end access to forms that allow us to create, edit and publish blog entries without needing to use the admin. +Along the way we'll learn that the Django template language is quite similar +to the Jinja2 language (in fact, Jinja2 was modelled on the Django version). +We'll also get a chance to learn a bit more about the features that the Django +test framework provides over and above the standard Python ``unittest`` +library. + Finally, we'll discuss some of the strengths and weaknesses of Django. What makes it a good choice for some projects but not for others. diff --git a/source/presentations/session07.rst b/source/presentations/session07.rst index 06095080..8301bf58 100644 --- a/source/presentations/session07.rst +++ b/source/presentations/session07.rst @@ -1721,7 +1721,7 @@ development server: Viewing the Admin ----------------- -Load ``http://localhost:8000/``. You should see this: +Load ``http://localhost:8000/admin/``. You should see this: .. image:: img/django-admin-login.png :align: center diff --git a/source/presentations/week06.rst b/source/presentations/week06.rst index 78c7f8bd..ddf5e09d 100644 --- a/source/presentations/week06.rst +++ b/source/presentations/week06.rst @@ -7,122 +7,6 @@ blah blah blah -Customized Admin ----------------- - -The Django Admin displays ``ModelAdmin`` instances for any models that are -registered - -.. class:: incremental - -* The object ``admin.site`` is a global instance of the ``Admin`` class. -* Each call to ``admin.site.register`` adds a new model to the global *site* -* ``register`` takes two args: a *Model* subclass and a *ModelAdmin* subclass -* If you call it with only the *Model* subclass, the *ModelAdmin* is - automatically generated. -* You can create, and customize, a *ModelAdmin* subclass for your models. - - - - -Create a PollAdmin ------------------- - -In ``admin.py`` add the following code (above the calls to ``register``): - -.. code-block:: python - - class PollAdmin(admin.ModelAdmin): - list_display = ('pub_date', 'question', - 'published_today') - list_filter = ('pub_date', ) - ordering = ('pub_date', ) - -.. class:: incremental - -Then add this new class to the ``register`` call for our ``Poll``: - -.. code-block:: python - :class: incremental - - admin.site.register(Poll, PollAdmin) - -More Convenient Relations -------------------------- - -In our Admin site, you can see the ``Poll`` to which a ``Choice`` belongs. - -.. class:: incremental - -It'd be a lot nicer to be able to manage the ``Choices`` for a ``Poll`` from -the poll admin page, wouldn't it? - -.. class:: incremental - -The Django Admin provides a special type of ``ModelAdmin`` for just this -purpose: The ``InlineModelAdmin``. - -.. class:: incremental - -There are two flavors, *stacked* and *tabular*. The *tabular* version is more -compact as it displays each related object in a single table row. - -Create a Choice Inline ----------------------- - -Add the following code *above* our ``PollAdmin`` class in ``admin.py``: - -.. code-block:: python - - class ChoiceInline(admin.TabularInline): - model = Choice - extra = 3 - ordering = ('choice', ) - -Then, add the inline to ``PollAdmin``: - -.. code-block:: python - - class PollAdmin(admin.ModelAdmin): - # ... - inlines = (ChoiceInline, ) - -Method Attributes for the Admin -------------------------------- - -For example, methods of a class you use in the admin can have special -attributes that alter how it works. Make these changes to ``models.py`` - -.. code-block:: python - - class Poll(models.Model): - ... - def published_today(self): - now = timezone.now() - time_delta = now - self.pub_date - return time_delta.days == 0 - published_today.boolean = True - published_today.short_description = "Published Today?" - - -Reap the Rewards ----------------- - -Good work. You've set up a fully functional CRUD admin interface for your -application database in about 25 lines of code. - -.. class:: incremental - -Play with it for a bit. - -Lab - Part Three ----------------- - -In this part, we'll add public views and set up a way for visitors to vote -in our poll. - -Along the way, we'll learn a bit about Django's *Generic Views* and the -*Django Templating Language* Django Views ------------ From 9ff0c39a7af35326586bb207e36553b0446f5707 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 27 Jul 2013 17:55:51 -0700 Subject: [PATCH 136/487] * add the eighth session presentation --- source/presentations/session08.rst | 848 +++++++++++++++++++++++++++++ 1 file changed, 848 insertions(+) create mode 100644 source/presentations/session08.rst diff --git a/source/presentations/session08.rst b/source/presentations/session08.rst new file mode 100644 index 00000000..d9b41d19 --- /dev/null +++ b/source/presentations/session08.rst @@ -0,0 +1,848 @@ +Internet Programming with Python +================================ + +.. image:: img/django-pony.png + :align: left + :width: 50% + +Session 8: A Django Application + +.. class:: intro-blurb right + +Wherein we complete our Django blog app. + +.. class:: image-credit + +image: http://djangopony.com/ + + +Where We Stand +-------------- + +We've created a couple of models, Post and Category, that make up our blog +app. + +.. class:: incremental + +We've taken some time to get familiar with the basic workings of the Django +ORM. + +.. class:: incremental + +We've made a minor modification to our model classes and written tests for it. + +.. class:: incremental + +And we've installed the Django Admin site and added our app to it. + + +Customizing the Admin +--------------------- + +We have noted, however, that the admin isn't exactly right for our needs. + +.. class:: incremental + +* Listing of posts should show created, modified and published dates +* Listing of posts should show the author of a post, with a link to the author +* The date information for a post should be displayed on the edit page +* It should be possible to add a post to a category while creating or editing + it + +.. class:: incremental small center + +https://docs.djangoproject.com/en/1.5/ref/contrib/admin/ + + +The ModelAdmin Class +-------------------- + +Open ``admin.py`` from your ``myblog`` package. + +.. class:: incremental + +* The ``admin.site`` is a globally available instance of the ``Admin`` class. +* It is initialized at runtime automatically. +* It stores a registry of the models that are registered with it. +* Each call to ``admin.site.register`` adds a new model to the global *site*. +* ``register`` takes two args: a *Model* subclass and an optional *ModelAdmin* subclass +* If you call it without the optional subclass, you get the default. + +.. class:: incremental + +Most usable admin functions are provided by the ModelAdmin. + + +Custom ModelAdmin +----------------- + +Our first task is to list date and author information. + +.. container:: incremental + + In ``admin.py`` add the following code (): + + .. code-block:: python + :class: small + + # this is new + class PostAdmin(admin.ModelAdmin): + list_display = ('__unicode__', 'created_date', 'modified_date', + 'published_date', 'author') + + admin.site.register(Post, PostAdmin) #<- update this registration + +.. class:: incremental + +Let's see what that did. + + +View The Results +---------------- + +If you haven't already, activate your virtualenv then fire up the development +server: + +:: + + (djangoenv)$ python manage.py runserver + +.. class:: incremental + +Load http://localhost:8000/admin and click through to the Post admin. + +.. class:: incremental + +Pretty simple, eh? + + +List Display +------------ + +A Couple of things about the ``list_display`` option are important to know: + +.. class:: incremental + +* The value you provide must be an iterable even if it has only one item +* Each item in the iterable becomes a column in the list +* The first item is the one that links to the change page for that object + + * That can be customized by the ``list_display_links`` option + +* Listed items can be field names or callables. + +* Callables can be module-level functions, or methods on the ModelAdmin or + Model + + +A Better Author Listing +----------------------- + +Let's use this last bit to fix the author listing. + +.. class:: incremental + +We'll need functionality that provides: + +.. class:: incremental + +* The full name of the author, if present, otherwise the username. +* A link to the admin change form for that author. + +.. class:: incremental + +Where should this go? Module? ModelAdmin? Model? + +.. class:: incremental + +* The first could be useful in public listings +* The second is really only useful on the backend + + +Add Tests +--------- + +In ``tests.py`` add the following test: + +.. code-block:: python + :class: small + + class PostTestCase(TestCase): + #... + def test_author_name(self): + for author in User.objects.all(): + fn, ln, un = (author.first_name, + author.last_name, + author.username) + author_name = Post(author=author).author_name() + if not (fn and ln): + self.assertEqual(author_name, un) + else: + if fn: + self.assertTrue(fn in author_name) + if ln: + self.assertTrue(ln in author_name) + + +Add Tests +--------- + +To test the admin, we'll first need a new TestClass: + +.. code-block:: python + :class: small + + # new imports + from django.contrib.admin.sites import AdminSite + from myblog.admin import PostAdmin + + # new TestCase + class PostAdminTestCase(TestCase): + fixtures = ['myblog_test_fixture.json', ] + + def setUp(self): + admin = AdminSite() + self.ma = PostAdmin(Post, admin) + for author in User.objects.all(): + title = "%s's title" % author.username + post = Post(title=title, author=author) + post.save() + + +Add Tests +--------- + +And then we need a test added to it: + +.. code-block:: python + :class: small + + def test_author_link(self): + expected_link_path = '/admin/auth/user/%s' + for post in Post.objects.all(): + expected = expected_link_path % post.author.pk + actual = self.ma.author_link(post) + self.assertTrue(expected in actual) + +.. container:: incremental + + Quit the django server and run your tests: + + .. class:: small + + :: + + (djangoenv)$ python manage.py test myblog + ... + Ran 4 tests in 0.026s + FAILED (errors=2) + + +Make Them Pass +-------------- + +First, add the ``author_name`` method to our Post model in ``models.py``: + +.. code-block:: python + :class: small + + def author_name(self): + raw_name = "%s %s" % (self.author.first_name, + self.author.last_name) + name = raw_name.strip() + if not name: + name = self.author.username + return name + +.. class:: small incremental + +:: + + (djangoenv)$ python manage.py test myblog + ... + Ran 4 tests in 0.027s + FAILED (errors=1) + + +Make Them Pass +-------------- + +Finally, add the ``author_link`` method to the PostAdmin in ``admin.py``: + +.. code-block:: python + :class: small + + # add an import + from django.core.urlresolvers import reverse + + # and a method + class PostAdmin(admin.ModelAdmin): + #... + def author_link(self, post): + url = reverse('admin:auth_user_change', args=(post.id,)) + name = post.author_name() + return '%s' % (url, name) + +.. class:: small incremental + +:: + + (djangoenv)$ python manage.py test myblog + ...Ran 4 tests in 0.035s + OK + + +Hook It Up +---------- + +First, replace the ``'author'`` name in ``list_display`` with +``'author_link'``: + +.. code-block:: python + :class: small + + list_display = (..., 'author_link') + +.. container:: incremental + + We also need to let the admin know our HTML is safe: + + .. code-block:: python + :class: small + + def author_link(self, post): + #... method body + author_link.allow_tags = True + + +Wait, What?? +------------ + +In Python, *everything* is an object. Even methods of classes. + +.. class:: incremental + +The Django admin uses special *method attributes* to control the methods you +create for ``list_display``. + +.. container:: incremental + + Another special attribute controls the column title used in the list page: + + .. code-block:: python + :class: small + + def author_link(self, post): + #... method body + author_link.allow_tags = True + author_link.short_description = "Author" #<- add this + + +See The Results +--------------- + +Start up the Django server again and see what you've done: + +.. class:: small + +:: + + (djangoenv)$ python manage.py runserver + +.. class:: incremental + +Reload your admin site, click on the Post admin and see the new 'Author' +column. + +.. class:: incremental + +* Click on an author name. +* Set the first and last names (if you haven't already). +* Go back to Posts and see the outcome of this change. + +.. class:: incremental + +Not bad, eh? + + +Change Form Fields +------------------ + +Date fields that have ``auto_now`` or ``auto_now_add`` set automatically +become uneditable. + +.. class:: incremental + +Because they are uneditable, the Django Admin leaves them out. + +.. class:: incremental + +We'd like to see them, though. + +.. class:: incremental + +We can use another built-in Admin option to help us: ``readonly_fields`` + + +Update PostAdmin +---------------- + +Again, in ``admin.py`` let's add the following to our PostAdmin class: + +.. code-block:: python + :class: small + + class PostAdmin(admin.ModelAdmin): + list_display = (...) + readonly_fields = ('created_date', 'modified_date') + #... + +.. class:: incremental + +Reload the Admin and click on a single post. Did that work? + +.. class:: incremental + +Add a new post and look at the form. How do those fields look? + + +Hide Fields on Add +------------------ + +Our readonly fields really shouldn't be there when we add a new object. + +.. class:: incremental + +ModelAdmin provides a hook to customize this: ``get_readonly_fields``. + +.. class:: incremental + +Overriding this is altering standard functionality, so let's add a test +proving: + +.. class:: incremental + +* If we load the form to add a post, we don't see these fields +* If we load the form to edit a post, we do. + + +Add A Test +---------- + +In our PostAdminTestCase class, add: + +.. code-block:: python + :class: small + + # add this to the setUp() method: + def setUp(self): + #... + self.client.login(username='admin', password='secret') + + # and add a new test method: + def test_readonly_fields_in_page(self): + readonly_fields = self.ma.readonly_fields + add_resp = self.client.get('/admin/myblog/post/add/') + for fieldname in readonly_fields: + self.assertFalse(fieldname in add_resp.content) + for post in Post.objects.all(): + edit_resp = self.client.get('/admin/myblog/post/%d/' % post.pk) + for fieldname in readonly_fields: + self.assertTrue(fieldname in edit_resp.content) + + +Run The Test +------------ + +We're using the test client. Django provides this automatically on TestCase +subclasses. + +.. container:: incremental + + Quit the django browser and run your tests: + + .. class:: small + + :: + + (djangoenv)$ python manage.py test myblog + ... + ---------------------------------------------------------------------- + Ran 5 tests in 0.302s + + FAILED (failures=1) + + +Make It Pass +------------ + +.. container:: incremental + + Override ``get_readonly_fields`` on the PostAdmin class: + + .. code-block:: python + :class: small incremental + + def get_readonly_fields(self, request, obj=None): + fields = () + # if there is no object, we must be adding a new post + # otherwise we are editing one that exists. + if obj is not None: + fields = self.readonly_fields + return fields + +.. class:: incremental small + +:: + + (djangoenv)$ python manage.py test myblog + ... + Ran 5 tests in 0.364s + OK + + +Categorize Posts +---------------- + +We'd like to be able to add categories to posts while adding or editing them. + +.. class:: incremental + +But there is no field on the ``Post`` model that would show them. + +.. class:: incremental + +Django provides the concept of an ``inline`` form to allow adding objects that +are related when there is no field available. + +.. class:: incremental + +In the Django Admin, these are created using subclasses of the +``InlineAdmin``. + + +Create an Inline Admin +---------------------- + +In ``admin.py`` add the following code *above* the definition of PostAdmin: + +.. code-block:: python + :class: small + + class CategoryInlineAdmin(admin.TabularInline): + model = Category.posts.through + extra = 1 + +.. container:: incremental + + And then add one line to the PostAdmin class definition: + + .. code-block:: python + :class: small + + class PostAdmin(admin.ModelAdmin): + #... other options + inlines = [CategoryInlineAdmin, ] + + #... methods + +Try It Out +---------- + +Restart the Django server and see what you've done: + +.. class:: small + +:: + + (djangoenv)$ python manage.py runserver + +.. class:: incremental + +Note that you can even add *new* categories via the inline form. + +.. class:: incremental + +But, in the form for a category, you see the field for Post. That shouldn't be +there. + + +A Final Tweak +------------- + +See if you can figure out how to remove the ``posts`` field from the +CategoryAdmin. + +.. code-block:: python + :class: small incremental + + # create a custom model admin class + class CategoryAdmin(admin.ModelAdmin): + exclude = ('posts', ) + + # and register Category to use it in the Admin + admin.site.register(Category, CategoryAdmin) + + +PLACEHOLDER +----------- + +Do we have time to do an admin action here? if so, add actions to publish, +unpublish items in bulk + + +A Public Face +------------- + +Point your browser at http://localhost:8000/ + +.. class:: incremental + +What do you see? + +.. class:: incremental + +Why? + +.. class:: incremental + +We need to add some public pages for our blog. + +.. class:: incremental + +In Django, the code that builds a page that you can see is called a *view*. + +Django Views +------------ + +A *view* can be defined as a *callable* that takes a request and returns a +response. + +.. class:: incremental + +This should sound pretty familiar to you. + +.. class:: incremental + +Classically, Django views were functions. + +.. class:: incremental + +Version 1.3 added support for Class-based Views (a class with a ``__call__`` +method is a callable) + + +A Basic View +------------ + +Let's add a really simple view to our app. + +.. class:: incremental + +It will be a stub for our public UI. Add this to ``views.py`` in ``myblog`` + +.. code-block:: python + :class: small incremental + + from django.http import HttpResponse + + def stub_view(request, *args, **kwargs): + body = "Stub View\n\n" + if args: + body += "Args:\n" + body += "\n".join(["\t%s" % a for a in args]) + if kwargs: + body += "Kwargs:\n" + body += "\n".join(["\t%s: %s" % i for i in kwargs.items()]) + return HttpResponse(body, content_type="text/plain") + + +Hooking It Up +------------- + +We talked in the previous session about the Django urlconf + +.. class:: incremental + +We used our project urlconf to hook the Django admin into our project. + +.. class:: incremental + +We want to do the same thing for our new app. + +.. class:: incremental + +In general, an *app* that serves any sort of views should contain its own +urlconf. + +.. class:: incremental + +The project urlconf should mainly *include* these where possible. + + +Adding A Urlconf +---------------- + +Create a new file ``urls.py`` inside the ``myblog`` app package. + +.. container:: incremental + + Open it in your editor and add the following code: + + .. code-block:: python + :class: small + + from django.conf.urls import patterns, url + + urlpatterns = patterns('myblog.views', + url(r'^$', + 'stub_view', + name="blog_index"), + ) + + +Include Blog Urls +----------------- + +In order for our new urls to load, we'll need to include them in our project +urlconf + +.. container:: incremental + + Open ``urls.py`` from the ``mysite`` project package and add this: + + .. code-block:: python + :class: small + + urlpatterns = patterns('', + url(http://github.com/r'%5E',%20include('myblog.urls')), #<- add this + #... other included urls + ) + +.. class:: incremental + +Try reloading http://localhost:8000/ + +.. class:: incremental + +You should see some output now. + + +A Word On Prefixes +------------------ + +The ``patterns`` function takes a first argument called the *prefix* + +.. class:: incremental + +When it is not empty, it is added to any view names in ``url()`` calls in the +same ``patterns``. + +.. class:: incremental + +In a root urlconf like the one in ``mysite``, this isn't too useful + +.. class:: incremental + +But in ``myblog.urls`` it lets us refer to views by simple function name + +.. class:: incremental + +No need to import every view. + + +Project URL Space +----------------- + +A project is defined by the urls a user can visit. + +.. class:: incremental + +What should our users be able to see when they visit our blog? + +.. class:: incremental + +* A list view that shows blog posts, most recent first. +* An individual post view, showing a single post (a permalink). +* An archive view that shows all posts for a year, or a month within a year. +* A category view that shows all posts in a given category. + +.. class:: incremental + +Let's add urls for each of these, use the stub view for now. + + +Our URLs +-------- + +We've already got a good url for the list page: ``blog_index`` at '/' + +.. container:: incremental + + For the view of a single post, we'll need to capture the id of the post. + Add this to ``urlpatterns``: + + .. code-block:: python + :class: small incremental + + url(http://github.com/r'%5Eposts/(/d+)/$', + 'stub_view', + name="blog_detail"), + +.. class:: incremental + +``(\d+)`` captures one or more digits as the post_id. + +.. class:: incremental + +Load http://localhost:8000/posts/1234/ and see what you get. + + +A Word on Capture in URLs +------------------------- + +When you load the above url, you should see ``1234`` listed as an *arg* + +.. container:: incremental + + Try changing the regexp like so: + + .. code-block:: python + :class: small + + r'^posts/(?P\d+)/$' + +.. class:: incremental + +Reload the same url. Notice the change. + +.. class:: incremental + +How you declare a capture group in your url pattern regexp influenced how it +will be passed to the view callable. + + +Archive View URLs +----------------- + +Consider our archive requirement. + +.. container:: incremental + + Can you think of a way to use one view for that? + + .. code-block:: python + :class: small incremental + + url(http://github.com/r'%5Earchive/(?P%3Cyear%3E[\d]{4})/$', + 'stub_view', #<- this can be the same view + name="yearly_archive"), + url(http://github.com/r'%5Earchive/(?P%3Cyear%3E[\d]{4})/(?P[\d]{2})/$', + 'stub_view', #<- in multiple urls + name="monthly_archive"), + +.. class:: incremental + +In this case, month is *optional*, so it **must** be a kwarg + + From e55cf951281abfcad25ad8cdda973808a3352316 Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 28 Jul 2013 01:11:36 -0700 Subject: [PATCH 137/487] fix up a bit of session 07 complete session 08, for some definition of 'complete' --- source/presentations/session07.rst | 2 +- source/presentations/session08.rst | 878 ++++++++++++++++++++++++----- source/presentations/week06.rst | 184 ------ 3 files changed, 730 insertions(+), 334 deletions(-) diff --git a/source/presentations/session07.rst b/source/presentations/session07.rst index 8301bf58..9b43e029 100644 --- a/source/presentations/session07.rst +++ b/source/presentations/session07.rst @@ -957,7 +957,7 @@ South supports forward, backward and data migrations. .. class:: incremental -We'll learn a bit more about this in our next session. +We won't have time to cover it in this class, but know it's there. Break Time diff --git a/source/presentations/session08.rst b/source/presentations/session08.rst index d9b41d19..02618b3c 100644 --- a/source/presentations/session08.rst +++ b/source/presentations/session08.rst @@ -45,7 +45,6 @@ We have noted, however, that the admin isn't exactly right for our needs. * Listing of posts should show created, modified and published dates * Listing of posts should show the author of a post, with a link to the author -* The date information for a post should be displayed on the edit page * It should be possible to add a post to a category while creating or editing it @@ -365,142 +364,6 @@ column. Not bad, eh? -Change Form Fields ------------------- - -Date fields that have ``auto_now`` or ``auto_now_add`` set automatically -become uneditable. - -.. class:: incremental - -Because they are uneditable, the Django Admin leaves them out. - -.. class:: incremental - -We'd like to see them, though. - -.. class:: incremental - -We can use another built-in Admin option to help us: ``readonly_fields`` - - -Update PostAdmin ----------------- - -Again, in ``admin.py`` let's add the following to our PostAdmin class: - -.. code-block:: python - :class: small - - class PostAdmin(admin.ModelAdmin): - list_display = (...) - readonly_fields = ('created_date', 'modified_date') - #... - -.. class:: incremental - -Reload the Admin and click on a single post. Did that work? - -.. class:: incremental - -Add a new post and look at the form. How do those fields look? - - -Hide Fields on Add ------------------- - -Our readonly fields really shouldn't be there when we add a new object. - -.. class:: incremental - -ModelAdmin provides a hook to customize this: ``get_readonly_fields``. - -.. class:: incremental - -Overriding this is altering standard functionality, so let's add a test -proving: - -.. class:: incremental - -* If we load the form to add a post, we don't see these fields -* If we load the form to edit a post, we do. - - -Add A Test ----------- - -In our PostAdminTestCase class, add: - -.. code-block:: python - :class: small - - # add this to the setUp() method: - def setUp(self): - #... - self.client.login(username='admin', password='secret') - - # and add a new test method: - def test_readonly_fields_in_page(self): - readonly_fields = self.ma.readonly_fields - add_resp = self.client.get('/admin/myblog/post/add/') - for fieldname in readonly_fields: - self.assertFalse(fieldname in add_resp.content) - for post in Post.objects.all(): - edit_resp = self.client.get('/admin/myblog/post/%d/' % post.pk) - for fieldname in readonly_fields: - self.assertTrue(fieldname in edit_resp.content) - - -Run The Test ------------- - -We're using the test client. Django provides this automatically on TestCase -subclasses. - -.. container:: incremental - - Quit the django browser and run your tests: - - .. class:: small - - :: - - (djangoenv)$ python manage.py test myblog - ... - ---------------------------------------------------------------------- - Ran 5 tests in 0.302s - - FAILED (failures=1) - - -Make It Pass ------------- - -.. container:: incremental - - Override ``get_readonly_fields`` on the PostAdmin class: - - .. code-block:: python - :class: small incremental - - def get_readonly_fields(self, request, obj=None): - fields = () - # if there is no object, we must be adding a new post - # otherwise we are editing one that exists. - if obj is not None: - fields = self.readonly_fields - return fields - -.. class:: incremental small - -:: - - (djangoenv)$ python manage.py test myblog - ... - Ran 5 tests in 0.364s - OK - - Categorize Posts ---------------- @@ -546,6 +409,7 @@ In ``admin.py`` add the following code *above* the definition of PostAdmin: #... methods + Try It Out ---------- @@ -764,7 +628,6 @@ What should our users be able to see when they visit our blog? * A list view that shows blog posts, most recent first. * An individual post view, showing a single post (a permalink). -* An archive view that shows all posts for a year, or a month within a year. * A category view that shows all posts in a given category. .. class:: incremental @@ -822,27 +685,744 @@ How you declare a capture group in your url pattern regexp influenced how it will be passed to the view callable. -Archive View URLs +Category View URL ----------------- -Consider our archive requirement. +Try writing the URL pattern for the category view on your own. .. container:: incremental - Can you think of a way to use one view for that? + My version looks like this: .. code-block:: python - :class: small incremental + :class: small - url(http://github.com/r'%5Earchive/(?P%3Cyear%3E[\d]{4})/$', - 'stub_view', #<- this can be the same view - name="yearly_archive"), - url(http://github.com/r'%5Earchive/(?P%3Cyear%3E[\d]{4})/(?P[\d]{2})/$', - 'stub_view', #<- in multiple urls - name="monthly_archive"), + url(http://github.com/r'%5Ecategory/(?P%3Ccategory_id%3E\d+)/$', + 'stub_view', + name="category_view"), + +.. class:: incremental + +At this point, we should have three url patterns in our urlconf + + +Full Urlconf +------------ + +.. code-block:: python + :class: small + + from django.conf.urls import patterns, url + + urlpatterns = patterns('myblog.views', + url(r'^$', + 'stub_view', + name="blog_index"), + url(http://github.com/r'%5Eposts/(?P%3Cpost_id%3E\d+)/$', + 'stub_view', + name="blog_detail"), + url(http://github.com/r'%5Ecategory/(?P%3Ccategory_id%3E\d+)/$', + 'stub_view', + name="category_view") + ) + + +Testing Views +------------- + +Before we begin, we need to add some tests for the views we are about to +create. + +.. class:: incremental + +We'll need tests for a list view, a detail view and a category view + +.. class:: incremental + +To save us time, I've written these tests already .. class:: incremental -In this case, month is *optional*, so it **must** be a kwarg +You can find them in the class resources directory: ``blog_view_tests.py`` + +.. class:: incremental + +Copy the TestCase and imports from that file into our blog ``tests.py`` file. + + +Run The Tests +------------- + +:: + + (djangoenv)$ python manage.py test myblog + ... + ---------------------------------------------------------------------- + Ran 8 tests in 0.478s + + FAILED (failures=3) + Destroying test database for alias 'default'... + + +Our First View +-------------- + +Add the view for listing blog posts to ``views.py``. + +.. code-block:: python + :class: small + + # add these imports + from django.template import RequestContext, loader + from myblog.models import Post + + # and this view + def list_view(request): + published = Post.objects.exclude(published_date__exact=None) + posts = published.order_by('-published_date') + template = loader.get_template('list.html') + context = RequestContext(request, { + 'posts': posts, + }) + body = template.render(context) + return HttpResponse(body, content_type="text/html") + + +Getting Posts +------------- + +.. code-block:: python + :class: small + + published = Post.objects.exclude(published_date__exact=None) + posts = published.order_by('-published_date') + +.. class:: incremental + +We begin by using the QuerySet API to fetch all the posts that have +``published_date`` set + +.. class:: incremental + +Using the chaining nature of the API we order these posts by +``published_date`` + +.. class:: incremental + +Remember, at this point, no query has actually been issued to the database. + + +Getting a Template +------------------ + +.. code-block:: python + :class: small + + template = loader.get_template('list.html') + +.. class:: incremental + +Django uses configuration to determine how to find templates. + +.. class:: incremental + +By default, Django looks in installed *apps* for a ``templates`` directory + +.. class:: incremental + +It also provides a place to list specific directories. + +.. class:: incremental + +Let's set that up in ``settings.py`` + + +Project Templates +----------------- + +In ``settings.py`` find ``TEMPLATE_DIRS`` and add the absolute path to your +``mysite`` project package: + +.. code-block:: python + :class: small + + TEMPLATE_DIRS = ('/absolute/path/to/mysite/mysite/templates', ) + +.. class:: incremental + +Then add a ``templates`` directory to your ``mysite`` project package + +.. class:: incremental + +Finally, in that directory add a new file ``base.html`` and populate it with +the following: + + +base.html +--------- + +.. code-block:: jinja + :class: small + + + + + My Django Blog + + +

    +
    + {% block content %} + [content will go here] + {% endblock %} +
    +
    + + + + +Templates in Django +------------------- + +Before we move on, a quick word about Django templates. + +.. class:: incremental + +We've seen Jinja2 which was "inspired by Django's templating system". + +.. class:: incremental + +Basically, you already know how to write Django templates. + +.. class:: incremental + +Django templates **do not** allow any python expressions. + +.. class:: incremental center small + +https://docs.djangoproject.com/en/1.5/ref/templates/builtins/ + + +Blog Templates +-------------- + +Our view tries to load ``list.html``. + +.. class:: incremental + +This template is probably specific to the blog functionality of our site + +.. class:: incremental + +It is common to keep shared templates in your project directory and +specialized ones in app directories. + +.. class:: incremental + +Add a ``templates`` directory to your ``myblog`` app, too. + +.. class:: incremental + +In it, create a new file ``list.html`` and add this: + + +list.html +--------- + +.. code-block:: jinja + :class: tiny + + {% extends "base.html" %} + + {% block content %} +

    Recent Posts

    + + {% comment %} here is where the query happens {% endcomment %} + {% for post in posts %} +
    +

    {{ post }}

    + +
    + {{ post.text }} +
    +
      + {% for category in post.categories.all %} +
    • {{ category }}
    • + {% endfor %} +
    +
    + {% endfor %} + {% endblock %} + + +Template Context +---------------- + +.. code-block:: python + :class: small + + context = RequestContext(request, { + 'posts': posts, + }) + body = template.render(context) + +.. class:: incremental + +Like Jinja2, django templates are rendered by passing in a *context* + +.. class:: incremental + +Django's RequestContext provides common bits, similar to the global context in +Flask + +.. class:: incremental + +We add our posts to that context so they can be used by the template. + + +Return a Response +----------------- + +.. code-block:: python + :class: small + + return HttpResponse(body, content_type="text/html") + +.. class:: incremental + +Finally, we build an HttpResponse and return it. + +.. class:: incremental + +This is, fundamentally, no different from the ``stub_view`` just above. + + +Fix URLs +-------- + +We need to fix the url for our blog index page + +.. container:: incremental + + Update ``urls.py`` in ``myblog``: + + .. code-block:: python + :class: small + + url(r'^$', + 'list_view', + name="blog_index"), + +.. class:: incremental small + +:: + + (djangoenv)$ python manage.py test myblog + ... + Ran 8 tests in 0.494s + FAILED (failures=2) + + +Common Patterns +--------------- + +This is a common pattern in Django views: + +.. class:: incremental + +* get a template from the loader +* build a context, usually using a RequestContext +* render the template +* return an HttpResponse + +.. class:: incremental + +So common in fact that Django provides two shortcuts for us to use: + +.. class:: incremental + +* ``render(request, template[, ctx][, ctx_instance])`` +* ``render_to_response(template[, ctx][, ctx_instance])`` + + +Shorten Our View +---------------- + +Let's replace most of our view with the ``render`` shortcut + +.. code-block:: python + :class: small + + # replace RequestContext and loader import + from django.shortcuts import render + + # rewrite our view + def list_view(request): + published = Post.objects.exclude(published_date__exact=None) + posts = published.order_by('-published_date') + context = {'posts': posts} + return render(request, 'list.html', context) + +.. class:: incremental + +Remember though, all we did manually before is still happening + + +Detail View +----------- + +Next, let's write a view function for the detail view of a post + +.. container:: incremental + + It should have the following signature: + + .. code-block:: python + :class: small + + detail_view(request, post_id) + +.. class:: incremental + +We will call the template ``detail.html`` + +.. class:: incremental + +Let's start with the code in ``views.py`` + + +detail_view +----------- + +.. code-block:: python + :class: incremental small + + def detail_view(request, post_id): + published = Post.objects.exclude(published_date__exact=None) + try: + post = published.get(pk=post_id) + except Post.DoesNotExist: + raise Http404 + context = {'post': post} + return render(request, 'detail.html', context) + +.. class:: incremental + +All models raise a DoesNotExist exception if ``get`` returns nothing. + +.. class:: incremental + +We can use that fact to raise a Not Found exception. + +.. class:: incremental + +Django will handle the rest for us. + + +detail.html +----------- + +.. code-block:: jinja + :class: small + + {% extends "base.html" %} + + {% block content %} + Home +

    {{ post }}

    + +
    + {{ post.text }} +
    +
      + {% for category in post.categories.all %} +
    • {{ category }}
    • + {% endfor %} +
    + {% endblock %} + + +Hook it Up +---------- + +In order to view a single post, we'll need a link from the list view + +.. container:: incremental + + We can use the ``url`` template tag (like flask url_for): + + .. code-block:: jinja + :class: small + + {% url '' arg1 arg2 %} + +.. class:: incremental + +In our ``list.html`` template, let's link the post titles: + +.. code-block:: jinja + :class: small incremental + + {% for post in posts %} +
    +

    + {{ post }} +

    + ... + + +Fix URLs +-------- + +Again, we need to insert our new view into the existing ``urls.py`` in +``myblog``: + +.. code-block:: python + :class: small + + url(http://github.com/r'%5Eposts/(?P%3Cpost_id%3E\d+)/$', + 'detail_view', + name="blog_detail"), + +.. class:: incremental small + +:: + + (djangoenv)$ python manage.py test myblog + ... + Ran 8 tests in 0.513s + FAILED (failures=1) + + +A Moment To Play +---------------- + +We've got some good stuff to look at now. Fire up the server + +.. class:: incremental + +Reload your blog index page and click around a bit. + +.. class:: incremental + +You can now move back and forth between list and detail view. + +.. class:: incremental + +Try loading the detail view for a post that doesn't exist + + +Category Lists +-------------- + +Let's implement the category listing next + +.. class:: incremental + +Before we do so, make sure you have added categories to any posts you've +created. + +.. class:: incremental + +Go to http://localhost:8000/admin/ and make sure: + +.. class:: incremental + +* you have at least three or four posts +* each post is in one or more categories +* at least one category has more than one post + + +Category View +------------- + +The view should have the following signature: + +.. code-block:: python + :class: small + + category_view(request, category_id): + +.. class:: incremental + +We can re-use the ``list.html`` template with some minor modifications + +.. class:: incremental + +Let's start by adding view code to ``views.py`` + + +category_view +------------- + +.. code-block:: python + :class: small incremental + + # add an import + from myblog.models import Category + + # and this function + def category_view(request, category_id): + try: + category = Category.objects.get(pk=category_id) + except Category.DoesNotExist: + raise Http404 + published = category.posts.exclude(published_date__exact=None) + context = { + 'posts': published.order_by('-published_date'), + 'title': "Posts in %s" % category.name, + 'description': category.description + } + return render(request, 'list.html', context) + + +Backport Changes +---------------- + +We've added two new items to the template context + +.. class:: incremental + +Let's update ``list.html`` to use ``title`` and ``description`` + +.. code-block:: jinja + :class: small incremental + + {% block content %} +

    {{ title }}

    +

    {{ description }}

    + +.. container:: incremental + + Also go back and update the template context in ``list_view`` + + .. code-block:: jinja + :class: small + + context = {'posts': posts, 'title': 'Recent Posts', + 'description': ''} + + +Hook It Up +---------- + +To view a category, we'll need to link categories to in templates to this view + +.. class:: incremental + +Again, use the ``url`` template tag + +.. class:: incremental + +The categories for a post are listed in both ``list.html`` and ``detail.html`` + +.. class:: incremental + +Add links to both places now. + + +My Version +---------- + +.. code-block:: jinja + :class: small incremental + + # in both templates +
      + {% for category in post.categories.all %} +
    • + + {{ category }} +
    • + {% endfor %} +
    + +.. class:: incremental + + +Fix URLs +-------- + +Substitute the view name ``category_view`` into ``urls.py``: + +.. code-block:: python + :class: small + + url(http://github.com/r'%5Ecategory/(?P%3Ccategory_id%3E\d+)/$', + 'category_view', + name="category_view") + +.. class:: incremental + +:: + + (djangoenv)$ python manage.py test myblog + ... + Ran 8 tests in 0.547s + OK + + +Congratulations +--------------- + +You've got a functional Blog + +.. class:: incremental + +It's not very pretty, though. + +.. class:: incremental + +We can fix that by adding some css + +.. class:: incremental + +This gives us a chance to learn about Django's handling of *static files* + + +Static Files +------------ + +Like templates, Django expects to find static files in particular locations + +.. class:: incremental + +It will look for them in a directory named ``static`` in any installed apps. + +.. class:: incremental + +They will be served from the url path in the STATIC_URL setting. + +.. class:: incremental + +By default, this is ``/static/`` + + +Add CSS +------- + +I've prepared a css file for us to use. You can find it in the class resources + +.. class:: incremental + +Create a new directory ``static`` in the ``myblog`` app. + +.. class:: incremental + +Copy the ``django_css`` file into that new directory. + +.. container:: incremental + + Then add this link to the of ``base.html``: + + .. code-block:: html + :class: small + + My Django Blog + diff --git a/source/presentations/week06.rst b/source/presentations/week06.rst index ddf5e09d..b8b5a8ce 100644 --- a/source/presentations/week06.rst +++ b/source/presentations/week06.rst @@ -8,190 +8,6 @@ blah blah blah -Django Views ------------- - -Django views are callables that take a request and return a response. - -.. class:: incremental - -From the beginning, these have been functions. They still can be. - -.. class:: incremental - -Version 1.3 added support for Class-based Views. - -.. class:: incremental - -Really, they've always been there implicitly. The Admin is just a big -class-based view. - -Generic Views -------------- - -One of the most common uses for Class-based Views is in creating Generic Views. - -.. class:: incremental - -Some public views are so common that providing a simple and generic interface -for making them is a big win. - -.. class:: incremental - -* Showing a list of objects of some type. -* Showing the details of a single object of some type. -* Displaying a static HTML template (or a template with some dynamic context) -* Displaying and processing a simple HTML form. - -Our Application ---------------- - -We'd like to be able to add some views that show our polls to the public. - -.. class:: incremental - -What views would we like to have? - -.. class:: incremental - -* A list of all polls, perhaps ordered by publication date -* A display of a single poll, showing each choice and allowing a vote -* A view that processes a vote -* A view that shows the poll results after you vote. - -.. class:: incremental - -I start by configuring my URLs, it helps me think about the app API. - -Configure URLs --------------- - -In your ``polls`` app package, add a new file: ``urls.py``. Open it in an -editor: - -.. code-block:: python - :class: incremental small - - from django.conf.urls import patterns, url - from django.http import HttpResponse - - def stub(request, *args, **kwargs): - return HttpResponse('stub view', mimetype="text/plain") - - urlpatterns = patterns('', - url(http://github.com/r'%5E"),%20stub,%20name=%22poll_list"), - url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/$', stub, name="poll_detail"), - url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/vote/$' stub, name="poll_vote"), - url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/result/$', stub, name="poll_result"), - ) - -Hook URLs to the Root ---------------------- - -Like with the Django Admin, we can now add all the urls for our poll app at -once. - -.. class:: incremental - -In the ``urls.py`` in our ``mysite`` project package, add the following: - -.. code-block:: python - :class: incremental small - - urlpatterns = patterns('', - url(http://github.com/r'%5Eadmin/',%20include(admin.site.urls)), - url(http://github.com/r'%5Epolls/',%20include('polls.urls')), # ADD - ) - -.. class:: incremental - -Restart the development server and load ``http://localhost:8000/polls/`` - -Generic Poll List ------------------ - -Django's Generic Views allow you to do quite a lot with just a little code. -Edit ``urls.py``: - -.. code-block:: python - :class: incremental small - - # add this import - from django.views.generic import ListView - - # edit the url pattern for the poll list: - url(r'^$', - ListView.as_view( - queryset=Poll.objects.order_by('-pub_date')[:5], - context_object_name='polls', - template_name="polls/list.html" - ), - name="poll_list"), - -.. class:: incremental - -Now, we just need to make that template - -Django Templates ----------------- - -The `Django Template Language -`_ looks a *lot* like -Jinja2. It is, however, quite a bit more limited. - -.. class:: incremental - -* variables available in context may be printed with ``{{ name }}`` -* variables that are objects or dictionaries may be addressed with dots: ``{{ - name.attr }}`` -* *filters* are available and look the same ``{{ name|upper }}`` -* logical *tags*: ``{% for x in y %}{{ x }}{% endfor %}`` -* available filters and tags may be extended with custom code -* templates can be *extended* and *included* -* you may define *blocks* in templates to be filled by other templates. -* you **may not** execute arbitrary python or assign variables and use them - -Setting Up ----------- - -In ``assignments/week06/lab/source`` you'll find a file ``base.html``. - -.. class:: incremental - -Create a new directory, ``templates`` in your ``polls`` app package. - -.. class:: incremental - -Copy the ``base.html`` file into that new directory. - -.. class:: incremental - -Next, create a folder ``polls`` *inside* that new templates directory. We'll -add our individual templates here. - -List Template -------------- - -Add ``list.html`` inside ``templates/polls``: - -.. code-block:: django - :class: small - - {% extends "base.html" %} - - {% block content %} -

    Latest Polls

    - {% for poll in polls %} - - {% endfor %} - {% endblock %} - -.. class:: incremental - -Now, load ``http://localhost:8000/polls/`` again. - Detail View ----------- From d3a94b9913cd41a6496c098b0107088f739365ca Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 28 Jul 2013 01:23:04 -0700 Subject: [PATCH 138/487] removing files we won't be using at all --- source/presentations/week09.rst | 618 -------------------------------- source/presentations/week10.rst | 341 ------------------ 2 files changed, 959 deletions(-) delete mode 100644 source/presentations/week09.rst delete mode 100644 source/presentations/week10.rst diff --git a/source/presentations/week09.rst b/source/presentations/week09.rst deleted file mode 100644 index 7c170b09..00000000 --- a/source/presentations/week09.rst +++ /dev/null @@ -1,618 +0,0 @@ -Internet Programming with Python -================================ - -.. image:: img/cloud_cover.jpg - :align: left - :width: 50% - -Week 9: The Cloud - -.. class:: intro-blurb right - -| Every cloud has its silver lining -| but it is sometimes a little difficult -| to get it to the mint. -| --Don Marquis - - -.. class:: image-credit - -image: mnsc http://www.flickr.com/photos/mnsc/2768391365/ - CC-BY - -Deployment ----------- - -You've built your app, tested it, now it's time to *go live* - -.. class:: incremental - -What are your options? - -.. class:: incremental center - -**It Depends** - -The Traditional Way --------------------- - -In the old days™ you had one option - -.. class:: incremental - -Buy a server, build it and host it yourself - -.. class:: incremental - -You have total control - -.. class:: incremental small - -* buy exactly the hardware you want -* run only the services you need - -.. class:: incremental - -You *also* have total responsibility - -.. class:: incremental small - -* when something breaks, you have to fix it -* you bear *all* the costs yourself - -Traditional Drawbacks ---------------------- - -Expensive - -.. class:: incremental - -* Server-class hardware $2k-$10k or more -* Systems Administrator $90K/year - -.. class:: incremental - -Inefficient - -.. class:: incremental - -* Most web sites don't get enough traffic to tax a good server -* Web traffic tends to be assymetrical -* Systems administration tasks also highly assymetrical - -.. class:: incremental - -A problem of resource utilization - -The First Solution ------------------- - -VPS (*Virtual Private Server*) - -.. class:: incremental - -A part of a server (or perhaps an entire server) purchased from a provider. - -.. class:: incremental - -You pay for only a portion of a server and a portion of a systems -administrator. - -.. class:: incremental - -You retain control of the system - -.. class:: incremental - -You also retain responsibility for everything above the bare iron. - -VPS Outcomes ------------- - -Benefits - -.. class:: incremental - -* Reduced cost ($30-$100+/month vs server and salary) -* Reduced burden (The provider handles hardware upkeep and low-level - maintenance) -* Retain control of your full software stack - -.. class:: incremental - -Drawbacks - -.. class:: incremental - -* You install and maintain the web stack (requires knowledge) -* You lose control over resource utilization -* Your resources are still fixed (always the same size) - -The Second Solution -------------------- - -Shared Hosting - -.. class:: incremental - -You pay a provider to set you up with a [django/flask/pyramid/etc.] system. - -.. class:: incremental - -Hardware and most software maintenance is provided - -.. class:: incremental - -You are able to install some (but perhaps not all) add-ons - -.. class:: incremental - -This solution is very popular in the PHP world - -.. class:: incremental - -Much less so with Python. Why?... - -Shared Hosting Outcomes ------------------------ - -Benefits - -.. class:: incremental - -* Enormously less expensive ($5-$15+/month) -* Much lower maintenance burden -* Simplified installation process - -.. class:: incremental - -Drawbacks - -.. class:: incremental - -* Tight resource restrictions (cpu, ram, disk space) -* Little to no control over most of the stack -* Reduced availability of some frameworks or packages - -.. class:: incremental - -And still, no ability to grow if you need - -The Third Solution ------------------- - -.. class:: big-centered incremental - -**The Cloud** - -.. class:: incremental center small - -(*cue fanfare*) - -The Cloud Concept ------------------ - -You don't know today what you will need tomorrow - -.. class:: incremental - -Today your website is getting 100-500 unique visitors - -.. class:: incremental - -Tomorrow you might have 10,000, 100,000. Who knows? - -.. class:: incremental - -Should you have to buy enough hardware to handle that traffic today? - -.. class:: incremental - -Cloud computing offers rapid deployment solutions so you can scale at will - -What is 'the Cloud'? --------------------- - -Really, it differs from place to place. - -.. class:: incremental - -Some are more do-it-yourself (Amazon EC2, Rackspace Cloud) - -.. class:: incremental - -Some are more automated (Heroku, Elastic Beanstalk, AppEngine) - -.. class:: incremental - -All try to abstract common deployment tasks to make it easy to repeat - -.. class:: incremental - -So, how does that work? - -Fabric ------- - -Fabric is *not* a cloud service. Instead, it's a tool built to help developers -simplify the process of deploying complex apps to a server. - -.. class:: incremental - -It can be used in any setup where you have ``ssh`` access to the filesystem -of the remote server. - -.. class:: incremental - -Your classmate Austin used it a couple of weeks back to deploy Django to his -bluebox VM. - -.. class:: incremental - -Today, he's going to share that experience with you... - -Heroku ------- - -.. image:: img/heroku-logo.png - :align: center - :width: 50% - -.. class:: incremental center - -I tried a number of cloud providers - -.. class:: incremental center - -This was hands-down the easiest. - -Heroku - Sign-up ----------------- - -You'll need a Heroku account to do anything, so the first step is to get that - -.. class:: incremental - -Go to http://www.heroku.com - -.. class:: incremental - -Click on 'Sign Up' and enter your email address - -.. class:: incremental - -When the email arrives, click the link and create your password - -.. class:: incremental - -Once you've signed up, you'll see your 'dashboard' page with tips on getting -started. - -Heroku - Setup --------------- - -Like pretty much all the 'cloud' providers out there, Heroku has some -command-line tools you need to use. - -.. class:: incremental - -You can find them at https://toolbelt.heroku.com/ - -.. class:: incremental - -Download and install the package, and then login: - -.. class:: incremental - -:: - - $ heroku login - Email: your-email@your.domain.com - Password: - -.. class:: incremental - -The tool will find, or help you create, an ssh public key - -Heroku - Branch my App ----------------------- - -As an exercise, I decided to deploy the *djangor* micro-blog app we created in -class. - -.. class:: incremental - -The first step was to clone the app, then create a local branch for deployment: - -.. class:: incremental small - -:: - - $ mkdir heroku-test - $ cd heroku-test - $ git clone git@github.com:cewing/training.django_microblog.git - ... - $ cd training.django_microblog - $ git checkout -b heroku-deploy - Switched to a new branch 'heroku-deploy' - $ - -Heroku - Setup Virtualenv -------------------------- - -Again, like many cloud providers Heroku uses virtualenvs to ensure it's -installed correctly - -.. class:: incremental - -I set up a python 2.7 virtualenv right in my git repository: - -.. class:: incremental small - -:: - - $ ~/pythons/bin/virtualenv-2.7 --distribute venv - ... - $ source venv/bin/activate - (venv)$ - -.. class:: incremental - -I don't want to check that virtualenv into git, so I add ``venv`` to my -.gitignore file. - -.. class:: incremental - -That way, git will ignore that directory and everything in it. - -Heroku - Install Dependencies ------------------------------ - -For Heroku to work, it needs to know what packages you'll need installed. - -.. class:: incremental - -We can use ``pip`` to take care of this: - -.. class:: incremental small - -:: - - (venv)$ pip install Django=1.4.5 psycopg2 dj-database-url - -.. class:: incremental - -Psycopg2 is a DBAPI connector for PostgreSQL. Heroku requires Postgresql - -.. class:: incremental - -``dj-database-url`` allows the Django DB settings to come from an ``env`` variable. - -Heroku - Freeze Dependencies ----------------------------- - -Heroku uses ``pip`` too. It uses a file called ``requirements.txt`` to know -what to do. - -.. class:: incremental - -You create that file: - -.. class:: incremental small - -:: - - (venv)$ pip freeze > requirements.txt - -.. class:: incremental - -Then, add the file to your repository and commit: - -.. class:: incremental small - -:: - - (venv)$ git add requirements.txt - (venv)$ git commit -m "setting requirements for heroku" - -Heroku - Django Settings ------------------------- - -To adapt Django to the Heroku environment, we need to add the following to the -end of our ``settings.py`` file: - -.. code-block:: python - :class: incremental small - - # Parse database configuration from $DATABASE_URL - import dj_database_url - DATABASES['default'] = dj_database_url.config() - - # Honor the 'X-Forwarded-Proto' header for request.is_secure() - SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') - -.. class:: incremental - -Commit these changes to your heroku-deploy branch. - -.. class:: incremental - -Local development settings are different. You can `use different settings for -production and development -`_ - -Heroku - Procfile ------------------ - -Finally, we need to create a file named ``Procfile``. - -.. class:: incremental - -Heroku uses this to learn about the processes we want running. - -.. class:: incremental - -Lines in the file take the form *process_type*: *command*, - -.. class:: incremental - -Create the file ``Procfile`` and add the following text: - -.. class:: incremental small - -web: python manage.py runserver 0.0.0.0:$PORT --noreload - -.. class:: incremental small - -Then, add and commit that file to the repository. - -Heroku - Create and Deploy --------------------------- - -At this point, we're ready to go. - -.. class:: incremental - -First, we create a new ``app`` in heroku with our repo: - -.. class:: incremental small - -:: - - (venv)$ heroku create - Creating fierce-plains-6505... done, stack is cedar - http://fierce-plains-6505.herokuapp.com/ | git@heroku.com:fierce-plains-6505.git - Git remote heroku added - (venv)$ - -.. class:: incremental - -Then, deploy it by 'pushing' to the heroku remote (master branch): - -.. class:: incremental small - -:: - - (venv)$ git push heroku heroku-deploy:master - -Heroku - What Happens ---------------------- - -Heroku works like github, in a way. - -.. class:: incremental - -When our repository is *pushed*, a hook script detects the update and starts -working. - -.. class:: incremental - -* Heroku `detects `_ that we - are building a python project -* A python virtualenv is created -* ``pip`` installs the dependencies in ``requirements.txt`` -* Heroku further detects that we are building a Django app and runs - ``collectstatic`` -* Our ``Procfile`` is read, and data about the processes we want is written to - the environment - -Heroku - Syncdb ---------------- - -Heroku will not run syncdb for us. We have to do that on our own. - -.. class:: incremental - -Heroku *does* provide us with a way to run one-off commands on our server, though: - -.. class:: incremental - -:: - - (venv)$ heroku run python manage.py syncdb - -.. class:: incremental - -This command is run through an ssh tunnel. We can interact with it. - -.. class:: incremental - -We can use other commands, like ``shell`` with ``heroku run``. - -Heroku - Reap the Rewards -------------------------- - -All we have to do now is start a process so we can see our work: - -.. class:: incremental small - -:: - - (venv)$ heroku ps:scale web=1 - Scaling web processes... done, now running 1 - (venv)$ heroku ps - === web: `python manage.py runserver 0.0.0.0:$PORT --noreload` - web.1: up 2013/03/05 06:28:13 (~ 21m ago) - (venv)$ heroku open - -.. class:: incremental - -That last bit will automatically open a web browser pointing at the URL where -may be seen. - -Heroku - DNS ------------- - -Heroku does not want you to point A record DNS names at it's services. -``www.mydomain.com`` is okay, but ``mydomain.com`` is not. - -.. class:: incremental - -They also don't want you to use IP addresses, since their architecture means -IP addresses change. - -.. class:: incremental - -I set up a CNAME record for ``microblog.crisewing.com``. It points to the URL -opened when I type ``heroku open``. - -.. class:: incremental - -So long as I keep this heroku ``app``, that domain name will not change. - -Clean-up --------- - -This is but one example of a cloud deployment. - -.. class:: incremental - -It is considerably easier to do than most other cloud deployments. - -.. class:: incremental - -It is also considerably more constrained than other deployments. - -Take-away ---------- - -When you are making choices about deployment, you **must** take into -consideration your needs, both now and in the future: - -.. class:: incremental - -* What type of Framework will you use? -* What type of Database will you use? -* What growth do you expect to experience (best and worst case)? -* How much control do you want over *all* the processes that make your website - run? -* How much time/expertise do you have (or can you afford to acquire)? - -.. class:: incremental - -Carefully consider these questions, and you will find an appropriate solution. - -Lab Time --------- - -For the rest of today, we work on your projects. - diff --git a/source/presentations/week10.rst b/source/presentations/week10.rst deleted file mode 100644 index a31a1e34..00000000 --- a/source/presentations/week10.rst +++ /dev/null @@ -1,341 +0,0 @@ -Internet Programming with Python -================================ - -.. image:: img/plone-icon-256-white-bg.png - :align: left - :width: 38% - -| Week 9: System Example: -| The Plone CMS - -.. class:: intro-blurb right - -Content management done right. - - -.. class:: image-credit - -The Plone logo is a trademark of the Plone Foundation. - -This Week ---------- - -We'll have an introduction to the Plone Content Management System - -.. class:: incremental - -We'll see a demo of this system in action - -.. class:: incremental - -We'll talk a bit about the differences between a system and a framework - -.. class:: incremental - -We'll spend the rest of the time working on your Final Projects. - -What is Plone? --------------- - -Plone is a Content Management System - -.. class:: incremental - -**System**: A tightly integrated set of tools oriented to a purpose - -.. class:: incremental - -**Content Management**: The task of creating, editing, organizing and -controlling access to content throughout it's lifecycle. - -.. class:: incremental - -**Content**: Information and materials stored in a website which has value -that can be maintained over time. - -Plone Features --------------- - -Plone comes with an extensive feature set OOTB: - -.. class:: incremental - -* Fully translated UI, with over 40 languages supported -* Fine-grained permissions system for access to content and actions -* Built-in, fully configurable user and group management -* Workflow configurable per content type -* Automatic and configurable versioning of content -* Built-in system for event handling, including user notifications -* Built-in content rules allowing for complex automation of common actions -* Content Type framework allowing for TTW creation of new types -* Theme engine allowing for TTW creation of custom themes - -And There's More ----------------- - -By installing additional packages in the core distribution get: - -.. class:: incremental - -* In-place content staging (working copies) -* Powerfully flexible caching -* Per-location workflow configuration - -.. class:: incremental - -And with other add-ons you can have - -.. class:: incremental - -* Multi-lingual content -* TTW form building -* layered calendars -* much, much more... - - -Separators ----------- - -What is it that separates Plone from other web-based CMS solutions? - -.. class:: incremental - -* Simplicity -* Scalability -* Speed -* Security - - -Simplicity ----------- - -Plone features an in-place content editing model - -.. class:: incremental - -Users create content in the place where they want it to be located - -.. class:: incremental - -There is no separate authoring back-end where you must go to create and place -content - -.. class:: incremental - -All aspects of management: workflow, security, versioning and staging can be -managed in-place. - -Scalability ------------ - -Plone is fast and easy enough to support small websites - -.. class:: incremental - -But you can scale it up to the very largest sizes - -.. class:: incremental - -Corporate or Education intranets with over 100,000 pieces of content are not -unusual. - -Speed ------ - -Out of the box, Plone can serves content faster than Drupal, WordPress or -SharePoint. - -.. class:: incremental - -With the simple installation of a caching add-on, this speed is greatly -accelerated. - -.. class:: incremental - -Support for load-balancing and HTTP acceleration means you can push it further -yet. - -Security --------- - -Issues reported for various technologies in CVE (last 3 years): - -.. class:: incremental - -* Plone: 13 (9) -* Zope: 27 (9) -* Python: 111 (65) -* Drupal: 371 (269) -* Joomla: 653 (441) -* MySQL: 282 (84) -* PostgreSQL: 82 (22) -* PHP: 18,859 (5,813) - -.. class:: incremental - -And then there is Plone's true secret weapon - -Community ---------- - -.. image:: img/plone_conf_2012.jpg - :align: center - :width: 85% - -About the Community -------------------- - -Plone has more than 300 *active* core contributors. - -.. class:: incremental - -The `add-on ecosystem `_ contains ~850 public -repositories - -.. class:: incremental - -The community averages one major sprint each month, in locations in Asia, -Africa, Europe, South America, North America and Australia. - -.. class:: incremental - -Plone is a "do-ocracy", meaning that your standing in the community is -determined by your contributions - -History -------- - -In 1999 Plone is a theme for the Zope Content Management Framework. - -.. class:: incremental - -* By 2001, it had grown popular enough to warrant a public release. -* In 2003 Plone 1.0 is released -* In 2004 Plone 2.0 brings the Archetypes Content Type Framework -* In 2005 Plone 2.1 brings default content types via Archetypes -* In 2006 Plone 2.5 brings versioning and pluggable authentication -* In 2007 Plone 3.0 integrates the Zope Component Architecture -* In 2010 Plone 4.0 brings speed and the Dexterity Content Framework -* This week, Plone 4.3rc1 brings through the web theming - -Installation ------------- - -Plone is an application that runs *on top of* the Zope Application Server. - -.. class:: incremental - -Installing Plone involves installing Zope, the ZODB and a number of other -technologies. - -.. class:: incremental - -Forget all that, just use the installers - -.. class:: incremental - -Go to http://plone.org, click "download now", pick the right installer and go. - -Running Plone -------------- - -After running the installer of your choice, you start Plone from the command -line: - -.. class:: incremental - -:: - - $ bin/instance fg - -.. class:: incremental - -This runs plone in the *foreground* which allows you to see errors if they -happen and get tracebacks. - -.. class:: incremental - -Once you see the message "Zope Ready to handle requests", the system is running - -Setting up Your First Site --------------------------- - -When the site is running, you'll find it at localhost:8080 - -.. class:: incremental - -Load that page and you see a message instructing you to add your first site - -.. class:: incremental - -Click the button, and your site is created with a bit of default content - -.. class:: incremental - -At that point, you can start managing content - -Demo of Plone -------------- - -.. class:: big-centered - -Let's see it in action - -Take-away ---------- - -Plone is a full-featured and flexible Content Management System - -.. class:: incremental - -Plone customization is generally going to be *integration* - altering existing -functionality to fit business needs. - -.. class:: incremental - -Treating Plone as a *framework* - trying to build arbitrary web applications - -is not easy. - -.. class:: incremental - -But if the feature set it offers is in largely in line with your needs, you -won't find a better tool. - -Reminder --------- - -Your final projects are **due Friday at noon**. - -.. class:: incremental - -I will not accept submissions that arrive after noon on Friday (March 15). - -.. class:: incremental - -You will need to supply: - -.. class:: incremental - -* A Link to your site deployed online (your VM, in the cloud, ...) -* A Link to **your project source code repository** in Github. -* Text describing **the goals and outcomes** of your project. -* Instructions on **how I can run your project locally** on my laptop - -Another reminder ----------------- - -.. class:: big-centered - -**LEAVE TIME FOR DEPLOYMENT** - -Final Word ----------- - -.. class:: big-centered - -**thank you all** - -Lab Time --------- - -For the rest of today, we work on your projects. From 9699dcc1bb6f795b2efbdc4ed01a003be4233400 Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 28 Jul 2013 01:23:33 -0700 Subject: [PATCH 139/487] add the pyramid session file --- source/presentations/session09.rst | 1283 ++++++++++++++++++++++++++++ 1 file changed, 1283 insertions(+) create mode 100644 source/presentations/session09.rst diff --git a/source/presentations/session09.rst b/source/presentations/session09.rst new file mode 100644 index 00000000..4a4cd3cf --- /dev/null +++ b/source/presentations/session09.rst @@ -0,0 +1,1283 @@ +Internet Programming with Python +================================ + +.. image:: img/pyramid-medium.png + :align: left + :width: 50% + +Week 8: Pyramid + +.. class:: intro-blurb right + +| Wherein we learn +| it's not built by aliens + + +What is Pyramid? +---------------- + +A Web Framework + +.. class:: incremental + +"Its primary job is to make it easier for a developer to create an arbitrary +web application" + +.. class:: incremental + +Makes as few decisions as possible for you. + +.. class:: incremental + +Allows *you* to make decisions, and provides tools to support you when you do + +.. class:: incremental + +"Pay only for what you eat" + + +Why is Pyramid? +--------------- + +Micro-frameworks are great for lightweight apps + +.. class:: incremental + +Micro-frameworks do not scale up or change specs easily + +.. class:: incremental + +Full-stack frameworks have lots of opinions. *Bending* them can be difficult. + +.. class:: incremental + +Pyramid can build a lightweight app easily, but it can also scale and bend + + +History - Zope and Repoze +------------------------- + +Many of the core developers of Pyramid started as Zope developers. + +.. class:: incremental + +Born in 1996, Zope was the first Python web framework, and possibly the first +in any language. + +.. class:: incremental + +After 14 years, the developers of Zope had seen and learned *a lot*. + +.. class:: incremental + +Repoze was a short-lived (2008-2010) framework intended to embody the lessons +learned from Zope. + + +History - Pylons +---------------- + +Pylons was released in 2005. + +.. class:: incremental + +It was among the first frameworks to fully embrace the WSGI specification. + +.. class:: incremental + +The creators of Pylons build WebTest, WebError and WebOb (abstracted HTTP +request and response objects) + + +History - 2010 +-------------- + +In 2010, the authors of Repoze and Pylons got together and made an unusual +decision. + +.. class:: incremental + +Why duplicate efforts when there are already so many other frameworks? + +.. class:: incremental + +Repoze was re-named 'Pyramid' and the 'Pylons Project' was born to shepherd +this new combined project. + + +Implications +------------ + +Pylons was a framework predicated largely on relational persistence and URL +Dispatch. + +.. class:: incremental + +Zope/Repoze was based on the ZODB and Object Traversal. + +.. class:: incremental + +Each of these approaches has strengths and weaknesses. + +.. class:: incremental + +Pyramid supports neither, both and even combinations of the two. + + +Relational DB / URL Dispatch +---------------------------- + +You've seen this before, both in Flask and Django + +.. class:: incremental + +SQLite3, the Django ORM, both are examples of relational persistence models + +.. class:: incremental + +Routes/urlpatterns, both are examples of URL Dispatch + +.. class:: incremental + +Pyramid can work this way too. SQLAlchemy, Route-based views. + +.. class:: incremental + +Been there, done that. Let's see something else. + + +ZODB +---- + +ORMs allow developers to pretend that Objects are like DB Tables. + +.. class:: incremental + +But Objects are *not* tables, so there's a `conceptual mismatch +`_ between +the two. + +.. class:: incremental + +The ZODB is an *object store*, rather than a relational database. + +.. class:: incremental + +If your data is best represented by *heterogenous* objects, it's a better +persistence solution. + + +Traversal - Object Graphs +------------------------- + +Python objects can *contain* other objects. + +.. class:: incremental + +Using *dict*-like structures, you can build a *graph* of objects: + +.. class:: incremental + +:: + + Family + ├── Parents + │ ├── Cris + │ ├── Kristina + ├── Children + │ ├── Kieran + │ ├── Finnian + + +Traversal - Path Lookup +----------------------- + +You can *traverse* across the object graph by treating a URL as a series of +*node names* + +.. class:: incremental small + +:: + + http://family/parents/cris -> family['parents']['cris'] + +.. class:: incremental + +Further path segments can be view names or information passed to the view + +.. class:: incremental small + +:: + + http://family/parents/cris/edit -> edit view + http://family/parents/cris/next/steps -> subpath = /next/steps + + +Break Time +---------- + +We've got the concept of object stores and traversal + +.. class:: incremental + +The next step is to see how those work in real life. + +.. class:: incremental + +Take the next few minutes here to ensure that you have a working Pyramid setup +with the ZODB and a project created with ``pcreate -s zodb``. + + +Lab - Part One +-------------- + +.. class:: big-centered + +Getting To Know Pyramid + + +Scaffolds and Opinions +---------------------- + +Pyramid uses what it calls *scaffolds* to get you started on a new project. + +.. class:: incremental + +When you ran ``pcreate -s zodb wikitutorial`` you were invoking the *zodb +scaffold* + +.. class:: incremental + +Pyramid the framework is highly un-opinionated. + +.. class:: incremental + +*Scaffolds*, conversely, can be quite opinionated. The one we used has chosen +our persistence mechanism (ZODB) and how we will reach our code (Traversal). + + +Project Layout +-------------- + +Running ``pcreate`` has set up a file structure for us: + +.. class:: small + +:: + + wikitutorial/ + CHANGES.txt + development.ini + MANIFEST.in + production.ini + README.txt + setup.cfg + setup.py + wikitutorial/ + __init__.py + models.py + static/ + templates/ + tests.py + views.py + + +Similarities to Django +---------------------- + +Our project is organized with an outer *project* folder and an inner *package* +folder (see the ``__init__.py``?) + +.. class:: incremental + +The name of that outer directory is not really important. + +.. class:: incremental + +Our inner *package* folder has a models.py, tests.py and views.py module + +.. class:: incremental + +Our inner *package* folder has a ``static/`` and ``templates/`` directory + + +Differences from Django +----------------------- + +Our *outer* module has a ``setup.py`` file, which allows it to be installed +with ``pip`` or ``easy_install`` + +.. class:: incremental + +There is no ``manage.py`` file. Pyramid commands are console scripts. + +.. class:: incremental + +There is nothing magical in Pyramid about the name of the ``models.py`` +module. + +.. class:: incremental + +There is nothing magical in Pyramid about the names of the ``static/`` or +``templates/`` directories. + + +Pyramid System Configuration +---------------------------- + +Pyramid keeps configuration intended for an entire installation in ``.ini`` +files at the top of a project. + +.. class:: incremental + +When you deploy an app to some wsgi server, you'll reference one of these files + +.. class:: incremental + +Settings there affect the environment of all apps that are running in that +wsgi server. + +.. class:: incremental + +It is much like Django's ``settings.py`` but is not a python module. + + +Pyramid is Python +----------------- + +Running a Pyramid application is really just like running a Python module. In +the ``__init__.py`` file of your app *package*, you'll find a ``main`` +function: + +.. code-block:: python + :class: small incremental + + def main(global_config, **settings): + """ This function returns a Pyramid WSGI application. + """ + config = Configurator(root_factory=root_factory, + settings=settings) + config.add_static_view('static', 'static', cache_max_age=3600) + config.scan() + return config.make_wsgi_app() + +.. class:: incremental + +App-level configuration is done here. + + +App Configuration +----------------- + +.. code-block:: python + :class: small + + def main(global_config, **settings): + +.. class:: incremental + +``global_config`` will be a dictionary of the settings from your ``.ini`` file +that come in the [DEFAULT] section (if there is one). These settings will be +shared across all apps that are involved in the system. + +.. class:: incremental + +The ``settings`` passed in here are the settings from your ``.ini`` file that +come in the section that corresponds to your application. They will be used +only by your app. + + +App Configuration +----------------- + +.. code-block:: python + :class: small + + config = Configurator(root_factory=root_factory, + settings=settings) + config.add_static_view('static', 'static', cache_max_age=3600) + config.scan() + +.. class:: incremental + +Pyramid does configuration work when an app is run using the ``Configurator`` +class. + +.. class:: incremental + +The ``Configurator`` provides an extensible API for configuring just about +everything. + +.. class:: incremental + +You can read more in `the pyramid.config documentation +`_ + + +The Application Root +-------------------- + +The ``Configurator`` constructor can take a ``root_factory`` keyword argument. + +.. class:: incremental + +The ``root_factory`` of your app returns the router that determines how to +dispatch individual requests. + +.. class:: incremental + +If you do not provide this argument, the default root factory, which uses URL +Dispatch, will be used. + +.. class:: incremental + +In our case, we want to use Traversal for our app, so we provide a custom +``root_factory``. + + +Our Root Factory +---------------- + +.. code-block:: python + :class: small + + from pyramid_zodbconn import get_connection + from .models import appmaker + + def root_factory(request): + conn = get_connection(request) + return appmaker(conn.root()) + +.. class:: incremental + +We grab a connection to the ZODB and pass that into a call to ``appmaker``, +the result is returned (and becomes our app root). + +.. class:: incremental + +So what exactly does ``appmaker`` do? + + +The appmaker +------------ + +.. code-block:: python + :class: small + + def appmaker(zodb_root): + if not 'app_root' in zodb_root: + app_root = MyModel() + zodb_root['app_root'] = app_root + import transaction + transaction.commit() + return zodb_root['app_root'] + +.. class:: incremental + +We ensure that there is an ``app_root`` object stored in the ZODB, and return +it. That simple Python object will manage our *Traversal* based application. + + +Seeing It Live +-------------- + +You've done this at home, but let's repeat the exercise here. + +.. class:: incremental + +In a terminal, change directories into your ``wikitutorial`` *project* folder +(where you see ``development.ini``). Fire up your pyramid virtualenv and serve +our app: + +.. class:: incremental + +:: + + (pyramidenv)$ pserve development.ini + Starting server in PID 16698. + serving on http://0.0.0.0:6543 + +.. class:: incremental + +Load http://localhost:6543 and view your app root. + + +Why is it Pretty? +----------------- + +If we understand correctly what is happening so far, we are looking at an +instance of ``MyModel``. + +.. class:: incremental + +What makes it look like this? + +.. class:: incremental + +The secret sauce lies in *view configuration* + + +Pyramid Views +------------- + +.. code-block:: python + :class: small + + from pyramid.view import view_config + from .models import MyModel + + @view_config(context=MyModel, renderer='templates/mytemplate.pt') + def my_view(request): + return {'project': 'wikitutorial'} + +.. class:: incremental + +Pyramid views can be configured with the ``@view_config()`` decorator. + +.. class:: incremental + +Or call ``config.add_view()`` method in your app ``main``. + +.. class:: incremental + +``config.scan()`` in ``main`` picks up all config decorators. + + +View Configuration +------------------ + +.. class:: small + +The ``view_config`` decorator (and the ``add_view`` method) take a number of +interesting arguments. In our case there are two. + +.. class:: incremental small + +``renderer`` is used to designate how the results returned by the view +callable will be handled. In our case, it's a template that will render to an +HTML page. + +.. class:: incremental small + +``context`` determines the *type* of object for which this view may be used. It +is an example of a ``predicate`` argument, which can be used to place +restrictions on when and how a view may be called. + +.. class:: incremental small + +Predicates are a very powerful system for choosing views. Read more about them +in `view configuration +`_ + + +Lab - Part Two +-------------- + +.. class:: big-centered + +Data Models and Tests + +Wiki Models +----------- + +Now that we have a basic idea of what's going on in the code generated for us, +it's time to build our wiki models. + +.. class:: incremental + +We'll need to have a Python class that corresponds to a *page* in our wiki. + +.. class:: incremental + +This will be the type of object we view when we are looking at the wiki. + +.. class:: incremental + +We'll also need to have a *root* object, which will be a container for all the +*pages* we create for the wiki. + + +Persistence Magic +----------------- + +In an SQL database, data *about* an object is written to tables. In the ZODB, +the *object itself* is saved in the database. + +.. class:: incremental + +The ZODB provides base classes that will *automatically save themselves*. We +will use two of these: + +.. class:: incremental + +* **Persistent** - a class that automatically tracks changes to class + attributes and saves them. + +* **PersistentMapping** - roughly equivalent to a Python *dictionary*, this + class will save changes to itself *and its keys and values*. + +.. class:: incremental small + +The ZODB also provides lists and more complex persistent data structures like +BTrees. + + +Traversal Magic +--------------- + +Traversal is supported by two object properties: ``__name__`` and +``__parent__``. + +.. class:: incremental + +Every object in a system which is going to use Traversal **must** provide +these two attributes. + +.. class:: incremental + +The *root* object in a Traversal system will have both of these attributes set +to ``None``. + + +The Wiki Class +-------------- + +Open ``models.py`` from our ``wikitutorial`` *package* directory. + +.. class:: incremental + +First, delete the ``MyModel`` class. We won't need it. + +.. class:: incremental + +Add the following in its place: + +.. code-block:: python + :class: incremental + + class Wiki(PersistentMapping): + __name__ = None + __parent__ = None + + +The Page Class +-------------- + +To that same file (models.py) add one import and a second class definition: + +.. code-block:: python + + from persistent import Persistent + + class Page(Persistent): + def __init__(self, data): + self.data = data + +.. class:: incremental + +What about ``__name__`` and ``__parent__``? + +.. class:: incremental + +We'll add those to each instance when we create it. + + +Update Appmaker +--------------- + +The existing ``appmaker`` function needs to be updated for our new models: + +.. code-block:: python + + def appmaker(zodb_root): + if not 'app_root' in zodb_root: + app_root = Wiki() + frontpage = Page('This is the front page') + app_root['FrontPage'] = frontpage + frontpage.__name__ = 'FrontPage' + frontpage.__parent__ = app_root + zodb_root['app_root'] = app_root + import transaction + transaction.commit() + return zodb_root['app_root'] + + +A Last Bit of Cleanup +--------------------- + +We've deleted the ``MyModel`` class. But we still have *views* that +reference the class. + +.. class:: incremental + +Open the ``views.py`` file in your *package* directory and comment out +everything **except** the first line: + +.. code-block:: python + :class: incremental + + from pyramid.view import view_config + +.. class:: incremental + +Next, we'll test our models. + + +Test the Wiki Model +------------------- + +Open ``tests.py`` from the *package* directory. Delete the ``ViewTests`` +class and replace it with the following: + +.. code-block:: python + :class: small + + class WikiModelTests(unittest.TestCase): + + def _getTargetClass(self): + from wikitutorial.models import Wiki + return Wiki + + def _makeOne(self): + return self._getTargetClass()() + + def test_it(self): + wiki = self._makeOne() + self.assertEqual(wiki.__parent__, None) + self.assertEqual(wiki.__name__, None) + + +Test the Page Model +------------------- + +Add the following test class as well: + +.. code-block:: python + :class: small + + class PageModelTests(unittest.TestCase): + + def _getTargetClass(self): + from wikitutorial.models import Page + return Page + + def _makeOne(self, data=u'some data'): + return self._getTargetClass()(data=data) + + def test_constructor(self): + instance = self._makeOne() + self.assertEqual(instance.data, u'some data') + + +Test Appmaker +------------- + +One more test class: + +.. code-block:: python + :class: small + + class AppmakerTests(unittest.TestCase): + + def _callFUT(self, zodb_root): + from .models import appmaker + return appmaker(zodb_root) + + def test_it(self): + root = {} + self._callFUT(root) + self.assertEqual(root['app_root']['FrontPage'].data, + 'This is the front page') + + +A Quick Interlude +----------------- + +In your *package* directory you should see a file: ``Data.fs``. + +.. class:: incremental + +This is the ZODB. It contains references to a class that doesn't exist +anymore (MyModel). This means it is broken. + +.. class:: incremental + +Make sure Pyramid is not running. + +.. class:: incremental + +Delete Data.fs. It will be re-created as needed. + +.. class:: incremental + +You can also delete Data.fs.* (.tmp, .index, .lock) + + +Run our Tests +------------- + +Finally, let's run our tests:: + + (pyramidenv)$ python setup.py test + ... + Ran 3 tests in 0.000s + + OK + +.. class:: incremental + +We can also run tests to tell us our code-coverage: + +.. class:: incremental small + +:: + + (pyramidenv)$ nosetests --cover-package=tutorial --cover-erase --with-coverage + + +Break +----- + +.. class:: big-centered + +Take a few minutes to breathe + + +Lab - Part Three +---------------- + +.. class:: big-centered + +Views and Templates + + +Preparing for Views +------------------- + +Our ``Page`` model has a ``data`` attribute, which represents the text in the +page. + +.. class:: incremental + +Our pages will use ReStructuredText, a plain-text format that can be rendered +to HTML with a Python module called ``docutils``. + +.. class:: incremental + +Our project is installable as a python package. It declares its own +*dependencies* so that they will also be installed. + +.. class:: incremental + +We need to add the ``docutils`` package to this list. + + +Package Dependencies +-------------------- + +Open the ``setup.py`` file from our *project* directory. Add ``docutils`` to +the list ``requires``: + +.. code-block:: python + + requires = [ + 'pyramid', + 'pyramid_zodbconn', + 'transaction', + 'pyramid_tm', + 'pyramid_debugtoolbar', + 'ZODB3', + 'waitress', + 'docutils', # <- ADD THIS + ] + + +Complete the Change +------------------- + +Any time you make a change to ``setup.py`` for a package you are working on, +you need to re-install that package to pick up the changes:: + + (pyramidenv)$ python setup.py develop + +.. class:: incremental + +You'll see a whole bunch of stuff flicker by. In it will be a reference to +``Searching for docutils``. + + +Adding Views +------------ + +Open ``views.py`` again. Add the following: + +.. code-block:: python + :class: small + + from docutils.core import publish_parts + import re + + from pyramid.httpexceptions import HTTPFound + from pyramid.view import view_config # <- ALREADY THERE + + from wikitutorial.models import Page + + # regular expression used to find WikiWords + wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") + + @view_config(context='.models.Wiki') + def view_wiki(context, request): + return HTTPFound(location=request.resource_url(context, + 'FrontPage')) + + +Some Notes +---------- + +New pages in a typical wiki are added by writing *WikiWords* into the page. + +.. class:: incremental + +``r"\b([A-Z]\w+[A-Z]+\w+)"`` is a regular expression that will locate +WikiWords. + +.. class:: incremental + +Note that the ``@view_config`` for the ``view_wiki`` function has no +``renderer`` argument. It will never be *shown* + +.. class:: incremental + +Instead, it returns ``HTTPFound``, (``302 Found``). Calling +``request.resource_url`` provides a URL for the redirect. + + +Add a Page View +--------------- + +.. code-block:: python + :class: small + + @view_config(context='.models.Page', renderer='templates/view.pt') + def view_page(context, request): + wiki = context.__parent__ + + def check(match): + word = match.group(1) + if word in wiki: + page = wiki[word] + view_url = request.resource_url(http://github.com/page) + return '%s' % (view_url, word) + else: + add_url = request.application_url + '/add_page/' + word + return '%s' % (add_url, word) + + content = publish_parts( + context.data, writer_name='html')['html_body'] + content = wikiwords.sub(check, content) + edit_url = request.resource_url(http://github.com/context,%20'edit_page') + return dict(page=context, content=content, edit_url=edit_url) + + +Adding Templates +---------------- + +What will the page template for the ``view_page`` function need to be called? + +.. class:: incremental + +Go ahead and create ``view.pt`` in your ``templates`` directory. + +.. class:: incremental + +While you're there, also copy the file ``base.pt`` from +``assignments/week08/lab`` in the class repo. + +.. class:: incremental + +Like Django templates, Chameleon templates can extend other templates. Our +``base.pt`` template will be the master, and our ``view.pt`` and ``edit.pt`` +templates will extend it. + + +The view.pt Template +-------------------- + +Type this code into your ``view.pt`` file: + +.. code-block:: xml + + + +
    + Page text goes here. +
    +

    + + Edit this page + +

    +
    +
    + + +A Few Notes +----------- + +Chameleon page templates are valid XML. The templating language uses ``tal``/``metal`` +namespace XML tag attributes. + +.. class:: incremental + +```` tells us we will be using +``base.pt`` as our main template *macro*. + +.. class:: incremental + +Template *macros* can define one or more *slots*. These are like the *blocks* +in Jinja2 or Django templates. + +.. class:: incremental + +```` tells us that everything +here will go in the ``main-content`` slot. + + +More Notes +---------- + +.. code-block:: xml + +
    + Page text goes here. +
    + +This uses the ``tal`` directive ``replace`` to completely replace the +``
    `` tag with whatever html is in ``content``. + +.. code-block:: xml + :class: incremental + + + Edit this page + + +.. class:: incremental + +Here, we use the ``tal`` directive ``attributes`` to set the ``href`` for our +anchor to the value passed into our template as ``edit_url``. + + +View Your Work +-------------- + +We've created the following: + +.. class:: incremental small + +* A wiki view that redirects to the automatically-created FrontPage page +* A page view that will render the ``data`` from a page, along with a url for + editing that page +* A page template to show a wiki page. + +.. class:: incremental + +That's all we need to be able to see our work. Start Pyramid: + +.. class:: incremental small + +:: + + (pyramidenv)$ pserve development.ini + Starting server in PID 43925. + serving on http://0.0.0.0:6543 + +.. class:: incremental + +Load http://localhost:6543/ + + +What You Should See +------------------- + +.. image:: img/wiki_frontpage.png + :align: center + :width: 95% + + +Editing a Page +-------------- + +Back in ``views.py`` add the following: + +.. code-block:: python + :class: small + + @view_config(name='edit_page', context='.models.Page', + renderer='templates/edit.pt') + def edit_page(context, request): + if 'form.submitted' in request.params: + context.data = request.params['body'] + return HTTPFound(location = request.resource_url(http://github.com/context)) + + return dict(page=context, + save_url=request.resource_url(http://github.com/context,%20'edit_page')) + + +The Edit Template +----------------- + +Create and fill ``edit.pt`` in ``templates``: + +.. code-block:: xml + :class: small + + + + Editing + Page Name Goes Here + + + +
    + +
    +
    + +
    + + {% endif %} +

    Posts

    +
      + {% for entry in entries %} +
    • +

      {{ entry.title }}

      +
      + {{ entry.text|safe }} +
      +
    • + {% else %} +
    • No entries here so far
    • + {% endfor %} +
    +{% endblock %} \ No newline at end of file From 801a1906a1b15b199cf6679036e998b88f789d45 Mon Sep 17 00:00:00 2001 From: cewing Date: Wed, 31 Jul 2013 00:49:38 -0700 Subject: [PATCH 148/487] * make all pyramid readings point to 'latest' * add security to pyramid walk-through --- source/main/readings.rst | 8 +- source/presentations/session10.rst | 676 ++++++++++++++++++++++++++++- 2 files changed, 676 insertions(+), 8 deletions(-) diff --git a/source/main/readings.rst b/source/main/readings.rst index 3d277928..299ac74b 100644 --- a/source/main/readings.rst +++ b/source/main/readings.rst @@ -226,14 +226,16 @@ Sessions 9 & 10 - Pyramid ------------------------- Why you should care about `Traversal -`_. +`_. Compare and contrast forms of dispatch in Pyramid: * `URL Route Dispatch `_ * `Object Traversal - `_ + `_ + + Learn a bit about the `ZODB `_ @@ -249,7 +251,7 @@ Learn a bit about the `ZODB `_ Learn a bit about the Chameleon ZPT templating language: * Read about `Chameleon Templates in Pyramid - `_ + `_ * A `Quick Intro to TAL `_ * `Chameleon Documentation `_ diff --git a/source/presentations/session10.rst b/source/presentations/session10.rst index 2e08138b..f3d28d04 100644 --- a/source/presentations/session10.rst +++ b/source/presentations/session10.rst @@ -620,16 +620,682 @@ Check Your Tests **WAHOOOOOOO!!!** -In-Class Exercises +Security +-------- + +We've got a solid start on a wiki that works. + +.. class:: incremental + +But everyone who visits the wiki can author and edit pages. + +.. class:: incremental + +It's a recipe for **TOTAL CHAOS** + +.. class:: incremental + +Let's lock it down a bit. + + +AuthN and AuthZ +--------------- + +There are two aspects to the process of access control online. + +.. class:: incremental + +* **Authentication**: Verification of the identity of a *principal* +* **Authorization**: Enumeration of the rights of that *principal* in a + context. + +.. class:: incremental + +All systems with access control involve both of these aspects. + +.. class:: incremental + +AuthZ in our Flask and Django apps was minimal + + +Pyramid Security +---------------- + +In Pyramid these two aspects are handled by separate configuration settings: + +.. class:: incremental + +* ``config.set_authentication_policy(AuthnPolicy())`` +* ``config.set_authorization_policy(AuthzPolicy())`` + +.. class:: incremental + +If you set one, you must set the other. + +.. class:: incremental + +Pyramid comes with a few policy classes included. + +.. class:: incremental + +You can also roll your own, so long as they fulfill the contract. + + +Our Wiki Security +----------------- + +We'll be using two built-in policies today: + +.. class:: incremental + +* ``AuthTktAuthenticationPolicy``: sets an expirable authentication ticket + cookie. +* ``ACLAuthorizationPolicy``: uses an *Access Control List* to grant + permissions to *principals* + +.. class:: incremental + +Our access control system will have the following properties: + +.. class:: incremental + +* Everyone can view pages +* Users who log in may be added to an 'editors' group +* Editors can add and edit pages. + + +Testing First +------------- + +Let's begin by testing for our desired properties. + +.. class:: incremental + +We'll need to create a new TestCase for this. + +.. class:: incremental + +This TestCase will be a bit different. We need a request to engage security + +.. class:: incremental + +These tests will be *functional tests* where our earlier tests were *unit +tests* + +.. class:: incremental + +We'll set up a zodb and a full-fledged app. + + +In tests.py +----------- + +We'll need some information for testing logging in: + +.. code-block:: python + :class: small + + class FunctionalTests(unittest.TestCase): + + viewer_login = '/login?login=viewer&password=viewer' \ + '&came_from=FrontPage&form.submitted=Login' + viewer_wrong_login = '/login?login=viewer&password=incorrect' \ + '&came_from=FrontPage&form.submitted=Login' + editor_login = '/login?login=editor&password=editor' \ + '&came_from=FrontPage&form.submitted=Login' + + +Test Setup +---------- + +We'll also need to create an app and provide a zodb to hold it: + +.. code-block:: python + :class: tiny + + class FunctionalTests(unittest.TestCase): + #... + def setUp(self): + import tempfile + import os.path + from wikitutorial import main + self.tmpdir = tempfile.mkdtemp() + + dbpath = os.path.join( self.tmpdir, 'test.db') + uri = 'file://' + dbpath + settings = { 'zodbconn.uri' : uri , + 'pyramid.includes': ['pyramid_zodbconn', + 'pyramid_tm'] } + + app = main({}, **settings) + self.db = app.registry._zodb_databases[''] + from webtest import TestApp + self.testapp = TestApp(app) + + +Test Teardown +------------- + +And since we set all that up, we need to destroy it after each test, too: + +.. code-block:: python + :class: small + + def tearDown(self): + import shutil + self.db.close() + shutil.rmtree( self.tmpdir ) + + +Testing Login +------------- + +Let's add a few tests to demonstrate that ``AuthN`` works: + +.. code-block:: python + :class: small + + def test_successful_log_in(self): + res = self.testapp.get( self.viewer_login, status=302) + self.assertEqual(res.location, 'http://localhost/FrontPage') + + def test_failed_log_in(self): + res = self.testapp.get( self.viewer_wrong_login, status=200) + self.assertTrue('login' in res.body) + + +Testing Anonymous Users +----------------------- + +We should verify that anonymous users can see pages, but cannot edit or add: + +.. code-block:: python + :class: small + + def test_anonymous_user_cannot_edit(self): + res = self.testapp.get('/FrontPage/edit_page', status=200) + self.assertTrue('Login' in res.body) + + def test_anonymous_user_cannot_add(self): + res = self.testapp.get('/add_page/NewPage', status=200) + self.assertTrue('Login' in res.body) + + +Testing Viewers +--------------- + +Authenticated users who are not editors should be the same: + +.. code-block:: python + :class: small + + def test_viewer_user_cannot_edit(self): + res = self.testapp.get( self.viewer_login, status=302) + res = self.testapp.get('/FrontPage/edit_page', status=200) + self.assertTrue('Login' in res.body) + + def test_viewer_user_cannot_add(self): + res = self.testapp.get( self.viewer_login, status=302) + res = self.testapp.get('/add_page/NewPage', status=200) + self.assertTrue('Login' in res.body) + + +Testing Editors +--------------- + +Finally, editors should be able to do it all: + +.. code-block:: python + :class: small + + def test_editors_member_user_can_edit(self): + res = self.testapp.get( self.editor_login, status=302) + res = self.testapp.get('/FrontPage/edit_page', status=200) + self.assertTrue('Editing' in res.body) + + def test_editors_member_user_can_add(self): + res = self.testapp.get( self.editor_login, status=302) + res = self.testapp.get('/add_page/NewPage', status=200) + self.assertTrue('Editing' in res.body) + + def test_editors_member_user_can_view(self): + res = self.testapp.get( self.editor_login, status=302) + res = self.testapp.get('/FrontPage', status=200) + self.assertTrue('FrontPage' in res.body) + + +One Bit of Cleanup ------------------ -Try to accomplish as many of these as you can before you leave: +These lines in our test setup will cause us problems: + +.. code-block:: python + :class: small + + from webtest import TestApp + self.testapp = TestApp(app) + +.. class:: incremental + +We have introduced a dependency on the package ``webtest`` + +.. class:: incremental + +Our package should be explicit about its dependencies. + +.. class:: incremental + +Do you remember how to declare a dependency? + + +Fix setup.py / re-install +------------------------- + +In ``setup.py`` find ``requires`` and add the following: + +.. code-block:: python + :class: small + + requires = [ + #... + 'docutils', + 'webtest', #<- we are adding this line + ] + +.. class:: incremental + +Then, re-install our package using ``develop``: + +.. class:: incremental small + +:: + + (pyramidenv)$ python setup.py develop + + +Run Our Tests +------------- + +We can run these tests, to verify that they don't just work: + +.. class:: small incremental + +:: + + (pyramidenv)$ python setup.py test + + ---------------------------------------------------------------------- + Ran 18 tests in 1.032s + + FAILED (failures=2, errors=7) + +.. class:: incremental + +Great! Lot's of problems to fix! + + +Contextual ACLs +--------------- + +In Pyramid, ACL security is *contextual*. + +.. class:: incremental + +What a user is allowed to do is dependent on *context*. + +.. class:: incremental + +In a *traversal* app, context is defined as the object you are viewing. .. class:: incremental -* Make the add_page view show "Adding " in the header (*do not create - a new template to do this*) -* Make the edit_page and add_page views **only** change data on POST. +A *view* can require a given permission. + +.. class:: incremental + +The object viewed is responsible for determining *who* has *what rights*. + + +ACL Inheritance +--------------- + +Under the default ACL policy, permissions are inherited. + +.. class:: incremental + +If *this* object does not declare an ACL, then its ``__parent__`` is checked + +.. class:: incremental + +If you get all the way back to the root without hitting an ACL, then access is +denied. + +.. class:: incremental + +Thus, the default ACL policy is secure by default. + +.. class:: incremental + +Let's set up our policy. + + +Our Users and Groups +-------------------- + +Create a new file ``security.py`` in your wikitutorial package and add the +following: + +.. code-block:: python + :class: small incremental + + USERS = { + 'editor': 'editor', + 'viewer': 'viewer', + } + + GROUPS = { + 'editor': ['group:editors'], + } + + def groupfinder(userid, request): + if userid in USERS: + return GROUPS.get(userid, []) + + +Security Configuration +---------------------- + +In our ``__init__.py`` file, add the following: + +.. code-block:: python + :class: small + + # a few imports + from pyramid.authentication import AuthTktAuthenticationPolicy + from pyramid.authorization import ACLAuthorizationPolicy + from .security import groupfinder + + # and some configuration + def main(global_config, **settings): + """ This function returns a Pyramid WSGI application. + """ + authn_policy = AuthTktAuthenticationPolicy( + 'youdontknowit', callback=groupfinder, hashalg='sha512') + authz_policy = ACLAuthorizationPolicy() + config = Configurator(...) #<- already there + config.set_authentication_policy(authn_policy) + config.set_authorization_policy(authz_policy) + #... + + +Add an ACL +---------- + +We can set a global ACL on our wiki root class: + +.. code-block:: python + :class: small + + # add an import + from pyramid.security import Allow, Everyone + + # and alter our wiki class: + class Wiki(PersistentMapping): + #... + __acl__ = [(Allow, Everyone, 'view'), + (Allow, 'group:editors', 'edit')] + +.. class:: incremental + +An ACL is a list of Access Control Entries + +.. class:: incremental + +Each ACE is a tuple of *action*, *principal* and *permission* + + +Require Permission +------------------ + +In order to match, an ACE must *Allow* the current *principal* the required +*permission* + +.. class:: incremental + +Our ``views`` are responsible for saying what *permission* is required + +.. code-block:: python + :class: incremental small + + # for the view_page() view: + @view_config(context='.models.Page', renderer='templates/view.pt', + permission='view') + + # for add_page() and edit_page() + @view_config(route_name='', renderer='templates/edit.pt', + permission='edit') + + +Provide Login/Logout +-------------------- + +We need to allow users a way to log in and out. Start with the views: + +.. code-block:: python + :class: small + + # add imports to views.py + from pyramid.view import forbidden_view_config + from pyramid.security import remember, forget + from wikitutorial.security import USERS + + # and a logout view: + @view_config(context='.models.Wiki', name='logout') + def logout(context, request): + headers = forget(request) + return HTTPFound(location=request.resource_url(http://github.com/context), + headers=headers) + +.. class:: incremental + +Next, add the login view + + +The Login View +-------------- + +.. code-block:: python + :class: tiny + + @view_config(context='.models.Wiki', name='login', + renderer='templates/login.pt') + @forbidden_view_config(renderer='templates/login.pt') + def login(request): + login_url = request.resource_url(http://github.com/request.context,%20'login') + referrer = request.url + if referrer == login_url: + referrer = '/' # never use the login form itself as came_from + came_from = request.params.get('came_from', referrer) + message = login = password = '' + if 'form.submitted' in request.params: + login = request.params['login'] + password = request.params['password'] + if USERS.get(login) == password: + headers = remember(request, login) + return HTTPFound(location = came_from, + headers = headers) + message = 'Failed login' + + ctxt = dict(message=message, came_from=came_from, + login=login, password=password, + url=request.application_url + '/login',) + return ctxt + + + + + +The Login Template +------------------ + +Add ``login.pt`` to the ``templates`` directory + +.. code-block:: xml + :class: small + + + + Login
    + +
    + + +
    + +
    +
    + +
    +
    +
    + + +Unblock Logout Link +------------------- + +All along, we've had a logout link in our ``base.pt`` + +.. class:: incremental + +But we've been blocking it from showing in our templates. + +.. class:: incremental + +Let's allow it to show in the ``view.pt`` and ``edit.pt`` templates: + +.. code-block:: xml + :class: small incremental + + + + + +Conditional Logout +------------------ + +Look at ``base.pt``: + +.. code-block:: xml + :class: small + + + + Logout + + + +.. class:: incremental + +Showing the 'logout' link is dependent on ``logged_in`` + +.. class:: incremental + +We have to make sure that this boolean flag is in the template context + + +Add logged_in Flag +------------------ + +Back in ``views.py`` add the following import: + +.. code-block:: python + :class: small + + from pyramid.security import authenticated_userid + +.. class:: incremental + +This will return the id of the authenticated user, or None. + +.. container:: incremental + + Add this to all return contexts for our views (except ``login``): + + .. code-block:: python + :class: small + + logged_in = authenticated_userid(request) + + +Check Your Work +--------------- + +.. class:: small + +:: + + (pyramidenv)$ python setup.py test + ... + test_anonymous_user_cannot_add (wikitutorial.tests.FunctionalTests) ... ok + test_anonymous_user_cannot_edit (wikitutorial.tests.FunctionalTests) ... ok + test_editors_member_user_can_add (wikitutorial.tests.FunctionalTests) ... ok + test_editors_member_user_can_edit (wikitutorial.tests.FunctionalTests) ... ok + test_editors_member_user_can_view (wikitutorial.tests.FunctionalTests) ... ok + test_failed_log_in (wikitutorial.tests.FunctionalTests) ... ok + test_successful_log_in (wikitutorial.tests.FunctionalTests) ... ok + test_viewer_user_cannot_add (wikitutorial.tests.FunctionalTests) ... ok + test_viewer_user_cannot_edit (wikitutorial.tests.FunctionalTests) ... ok + ... + ---------------------------------------------------------------------- + Ran 18 tests in 1.143s + + OK + + +Reap the Reward +--------------- + +Check your work in a browser: + +.. class:: small + +:: + + (pyramidenv)$ pserve development.ini + Starting server in PID 36414. + serving on http://0.0.0.0:6543 + +.. class:: + +Visit http://localhost:6543 and play for a bit + + +Next Steps +---------- + +We've got a workable basic wiki here, but there are some improvements that +could be nice: + +.. class:: incremental + +* Make the add_page view show "Adding " in the header without + creating a new template +* Improve messaging to let users know when they've saved or created a page. * Make the link that says "You can return to the FrontPage" disappear when you are viewing the front page. +* Improve security by forcing the edit_page and add_page views **only** change + data on POST. +* Improve the security model a bit: 'viewers' can add pages, and retain the + ability to edit pages they created. + + +Closing Up +---------- + +But all that's for another time. + +.. class:: incremental + +For this session, we are done. From 60ebfc82fab7d928127ef7e9bbc565b275ec7b28 Mon Sep 17 00:00:00 2001 From: cewing Date: Wed, 31 Jul 2013 01:01:22 -0700 Subject: [PATCH 149/487] add resources for django and pyramid sessions --- resources/session01/session1.py | 21 + resources/session07/myblog_test_fixture.json | 38 ++ resources/session08/blog_view_tests.py | 60 +++ resources/session08/django_blog.css | 74 ++++ resources/session08/mysite/manage.py | 10 + resources/session08/mysite/myblog/__init__.py | 0 resources/session08/mysite/myblog/admin.py | 37 ++ .../myblog/fixtures/myblog_test_fixture.json | 38 ++ resources/session08/mysite/myblog/models.py | 36 ++ .../mysite/myblog/static/django_blog.css | 74 ++++ .../mysite/myblog/templates/detail.html | 20 + .../mysite/myblog/templates/list.html | 27 ++ resources/session08/mysite/myblog/tests.py | 118 ++++++ resources/session08/mysite/myblog/urls.py | 14 + resources/session08/mysite/myblog/views.py | 47 +++ resources/session08/mysite/mysite/__init__.py | 0 resources/session08/mysite/mysite/settings.py | 158 ++++++++ .../mysite/mysite/templates/base.html | 16 + resources/session08/mysite/mysite/urls.py | 18 + resources/session08/mysite/mysite/wsgi.py | 32 ++ resources/session10/base.pt | 62 +++ resources/session10/wikitutorial/.coverage | Bin 0 -> 75448 bytes resources/session10/wikitutorial/CHANGES.txt | 4 + resources/session10/wikitutorial/MANIFEST.in | 2 + resources/session10/wikitutorial/README.txt | 1 + .../session10/wikitutorial/development.ini | 65 +++ .../session10/wikitutorial/production.ini | 60 +++ resources/session10/wikitutorial/setup.cfg | 27 ++ resources/session10/wikitutorial/setup.py | 45 +++ .../wikitutorial/wikitutorial/__init__.py | 26 ++ .../wikitutorial/wikitutorial/models.py | 31 ++ .../wikitutorial/wikitutorial/security.py | 14 + .../wikitutorial/static/favicon.ico | Bin 0 -> 1406 bytes .../wikitutorial/static/footerbg.png | Bin 0 -> 333 bytes .../wikitutorial/static/headerbg.png | Bin 0 -> 203 bytes .../wikitutorial/wikitutorial/static/ie6.css | 8 + .../wikitutorial/static/middlebg.png | Bin 0 -> 2797 bytes .../wikitutorial/static/pylons.css | 372 ++++++++++++++++++ .../wikitutorial/static/pyramid-small.png | Bin 0 -> 7044 bytes .../wikitutorial/static/pyramid.png | Bin 0 -> 33055 bytes .../wikitutorial/static/transparent.gif | Bin 0 -> 49 bytes .../wikitutorial/templates/base.pt | 62 +++ .../wikitutorial/templates/edit.pt | 15 + .../wikitutorial/templates/login.pt | 16 + .../wikitutorial/templates/mytemplate.pt | 76 ++++ .../wikitutorial/templates/view.pt | 13 + .../wikitutorial/wikitutorial/tests.py | 200 ++++++++++ .../wikitutorial/wikitutorial/views.py | 106 +++++ 48 files changed, 2043 insertions(+) create mode 100644 resources/session01/session1.py create mode 100644 resources/session07/myblog_test_fixture.json create mode 100644 resources/session08/blog_view_tests.py create mode 100644 resources/session08/django_blog.css create mode 100644 resources/session08/mysite/manage.py create mode 100644 resources/session08/mysite/myblog/__init__.py create mode 100644 resources/session08/mysite/myblog/admin.py create mode 100644 resources/session08/mysite/myblog/fixtures/myblog_test_fixture.json create mode 100644 resources/session08/mysite/myblog/models.py create mode 100644 resources/session08/mysite/myblog/static/django_blog.css create mode 100644 resources/session08/mysite/myblog/templates/detail.html create mode 100644 resources/session08/mysite/myblog/templates/list.html create mode 100644 resources/session08/mysite/myblog/tests.py create mode 100644 resources/session08/mysite/myblog/urls.py create mode 100644 resources/session08/mysite/myblog/views.py create mode 100644 resources/session08/mysite/mysite/__init__.py create mode 100644 resources/session08/mysite/mysite/settings.py create mode 100644 resources/session08/mysite/mysite/templates/base.html create mode 100644 resources/session08/mysite/mysite/urls.py create mode 100644 resources/session08/mysite/mysite/wsgi.py create mode 100644 resources/session10/base.pt create mode 100644 resources/session10/wikitutorial/.coverage create mode 100644 resources/session10/wikitutorial/CHANGES.txt create mode 100644 resources/session10/wikitutorial/MANIFEST.in create mode 100644 resources/session10/wikitutorial/README.txt create mode 100644 resources/session10/wikitutorial/development.ini create mode 100644 resources/session10/wikitutorial/production.ini create mode 100644 resources/session10/wikitutorial/setup.cfg create mode 100644 resources/session10/wikitutorial/setup.py create mode 100644 resources/session10/wikitutorial/wikitutorial/__init__.py create mode 100644 resources/session10/wikitutorial/wikitutorial/models.py create mode 100644 resources/session10/wikitutorial/wikitutorial/security.py create mode 100644 resources/session10/wikitutorial/wikitutorial/static/favicon.ico create mode 100644 resources/session10/wikitutorial/wikitutorial/static/footerbg.png create mode 100644 resources/session10/wikitutorial/wikitutorial/static/headerbg.png create mode 100644 resources/session10/wikitutorial/wikitutorial/static/ie6.css create mode 100644 resources/session10/wikitutorial/wikitutorial/static/middlebg.png create mode 100644 resources/session10/wikitutorial/wikitutorial/static/pylons.css create mode 100644 resources/session10/wikitutorial/wikitutorial/static/pyramid-small.png create mode 100644 resources/session10/wikitutorial/wikitutorial/static/pyramid.png create mode 100644 resources/session10/wikitutorial/wikitutorial/static/transparent.gif create mode 100644 resources/session10/wikitutorial/wikitutorial/templates/base.pt create mode 100644 resources/session10/wikitutorial/wikitutorial/templates/edit.pt create mode 100644 resources/session10/wikitutorial/wikitutorial/templates/login.pt create mode 100644 resources/session10/wikitutorial/wikitutorial/templates/mytemplate.pt create mode 100644 resources/session10/wikitutorial/wikitutorial/templates/view.pt create mode 100644 resources/session10/wikitutorial/wikitutorial/tests.py create mode 100644 resources/session10/wikitutorial/wikitutorial/views.py diff --git a/resources/session01/session1.py b/resources/session01/session1.py new file mode 100644 index 00000000..228296d8 --- /dev/null +++ b/resources/session01/session1.py @@ -0,0 +1,21 @@ +import socket + + +def get_constants(prefix): + return dict( (getattr(socket, n), n) + for n in dir(socket) + if n.startswith(prefix)) + + +def get_address_info(host, port): + families = get_constants('AF_') + types = get_constants('SOCK_') + protocols = get_constants('IPPROTO_') + for response in socket.getaddrinfo(host, port): + fam, typ, pro, nam, add = response + print 'family: ', families[fam] + print 'type: ', types[typ] + print 'protocol: ', protocols[pro] + print 'canonical name: ', nam + print 'socket address: ', add + print diff --git a/resources/session07/myblog_test_fixture.json b/resources/session07/myblog_test_fixture.json new file mode 100644 index 00000000..592dea17 --- /dev/null +++ b/resources/session07/myblog_test_fixture.json @@ -0,0 +1,38 @@ +[ +{ + "pk": 1, + "model": "auth.user", + "fields": { + "username": "admin", + "first_name": "Mr.", + "last_name": "Administrator", + "is_active": true, + "is_superuser": true, + "is_staff": true, + "last_login": "2013-05-24T05:35:58.628Z", + "groups": [], + "user_permissions": [], + "password": "pbkdf2_sha256$10000$1rQazFNdOfFt$6aw/uIrv2uASkZ7moXMTajSN+ySYuowBnbP6ILNQntE=", + "email": "admin@example.com", + "date_joined": "2013-05-24T05:35:58.628Z" + } +}, +{ + "pk": 2, + "model": "auth.user", + "fields": { + "username": "noname", + "first_name": "", + "last_name": "", + "is_active": true, + "is_superuser": true, + "is_staff": true, + "last_login": "2013-05-24T05:35:58.628Z", + "groups": [], + "user_permissions": [], + "password": "pbkdf2_sha256$10000$1rQazFNdOfFt$6aw/uIrv2uASkZ7moXMTajSN+ySYuowBnbP6ILNQntE=", + "email": "noname@example.com", + "date_joined": "2013-05-24T05:35:58.628Z" + } +} +] diff --git a/resources/session08/blog_view_tests.py b/resources/session08/blog_view_tests.py new file mode 100644 index 00000000..6f67f18e --- /dev/null +++ b/resources/session08/blog_view_tests.py @@ -0,0 +1,60 @@ +import datetime +from django.test import TestCase +from django.utils.timezone import utc +from djagno.contrib.auth.models import User + +from myblog.models import Post, Category + + +class FrontEndTestCase(TestCase): + """test views provided in the front-end""" + fixtures = ['myblog_test_fixture.json', ] + + def setUp(self): + self.now = datetime.datetime.utcnow().replace(tzinfo=utc) + self.timedelta = datetime.timedelta(15) + author = User.objects.get(pk=1) + self.category = Category(name='A Category') + self.category.save() + for count in range(1,11): + post = Post(title="Post %d Title" % count, + text="foo", + author=author) + if count < 6: + # publish the first five posts + pubdate = self.now - self.timedelta * count + post.published_date = pubdate + post.save() + if bool(count & 1): + # put odd items in category: + self.category.posts.add(post) + + def test_list_only_published(self): + resp = self.client.get('/') + self.assertTrue("Recent Posts" in resp.content) + for count in range(1,11): + title = "Post %d Title" % count + if count < 6: + self.assertContains(resp, title, count=1) + else: + self.assertNotContains(resp, title) + + def test_details_only_published(self): + for count in range(1,11): + title = "Post %d Title" % count + post = Post.objects.get(title=title) + resp = self.client.get('/posts/%d/' % post.pk) + if count < 6: + self.assertEqual(resp.status_code, 200) + self.assertContains(resp, title) + else: + self.assertEqual(resp.status_code, 404) + + def test_category_only_published(self): + resp = self.client.get('/category/%d/' % self.category.pk) + for count in range(1,11): + title = "Post %d Title" % count + if count < 6 and bool(count & 1): + self.assertContains(resp, title, count=1) + else: + self.assertNotContains(resp, title) \ No newline at end of file diff --git a/resources/session08/django_blog.css b/resources/session08/django_blog.css new file mode 100644 index 00000000..64560dc0 --- /dev/null +++ b/resources/session08/django_blog.css @@ -0,0 +1,74 @@ +body { + background-color: #eee; + color: #111; + font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + margin:0; + padding:0; +} +#container { + margin:0; + padding:0; + margin-top: 0px; +} +#header { + background-color: #333; + border-botton: 1px solid #111; + margin:0; + padding:0; +} +#control-bar { + margin: 0em 0em 1em; + list-style: none; + list-style-type: none; + text-align: right; + color: #eee; + font-size: 80%; + padding-bottom: 0.4em; +} +#control-bar li { + display: inline-block; +} +#control-bar li a { + color: #eee; + padding: 0.5em; + text-decoration: none; +} +#control-bar li a:hover { + color: #cce; +} +#content { + margin: 0em 1em 1em; +} + +ul#entries { + list-style: none; + list-style-type: none; +} +div.entry { + margin-right: 2em; + margin-top: 1em; + border-top: 1px solid #cecece; +} +ul#entries li:first-child div.entry { + border-top: none; + margin-top: 0em; +} +div.entry-body { + margin-left: 2em; +} +.notification { + float: right; + text-align: center; + width: 25%; + padding: 1em; +} +.info { + background-color: #aae; +} +ul.categories { + list-style: none; + list-style-type: none; +} +ul.categories li { + display: inline; +} \ No newline at end of file diff --git a/resources/session08/mysite/manage.py b/resources/session08/mysite/manage.py new file mode 100644 index 00000000..8a50ec04 --- /dev/null +++ b/resources/session08/mysite/manage.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) diff --git a/resources/session08/mysite/myblog/__init__.py b/resources/session08/mysite/myblog/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/resources/session08/mysite/myblog/admin.py b/resources/session08/mysite/myblog/admin.py new file mode 100644 index 00000000..a2c21638 --- /dev/null +++ b/resources/session08/mysite/myblog/admin.py @@ -0,0 +1,37 @@ +from django.contrib import admin +from django.core.urlresolvers import reverse +from myblog.models import Post, Category + + +class CategoryInlineAdmin(admin.TabularInline): + model = Category.posts.through + extra = 1 + verbose_name = "Category" + verbose_name_plural = "Categories" + + +class PostAdmin(admin.ModelAdmin): + list_display = ('__unicode__', 'created_date', 'modified_date', + 'published_date', 'author_link') + readonly_fields = ('created_date', 'modified_date') + inlines = [CategoryInlineAdmin, ] + + def author_link(self, post): + url = reverse('admin:auth_user_change', args=(post.id,)) + name = post.author_name() + return '%s' % (url, name) + author_link.allow_tags = True + + def get_readonly_fields(self, request, obj=None): + fields = () + if obj is not None: + fields = self.readonly_fields + return fields + + +class CategoryAdmin(admin.ModelAdmin): + exclude = ('posts', ) + + +admin.site.register(Post, PostAdmin) +admin.site.register(Category, CategoryAdmin) diff --git a/resources/session08/mysite/myblog/fixtures/myblog_test_fixture.json b/resources/session08/mysite/myblog/fixtures/myblog_test_fixture.json new file mode 100644 index 00000000..592dea17 --- /dev/null +++ b/resources/session08/mysite/myblog/fixtures/myblog_test_fixture.json @@ -0,0 +1,38 @@ +[ +{ + "pk": 1, + "model": "auth.user", + "fields": { + "username": "admin", + "first_name": "Mr.", + "last_name": "Administrator", + "is_active": true, + "is_superuser": true, + "is_staff": true, + "last_login": "2013-05-24T05:35:58.628Z", + "groups": [], + "user_permissions": [], + "password": "pbkdf2_sha256$10000$1rQazFNdOfFt$6aw/uIrv2uASkZ7moXMTajSN+ySYuowBnbP6ILNQntE=", + "email": "admin@example.com", + "date_joined": "2013-05-24T05:35:58.628Z" + } +}, +{ + "pk": 2, + "model": "auth.user", + "fields": { + "username": "noname", + "first_name": "", + "last_name": "", + "is_active": true, + "is_superuser": true, + "is_staff": true, + "last_login": "2013-05-24T05:35:58.628Z", + "groups": [], + "user_permissions": [], + "password": "pbkdf2_sha256$10000$1rQazFNdOfFt$6aw/uIrv2uASkZ7moXMTajSN+ySYuowBnbP6ILNQntE=", + "email": "noname@example.com", + "date_joined": "2013-05-24T05:35:58.628Z" + } +} +] diff --git a/resources/session08/mysite/myblog/models.py b/resources/session08/mysite/myblog/models.py new file mode 100644 index 00000000..44ed1e0f --- /dev/null +++ b/resources/session08/mysite/myblog/models.py @@ -0,0 +1,36 @@ +from django.db import models +from django.contrib.auth.models import User + + +class Post(models.Model): + title = models.CharField(max_length=128) + text = models.TextField(blank=True) + author = models.ForeignKey(User) + created_date = models.DateTimeField(auto_now_add=True) + modified_date = models.DateTimeField(auto_now=True) + published_date = models.DateTimeField(blank=True, null=True) + + def __unicode__(self): + return self.title + + def author_name(self): + raw_name = "%s %s" % (self.author.first_name, + self.author.last_name) + name = raw_name.strip() + if not name: + name = self.author.username + return name + + +class Category(models.Model): + name = models.CharField(max_length=128) + description = models.TextField(blank=True) + posts = models.ManyToManyField(Post, + blank=True, + null=True, + related_name='categories' + ) + + def __unicode__(self): + return self.name + diff --git a/resources/session08/mysite/myblog/static/django_blog.css b/resources/session08/mysite/myblog/static/django_blog.css new file mode 100644 index 00000000..64560dc0 --- /dev/null +++ b/resources/session08/mysite/myblog/static/django_blog.css @@ -0,0 +1,74 @@ +body { + background-color: #eee; + color: #111; + font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + margin:0; + padding:0; +} +#container { + margin:0; + padding:0; + margin-top: 0px; +} +#header { + background-color: #333; + border-botton: 1px solid #111; + margin:0; + padding:0; +} +#control-bar { + margin: 0em 0em 1em; + list-style: none; + list-style-type: none; + text-align: right; + color: #eee; + font-size: 80%; + padding-bottom: 0.4em; +} +#control-bar li { + display: inline-block; +} +#control-bar li a { + color: #eee; + padding: 0.5em; + text-decoration: none; +} +#control-bar li a:hover { + color: #cce; +} +#content { + margin: 0em 1em 1em; +} + +ul#entries { + list-style: none; + list-style-type: none; +} +div.entry { + margin-right: 2em; + margin-top: 1em; + border-top: 1px solid #cecece; +} +ul#entries li:first-child div.entry { + border-top: none; + margin-top: 0em; +} +div.entry-body { + margin-left: 2em; +} +.notification { + float: right; + text-align: center; + width: 25%; + padding: 1em; +} +.info { + background-color: #aae; +} +ul.categories { + list-style: none; + list-style-type: none; +} +ul.categories li { + display: inline; +} \ No newline at end of file diff --git a/resources/session08/mysite/myblog/templates/detail.html b/resources/session08/mysite/myblog/templates/detail.html new file mode 100644 index 00000000..a3d07005 --- /dev/null +++ b/resources/session08/mysite/myblog/templates/detail.html @@ -0,0 +1,20 @@ +{% extends "base.html" %} + +{% block content %} +Home +

    {{ post }}

    + +
    + {{ post.text }} +
    + +{% endblock %} \ No newline at end of file diff --git a/resources/session08/mysite/myblog/templates/list.html b/resources/session08/mysite/myblog/templates/list.html new file mode 100644 index 00000000..57844769 --- /dev/null +++ b/resources/session08/mysite/myblog/templates/list.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} + +{% block content %} +

    {{ title }}

    +

    {{ description }}

    + {% for post in posts %} +
    +

    + {{ post }} +

    + +
    + {{ post.text }} +
    +
      + {% for category in post.categories.all %} +
    • + + {{ category }} +
    • + {% endfor %} +
    +
    + {% endfor %} +{% endblock %} \ No newline at end of file diff --git a/resources/session08/mysite/myblog/tests.py b/resources/session08/mysite/myblog/tests.py new file mode 100644 index 00000000..61d771e2 --- /dev/null +++ b/resources/session08/mysite/myblog/tests.py @@ -0,0 +1,118 @@ +import datetime +from django.test import TestCase +from django.contrib.auth.models import User +from django.contrib.admin.sites import AdminSite +from django.utils.timezone import utc + +from myblog.models import Post +from myblog.models import Category +from myblog.admin import PostAdmin + + +class PostTestCase(TestCase): + fixtures = ['myblog_test_fixture.json', ] + + def setUp(self): + self.user = User.objects.get(pk=1) + + def test_unicode(self): + expected = "This is a title" + p1 = Post(title=expected) + actual = unicode(p1) + self.assertEqual(expected, actual) + + def test_author_name(self): + for author in User.objects.all(): + fn, ln, un = (author.first_name, author.last_name, + author.username) + author_name = Post(author=author).author_name() + if not (fn and ln): + self.assertEqual(author_name, un) + else: + if fn: + self.assertTrue(fn in author_name) + if ln: + self.assertTrue(ln in author_name) + + +class CategoryTestCase(TestCase): + + def test_unicode(self): + expected = "A Category" + c1 = Category(name=expected) + actual = unicode(c1) + self.assertEqual(expected, actual) + + +class PostAdminTestCase(TestCase): + fixtures = ['myblog_test_fixture.json', ] + + def setUp(self): + admin = AdminSite() + self.ma = PostAdmin(Post, admin) + for author in User.objects.all(): + title = "%s's title" % author.username + post = Post(title=title, author=author) + post.save() + self.client.login(username='admin', password='secret') + + def test_author_link(self): + expected_link_path = '/admin/auth/user/%s' + for post in Post.objects.all(): + expected = expected_link_path % post.author.pk + actual = self.ma.author_link(post) + self.assertTrue(expected in actual) + + +class FrontEndTestCase(TestCase): + """test views provided in the front-end""" + fixtures = ['myblog_test_fixture.json', ] + + def setUp(self): + self.now = datetime.datetime.utcnow().replace(tzinfo=utc) + self.timedelta = datetime.timedelta(15) + author = User.objects.get(pk=1) + self.category = Category(name='A Category') + self.category.save() + for count in range(1,11): + post = Post(title="Post %d Title" % count, + text="foo", + author=author) + if count < 6: + # publish the first five posts + pubdate = self.now - self.timedelta * count + post.published_date = pubdate + post.save() + if bool(count & 1): + # put odd items in category: + self.category.posts.add(post) + + def test_list_only_published(self): + resp = self.client.get('/') + self.assertTrue("Recent Posts" in resp.content) + for count in range(1,11): + title = "Post %d Title" % count + if count < 6: + self.assertContains(resp, title, count=1) + else: + self.assertNotContains(resp, title) + + def test_details_only_published(self): + for count in range(1,11): + title = "Post %d Title" % count + post = Post.objects.get(title=title) + resp = self.client.get('/posts/%d/' % post.pk) + if count < 6: + self.assertEqual(resp.status_code, 200) + self.assertContains(resp, title) + else: + self.assertEqual(resp.status_code, 404) + + def test_category_only_published(self): + resp = self.client.get('/category/%d/' % self.category.pk) + for count in range(1,11): + title = "Post %d Title" % count + if count < 6 and bool(count & 1): + self.assertContains(resp, title, count=1) + else: + self.assertNotContains(resp, title) diff --git a/resources/session08/mysite/myblog/urls.py b/resources/session08/mysite/myblog/urls.py new file mode 100644 index 00000000..9565f66d --- /dev/null +++ b/resources/session08/mysite/myblog/urls.py @@ -0,0 +1,14 @@ +from django.conf.urls import patterns, url + + +urlpatterns = patterns('myblog.views', + url(r'^$', + 'list_view', + name="blog_index"), + url(http://github.com/r'%5Eposts/(?P%3Cpost_id%3E\d+)/$', + 'detail_view', + name="blog_detail"), + url(http://github.com/r'%5Ecategory/(?P%3Ccategory_id%3E\d+)/$', + 'category_view', + name="category_view") +) diff --git a/resources/session08/mysite/myblog/views.py b/resources/session08/mysite/myblog/views.py new file mode 100644 index 00000000..c917399b --- /dev/null +++ b/resources/session08/mysite/myblog/views.py @@ -0,0 +1,47 @@ +from django.http import HttpResponse, Http404 +from django.shortcuts import render + +from myblog.models import Post, Category + + +def stub_view(request, *args, **kwargs): + body = "Stub View\n\n" + if args: + body += "Args:\n" + body += "\n".join(["\t%s" % a for a in args]) + if kwargs: + body += "Kwargs:\n" + body += "\n".join(["\t%s: %s" % i for i in kwargs.items()]) + return HttpResponse(body, content_type="text/plain") + + +def list_view(request): + published = Post.objects.exclude(published_date__exact=None) + posts = published.order_by('-published_date') + context = {'posts': posts, 'title': 'Recent Posts', + 'description': ''} + return render(request, 'list.html', context) + + +def detail_view(request, post_id): + published = Post.objects.exclude(published_date__exact=None) + try: + post = published.get(pk=post_id) + except Post.DoesNotExist: + raise Http404 + context = {'post': post} + return render(request, 'detail.html', context) + + +def category_view(request, category_id): + try: + category = Category.objects.get(pk=category_id) + except Category.DoesNotExist: + raise Http404 + published = category.posts.exclude(published_date__exact=None) + context = { + 'posts': published.order_by('-published_date'), + 'title': "Posts in %s" % category.name, + 'description': category.description + } + return render(request, 'list.html', context) diff --git a/resources/session08/mysite/mysite/__init__.py b/resources/session08/mysite/mysite/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/resources/session08/mysite/mysite/settings.py b/resources/session08/mysite/mysite/settings.py new file mode 100644 index 00000000..c8043bbf --- /dev/null +++ b/resources/session08/mysite/mysite/settings.py @@ -0,0 +1,158 @@ +# Django settings for mysite project. + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +ADMINS = ( + # ('Your Name', 'your_email@example.com'), +) + +MANAGERS = ADMINS + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': 'mysite.db', + # The following settings are not used with sqlite3: + 'USER': '', + 'PASSWORD': '', + 'HOST': '', + 'PORT': '', + } +} + +# Hosts/domain names that are valid for this site; required if DEBUG is False +# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts +ALLOWED_HOSTS = [] + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# In a Windows environment this must be set to your system time zone. +TIME_ZONE = 'America/Chicago' + +# Language code for this installation. All choices can be found here: +# http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGE_CODE = 'en-us' + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + +# If you set this to False, Django will not format dates, numbers and +# calendars according to the current locale. +USE_L10N = True + +# If you set this to False, Django will not use timezone-aware datetimes. +USE_TZ = True + +# Absolute filesystem path to the directory that will hold user-uploaded files. +# Example: "/var/www/example.com/media/" +MEDIA_ROOT = '' + +# URL that handles the media served from MEDIA_ROOT. Make sure to use a +# trailing slash. +# Examples: "http://example.com/media/", "http://media.example.com/" +MEDIA_URL = '' + +# Absolute path to the directory static files should be collected to. +# Don't put anything in this directory yourself; store your static files +# in apps' "static/" subdirectories and in STATICFILES_DIRS. +# Example: "/var/www/example.com/static/" +STATIC_ROOT = '' + +# URL prefix for static files. +# Example: "http://example.com/static/", "http://static.example.com/" +STATIC_URL = '/static/' + +# Additional locations of static files +STATICFILES_DIRS = ( + # Put strings here, like "/home/html/static" or "C:/www/django/static". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +# List of finder classes that know how to find static files in +# various locations. +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', +# 'django.contrib.staticfiles.finders.DefaultStorageFinder', +) + +# Make this unique, and don't share it with anybody. +SECRET_KEY = '(g!gi6orza2nez)tf-xj_g%5g3!+pmdhs15xjgat)0g!10qku*' + +# List of callables that know how to import templates from various sources. +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', +# 'django.template.loaders.eggs.Loader', +) + +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + # Uncomment the next line for simple clickjacking protection: + # 'django.middleware.clickjacking.XFrameOptionsMiddleware', +) + +ROOT_URLCONF = 'mysite.urls' + +# Python dotted path to the WSGI application used by Django's runserver. +WSGI_APPLICATION = 'mysite.wsgi.application' + +TEMPLATE_DIRS = ( + # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. + '/Users/cewing/projects/training/uw_pce/training.python_web/scripts/session07/mysite/mysite/templates' +) + +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + # Uncomment the next line to enable the admin: + 'django.contrib.admin', + # Uncomment the next line to enable admin documentation: + # 'django.contrib.admindocs', + 'myblog', +) + +# A sample logging configuration. The only tangible logging +# performed by this configuration is to send an email to +# the site admins on every HTTP 500 error when DEBUG=False. +# See http://docs.djangoproject.com/en/dev/topics/logging for +# more details on how to customize your logging configuration. +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse' + } + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler' + } + }, + 'loggers': { + 'django.request': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': True, + }, + } +} diff --git a/resources/session08/mysite/mysite/templates/base.html b/resources/session08/mysite/mysite/templates/base.html new file mode 100644 index 00000000..b498be4e --- /dev/null +++ b/resources/session08/mysite/mysite/templates/base.html @@ -0,0 +1,16 @@ + + + + My Django Blog + + + +
    +
    + {% block content %} + [content will go here] + {% endblock %} +
    +
    + + \ No newline at end of file diff --git a/resources/session08/mysite/mysite/urls.py b/resources/session08/mysite/mysite/urls.py new file mode 100644 index 00000000..2d609f79 --- /dev/null +++ b/resources/session08/mysite/mysite/urls.py @@ -0,0 +1,18 @@ +from django.conf.urls import patterns, include, url + +# Uncomment the next two lines to enable the admin: +from django.contrib import admin +admin.autodiscover() + +urlpatterns = patterns('', + url(http://github.com/r'%5E',%20include('myblog.urls')), + # Examples: + # url(http://github.com/r'%5E'),%20'mysite.views.home',%20name='home'), + # url(http://github.com/r'%5Emysite/',%20include('mysite.foo.urls')), + + # Uncomment the admin/doc line below to enable admin documentation: + # url(http://github.com/r'%5Eadmin/doc/',%20include('django.contrib.admindocs.urls')), + + # Uncomment the next line to enable the admin: + url(http://github.com/r'%5Eadmin/',%20include(admin.site.urls)), +) diff --git a/resources/session08/mysite/mysite/wsgi.py b/resources/session08/mysite/mysite/wsgi.py new file mode 100644 index 00000000..34e900eb --- /dev/null +++ b/resources/session08/mysite/mysite/wsgi.py @@ -0,0 +1,32 @@ +""" +WSGI config for mysite project. + +This module contains the WSGI application used by Django's development server +and any production WSGI deployments. It should expose a module-level variable +named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover +this application via the ``WSGI_APPLICATION`` setting. + +Usually you will have the standard Django WSGI application here, but it also +might make sense to replace the whole Django WSGI application with a custom one +that later delegates to the Django one. For example, you could introduce WSGI +middleware here, or combine a Django application with an application of another +framework. + +""" +import os + +# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks +# if running multiple sites in the same mod_wsgi process. To fix this, use +# mod_wsgi daemon mode with each site in its own daemon process, or use +# os.environ["DJANGO_SETTINGS_MODULE"] = "mysite.settings" +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + +# This application object is used by any WSGI server configured to use this +# file. This includes Django's development server, if the WSGI_APPLICATION +# setting points here. +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() + +# Apply WSGI middleware here. +# from helloworld.wsgi import HelloWorldApplication +# application = HelloWorldApplication(application) diff --git a/resources/session10/base.pt b/resources/session10/base.pt new file mode 100644 index 00000000..6d7e665c --- /dev/null +++ b/resources/session10/base.pt @@ -0,0 +1,62 @@ + + + + Pyramid Wiki + + + + + + + + +
    +
    +
    +
    + pyramid +
    +
    +
    +
    +
    +
    + + Viewing Page Name Goes + Here + +
    + You can return to the + FrontPage. +
    + +
    +
    +
    +
    + +
    +
    +
    + + + \ No newline at end of file diff --git a/resources/session10/wikitutorial/.coverage b/resources/session10/wikitutorial/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..10fd5510b1aac3d02b71cf8492a2133bd49643ee GIT binary patch literal 75448 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⋘> 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�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 PHzar38<;6fm{9w_QSY%U literal 0 HcmV?d00001 diff --git a/resources/session10/wikitutorial/CHANGES.txt b/resources/session10/wikitutorial/CHANGES.txt new file mode 100644 index 00000000..35a34f33 --- /dev/null +++ b/resources/session10/wikitutorial/CHANGES.txt @@ -0,0 +1,4 @@ +0.0 +--- + +- Initial version diff --git a/resources/session10/wikitutorial/MANIFEST.in b/resources/session10/wikitutorial/MANIFEST.in new file mode 100644 index 00000000..8bf2ce54 --- /dev/null +++ b/resources/session10/wikitutorial/MANIFEST.in @@ -0,0 +1,2 @@ +include *.txt *.ini *.cfg *.rst +recursive-include wikitutorial *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml diff --git a/resources/session10/wikitutorial/README.txt b/resources/session10/wikitutorial/README.txt new file mode 100644 index 00000000..0d22b384 --- /dev/null +++ b/resources/session10/wikitutorial/README.txt @@ -0,0 +1 @@ +wikitutorial README diff --git a/resources/session10/wikitutorial/development.ini b/resources/session10/wikitutorial/development.ini new file mode 100644 index 00000000..9dc585f2 --- /dev/null +++ b/resources/session10/wikitutorial/development.ini @@ -0,0 +1,65 @@ +### +# app configuration +# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html +### + +[app:main] +use = egg:wikitutorial + +pyramid.reload_templates = true +pyramid.debug_authorization = false +pyramid.debug_notfound = false +pyramid.debug_routematch = false +pyramid.default_locale_name = en +pyramid.includes = + pyramid_debugtoolbar + pyramid_zodbconn + pyramid_tm + +tm.attempts = 3 +zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 + +# By default, the toolbar only appears for clients from IP addresses +# '127.0.0.1' and '::1'. +# debugtoolbar.hosts = 127.0.0.1 ::1 + +### +# wsgi server configuration +### + +[server:main] +use = egg:waitress#main +host = 0.0.0.0 +port = 6543 + +### +# logging configuration +# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html +### + +[loggers] +keys = root, wikitutorial + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = INFO +handlers = console + +[logger_wikitutorial] +level = DEBUG +handlers = +qualname = wikitutorial + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s diff --git a/resources/session10/wikitutorial/production.ini b/resources/session10/wikitutorial/production.ini new file mode 100644 index 00000000..2b952479 --- /dev/null +++ b/resources/session10/wikitutorial/production.ini @@ -0,0 +1,60 @@ +### +# app configuration +# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html +### + +[app:main] +use = egg:wikitutorial + +pyramid.reload_templates = false +pyramid.debug_authorization = false +pyramid.debug_notfound = false +pyramid.debug_routematch = false +pyramid.default_locale_name = en +pyramid.includes = + pyramid_tm + pyramid_zodbconn + +tm.attempts = 3 +zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000 + +### +# wsgi server configuration +### + +[server:main] +use = egg:waitress#main +host = 0.0.0.0 +port = 6543 + +### +# logging configuration +# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html +### + +[loggers] +keys = root, wikitutorial + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console + +[logger_wikitutorial] +level = WARN +handlers = +qualname = wikitutorial + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s diff --git a/resources/session10/wikitutorial/setup.cfg b/resources/session10/wikitutorial/setup.cfg new file mode 100644 index 00000000..46289de6 --- /dev/null +++ b/resources/session10/wikitutorial/setup.cfg @@ -0,0 +1,27 @@ +[nosetests] +match=^test +nocapture=1 +cover-package=wikitutorial +with-coverage=1 +cover-erase=1 + +[compile_catalog] +directory = wikitutorial/locale +domain = wikitutorial +statistics = true + +[extract_messages] +add_comments = TRANSLATORS: +output_file = wikitutorial/locale/wikitutorial.pot +width = 80 + +[init_catalog] +domain = wikitutorial +input_file = wikitutorial/locale/wikitutorial.pot +output_dir = wikitutorial/locale + +[update_catalog] +domain = wikitutorial +input_file = wikitutorial/locale/wikitutorial.pot +output_dir = wikitutorial/locale +previous = true diff --git a/resources/session10/wikitutorial/setup.py b/resources/session10/wikitutorial/setup.py new file mode 100644 index 00000000..ebf894e9 --- /dev/null +++ b/resources/session10/wikitutorial/setup.py @@ -0,0 +1,45 @@ +import os + +from setuptools import setup, find_packages + +here = os.path.abspath(os.path.dirname(__file__)) +README = open(os.path.join(here, 'README.txt')).read() +CHANGES = open(os.path.join(here, 'CHANGES.txt')).read() + +requires = [ + 'pyramid', + 'pyramid_zodbconn', + 'transaction', + 'pyramid_tm', + 'pyramid_debugtoolbar', + 'ZODB3', + 'waitress', + 'docutils', + 'webtest', + ] + +setup(name='wikitutorial', + version='0.0', + description='wikitutorial', + long_description=README + '\n\n' + CHANGES, + classifiers=[ + "Programming Language :: Python", + "Framework :: Pyramid", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", + ], + author='', + author_email='', + url='', + keywords='web pylons pyramid', + packages=find_packages(), + include_package_data=True, + zip_safe=False, + install_requires=requires, + tests_require=requires, + test_suite="wikitutorial", + entry_points="""\ + [paste.app_factory] + main = wikitutorial:main + """, + ) diff --git a/resources/session10/wikitutorial/wikitutorial/__init__.py b/resources/session10/wikitutorial/wikitutorial/__init__.py new file mode 100644 index 00000000..44ee3ee8 --- /dev/null +++ b/resources/session10/wikitutorial/wikitutorial/__init__.py @@ -0,0 +1,26 @@ +from pyramid.config import Configurator +from pyramid_zodbconn import get_connection +from pyramid.authentication import AuthTktAuthenticationPolicy +from pyramid.authorization import ACLAuthorizationPolicy + +from .models import appmaker +from .security import groupfinder + + +def root_factory(request): + conn = get_connection(request) + return appmaker(conn.root()) + + +def main(global_config, **settings): + """ This function returns a Pyramid WSGI application. + """ + authn_policy = AuthTktAuthenticationPolicy( + 'youdontknowit', callback=groupfinder, hashalg='sha512') + authz_policy = ACLAuthorizationPolicy() + config = Configurator(root_factory=root_factory, settings=settings) + config.set_authentication_policy(authn_policy) + config.set_authorization_policy(authz_policy) + config.add_static_view('static', 'static', cache_max_age=3600) + config.scan() + return config.make_wsgi_app() diff --git a/resources/session10/wikitutorial/wikitutorial/models.py b/resources/session10/wikitutorial/wikitutorial/models.py new file mode 100644 index 00000000..c7ecbc23 --- /dev/null +++ b/resources/session10/wikitutorial/wikitutorial/models.py @@ -0,0 +1,31 @@ +from persistent.mapping import PersistentMapping +from persistent import Persistent +from pyramid.security import Allow, Everyone + + +class Wiki(PersistentMapping): + __name__ = None + __parent__ = None + __acl__ = [(Allow, Everyone, 'view'), + (Allow, 'group:editors', 'edit')] + + +class Page(Persistent): + + def __init__(self, data): + self.data = data + + +def appmaker(zodb_root): + if not 'app_root' in zodb_root: + app_root = Wiki() + frontpage = Page('This is the front page') + app_root['FrontPage'] = frontpage + frontpage.__name__ = 'FrontPage' + frontpage.__parent__ = app_root + zodb_root['app_root'] = app_root + import transaction + transaction.commit() + return zodb_root['app_root'] + + diff --git a/resources/session10/wikitutorial/wikitutorial/security.py b/resources/session10/wikitutorial/wikitutorial/security.py new file mode 100644 index 00000000..bb0ca862 --- /dev/null +++ b/resources/session10/wikitutorial/wikitutorial/security.py @@ -0,0 +1,14 @@ +USERS = { + 'editor': 'editor', + 'viewer': 'viewer', +} + + +GROUPS = { + 'editor': ['group:editors'], +} + + +def groupfinder(userid, request): + if userid in USERS: + return GROUPS.get(userid, []) diff --git a/resources/session10/wikitutorial/wikitutorial/static/favicon.ico b/resources/session10/wikitutorial/wikitutorial/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..71f837c9e27a57cc290a775b8260241d456582e9 GIT binary patch literal 1406 zcmZQzU<5(|0R}M0U}azs1F|%L7$l?s#Ec9aKoZP=&}eKW1$hQXJ8K3_byWuK^4)pUzxN(#<8UmvsK;IDHKmiOqXh0GT$f5y8Mn(lr zPEIj#Ai)ddFf%g)`Eo2Q!azQdBPb}Sz$wKF1QMLQK#sJuG@G&_7$~s=Ib0wh3I<>% w6A18w0hlQO2J+n8d=Qop8c;z43^FJH7?vVPfPvuvGXp~dBk4g5(gV^90E$0CbN~PV literal 0 HcmV?d00001 diff --git a/resources/session10/wikitutorial/wikitutorial/static/footerbg.png b/resources/session10/wikitutorial/wikitutorial/static/footerbg.png new file mode 100644 index 0000000000000000000000000000000000000000..1fbc873daa930207b3a5a07a4d34a9478241d67e GIT binary patch literal 333 zcmV-T0kZyyP)x;P*EWNYZUli+~q;(eTbfe*U$baTG!fAgG=`DK4DzIF9EWa~YA`tJ9_ z8KSNH@Hyb?@aX8R^MT1t_v-D!{?^ltv3)o9> f@a++B;w^4}o%yp?Jw|+(00000NkvXXu0mjfL|da= literal 0 HcmV?d00001 diff --git a/resources/session10/wikitutorial/wikitutorial/static/headerbg.png b/resources/session10/wikitutorial/wikitutorial/static/headerbg.png new file mode 100644 index 0000000000000000000000000000000000000000..0596f2020327efd97a4467c3025691844bb703d5 GIT binary patch literal 203 zcmV;+05t!JP)t-jh%+|_^FEwkAv~hm;c(PdXHHPSc-$gT+Ec53X`vdosFfm>3bJhR=002ovPDHLk FV1j%>T7Uom literal 0 HcmV?d00001 diff --git a/resources/session10/wikitutorial/wikitutorial/static/ie6.css b/resources/session10/wikitutorial/wikitutorial/static/ie6.css new file mode 100644 index 00000000..b7c8493d --- /dev/null +++ b/resources/session10/wikitutorial/wikitutorial/static/ie6.css @@ -0,0 +1,8 @@ +* html img, +* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none", +this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')", +this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("http://github.com/','').replace('")',''), +this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')", +this.runtimeStyle.backgroundImage = "none")),this.pngSet=true) +);} +#wrap{display:table;height:100%} diff --git a/resources/session10/wikitutorial/wikitutorial/static/middlebg.png b/resources/session10/wikitutorial/wikitutorial/static/middlebg.png new file mode 100644 index 0000000000000000000000000000000000000000..2369cfb7da3e5052c2ad4932a6d56240c92654c7 GIT binary patch literal 2797 zcmV4Tx0C)kNmUmQBSrfqTdoR7v5<-y@dJRoV0Fe@UkzPe5BmqJR7!t5oLbpCc6HqI?@={d8%D5al;0(=!Cz zYydD6nO!2_rJ!tuGDRE_#zA==00c_%EKZ!o62USwPXIWXSj`sE}8w<4jU*%sHzk2;U z$a?$5<7MdQoaVsz{O95^ejS$UX;36cb2fe1Y+3Y{{cC>d?Hh%b}~Geu0H=$|_LAH!zl zAj2Q0Uf9TEuaUC0Snjw2jC3cfEVxw!5{*}g2jLb zQa}a}gIur*tOxm^5bOYZKsl%aHJ}bOfD@nvoCX)bWpEwb1byH>7z88W8JGmG!3+dJ zc!&zoAT>xEGJwn=8;A|fhrFObC=7~)5};&A1WBP)&_<{bDu&9TgHRpxBXkP709}Q8 zpu5lzG!Fdvqf1r2MCzX|yZIz>xmnl~$ zpHUuUAPhr>A0wSn#5lp|XS`F#WweHcflJworSw_BrjROl77!Go4w=>|jpnXz2LrNOcbC zbnDFM8tF#rZqRMieW*v$W9ud9?bd78o7C6V57J+yU$1}9fM~!rNHN%J&}lGjXk-{| zxY@A9aLh>6$j@knQN7UvW2&*M@lxYz|7l}t!?UTdxjmOU*L&{Txvg_w*qYf2Z1>yVv7^}q*=@FKxBFo4U@x|B zupf8OcSvxkbQoaM*&*z0>?@8~M-Rufj;9^pI@vo(oK86X;mmSQb3W=kHqU6DU|!9< zVHaH&uFFA}!THSj3G)xkA9U4m<+@h8K6cY{%Av^?0i=GocG202Kesu9q`liwb@Yi zqU=@)9sQZ=k{U}lNr!Ug=Tzjp$&JcAxlD1HXj#{C)8$*2kFM}u@%>87O5V!$RXVHI zuNqqIzWU%AXiegp_O*Iz^VW{6^I3OfJ!yT~`d>C!Z7AOGYGd@qwmi+eb$P>^d^XkR z%jJvn2R1uzuG)gxBHYrwb?(-(tse{c1=k9#3QG##Z{uyd_MP>2rQdzpp0vHY$i8U* z4%`mWj{cplJC77A7OyBC-W9Z~c{g)+!R}Xkmh8D&Vp~$Rm$X;9cd#_Dw6#pXY)9Gq z@|5zv3Xh7$N{z~`mDBt9`+E1g?Qf{ktSYQ}cR+aH&Ox7p&DDn0C5Lc_at=MIiK^-R zp8b7Yt$J-??T5pn!-Ge{j&#&H)YTo;I9gN>*GucikHsIm`Ge;VtqrV(gN=;F!sFn$ z^!U>s6MpPJ5pbgYB>QB;PX<3#Hqn|2nxW?9&66!DErYGGtv#pwPqnu>w>AB2@$=!+ zI;ShnD4!`hOFEl(_S3l)=cdkQou9and||kKN&EeaF&A%lgm!da3b=ITviIeSo$j6I zuDDz|ebwpescYO08?84TZ?^T!>p9!&+I!)a=dH`P z{cd0HThQ0jAK8CrAbw!*4*$;B-SoRJ?&aK@xxelK_Cdizg@+}NG#*v|YVvF2p#9*P zAK5^Wa`oDjMp>M1#i^e9C^!r+xaf~-RMm2 zd;I&-4<;YlJ_dYz@G0Zdr@sILoAdna&gY5%000SaNLh0L01FcU01FcV0GgZ_0000` zNkl3M)`0?X^CI%pY5dZ)Ghq6c#BU2mL4m7>^xj0=#gtkGV1kD*#^bxk;#3qK# z1w@EpQ$noku{i^$7!@T*ax+fPAS4hh!X^U%5(tH;2fehL00000NkvXXu0mjf?v`T0 literal 0 HcmV?d00001 diff --git a/resources/session10/wikitutorial/wikitutorial/static/pylons.css b/resources/session10/wikitutorial/wikitutorial/static/pylons.css new file mode 100644 index 00000000..4b1c017c --- /dev/null +++ b/resources/session10/wikitutorial/wikitutorial/static/pylons.css @@ -0,0 +1,372 @@ +html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td +{ + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-size: 100%; /* 16px */ + vertical-align: baseline; + background: transparent; +} + +body +{ + line-height: 1; +} + +ol, ul +{ + list-style: none; +} + +blockquote, q +{ + quotes: none; +} + +blockquote:before, blockquote:after, q:before, q:after +{ + content: ''; + content: none; +} + +:focus +{ + outline: 0; +} + +ins +{ + text-decoration: none; +} + +del +{ + text-decoration: line-through; +} + +table +{ + border-collapse: collapse; + border-spacing: 0; +} + +sub +{ + vertical-align: sub; + font-size: smaller; + line-height: normal; +} + +sup +{ + vertical-align: super; + font-size: smaller; + line-height: normal; +} + +ul, menu, dir +{ + display: block; + list-style-type: disc; + margin: 1em 0; + padding-left: 40px; +} + +ol +{ + display: block; + list-style-type: decimal-leading-zero; + margin: 1em 0; + padding-left: 40px; +} + +li +{ + display: list-item; +} + +ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl +{ + margin-top: 0; + margin-bottom: 0; +} + +ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir +{ + list-style-type: circle; +} + +ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir +{ + list-style-type: square; +} + +.hidden +{ + display: none; +} + +p +{ + line-height: 1.5em; +} + +h1 +{ + font-size: 1.75em; + line-height: 1.7em; + font-family: helvetica, verdana; +} + +h2 +{ + font-size: 1.5em; + line-height: 1.7em; + font-family: helvetica, verdana; +} + +h3 +{ + font-size: 1.25em; + line-height: 1.7em; + font-family: helvetica, verdana; +} + +h4 +{ + font-size: 1em; + line-height: 1.7em; + font-family: helvetica, verdana; +} + +html, body +{ + width: 100%; + height: 100%; +} + +body +{ + margin: 0; + padding: 0; + background-color: #fff; + position: relative; + font: 16px/24px NobileRegular, "Lucida Grande", Lucida, Verdana, sans-serif; +} + +a +{ + color: #1b61d6; + text-decoration: none; +} + +a:hover +{ + color: #e88f00; + text-decoration: underline; +} + +body h1, body h2, body h3, body h4, body h5, body h6 +{ + font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif; + font-weight: 400; + color: #373839; + font-style: normal; +} + +#wrap +{ + min-height: 100%; +} + +#header, #footer +{ + width: 100%; + color: #fff; + height: 40px; + position: absolute; + text-align: center; + line-height: 40px; + overflow: hidden; + font-size: 12px; + vertical-align: middle; +} + +#header +{ + background: #000; + top: 0; + font-size: 14px; +} + +#footer +{ + bottom: 0; + background: #000 url(http://github.com/footerbg.png) repeat-x 0 top; + position: relative; + margin-top: -40px; + clear: both; +} + +.header, .footer +{ + width: 750px; + margin-right: auto; + margin-left: auto; +} + +.wrapper +{ + width: 100%; +} + +#top, #top-small, #bottom +{ + width: 100%; +} + +#top +{ + color: #000; + height: 230px; + background: #fff url(http://github.com/headerbg.png) repeat-x 0 top; + position: relative; +} + +#top-small +{ + color: #000; + height: 60px; + background: #fff url(http://github.com/headerbg.png) repeat-x 0 top; + position: relative; +} + +#bottom +{ + color: #222; + background-color: #fff; +} + +.top, .top-small, .middle, .bottom +{ + width: 750px; + margin-right: auto; + margin-left: auto; +} + +.top +{ + padding-top: 40px; +} + +.top-small +{ + padding-top: 10px; +} + +#middle +{ + width: 100%; + height: 100px; + background: url(http://github.com/middlebg.png) repeat-x; + border-top: 2px solid #fff; + border-bottom: 2px solid #b2b2b2; +} + +.app-welcome +{ + margin-top: 25px; +} + +.app-name +{ + color: #000; + font-weight: 700; +} + +.bottom +{ + padding-top: 50px; +} + +#left +{ + width: 350px; + float: left; + padding-right: 25px; +} + +#right +{ + width: 350px; + float: right; + padding-left: 25px; +} + +.align-left +{ + text-align: left; +} + +.align-right +{ + text-align: right; +} + +.align-center +{ + text-align: center; +} + +ul.links +{ + margin: 0; + padding: 0; +} + +ul.links li +{ + list-style-type: none; + font-size: 14px; +} + +form +{ + border-style: none; +} + +fieldset +{ + border-style: none; +} + +input +{ + color: #222; + border: 1px solid #ccc; + font-family: sans-serif; + font-size: 12px; + line-height: 16px; +} + +input[type=text], input[type=password] +{ + width: 205px; +} + +input[type=submit] +{ + background-color: #ddd; + font-weight: 700; +} + +/*Opera Fix*/ +body:before +{ + content: ""; + height: 100%; + float: left; + width: 0; + margin-top: -32767px; +} diff --git a/resources/session10/wikitutorial/wikitutorial/static/pyramid-small.png b/resources/session10/wikitutorial/wikitutorial/static/pyramid-small.png new file mode 100644 index 0000000000000000000000000000000000000000..a5bc0ade71d3da5eab67391e840ff20448c42cd6 GIT binary patch literal 7044 zcmV-~8++u5P) zdzci}o%cWIR8?Q*J}|@F9B_mg1Byg}C(F!U?yB?tajLqjd%9-|bY7;1uK18*V5JNA0O7?gXZwlyQ=~5JHG!Lh*b|$Y<8P_TL|# z){fhR;BEzDg%BvE2CYB0{SKvgL%|PzyK3dzgVxy)hL8oP zgmBZRUt48`ZSi0(nVmYx~8(+EYEAA$?mjKfCn^$(-Eb>KLf?+7wNzGj$H!W2z&q(0h@sm z;Q3q(EN6rhoyu~8DgY;PJcq#8Z(s?H`3pz*T zpTMB}uz#sO78ArN#2-VSUB-UfaPv<|S3GYJN88*m};B=E-pwi5>Cpr3~#m2mF^ zbAg?}4}e3!h5`0-!pNZw*M;qbvUq7kMxg|*CaCmX>+Fs*U0n|VIg;Wf;=TJnom z3djp76e4+kdRv0zQQ;$^(7TQru!>s%{1B+aKSv7fBtQ7IO8sH-jE{yQgO z(n-8q@b}lZuxVGAKW;Gy2DCvZJVGTH^kg}vuZ9X>I&cl} z8Q>Z8oA;?t(%GjRAzwbo;Ca#i4gK8iM?b5adGT^eIF!ojyhsoPKWRkbv{2CGpYFPd zsxnEevkm1)@&l3wZa&VPOUgLb2Bskr?PS~vO=XXC2$AUHBw!=3IIV0Ua08lT!`=PW zz^;?k>8A{ z+78_LH{+P{*%IQNZJ@e9S;V3R)KxnC<4s)zEECf-F-;50GO;YnO#uP{oex+Rfj}UU zf`K3b%Q{(WII}Gx_%GmlZoV9tc``ctl%gA0fVQ#TIJH9=9OTr70|Udb0GD_=kmA{pALLQ7l)v;h11 z=v%t|sI-16foilQ+6u%noLk}6iK1<#-fS}e_4MbSn7}Bsm$4PCIm9>}R#jv{&Lo_N zgybW6mz-zFX@sR1D=rLB&AXXmcnGDjz$R&n;IgE;%oN zG(vnJNVh(+~_RiHrGC_?D_E{S6h zFa>wd5;I_3Lcok?sOTTWn&V|6U==j)AGxQU1ud@*CLCl1(d+sg1vS#-h zKj*gpQ?w*L?T|ylfixuHkbc4Y$t9#FhxC=jZJ0l^j0t1&iFeyRca;QTqGS;Q2S-Z4 zAf_ZWWrD9=AK+)N1u#vK^oXWx+;X7_7mw$}LG?Fi=>u9Kcz71L7d;v0qNPUqfWqiW z4Db*AO>J1m8 z$pl(8{t|H1cl9mE_+hXQqnzVlw_~@opyIgheYD^c&~3n9Ho(hkYWbgcLgWQO8U~?Ykb;5& zN=r)_F=7N2l@*i?AMO(Gq=W{>p;t*9L9250zznpi2HH7s7fF}2ho$HV97a#Vbi#cJ ztvh$nbNP|qR*9h{N+z=Pg;gXa-UNCQ&TkL>I>T|$()kv5tZxDfiN(5@_xWQKtBpjD z>;?NEDA(U0wE76H?<9tnAuidJ1lxwN1wZ)fJ{Twkkm(h(x**x7=1kYvNV z?pTU?sdGw@Tf$i;B_$;|wvCWF?q<0vUQ0_0?|-nFTd&zoeaQ}@kr;>o5C9QMZA>|+ zc#?2JxT{oL@^#0dt`ru0c{_J5t4AS_0+7j&fNk3}H#f7txtVx;z=ZQps=a6xu>h@t z9YWh&uK;iL(#CQ0DwOX7=Z8X}shypjYXDJHR5UpfiHrj%Dk@su+S(c*NenT4`tKNgF*H!LHBWmy-+jf7)g?TNbf=MZa1BF$mvQGD_~JtT7qpmn5Kzg80^`zhxO~%^XHGY@x`fe z=3W&c77Ks~_BdY%g<%LJaij@$9O4QROCded3Fx%p+OhC=m$&ef)s=*UD%DX#G9QaZ z`|UzjN_nv&&yr-b7;Au7woy<}aCF_eb%kihO5#c%ee}_i88c>t zy1KfktE;O*J7+QxMb4Z#^K!>=ZUh3MP^hb}uI_{S`uaW9)z!z^+uH*xR;;)o7K;TZ zPMp{P%u!0kytcmk-S0LmSg-(q>#nlo? zEiEl)`Hutk6Hh!L@3`X**~>x$KT*>wg-DV#lPc-QDf@A(zK~PG1x$-!!-gTHq@|^W zRjXd(PakZgy**09*%k}`PZYxt#Nz@X6w;6w!T}K_9_!@j@i@(g1-qKdi0*=s`A}I5 zrG*d*XennqE(vYz8NKICM?ws1x z)bu|U6&2B@rlv~(F1X-=KaU?j-a@Nl-uc2b&9Jvfz%UF0Z3m`1Z;VGCdF0%eUV3Ss z<2Z~NGv=cwpL}w~<(FUHiu-!nym_zh042Q#Bh{2ou#)uIks=dZ)Yin!J z_Lp~D0dnHRiA9!WS+;F+?z!iVMte*>(kj57GiMGDJn%s2;lqcis;VmAw{PD}w@x?E z{q)mM7k%X`UomXkrntDc;MlQaRqnCa#TQ>}zWeUG-nDu6AsbFh4<+Q7aG_v`VWq=Z zwQ3bBUwMVrW5-2MzJO5| zU4VH>fE`;m^81||=-&HB!d)M5R(>m^N;L@!^B`b=VZaanayRpyYM}YJiDe`uo0JmU zwyCbFsz%4dd@`~JRN5BHvVy{$@j?jCfiaLcgE?!~talbJTsZ#t@#Doymo6P$UtfRp z(4j*kq?Go&dGp?N+x53C@J%eG#fD9W$+m3SvP&JuAsh}zmM&fT+_Y)aA|weTjvYIe zi2gf{KX6lBLPDQVH$=Z0Yafr5WPwy(MCf< zL!n37y1Kfv&>q()V6RxQ!kjQ+LOc?QP*6}Xxv{ZvMompk1g)ZWqE*^1pu4`le)!g{ zTfH#MX%zs^Dd8fK2v0uwByX-;=dPPHu^q)f-fD18?Q!1veTW^+MKrfnV}#FTM9p}r z&OM*YuR5FRnkowOQ`P>9Cw&(9TRNk#zxe?B_wJ%;_eZ?FYXi}p8z~jr8CkfSG3D^U zbqDy?i?!H}a6P2jJF1lMR8obWB>fGT3fs1AccNq4wzuqQAa7Ua?z`{)@QEj$Xg+e} zNab&S^P6#-Hf=hnloHj|)w^!L{q}A2Tsgtllt*%dVQmq)Vsq#j#@< zKCGbMZHEJJ&d3VR8Cd~SKL^}Oq$9@Gt=st1d+)M*?J7QQTuVSi={E8(q*g73lt`se zPCR{$V1FQ#Qi%!Gn}q2Ps;jG+G-=WwR;^m~rN+j_aoe|V?*f=Qb?SP{vb^zS?VqG{ zO(9$$5Qs@B9e}pBw!)T{7CB~h3HyaxpFLE45E?&HN=A1cm7S`6*`t3wktXMH(?b@~T zygq}$U>-U~=#ecYxwdM8fDAGTb4Ivh&BvUw@*@31td5gdyc|~sjl1*NzQ2hLAN-iY zqNgY?E90!Q&Z42Afrf?#Mvop%O-&7DWo1~FmC~+l+Z;W5gy!Z0?AWn`ZQHi7b?Y|v z?faO+hmX+K-cB?cCuWxtFeR3uHAdlnt)QgBQI0psP8s0QgiuN;5sgL-k`vv77hLzGT@Up(i?mHwuiejyQwW7yCj6=^$)LXX zT;dBCF8sp_FTAk6si|r5{{8#Uoiu6EKh2#x_k}Nf;S1Zky1LYJ&pkKp<(FT+ITnir z3kwUkMIw>W@pxR4B$%fvrw|?e;_);Hp_F2VhYlU42njhh*DNr|Hz9LE`ugmWCnwr$%0 zux(p1aFr5(*|TSV{NRHRZrr?i^JIYf`ug`TyX>+fWL9%UJRY|l$LXto=fMXbd}-di zdE?vL+lRgJ#v5Ne@4WLShr{8vqeqWc#A31Vq)C%j@7c5G>;nf5jE+Pid884pySqDa zU*hpN?lJ$Egl*f7H1^>}p@AfA2p*`LjtH7jr5 zzJ2Glw6ruVS+e9?k3ar+yW=>9ZQCIsL~QQdx!+s2Zrv4;NMv+08uc7Wj&GZu_uHK6 zw3cv6sUUitV4<6e+!RK8_YA-oK79CaKuD=SP)IB+);p;#dp9AzIBq`;$>WWO{S2|Bb;&^9D87d3xz`6m6erSBaujHRaMm< zJ|W=%tEQ%A&*sgWCrc^gx7>2e>-f~A^#1em^17<3s)_doX7 zV~;-k@WVIm-MjZQkw~Phy}iA7`0(MoufF=~)z3cr?Aj}?xMH^BIFyu>93s`Wa)u8d z9vLxWL=zy&%gYbD$5SL+QBhH6b#?WYj*gCk%F4?9Zk?2|NGYkRs@iUvW@lAZmG>!4 zqK*9g{LaeC$}L@8UHO%jl^>Jp_ifA+{0K(yL57K)5WIC2! z$1n^P2m~^YrH?u)8jVWZwsEh=>r0V=6x+9NH&(4$HN3U8)f_u^?4cWOxZxn0K+#w% zW_NUSIHqaF^7HfE1-HaV#s>ZBWkPjL3;3UOWR-BPT4<3}4GYkcEaaB!Z(}r}Y_w78 z?fVmesI9GSwM^@HG#1O3J&4wmKTCL?<0qU0sB_La$GPK zdm~(ebo8{#(xp~56*8x)qzBU_nnx;c>-|25r>Cc1q(?Y!>rasM{CIf)EzI^K`H{MeUPW_oeTv0z_u=^f*85lb_Uf^g7P2u1>nUx_8}s@4fGFiq_t}_~MJ@ z-~RTuZ`!nJ({+F-EG*ph_~VcNoK!pNOhOMelb)pWlg6LYiI$CYr$o9zQfhgm@PA)r z`;Mg>?FvmwKjHkVG*YCSo8mwI@sEG^(#n-@wYRlR%g@(wwoKB^Qv;KBn9Ne1iLCmE zVYSmlrb;(Y^>lx@Xy?wIOqnuuSzTRS2f3FfV(HSQRd?NW*W#|Ou5y69yu3XN7A*Mw zl~-PQ_!NxibU`Mlu3fvVapT7QytA{jX5`3`uP<7(=x4KM&pwmM1}9FqbmC=_ZgKinHwQf=07=4` zB+1sFluouxwws@H{;gcNaN)>*S+wXO%QPEGN=vXzDrE#d^i&J8 zNxF2x^{Hm&f^dT5Pq6u=oRML_zmAgL2nQfvef8CXZ+zn$^IKY4W`;tcVFd*R1Ofr~ z!_=PADVfr^;`*lI0XK2xJoOmD**k4~?zu`we`qBFH&p+S$?ZPv4lK*c(I^n!+ zf7Hv~R+nUTqU1`#dCrq`$(2og%w)6qy^@(omMzGh>D#ev80gJN{}yeCX#abVDLmk9 zdn25ePbXKp-Ii0rd2zVDE`qeurAsLpT}eP0jT7 z`yya^y_9nX(^Dw`?@NKizAxX`evh{L>T3u?I6?Gh@@JD)y@eDq*2!g9z_Zct<-Ky! z^63~-9fvU3=&zcYt-L=Dm_bKxHe9A9M<+s_A)*aoFmNK|=noNr!Ix}_eg<-qYxfOd i2&XM_{d<%B#s3F+!sT<+TNZKv00004sn-QC?SxVt;WN^z%9ti|1fLvb%&C|cZtdy7NR;skfsH~s$Z=lvs_ zWIub(?v7k@otZh&S{jNNsHCVcFfbU(N^&|dFz-&GzblXtp~tW5t%5Kx)G*3&(z@Qc z$6a2zLN+ba_o^!a|ym1!qri4~+MCW;kOSMr_MQpii zS?4^tkJK0+{25c0Ue5cmsK`!5jMxcd2QBM=Y}N$ZxEe!ex=22yBOK|buV8ci>wsQqy0~3#V{EYqi4U<@H zJGSaQ)>7^v^Ei^z!+6$I9p+N*V7Ik?g{=6oAL}IG=VPz#4wr3L@T6tEAv@vtK?K1m zUHF%pjv5E!p^jefRoL88igJXWt4@oWrGpTlcRZwx#Ok*y^UZj8&hvs*_seI9EBMd< z4GtkVEf@M}P@7=C=FO7u*s6c%!F=(dW#ML%=3E9aCrCVS2{+QHl?`E`| zP@SrL_)lCUU52qwEMvO{CVp9vwgRw<8TvwBAZu~z5U~qZB-cQ(|2F99R29=J?|;&b zlc*Ye!MDEIH2@(b);d&Y_~hHkKd~h6AXawaqcZk3Pkc@jBVv9vcvR$YEZz^Z!M59 zZhstGY1B8B^8orsm|jBc>|<8KX_$cx^rN&oK_>C^uthy0VP`%>KK ziXfHJDvscUjwDRl0pb*vEnv0$ElO0h#puHMpN?X8OX~Yx@XhCUGrIqJA3CZWTr3m> zG@5Iv6hx=Yba)=$uepMU{-=?VVbnW|y}o&a{0bf~hiZt?v_!iWDn>59-^B3^^wLGZ z>dk+14g!AF_XQBQ?PWV|IWu0_oCp~hPD_Yrs|=&F=ZX3)$clQMii!RI7rXzvI13Q4 zx6%~jKSR82j!t|G7$dYoH#$(xFSJtococwyNv>q|e{&;Oxl%E5c3qE=^t|aAsW&a$ zPRBokJ_X9Mzv|dQCWxXsB>qowjQXuuSf7S+g}pxg`RD|nH49g&3*Vpmfw%mvy`iDO ztM%xAbK2}!L_Bf3_9FZwa#Rd}C3dVnDaS$-(R!4E)Z{rvb#VUQe3ZVeY_1|(LXV!@ zU*haumNhd5y`jpcQ|P+tL*vQ?{wIFIahPayF9Z$23DL6|VTCp@8#(&Ia-hhj59LrM zZ+t=?(kk!&|LVW$2=7F;2d+t{zC^9ObIN$+0?mt;ZMLIvwtmO?pT(rZnsc0b?Bsr# zhz@Ntc39i+@zgpz0NRO(wKC^V^6&hy>e zjh<4Nh;5bQzn4IVIbwaU3CMadFEd()3QnhTC-faYPMjC#<^TLHwv@GMuq)7h`(Rh) zXJ)-KfR3=Va%x%crYsYzAq>eK3ec4NY}Nkpzgt$IvaKEsK+n#?*w*WiPPUKc&ZOc& z_#bxTdV7l6Ffj0LrR_L=HU7^rAM5+NG=vgn?YXbw!r{qJ595p~e*q25xw|K&#%|_h25v^BkqQT-!AtJW(^ zg@s#zERlr2^4mY@D@eL+%=XYyzqjs2d<;H&*G*;qxAuw%uJyGXPA-HfxT)u3u%|f% zfJm7%6Jr&T@0}*B7gn9|ILyCC+YgT+9{$|FKRdH^>Jw=%$LshBPt^24+L5_52#Gch z$&W)*!N1`6%r35%xLABrO{603pA_6ha9|f;AZg08@xa><)VtVVFS>DDVm? zxW5MytiOS>p=?f7M|!^=NV(pNdPg&?kXC`0Wv@V{MmL21Bq!Bhe|=lldc0Noe8NOn z=V}xKDhaxJc+%T9s~*>vf5iZMAg5KQSvtLm{?EsYh^e({)De|1XwQO>oDu$_bcQ3} zN?x_RP)w1Hd9iTAIVj~4jL``L-8tX}j8>22`0%C`Y)Ca)w31X?h#a|M&Jy3bI{ z1fKIXyPGnwg7_7@xcKDY6gv-V$9t-Go4WSG>K7nXRxrh>7hC*4=PJV94TY!MzBSC7 zxtwPZ&zz7A$x=Rd^|)>5ZD6}%FKS-YSU@e71WQfUSQL}DeHc^E7glc@&MeO46&ERi zc5>UJhxheW6~}MId4M(u)Ey`RU>e<#PIn}s)^7#lSmt%>1gu)cXk$@5^a1=0NYIP7JTnoEVSdAwJ*^MJTD?p% z?%0rCNH%q+`nGw$ZqY8}Nys&xAqr4)ee(cjQpM?wTGq!=mQfRK@%OOr2!FwL!+Q`A zo_46n7rLy{zZR?!>S5ezH$xReVuufmct(Ui87$PsN0ba4Uf}H`uJi3iS~*+Re|=-q z|HCx95(XjZ)J^?ZtMn_tjIP^XcY0aqt4Cx=gjbcq2-bC`tFJuh?l<#>x{~0hE9{-M zI6j!NcWl9A*s;&18#EhsBe4(jG|VfO^|{Mx(*BjT?28fvhM2|(ofss#4iy-fmP$SZ zt;F7Nmqs7aIs=K1Jd7*?R*yzmHXKd4x?M~01ETqAyRB&i*S!gy0r3!97+FTRc%DR2 zXQjHY=`=XrgL!IsET)j6o3gKuI+g9Ze+MtI)J6x>JFmzo2A)ez2XKyFJ8;-0yJ-jo zMW?`)!T~^7uNkw(s4T2!4%!`#re0}Z=>kN?cV{r3Fe~*7x9t`YerrnR=iIj5=^?C} zy_86ZrRZG&EE6JDs0EMvHjQ#LDQeVzu_zIh7|neZvn7MiG&AeGby*+SX<2xWD_R$*}C6WgNu{vKlu>eIeZtnh}3e-v9&U|3VcNIDsIcE8jkz z1PLWbYm%m$w#|q0#l8R$xM{ja)|-|S=(i>U5_ojL?a2L; zf>lq%drUuGaB?A#d3OD*^AVu2x2WTt-+LwY_pz)&=&Z`Y+7}nw@HGD2WbkyLPm;1j zO&9avHW_K#8H;R*_U*MJ0N+6le?c&V-i$ozeMQnsC%52evA5OW{ac39Z{69U3qSnO zw`%`d;m=CSTs{&e%-cJ5 zm{&BMi#JTMkKpY5GQ&+%O~i`1F(Z)b&WE%n|KOX7)N-8|kaf&BSN8Ddphj}8`6!4F z4N>NXHv=tY{jcHeNYTHUmf#TLk7glz3O~q&%9KprnR%7QoMGjKv9@*lXO-S%NYt4z zkKhJg7n6sn?YWWf%UI%+CuKOeGLR3%EX0I+<&5hk7TH43kUysj-rov2eT6!;C~}WZ)CL4@09q z6eNYMdgUaplF>-OCCUss(l*%jr;n$Aq^Bo+dR)w_vX1Aa6@dSu8%F(B`yZzrBce9%)HW_6P~4b0c>vk z*Vuw6;KL`ak?$37BWghcP9=kYc4DQHOuKqKxOq6X<)d(DTq?=zkPq@oR4GKz>?0W3 z$;dOnnqAkUH{@DCMt;g+D^+6TjU&N>Y@bPHjHYBOc`!*oE$sG;k*lSB!XFDahNLR~ z(sa9(NyGxdzP=8VP7;%!kd?jo5{Xiggd54w6Zs2no@`phjRtTDL3F^y-?*_P`}^Wy zNlrhV$9aihWGo{;-@(jKp-@1N;vMiPC!Tooib)T|0N`O1+<&<8_)O`I-ugqPoua49 zP}_k-ezCXWrbLPRTM9~>A!mW5k3*^IDOiPQtyXI(V3Wb$pYi0Io4CYzGeK^*C2H2+ zlGb7G{QDNNAPI`?hs4Rw!eZJjadk$A){AfOf~M$QC~oB_8D`#r2{ZQiV^~TlE%@l% zdYkP;JEcvtwdjhDAeC{^cMd(NpBL`r@!nfje~ zhxlk^Y`9s^%selaU8yJp@72RIR(05C)Ox#3n3 zLu}FK%)Cn+_vYoDI zLNIL_K<$8g)u&M?}d)+yyap&_~`?(k*;Jz{FNsnL$%=P5NBJYXsq@!Xt zek>XBAf%p3_wdK*CXNNAu6Uoa8~mIqjC|OaH*0KHaa0^YTqaWB z$)<=k(vLC5dZQ=+T7q_xhKR9i*|^_=kpF=setwA3-#N@B?Vkik#wTspnwFRHJ{Xt! z%v#cPG~_nJ0Ayo&+b6M&KLj(JFg5+CUa>ZO?&v5c_t&ll1C|v?P`M@S_~q^7N}#s< zq)gKYURiISKgyJ1&6Bcuy!fCT+ z8=7Umg!3gP>Y^n5lc< zHUGzD-N!7Uq@4bkGUZFeL4iiZ>siZLN!9O&-BiAoj1e{>J%%iIpA`(Ww%v9gYh08# z2$k(SVOI4>b8#RHUFAFuY>f<$`?GSE{~I}g1Sp42)z-UxUQg^ONRmxDmPk zlPo`H`8kCnOq5X-B6*%M`ej9Xvv$8|H{7@+bWvtVi%UU0ypj9fM3pr@Ip zHu*n#DEkkb=%l&*>WCw*Lh<%2m?3>S2OWoy2plCvy+i7Ef(cqOrOZ{9)SexFyzJSc z>0X^Su=PNiyz{9K1-EsESOwZs9!Y=VjH41+exx{Qc5s9KocA7?G@p9xA4YhyXKIKe4n8h5|I(gJ=+*RXOG!D1&V60vwFnonPC#|;p4_;!Y-xw`w>fAnCPUDOD2ZOnil15ZLU{RDo7N>^B@`cIKb zEiP*;80CNd9o|kZ2A5T`H56;&d79`tX#`Y|;s0Z__@((utK-LraD>Llo0bol&$zly z^nGA>y?lyCAWbH+!E*0Dg}eQh!?SG35(_nHdATZ2 z_q}r&uUM%)LQMD6m%^JQe!*N#)4+&?zr71vBEmU!X2nu0zPJt(rhtT%bwCafP+}}- zy^ERKBTKuM=}+Sl`k8h$er(W7mvL1bn-vU2!41q@!9_r=3WNPNAwabs zTB%)ZJT2`fig^S!Ukuu2v@5jsJ^>gmgApqhSN=N0%y{H`M9D;aT*0>hbWm~$c75wR zAvhtt%)~f7d$}6bIP;C9TrX}|O{_YktZ;~f^-RrLSk?&D7miO|BknIU!17|~U&I^51 z&0Kh}mUpBn5TU}1pO*uS8u6@Ng~%y&CqKkCz|k1|OY>)hpZqt51d1VoaTxHn z4QS{wMzJ$XYGejPE~l?UXeGKAsPn+~AZ0dqXI6Io@P>3rhVN+250?Q)r7-XXZMR>b zg)V)S0h%_*2tI>dm)Xj}3TND4?LNL5`EdJ_K1Wt6R6PjT%n=m-; zJUji6oG(-W5D@EQU3@Zka;+#?{u<$C;SHcw_ZO?3FqYYb797)D8MELIJp%HN`=+z& zYmAMWhVqjB)(UIpn zoc>aK*7^X3bG?lwy;L48)hF7W_HMlTJp;NqwnA*S3qX($-T7n>7KsrJIBGSqRPN)? z?(V5BYn<~B8@6)rn5o3>E}V+K4zHnyYiWeEGOCMGm#*ehhq3HJ-IxxWO&zFq5rN zl7JgkC49q=_eiVYIngUQDC}fY<~oNPurxZ2SdaTX@Ca`?O~GmuEU24&3cJw;yR#CH ze5A7_6bUS{L{oRw`DMBf$sd$uG}bXE&x+^UAx&xF zEOu>>IQ?dDYMnwtEQ$E{#`pf|%~j|xT)k3=Yb|xv(?eMX?lD5L2kI4xlIe%L9~;J> zb+e3cWZRF~+>*x9Hx#kG!fXg;Ou`Hcy!5nB%|9R;8`H$YzUG8r3>+7Cx+bQqtG&?4 zg{u=wk<4HEZWPbmnSABn^8HFCyDc)S=mV}+aEJU1ZlUF*vT`&|Yy-M#z`f~Ncf5eyL}8?Q4s1~&y=G58G&;&moWSjLILv=zc4gznaqATplG`;@z~1$Tu=5Y~o1g!x zAz32Pm5rV0EqY<-RIl1yHp{>cV|}Vf8e3HY+d(MP%Bk3tnxCV)o_*{@#Jheu)i0DBYCR*Or|*WD`_eD zw^3wOTNY=N(o&of^2Y6g#04Rr*p!dtAHK@jfhmS11q?&Q$eCQaxUqz5sB4ujI{O}g z&Vssv2~#=oj&2m>eEJ$RT zmSHLF&MkMWv%4X*Ma|iW>ryDB3Z=+T$Ll>)z}w&tJ?nI|5^-?;@b|P$L?^HqK!(Ri znz0}u5;%X#dm-rfe&d8^iiBZ>bK#SE!aEBo_*_i%(+{Xf;)t(nZR!#FJG5|srw1z} z!o4Zq);L;yYbz@C;H+#&@B<<|ZKoDQ^M@L)1&vLGZ#v3VO{W=-_t5#2FmtVvJ->YJ zVZyl()a?wG3v8=V%Qlr;rBW#ROfDBVDY1i9OOP1{oORG$A2EdUC%u3Fi7m3S3#5w8 zBTz3B$hozLFq1^K@8`$jE*TV>>j}G)kt~u;c_XGJUj!-ZX?;4FRlr{prcBzU8P%&7u zJtkS$&BQEojcxoBAN^@KizI-oR|~3}X<;!OegyFsuaJE4^-xE98K&O@Ux9chKR*}Zaan`{#DzBwaC+@I@t2r&>o9b#9x53*AycQTxx8>GlJD*WXO>-P|(O|-Me0ITkd!gu|kvpe9Fnc4$ z@{GxT6oX{Cqz?8Ayp5&1_yeeSzFXa&26l_O&Dy$q zGfFMST|rvxj1vu^JUbEju?Q{$Gi$ZX^O_sC3?_sVpLS2cnlwcO2XPrcWqAr~Mji^H z;GLX4p-S;_y zgSzT85V}ZgXcxn~Auj1kGK|C}j!fp21iZ=2+`~co65}6=sI}2Lj0$+8pAB2K})O4WdKcGX-uGXiogegx-IH z37f_wTEQCo@GL}9I^2?m5*O|DENSRylhz^hR|Z^AoSZ}j%JP-Q-){y_1n= z_<8fBqnDuMD^4#im&;jyB9y@g9QqRLLiuizafifzK{x^BZ^qb$kVd!ADL%48(0k_` zo5e2Bv>olzVon_rMgQQAg?!;KB%bY6e|L`_u$R2Yij{q;}Yi+ZDbeM_L_ z((pZ94STz)wK>Q~br+{1;5gr8mTdD6<7w9z=)Llz7Tex5+ztF?zk$iB*uO6eKPpuf zfCWP(w*|=9R@gY&F(&!ci$9QUR6+LYT(T1I9lyaa$_)qYo`m7{Os44U85c#+@OLQH zS9!gD&JtJv&IOqg<09z)^#Z)YF+l>YlZFOPfHn`dV}dD@(yRF(FI<~QWo?P&DY2b= zj^_Zs;2;?pef>|?lyZS@OgI@CSUOAit~@iDEDI@L-$kzl5v83~6ax_+u$1UFCM(Em zI}seH#fL_kh`FSS&UESWJ3@lsUn6EPzFU&Z?2&t;w>1a-o{A5ui_?Ol3YjuDtz462 z&onWYnOJDJKRTXaW`DFl>YC`Uz$Ml?Y$6Bv@6YzJ!m0tz-J2W+o^}3iycOZ96KM3@ zSWz$Fmofaj@Cx(~RCliAcN_5JLFbj33N<#qm5T+`au%6lK}LS4q`Y z`Dq>Alk%G&e}l3lRW%-P>FTEZo$zw6y+LkJT<_ypE}tOGSq1Hy!a%45b~Ei($v0Os zRAT_}dAvS!EIwJ5pOg2uOc2Y0>%B0o(t`eo6*X2QJ}xTH`CB!CA2v9&4M@;{&jFOb zAD*-Alqr>N7-XMQOlD?()7e~isAL5HM$&xhJpe-Au>%S3{(~NAqkPiWVZ? zPQ_0weg4H3A%^WAqp2(~w)>8c7U2;57G+4@;b@$1;o7aqe=JjVFIn2TGK)HZ z3#w4q#VqkEN2;%ReWD&0iMcnPEW2z4TG|BRJ2aw4($BbNhFu$_TCoB+t?5zk*pliJ z)AkWxiO%y#)1FMMUC#|zPXAg9V?c|b3B;0PF~Ctk*n709P5D93UeFfdwf|2*#PEH= zXo*GdZy}dfe|8+jWKL2u8v2>1CF~fK`yNY5!w&H{W!W;M6roTW1V%V#($4TIKZl;d zq#7FUS1Gk!FXF za4Z>h`h)H%6UTy`xCLHPdEHQ7js0|>I%k) zxR8#$0weWLzP$nJcTZ3JoNthkmxovQ!lC;!M7?~b>a^l!3u_4 zJoc!XtG&A$k?5rJ3$SWaUEnSy|MjI0-cph+n__A+DP`HK;-dOqx(WT-!(k%#lGQ~# zNG#~;3VE2qHCLkd1#)byeY>9E@j#IegJ-MEINMmKmatqek<`zY3UP$W=UU{y9bq}W?ZX{ zeJN0mTuk$Cp3%>$8(4oJo55WQc*n_5CsUt1#=c9%1@ zeLk9p*dXHH^5=%s1I}L(DRV{7qpdlcVldddSixOG4(ua&?!OA&q8y?=VyP_U<-M zPIyz_ivd@u>f)2ELw;pv@U>QI>_-rMJuy|SYWxo63uRMI*9|u<+8$Crw5a(6mH0;B1T!> z)RflTEHD&LHhzDx?cm~4-d2H<%Gaaj$?X)F7-P6f_Z>fr6QEL}_R!eesZGyY*OnbzgndMz{uFVd}zOv2rhcBl7kP^mc4vbN2deP4B6(t1}=U`3;? z%tx$(E}lLl&~)FcRb<&B%ro4tE~?jE?nrBZGHuq*eKg*Fz!TKTEbE2T)z#IG_rDhx zhbgBp&Pdpz*Bhdr2zi54)z3S8Kz@H51Yl<$dIXcCzcOJHrBe>5%ttj|lHyGNjRYom z4vguk$L(_?y16{iH=#`L)8K*q$+Mh0@zIi ziUJ)CLQu~}fH7C`^9Bgr@}&k0Gp(WU8ZHdGrb~&vq-2u;G{WISc0AEsk3hatu}~{0 zzlD?YOOBLfV5C{Lq96FuojTSq>-p{uT*yi7_Qcla|3N|cUj_)CSaFq^cA17WdgGx_ zoX_dk*2a5X9)s+)+@ zmk32y{vr`4X|C0LHTwPIV{7n4-T)aXv7jgWY?-Fj@?3>lo=6&yF35f8%Dsy$-KdVt zE&c(q$&2nlrcb=4=$ZG*(wrv@ZFVu?el%knhW7SwFm{ep%(4qeBg1yeg|j2At$wB+ zcZpGM*yl~NX}W{Q%}Rb-pP8xXzuK@#6Au?$NQfnEvr3aM!%@s$bRxWSd+^!d|IL-u$5doH)nA8S@))E z5!tP~)go(>jE$7MUNh6>L^24C0)n{2l@^L%o57F=Q$9kgo70f0-+7iE%bDIPG4CwI@2`^klU z;lUm@k;X3ewKvQ|)cWO5NzodVR_8o_e%c_-P?&18vJHHahz?QAXwANSo##AfJG3iR zqYaDJM8LP?F^h}KFbqK_%nt=#D;zSlI?BfsqKF>otgZKHJsjmpkz(zJ`&dQ1l%sAZ z{|#}c54Jnf%7DozbU6Q@fDQE)yr8d@+j2mKV%iOvi>WKb^mNy#QA~Y|W&-7moAO(+ z$H<4i~|X&8PJ9Ppog(OxdH=N&6V=qaJ~Q*||T}Kso4zh$?TNU)V2~&PcjHZ%4(T zBUjxDG4D>Tk?nRqD7IcL3kAJ45R+ihN<+d~EI)GYQ$ujtd)e(x=%V43phx}L00q-gul8iYGL>(GEbgnh4>MLmzr?@rf_m+n}_#aUiotxk-+ z(`oaBocGF`r|qZ<}8&p97?j>&GRfJ;jYsa8KwX3u40BS>`}k z39ZXw1YVtD1xFAQXEZ{l@bB(-_!SM;mwI_S(EnU$c`K*n%=2My4`u$+99=!b_e{G0 z%VMx|FFp5+bh(aocYGSE4GEHYPG+K!sEG$+xx4lPly(w1H?S>F)}mSmI>#z_W{qwFN*8r{b2iEoZ!Tb2)P_*y%HP>E#CV z*1|7Bhe!nV`Z|6#AU`Rl9bXCY?BoZwPSdX|Go`9v=jBF+Fo@6ixOJE7W?#flL6^VJ zWO6Y3Q{|{G9Y-}Ci~*M^1;(@UdLp`yxx!xrUJebqvm2e3e$DUHsjlqL%4er*h6!^QX`Z&E?QJxKN_~OylezIkKkfQ8Y08{ZJ%KRD4axZQ>bP!JiB`s>+_SRfYahg^T~=5V~Wu7XxV$>8Ip6ceya7EfkOh!3RB)+@_tevJCy|UcLsEj zia1(PDgMc*zrDOMer0+}t#!;H_KmRG~=}zv3bvDka}ouA>dM-AaDpX!fsMOK<6FYg=l&7$R#Cf7~yQ z{wiW}IS6vw9%9fGznNQPtL?mWt>8QOx-51%LWlNk)Or-w_4DV?iZ!6eLz5AoIT>p7 zlI~&dx@$Q3f2#3a`P^c1w`i4UVss*nfq}7x$E2|;8Sr>54pr=tar@VULit!i3elsg z292*@zgmy{`Ahg6=Ipp(GXJASD^W?Uoa-b(8TikiKid?;EKkm#9UL4aw&Qpw5N+Q- zKO)|Jo}xw`@HbqwLk0Pr1>SZ1xr2HZ30LR2%+gqa&t6u_Lamu(1NCIzkdkMCPUW(n zOC!)w-s91JPHcpO4hhQ8fIOCNiO|)^G&0Hj`k$iKc@t<3NQv>ilm7uje&8d??eUT- zAWO=T1IJos&u&u6pkO%4<-?u~y~jLrn)BZbx5Go+NYkT(JJ`I^2+`M_`If91m&qGd6Jl-1l7k-2i9n zM(BehxQ641u+IBpE31cWq$M{B!Oxpzo{tUUseSCXA!z2<`O&4T>1y2U^>Ttj)H4+w z!v{+LFV-I>ye2v?$JnSiljXY3`_QT3vC63FFq+J{)neNw!{qj`)930j>1hg|J)*lqg)xOSPXkL2xw`Xd zLiaNH0?#L(h;Vcl`IQnbrp*m@-&?GvTrCSw|IM{~zbH1Hju#`!4;^(a^w)a)s767a zjITuur{Jn<|D4&|BbZ<~y4p!`TMkV+H z6bvD|`Xi5M{FaSxzs3rv0px|O`c2Eqbt3P}iS!LDI7|54pe&p@K)m0P`jcSae#y8( ze&~Wk?6Ygvhi<W>kjI<*#U>B_h+92W6r?sw`-zZYoFA+x@4tCsL=-=Lih0a-i%O^+he8I%ZiBy{PCK}=H8K`D zXUo)&TA}|8stxP6m}jt&8Szm_5k{w)H?pQ`jfdTI3CcwlDd`dqiv}CH0Wu$r6mX#X zmEaN<S+dYoFZ`&XThlesO5!#B3*?dw9huYVdO8|nsZnuC(#yr2QVrSUjfo@@mYemyDFu*ST#s-E7?hY?3&g`nduxVkHpwE>omwjrA;P zFXO}s?1-D=bf8rgJQQk6^n4tuJ9}Nm$M>vED;S_3i3$fNM^^o4WZw6iQP6iV2wvTo zw_H#!?YTj(XxyA=;dg@;#=ZqK{W{u1j?oWZ*pTC2*4`MwObNGIH3J;q(8;YJZqE0wTCf8Tn6?0 z+a8cO+5uN{e^G~4E>hsi(lWk(`m%o9G;PUId>a&xusA>bvc9rP6xY{jEuTFoL!$IH zPv%Kbr@pDvjl{KSl@OWth9Z1nMY$v4wN-n3hDZkC0GOm_i17?> z!w{vjSG_~j?mKi2l?Wg_6h0DO2FcC(hG=gN2~dJG7<}PMi&K>Rqt(RzLPTpMuAF(X z-G;5(?_9dsX-x%?Opoj4KAh2W_5CM!TO8bSp8V0uTE|pi-AI=V!HA`Zhk7puJWHvl z;r;bg_44u*f70c2Gb>*FcsXNpsvbQm!H178(QfE^iCx%=Mi8`3UZ$Qi)ckqnzMm?8 zv+zXpesi`q=|Hq^$1}=}BPJrn;=$>UqpkPvynR6RT5+}Zb@K&vR!HMfB9WE|QF(2y z6w)PJ&dvfsk{bo-Hf2G_DYBo&*Yi0{1{*@tsJazZZ}v~hTH#HoJ)fEOA7Lw?KpVlQR zn*qc?i$Ks0b~!aq*H3(;e-!9YY{kR_kA<)#?x{7!9_WV?D6ZBlziOlT(U^2mszL_t z2Tm~fgkr2iVIMfyb@+(w3IQni@{iKp&)!&Ca_KH)P&! z{R;W3oe@#ZR72L^_(WK2M^8TalkQ2fa=gDy3^oYp}vaXQfn6ruu~icmD`gsSJv#~pH3{jtT_ zlrbebUBr31NIr+NlVlinPBL&W^8*ZY5bfG}6ct;o6_2)gh5%YC=%Ridb5|_{rL;clSsIi8;N7jGFEb!Ar z<7IUCCSF!$e}@6uI^7!S(Wa31H-j324NY`xVmZsM?NdTo=eswx^3uc25K5zE<*9SlwO zCy)#GL3y^%?GnWMH3GwFxiNbEEFjISMpCY_CHA&;{F?)gspz`JH2&b01Lo`y%MgFL zL(KTYhEHq0;#mBqFJ-=V;F-dr>o*rU?Xjtp7}vkYR{mQt%t4P=h{nYuq9t0H8QIP`u$-X^ZjWQMFp81$Aoxb{9?S1Y# zXKnb3}`%}Q$+M3ww z0N(1``dx#|n*>Q}<=6Q{-brFW&8Do2^X76aUCDS{n4rS76(23=Kn~wKMs8;N+#;jv z$#ytA=5k*MYNSAbV!i9=Db)jQrYj?HYr-!>OT5$wjT!Mu~kW1T)<9Gq*^ zCr#eJ$NN_yD3HjT|EUk_dcBX+{CRCcHAkS{W<@~2<*$kzgcJ0(8kq2Wid>z{NvIKB z=dBVxI7>mOIj=?q;ql0|P%AFt;q29#A(36?Z_N*rE(}dqC5-1u8W}MBvga1q!ZIX& zL}9e0W$!i_V1U2ABKb~z1H1GR+I}-rU(O)7?tk_F^>h_bQE1V22uYO&rAxX+Ksp7H zPLUKCk${c?YmGB7_ug~vK6~$TSO-Wu5xxJ3 z+I*em)Sy|0TY+15DAD}aFUui}3~`RJTbrA%(4mx9LP0t0(bjTLuw|ntp^NRF1Oxe_ zA6h`@EJ{3)$=_+tQ)9kvKYl*!o`pPdw?6SS9OsD5Ns0~TQLp`P&T&Kp6spdvT_FSn z{qcuK1DqrC-#4I1SZ_9xVPVjC zwg$2&PIYt4k0gwY4ZJWJa~q3KJN4{0n?Yh9Z^JmhDHYnMVKi+hz|uAkT@f($o5}|M zzs-M}7=*s6GyjUDdeJ@l_v>4-r&O@%YQ_%7)aL2Nx*$cNZ~taC98RPI2}CFr%PH7& zs(s&8>I|b3bACEp4j4>(9ecQf;QpjQMzl^`%nSh0%G_~}{hr$fafBXmWKXNMi&Zv)xs78ng4^xTFP!_CiyWKHY2Hk8)X6bh zfE&28yzSQdY-1kq2ShcLs=7K1{d{*K~wql9D^TpkwDN!B-B&ZWKV8F!)f$5Zw9rY5!{zQ3eycxRn0WWkZ{&n0 z3|Zs2EZtQZhAw&@n+<=3*5t6IW+#iNa#tyi5%NpZWvQAz&YNe7oz)k0SEO>eDGFKf z{Dm7JT>1r$RD9d8p%qb9YQ*KR@Y0zf4-8v```Nz`TYwpfU$A){y0&hVlvd36w*CmBed9I(mw0m1b{+5e_lHlQ z28-rQ)No;WdAVBA51%Z6xF$7&a%-rhUf5>>s4vuaihK&2PaVh;S;g3=obrC*dzz57D^2D1}|4 z*>xML&Bs0&d@(1`ZLr*QnyK1{Xz`6h40>)ab zDwOEfTP3&HF1G)v84(rwG*zKr^Dcj9bMwz}LPIN*zlp@Ayf~ape4orsO7r8q0Ralezyas6mZ)7Rpt=zZ=ub7RNrO()%jTF-3i~(z4JSr8SEWxE6l>f zJupCp_4k$&tLERZJtMwt>Pn-dwjU`}?HrV^xigV|_au46I7=dQK8l4u5chf`S@Fj6 z&4r^MuJN?cy!PEQBv5Si*1lWrW8NM6pr*RePq()urn_GWcp#^w%(@L(Ce-}v446Bq zkYUql4F)$c4+tG#8_;$>*!-Lggzd=4ryR{HXz;VsGl$hp)u)ugy=RGrpLQm9d2pQv z_`JTHYqho$gxjhQJ|i*dsAW24G$&TvS@WGvxu0G)a>AX&3w^F|Y^L#Kgfbo*hgpC1 zi0sQJIfIPTyzQ;|=hGWHPhUE&501-_=${N`h`7rS=QV?ENInNwN?ZgPzY<8p(y~>& zkt>a*TIE+iftx{p3Kp>}R$5(9!ADI<}UXR;<0!SZ4T9ZSnFq!pPNc4K06YmN>&m zIQMkwEGAaO?k`6Mu+B|+rah+gUD`eZyyH@?*K~y1&A#0|_qo%&6@PJJw_(xiqnX*p zqqXg55hN2QmUstA#Ce#h`ghc8KMbLc!I`C7o6WIDdiTvKzuK+bw8nARA9OQ10@}5* ze}4Si^j}&ow!Ep97QL42SEbQ@vFWwOxp@BlFf4SgN6eOl=nA0-rw~f$>8bWxRwg4& zO-Y&@@2WK)699B0WOHwC9i(@1K@Wd+-TJDtVwmvNHR58FKsWex;2}FH;&tE-U$(L0 zqdiWaO83vY@GXO%HoQ%kNs{neIpSKBty0Rq4IRw=`dOP0{qEH#ZB|{e{dn*qW{ML5$0 ztYa9M34}L@FZ}0d`~g-oi`^YYRh|l0=EU?L3s20>l3{#{ZElb6XW;+T0o7Zgb)CJHZkIV2XPc1a>?h!w@`9HFrJM~&En=mRo81v)pbtS`(& zq3c=hZGHklOD5m@Fn1Ad$^r(*WR?%JJ-_Cbm)$5Uc9uWsIk&d@?atPN$vqhxqksN% zfpAR%m+}4LLKC7%Rqygnqakm!^;NxD_~J7%E+k`WhOVZw6vV5gCLbeT8ex(@WJfd$ z*Gn~+B$H@oHa2|p^!z>}L38sju&3y0`~%uPy?xxJWX1Q4>uFaHLl@=B^O2utt_v?y zp1&=xxDFamQ7bl>ryD}atQ4zmE>%h|u`$mxq)4v_ygc6cx!fK05mcMs?Up2yURe^4 zPfSSY>r;%6CmGbdsB3c1lxTqoH zxA9Pi7XI)$>?YZv0y0`EaCm)s{v=XODAkxN|B#!R^~;pZXXT__?w@+XBVq$roPVAM z{agiT@pc4oy=i0f^CHS)hO6<~22FSUtd+F}K#((>PR^WayRlQRdJKU)RMZ<{KqGN+ zc5?D~;~D3RqN*G&jbLHjK=dYt{qvVv&S=AYeYjBRk1Nmo;#tg;U#Dj)=0O6RUI#tF zb{!iw#(RkW`i+{r&nH{)IQjgnh6Wr#p_adXIA=g34jB&m`4QafK*)js)#l*=n}oxE zOiAd;`cNu5Ncuj3foMg=#XfTW@a(x&6H`;vhb_p>MFI6KGEhto4iQvRmX@p_O-O2M zlQ_X(9Y20R@+i=Qp%V1?J}OL)vsExySWAD@OBv1b;j$9EX7v9`LT(0E{CZFs^u=7R z_sy!0_$N;<1}{1N{x_TjEDUZ1R&g5y1Ax)?JjlG;$~@!aFC z8i_sME#l3IlRQf}lA#)Tk*HVg4)B1t1X05`<$SeK#Z*51yTO+u9v*b|;W%&;y0_=cS5y6%NecA1Bx zs(jl-k;3tCzE>?uf3O7K2R5gCrd){lgKTI5@W}KD=lv0eZr%0TBBH%b!3fiA!&GD2lb`rdGp3N9!Jq<9sZTL7?brz=HHcMBJ@p3 zAuTE^^WWaKD5|Us0>T(zHnEKsTHUx@_VnI=H$nneJQ)isYkthC8ervt`uo||HYg#1 z__L*@-{hp$XLEC(f&zxktu3GIY?^1};JQRbN=7z<^pmX1 zwd{SB@sxRCI^W~`%sGXV)ZvHQ=UnV`T%El+UhwMrdS|NA(A&|)Y-bYtDY<}M``d==v)z^hvc-#@=MUk19AqMe||3q~eSj}YG-_6fG@fP;Uw8qGePPBOA zNK*F6k-bB)u;XoEwzm-k+=36g=?Xr0M>X4bYa!d)6MzRhIs>pj_I-QtU)mIM;n2|3 zl#r2m6c-=w1APQ{qD@!&+1rcp7zann+gq%*zWztHl;U@w@PD?j@THTD6nAmqKRG%1 zx+0J~p;KKfk!^=TyM*E2iI=2mm^{FIu66KnM13!o!963G+JQsw^_%*HmcIoGl0rtq zm*a+ub0dv~NA{#OAW4eBZ;l3nG|jn%H8nLwEGNq@xmtwG{oS?nh;CuJt*(c^wkJv( z?w3j6jWXv@pqtlU0BGL4v6g7KU_YkF-_~L=Q4$GGXkl5|ARq@HKYco*udg4IF65%* zy%azq3X0y0e83RZ$c*0f_xD$TvYA;oHdW06$i4waR(N(RJEHQ9V!zqe|g`Wjx2 z2p`9{?6+V497^T)miQ#aTvuJHdl?dmt#1!w=+xum{^dLB?5NV1h#_D6BzJ%%fC`ut znv`!>4cYIc^pnu&e&p#fk{)~Okf&3xcD*)B#Y^M>nKVs1>j50DIE1l^3uwW)zu zUy|TPNNHcTi@Ch-JpPN>lvk{YvWA+Pk48TeTDkLjf)kl0u)nk82OP$q#T-ySJf#Z! z8H6KcVnPQlG6`j6oV+n}YX7g+vpRS-5+E&n=EX{&K%VW-Yy3`t=0)3eUt;lg*nRKy zIaLE?iy583evVK{_4SSaI>C1ZS`PGN9Q`H-==np%jB|r=4i4cie7mGHvhyO1YP-2& zw7WRpV}7z+_dEy)$Q}hvO*$LPp&I%3Klbd5nSzGVM02%tU`#}J((8Gpo zQoZxBc06}0tFb+9)G#2zeIb9X(Bl2wxgogY-Udi!#}$a#B9{mvavY8EHK#DW$1w5maS8WK=*hTQ(7(#B ztEPKKLc|FnIVAc{qyM};ubvMOWP7P8IxXvIWhlCyJgz;nsuhb}vG!543ihXitmPt4 z4y}*2@H(nmx!7_#IXQRE+QOeiu7HJC(bdHUNyYCy8`@Z*au6VOI&);gvcQJbL|%3H z0V;BIt~*;qM1)H~00WXt#uCu^5yR|wgq<~Z##lFZi`{L29T^FWSFA1gwNgx0LWt!O zg^J9mYlQMBpIAtaIf;?QMkB#b46*F>U>Rg$m%}*s zENyI_f}O#OUzDa@YKzjbFYmV|S!?ji8kGL$*Yy+?_RJgyg5@GrjXaP1l?77d6V6qM z{Pme>mm3BT-Wiu^f=K^$ag^F}voG&6bsC#*zDPej@q4?9bClLnCD+l^>Y+$~h;i}J zn2u4s8C=EnNz$B1=bT6*DR#bs+s=+0T{2r?*b_vE2Fs&9Q+&Ot0J*%!v@v#kZTXZ| ztOT0pd%W@(NLi4seqr~frPd?{gAm#)cH*&R6UwmnBoRMniPNTv$wPXA-D&m!{g>(m zggL&3+S<>#eIRKC0l;4$W#qILqGm!)#IC9_N!MmG-yF60Wv3j}B!}H(>ctvwZTP_0 z%$bL9`ge7@BL<4VMv90xD=gQp!Uh=%3^c&vMjXe$OwM&BNGP(sJLWt`w>KA2==%m* zSImnH_mUQbXEt~Ob((*2eEjAZkVGeo4@vLxS&;4a&d&V-042iq$3y&7D3FHw`bo?H z$$oblz$Sw@{vk3j9MX5KwyGRZOkoUGI;C`+&Oh-K2Q!`C^%`~}Ahvfep{ zq;C1bF+x3l$5{nFo+#C19c0<;Zf>SPlnO`DKo6FIqS5?8vk`lKVmEB-xC)GK45(y8;05M_roOg62#tPs&O8rumM^wJ zwqRLc9^-rjIR}}`yri=7z9aAn*(AUhMon8!zA02$yMG2wKwbFt{JyB;Zrzl#gqHto z{qDBE`&p-!*K$Xt*@#W)aMVAV>PK%W)TEW(FJ%yI;XNCYs{9%*4*tqj`l`lcSSENf z42rfWB+LE4g=CE*Z!yL*l?*s1B^uLktxN?bUaoi&34Hs5|H*J7L(J7VpGb(%S4AK$ z%yi6GHR{TQllnz~ydcRagD;<(7yW6#u8eUi)Af48B~Oe#2Y&|cJ}m91bKahuwi!3N z8>W9&z{iNZ2MmgW*0V~lBk73t>gwub0VT2El5Lk`DF2xyp0)(@5d@Myu9U9^$@iY$ zRQA3avj%8we+HQF;sN_>7B%sajo1?Y*B9ICel=FP-MOE+klrVmP*Yo*)%I?DeqNuS zi_0iJF)@`xtWSypfi$u66cVje_zvb(ywf~0f%L79o>ekzy5ans<3+lX?%(^GD3akW zdvfa^KkUg<`}BD5_B@`$(-~c-%5)r^CQ3B#Hy)(^1wg*&EzHlieJ(4_#g+WbMm+lf zC+=nei{`DXso7nDf-^BOVJ;cWf}j9?vlpwGE7X$n^hrjv%dl9wE=ERwyOBE@O)ebH zFO&hJ!Y3G9q(nzDuc=Jge=QhjrwtXY!}ONsyOfX5{nCn@p--=`Q53 z6{<`#AF$?e{>D^CyC$u{K-REOXgU|ln=Gu`mxL81qHCrjo^&pb>7a*5f6vCJqOb2M zedgs%&ZwcTKK6uBF4CR28UP=4ryY?>z;87GE6_hbd#_td3yVN7>sOaHrf6{eeqDn3 zMU0$jQAr8Qqm`3p&mG;x8TSG92J(v_?~9=020+>6w6%GL^vx@YSj{Sd0nX=u#k0I}I>YEEzuRO^Xa2dT;HP1S*+ROIr}D+a2n zF-7I&BFh3w$(wEQN`<=s(N?H1#XbGyoe^A7UQSU~QL#tuFOV}rg|L^bdS51lA0j|4 zHd1{D9bG|I1vgCQ6>vdT?MCn~T>KnU7V}&uvu&+vt*bj7>ofg5mHq^noE8U@U*5ak zU2eebA9z9U%eBOFU;2BGtCKB6&gf^daHT6pQ2hn=4-B-pfB7N@7zWO9P0NO`y`qxP z#xMqflD_v6uh$#UO%z`K>_dAw2IV9^b@<&T?8Hej{|>g~jde^t_Yz}U1M1ce6hb|3 z;6L={PnM4dZfo6--O_dg+c0alrMJA!J$Ll&M-9o&x!9?eo;wWaCY6aNBg(XdqA(MZ z3HK;)qXa#r@LgK^_}=-h+R)bR_B6ATka!Qwg=Si8ur-7+5#oD63e}h`?`|%oGA{?s z;+U~AsmmUeo+@A+-tz`MI>U+2LHJNzu5o%_!XH$6j%SOQPk={B&K3CFUlnWg<9phx z$-fmKcYYvD&&S8dQ6q%WJCGrOn3O#QZV{!s+kNl*VgL^_c?1Lm*yH6j>0|r2^2e*$ zSSg+c$rA2&uvp3(;aP-3mMKfCk z3^|o!ezE05It)fH-^D76>cD(VsKGV$(-wZ~tl;E@#DiD>*4p>=Ryy84b}$^Q0nz=w z-Ti!zblNOxMZgreDCsuRT_|T0-=1g_g=od&L9)QJ5$$(ZJ1-4^)5#IAMZ~A)=b5}b zJZk9*3`J5@tecS?`jBPoawzLU3lLs(M+A4+_Pw6oP-r_A zbASQgWq+C+&7MFS<38DZmcg*6K=?@0A{}pxP_=?@(gKWa?y;N(Sp(87@`GXhNJoqx zX_s((%?S69lB+vKuGKkH!}er;i&Rk}_pW8RkJ-m?nKeL-^{14iGv-Sx;i4;(x;D2; zAf5r_aeGIHe1K=Tpw3lgV_`||b54^o{c&efl;mIOM0^dvQnQ4)h5 z9}`FwxZ&a9zeYIk=k900ZgGCZ!gk@he+(M5vdSwx)>yp{0cC$%$3n68?Hz~PUEP$y zwF@7q@NiPA4S`_2DGw&t=0!QQ|DOx61XwB!Dq+{}&2TuJEk@2CgiI_zEk6NEL@sl*0>2Z|Ng_X0>JDZXLT=_0Z+{op&zUnnpKB z!HAB;fngG?^REga8p&2q%NvZ}q4Jn>5OI;}MEUBexWClyjC1!6zM&F=AC-{ZXR2L1}pir&(w}lkcsGp(GHEM-h!f(aGXU0+n-nXYS zz$#-6=sa zakuEF2Z~_t?BWkS z8vdeKj zX5UE`j``1*ChFauHc|JNerNt}Vx@R(blUg}&iGY?&c{$cPtaDlx$5&yc9ucn?6B-? zfVIr%?I=ahuy5RoxZo}_#NKQ;Z5mVEu#xWZ;?-mW$7{fWFWMwx~DmE&47dps~x=Fz8&o#3AOFD{Ap`uC49du=hDu$-m}Nfyd_n;)5AjA@P`qjA9ZC? zk^B#F4ljkRpW3tMlz~p`44PZ&O0V-#kUchOV)2i5ZN0B+T^8IncvKWtSy@;jEA?B> zTy#>4(`W;zSCFpLb;C#ACW|NTrcQ?B>{a9}M14-2PO8;Z#OJNoekFq==b#!25EATvU^7W^JE)OBD6KVZ4C#_OO;rU5bZF_xTGs zzNE7yN@OxcZ9YG65SLMPOe|elWMZ&nt~NI0wbaJ6iN}dAAEXl5%8SK6ULO>_Sqi%T zsz#!h5*SU?|4MT$e&7t&wEH_uhRE}x>f`Q3kt13OVdEu&{lFaGjnP9VTluBfC4!~~ zr9$kROL)Mo+ggGQb-V+$C@)4_vkF;-IjoS_1d*GY&iq>R;Jo>EiEm| z%O3vrL(ukQN(%ChvgR3&nCWjF-c9M$R}mZ~Bc+X}yA<}~k2H>C2$ z{Ebou|1hW6jTnfN`i_!2IbU|;u42Qmk~ul|-#oTz9Gi7c_MD8ggIP5-jL81Ev}2)y zk;p7*jylH(nC;5E2RDqt3Mj>7)0_lTl=5k;UKU^RvR+h|%Z}-~X3JsCu0Emlh7s03 zN&Wq8$B%0_xT~S-&5Pz^Qiqk{2w5jRX)fYQ1AZ;q19p~|TT$VZ&z5Fcew$0*;z|CX zC4T($vAD4S(s;gIe;?z0F(6-&nC1!vSFd&|;i~{^x2VA+SZKPMPJX{L`~Vm??jN6p ze1o42m}SeST}Pm$O3%r(!#efqcXz`QG&Dq{U++;fo9+0_PGQ1g9hp*+s9(^2w=?r^ zZkT!Z+!VEDNVrClEXlJztu2i7N6`U;UNX}*JO0Fv)52<20k*ef?QJZQ)H?`~`hN1l8&P`STP z1(|};5MsS}=o7e|&W9XI*_(ceS$=T?ec4J=CHUqr*&e%YOJ=j54O(1TIWOsK@7aJ%{2(G*db@{B0$CFHvm z*_*(i>`FM5o_uyief?HW7>5PgJ(XAQ>Q@Nl_Q7mF0({2D-sy7m#w;r;OuSA%pYY$f zpRJ2ue4*=Qx^Z#h_K4^nR<708WFQ#K;iKgiAwI0Ad6gVoH0*~lFJ1JklJlDk)7dm8^04IWxF6~=E^`w@us1zU!YR|; z!dl$0FQV|Ngm*S_NQzO#Rf74N;o}Z-&B)z9DFJs{W|Sem>%pm-+waadqG9rl$FRM{ zo1rNe8*h`@j^UMbvjR2dU;#XgAX&%xfKk0SDo1?HdN$7RtaKkkYZk1JN+le>(-}i= zW%}Y*@W|blq{R&@hr&n{R8BVfe5GkI0om(Q8yi?%EqC+#oi-dG?G4Dfpz^C;Q2LYr zj;#Gvi_8AqyD8Y^^;<%qpMBqWFwrX4G(ZtkWD@f4iv5M)m0^to8HzFjU$6G^7B(;~ zOGCf!Q0Cb8d-O$;J!h1h-u&|HO*c|#&Pqt*4U9Q&f*?SPdQ-OpxVj>Qr3X(Q(UnF1~F6! zHDy#RXxj6*G84O=o&kL)-hyPCD)hglp-J(4zrAIr`tI&dU9FE$01uru=EibXdW+esp{`zoq47~W>S-s> z*|WH1!TVamg59K3MhnXiwsTbR6s3QKUlJhC*3-nu{iw=CQ19l^kYh1wRp?zlG*qg6 zm9(i|@nmQQeEvn>gIIrGT~%ctzapT?5Mez_*$%M&-D!+0<>mL@^=pw_bNK=3@1rdBq9)_Ha zu4!&v{KXpGKxeCisBPN2L{Bz@D{S!6Ng$tOMbTRjvjksMpe&_lO z(~+P@6o{ywfB#ZLAcIM&_Z@yXHm=xQ4W7Si95;shfdD$>4VWd->rq*%@=(Nzqrxn{ zWZH<=S&f)CsJHs6(Y!_=`!Vj}c6kbTv|; zkKOHAI6qB0gfa6IEm%bgaam(*MD6=|enPzX;woyo)1mIeZiuepYISoMeAbZ_&S-Yr zONRsZ0%}hB)WU+71np~Nsh>1OC1vEV1_?U0$%xhr#rr1xvf8->*~)N!zZo+SYKs12 z<}Cg?!I7)=y95ZI#92R~nHa$J~g)2>q$HdBtB5$67JVNrF^iU}9N}Qw+ z%VRtDe)3zF^}FRKmdNkbKHVwz}${J$%H=pS8OQNKcf;dM105RLmN3Ngu8 z?|}-R-ds10O{$}H1g!Yi)0JMQr5n`84Uv_vd=brOt zq+f$x);+J&i77+ym6-m9fH}`EG02iR4Msrc^TP~BIjja|I^tyOk9W;Xim0f@n!lo0 zltte!2$)nRF>U(u%0>3=S1~!B7v~wAkc!_OQe9o(I=Q%@7I@o0I1|6vVfe0MT)A1$sz99ut17Aqtlh7@ zYB7RyXSpr9F$s@t!1}h zJf^G06T#{^2M17u-=yc{oGCwAf#IW(5w*MQgaSw7d72yUUQ97n9nB->09Y=-RvToE zqL=MH$C#l!xL1@EsomkD%l&M=l-L=CvJIFL%eWT};)ihW$&rxN#k|KR|RwhMgm( zLaZ)V@MTW1BX4IcD@7Kjr!VJ$-Sxox3>+`YC@FVg>p*?=aq(RIn3I0 z_vLKvnV|RGwR*#8yr78+r_d)IveSBg`>L$Ex+iD*i#U<7z7LoN_+7*kch6z8pG)RhsaaV zsK766l_L%@xtrGbKClh7YzynxI2Ep5Ik}$s>tcY3>qW!;-CK@@h6TSvu%qG%1?t%= zT~iWi2o0o&GGk2ndf;UmOE_vOZpxTrq~>%^;ZnQ52*39hJB`h}iR$q2iA7(r&w}8F zbyJfM=MACusiRjId{Ko?PDVw)GAGD`XSuEQSIPAlvHXHT6QDjj&A&V@aC!MCQ4w!_ zptHl((1DBv;NkluUO>A?q^(!wK3i`s0u;oI^6%E}c7SLSnyk>jUIw(jXh}syg6Aa- z2JM>y?9fve(`{L3Az3O%wKWU4J6H~P`j7Pl}v_~e0-kyx%fIlO(Y}jDJ8E90X z0Kzu}a`Z^}BTs$uuJ4zabVgAf_v!lnC>$YMU4E|^sz z+ablF^amr;9x$)&WG|RZz;6RO2u$4EUVEu1s-mHxl>sk^=Q(hL4IohibxG(!7-|H1 zJiFLM2afZ^)RYi`$Q#tx9hmq?T95uXNoHi)B}o@(F6+Elzf5ycbxNP#*qQd6(0>nY zhn`k*7iAzpxbzF;zIRgm(5ppRU4*_W;@Y?^zCxA|!Kn8W_FHN%j(D5?%WD_3aPz^h zw%ZO}Jwzemyrco|t=Tm+wNYs3T}Df|u+pacIMt=YblhXgdkv%Sj&7i{NmpZMh2|!_ zd=p6*)&Exe23j7ZZZU8|fxC3TAk`=$4L}Oz`|WsbF9SovsGT}xd#y?X&oyB6@;(Gz zEjM=oBnFK;ch~#2gY6X;kNl~-rHFkvWyHL;Z{EybTF0wwWWqZ2=?gR^XC75?PWV}~ z9Tn$PvA=b7|i zY2;#5`JUd|Ke_eDA}J}UUvqPhfz^tOhX>go7mRY*E!C>H*)X(TxcN}e3^vbRP*6}3 z$h4+_C2l55qsG8bQvB=`D*wgXp_@ge@L3Uj5jd;i)M22=M^F&xEqVJ0yY?>hKG z&zFB-yHqMLCctvi#qIsuEev`24yr0=_=t8{bjQvlTSyG&G|qpZEVh;xZ~aOHCglZl56QFCuFrH+8AZZJD zTyQ;p{8(Ht9c`d`uDRKKf8KRvh6+Hk6?Y^FT+~CU;sEzwd|o*R%?`0N7>=h4HvA1U8)3x8V?`Z=UH^M*KKG zKi7SzM&f}FV{ZsBBZaQ2XL16Mfmo#i+!1SQYi&aB>{goP!SuSQS)R2@S7P&^GXW_lc9M?^#<;`FQ( zA_H9w7b}38G(r*zeE~{w5GF%1z)fUd@e=&HBeobf{p9|{x4PL+=*F?71!MH$`r|ex zzcsLBRbYomBQJwPG&_r}pPv5kaG0Gv7e+mlBV$%Kw*qNV4NVNIm&p?@nx>yrvfQEAP_>69ybGq~3vr2*N z16)cEPC+?(KkbN2|Kv(+2gF|bd6WH@m?QU&QC8E`qWls(l%OxJ= zzBSc1u}dm92T`dUFECSM)8=_Ylng%O#BK-*-LV&u>$a zca+R1ueWvw?ZxDlpFg|q058Mc5SRvXzqD1DnQ^oo#)APCI*;(;GMq1@Ic(d>SYKmZ zyD`-YooMA>V#a4fVvtXLYNVD7kWKMiY;}pIC-a*xLVEq8tlJgF6F1*0>`18Dl;DTq zMer}LM2SV-%rD-~{{|hce+MHYBVU5WQ34X;x`0yrPP6JX1r;9ic>ONkKy{$i>>ej4 zrQ zxd6J_fbFb)CL<%GKRY}7NP~r_zr8&eRWg_iE8usG96hi%ECXEuS zdi>YXOoKxybZ{Dv2u^A~B%g z*YyEum_(O{N+!dISHJXii9`G!4(GjKDsKivNH6!*Uyy1fdY)kA`oyZ8ef&T|4|_vo zzOe)AT(BjL;4t3P{+=4HK8^-aX(YkcXL)oj`!h_uUZL(u^nDQHOu|IX!CHyfr+Ot` zXG#LH$;lllEymJw6rVx1WHDJD_yxKTSUiv4MsV~nAF6B{V>*jmg1sDv>6(Uef+L38 zq#Jx{Nv-{zSJ`p+g!?84dh`$U{ji*Q>DI7+GM(C|fvSoO@5Ne!wL@$dG6$6y&tSGn z>NFKsCU3wG9jz=_u;|_${0klLj6qW0)QmKFN@f;%RuGG(pKJvmhX+z4OLyv%%*SKG zzDmXnCRR0dT49A_B$kqde4dx~trk6kM-6cq88Uv&~diuU+F#T!%E9 z48I0%;u}X9yXne3b8yO{YHQ3$Fx_mpq)5Bo>=3UQZA6E4ickG6J|@IzLiDR%@4%;~ zoLb6vx$B&cGeN5<)i$SSoY=-}G_4gKSp{`b^<)VIubGLdOWhT%lQIG3yjOMOXC z!Dq;j0@Iw2Jb29OL7}q6-u;pfd)KF+>YwX#pLI%0CU(tY&%w%1v|F%( zr#gNd;oBxqq!m9J-?t5&1sC*Rl;A}s7Nq_7(ksmfZOwI(=|9{bA|HMn0$JwV6Na2W z(v8R0C7)Z(H8L9}PS?(bpU;{^y4z!B-D&LYm%uiv8Bizz^cE* zE5psD9`@UpFp7Gy!z82&J>myC-eC?;{C9r5ofo5QObdue`Nn~+3WZkpBI#NSO%na* zvj%mY5k*vEX&&ujcoNbAZ)P7>*K`?!g;;Sm;??%>K6*s&b@|I(-B*;R8eu!?y(YsvQVEa$3@bx*o^CDC2S0uT?RfMyry8ttOHbcA-WZl>fbfDqF|cWlZ#wV2x3)+z&fP**jk7&H^gKE>f(-|$l z%aMn05oyFQ?@PE9S zJMK5F$0E~dqtaDRRg?LHc=X>YMU#X2(}3kECx;w2a3>vsrmMrSOt zql)qrbC&RL&Ac+Md)N_>pVbF9uijhxzFE4x;yDzW46{@(7pbYa_wo=e+wYPO}8yE6E8UNiS3ql#UBjH{VO)3UzYkjep~XlF_v|BG#&Up zy&;NKkN&;SIT9p;Be%v81R!%QQEjv zhu23vxkFQcY;V@@p(#>!ho+UP+>%n8wA$pY`q(P{7by%DZf^sAM0GDc{lbHc5SxMz2Sh=?N6Ja*&XDhq5)#qUk|Gl@1Th+Hl<2F*a z|7qyyGQLJ5_N{{WtlG + + + Pyramid Wiki + + + + + + + + +

    +
    +
    +
    + pyramid +
    +
    +
    +
    +
    +
    + + Viewing Page Name Goes + Here + +
    + You can return to the + FrontPage. +
    + +
    +
    +
    +
    + +
    +
    +
    + + + \ No newline at end of file diff --git a/resources/session10/wikitutorial/wikitutorial/templates/edit.pt b/resources/session10/wikitutorial/wikitutorial/templates/edit.pt new file mode 100644 index 00000000..9d6ef02a --- /dev/null +++ b/resources/session10/wikitutorial/wikitutorial/templates/edit.pt @@ -0,0 +1,15 @@ + + + Editing + Page Name Goes Here + + + + +
    + -
    -
    -
    -
    - -
    -
    -
    - - -
  • -
    - {% endif %} - -
      - {% for entry in entries %} -
    • -

      {{ entry.title }}

      -
      - {{ entry.text|safe }} -
      -
    • - {% else %} -
    • No entries so far
    • - {% endfor %} -
    -{% endblock %} - diff --git a/assignments/teachers/week06/answers/mysite/manage.py b/assignments/teachers/week06/answers/mysite/manage.py deleted file mode 100644 index 8a50ec04..00000000 --- a/assignments/teachers/week06/answers/mysite/manage.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env python -import os -import sys - -if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") - - from django.core.management import execute_from_command_line - - execute_from_command_line(sys.argv) diff --git a/assignments/teachers/week06/answers/mysite/mysite/__init__.py b/assignments/teachers/week06/answers/mysite/mysite/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/assignments/teachers/week06/answers/mysite/mysite/settings.py b/assignments/teachers/week06/answers/mysite/mysite/settings.py deleted file mode 100644 index 405f36e7..00000000 --- a/assignments/teachers/week06/answers/mysite/mysite/settings.py +++ /dev/null @@ -1,152 +0,0 @@ -# Django settings for mysite project. - -DEBUG = True -TEMPLATE_DEBUG = DEBUG - -ADMINS = ( - # ('Your Name', 'your_email@example.com'), -) - -MANAGERS = ADMINS - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': 'mysite.db', # Or path to database file if using sqlite3. - 'USER': '', # Not used with sqlite3. - 'PASSWORD': '', # Not used with sqlite3. - 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. - 'PORT': '', # Set to empty string for default. Not used with sqlite3. - } -} - -# Local time zone for this installation. Choices can be found here: -# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name -# although not all choices may be available on all operating systems. -# In a Windows environment this must be set to your system time zone. -TIME_ZONE = 'America/Chicago' - -# Language code for this installation. All choices can be found here: -# http://www.i18nguy.com/unicode/language-identifiers.html -LANGUAGE_CODE = 'en-us' - -SITE_ID = 1 - -# If you set this to False, Django will make some optimizations so as not -# to load the internationalization machinery. -USE_I18N = True - -# If you set this to False, Django will not format dates, numbers and -# calendars according to the current locale. -USE_L10N = True - -# If you set this to False, Django will not use timezone-aware datetimes. -USE_TZ = True - -# Absolute filesystem path to the directory that will hold user-uploaded files. -# Example: "/home/media/media.lawrence.com/media/" -MEDIA_ROOT = '' - -# URL that handles the media served from MEDIA_ROOT. Make sure to use a -# trailing slash. -# Examples: "http://media.lawrence.com/media/", "http://example.com/media/" -MEDIA_URL = '' - -# Absolute path to the directory static files should be collected to. -# Don't put anything in this directory yourself; store your static files -# in apps' "static/" subdirectories and in STATICFILES_DIRS. -# Example: "/home/media/media.lawrence.com/static/" -STATIC_ROOT = '' - -# URL prefix for static files. -# Example: "http://media.lawrence.com/static/" -STATIC_URL = '/static/' - -# Additional locations of static files -STATICFILES_DIRS = ( - # Put strings here, like "/home/html/static" or "C:/www/django/static". - # Always use forward slashes, even on Windows. - # Don't forget to use absolute paths, not relative paths. -) - -# List of finder classes that know how to find static files in -# various locations. -STATICFILES_FINDERS = ( - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', -# 'django.contrib.staticfiles.finders.DefaultStorageFinder', -) - -# Make this unique, and don't share it with anybody. -SECRET_KEY = ')-z(0n-exq%$(^6*sunt1b7q#zo!hy$f(-p#2@q1pjcsvc0y@)' - -# List of callables that know how to import templates from various sources. -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', -# 'django.template.loaders.eggs.Loader', -) - -MIDDLEWARE_CLASSES = ( - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - # Uncomment the next line for simple clickjacking protection: - # 'django.middleware.clickjacking.XFrameOptionsMiddleware', -) - -ROOT_URLCONF = 'mysite.urls' - -# Python dotted path to the WSGI application used by Django's runserver. -WSGI_APPLICATION = 'mysite.wsgi.application' - -TEMPLATE_DIRS = ( - # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". - # Always use forward slashes, even on Windows. - # Don't forget to use absolute paths, not relative paths. -) - -INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.messages', - 'django.contrib.staticfiles', - # Uncomment the next line to enable the admin: - 'django.contrib.admin', - # Uncomment the next line to enable admin documentation: - # 'django.contrib.admindocs', - 'polls', -) - -# A sample logging configuration. The only tangible logging -# performed by this configuration is to send an email to -# the site admins on every HTTP 500 error when DEBUG=False. -# See http://docs.djangoproject.com/en/dev/topics/logging for -# more details on how to customize your logging configuration. -LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'filters': { - 'require_debug_false': { - '()': 'django.utils.log.RequireDebugFalse' - } - }, - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'filters': ['require_debug_false'], - 'class': 'django.utils.log.AdminEmailHandler' - } - }, - 'loggers': { - 'django.request': { - 'handlers': ['mail_admins'], - 'level': 'ERROR', - 'propagate': True, - }, - } -} diff --git a/assignments/teachers/week06/answers/mysite/mysite/urls.py b/assignments/teachers/week06/answers/mysite/mysite/urls.py deleted file mode 100644 index 94976a0a..00000000 --- a/assignments/teachers/week06/answers/mysite/mysite/urls.py +++ /dev/null @@ -1,18 +0,0 @@ -from django.conf.urls import patterns, include, url - -# Uncomment the next two lines to enable the admin: -from django.contrib import admin -admin.autodiscover() - -urlpatterns = patterns('', - # Examples: - # url(http://github.com/r'%5E'),%20'mysite.views.home',%20name='home'), - # url(http://github.com/r'%5Emysite/',%20include('mysite.foo.urls')), - - # Uncomment the admin/doc line below to enable admin documentation: - # url(http://github.com/r'%5Eadmin/doc/',%20include('django.contrib.admindocs.urls')), - - # Uncomment the next line to enable the admin: - url(http://github.com/r'%5Eadmin/',%20include(admin.site.urls)), - url(http://github.com/r'%5Epolls/',%20include('polls.urls')) -) diff --git a/assignments/teachers/week06/answers/mysite/mysite/wsgi.py b/assignments/teachers/week06/answers/mysite/mysite/wsgi.py deleted file mode 100644 index 4169f1ec..00000000 --- a/assignments/teachers/week06/answers/mysite/mysite/wsgi.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -WSGI config for mysite project. - -This module contains the WSGI application used by Django's development server -and any production WSGI deployments. It should expose a module-level variable -named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover -this application via the ``WSGI_APPLICATION`` setting. - -Usually you will have the standard Django WSGI application here, but it also -might make sense to replace the whole Django WSGI application with a custom one -that later delegates to the Django one. For example, you could introduce WSGI -middleware here, or combine a Django application with an application of another -framework. - -""" -import os - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") - -# This application object is used by any WSGI server configured to use this -# file. This includes Django's development server, if the WSGI_APPLICATION -# setting points here. -from django.core.wsgi import get_wsgi_application -application = get_wsgi_application() - -# Apply WSGI middleware here. -# from helloworld.wsgi import HelloWorldApplication -# application = HelloWorldApplication(application) diff --git a/assignments/teachers/week06/answers/mysite/polls/__init__.py b/assignments/teachers/week06/answers/mysite/polls/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/assignments/teachers/week06/answers/mysite/polls/admin.py b/assignments/teachers/week06/answers/mysite/polls/admin.py deleted file mode 100644 index 33331596..00000000 --- a/assignments/teachers/week06/answers/mysite/polls/admin.py +++ /dev/null @@ -1,20 +0,0 @@ -from django.contrib import admin -from polls.models import Poll, Choice - - -class ChoiceInline(admin.TabularInline): - model = Choice - extra = 3 - ordering = ('choice', ) - - -class PollAdmin(admin.ModelAdmin): - list_display = ('pub_date', 'question', - 'published_today') - list_filter = ('pub_date', ) - ordering = ('pub_date', ) - inlines = (ChoiceInline, ) - - -admin.site.register(Poll, PollAdmin) -admin.site.register(Choice) diff --git a/assignments/teachers/week06/answers/mysite/polls/models.py b/assignments/teachers/week06/answers/mysite/polls/models.py deleted file mode 100644 index a32765c7..00000000 --- a/assignments/teachers/week06/answers/mysite/polls/models.py +++ /dev/null @@ -1,32 +0,0 @@ -from django.db import models -from django.utils import timezone - - -class Poll(models.Model): - question = models.CharField(max_length=200) - pub_date = models.DateTimeField('date published') - - def __unicode__(self): - return self.question - - def published_today(self): - now = timezone.now() - time_delta = now - self.pub_date - return time_delta.days == 0 - published_today.boolean = True - published_today.short_description = "Published Today?" - - def total_votes(self): - total = 0 - for choice in self.choice_set.all(): - total += choice.votes - return total - - -class Choice(models.Model): - poll = models.ForeignKey(Poll) - choice = models.CharField(max_length=200) - votes = models.IntegerField(default=0) - - def __unicode__(self): - return self.choice diff --git a/assignments/teachers/week06/answers/mysite/polls/templates/base.html b/assignments/teachers/week06/answers/mysite/polls/templates/base.html deleted file mode 100644 index 268c42bf..00000000 --- a/assignments/teachers/week06/answers/mysite/polls/templates/base.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - My Site - - -
    -
    - {% if messages %} - {% for message in messages %} -

    - {{ message }}

    - {% endfor %} - {% endif %} - {% block content %} - {% endblock %} -
    -
    - - \ No newline at end of file diff --git a/assignments/teachers/week06/answers/mysite/polls/templates/polls/detail.html b/assignments/teachers/week06/answers/mysite/polls/templates/polls/detail.html deleted file mode 100644 index a842f41c..00000000 --- a/assignments/teachers/week06/answers/mysite/polls/templates/polls/detail.html +++ /dev/null @@ -1,21 +0,0 @@ -{% extends "base.html" %} - -{% block content %} -

    {{ poll }}

    -{% if poll.choice_set.count > 0 %} -
    - {% csrf_token %} - {% for choice in poll.choice_set.all %} -
    - -
    - {% endfor %} - -
    -{% else %} -

    No choices are available for this poll

    -{% endif %} -{% endblock %} \ No newline at end of file diff --git a/assignments/teachers/week06/answers/mysite/polls/templates/polls/list.html b/assignments/teachers/week06/answers/mysite/polls/templates/polls/list.html deleted file mode 100644 index 2aeb2773..00000000 --- a/assignments/teachers/week06/answers/mysite/polls/templates/polls/list.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "base.html" %} - -{% block content %} -

    Latest Polls

    -{% for poll in polls %} -
    -

    {{ poll }}

    -

    Total Votes: {{ poll.total_votes }}

    -
    -{% endfor %} -{% endblock %} diff --git a/assignments/teachers/week06/answers/mysite/polls/templates/polls/result.html b/assignments/teachers/week06/answers/mysite/polls/templates/polls/result.html deleted file mode 100644 index 8937985a..00000000 --- a/assignments/teachers/week06/answers/mysite/polls/templates/polls/result.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "base.html" %} - -{% block content %} -

    {{ poll }}

    -
      - {% for choice in poll.choice_set.all %} -
    • {{ choice }} ({{choice.votes}} votes)
    • - {% endfor %} -
    -Back to the polls, please -{% endblock %} \ No newline at end of file diff --git a/assignments/teachers/week06/answers/mysite/polls/tests.py b/assignments/teachers/week06/answers/mysite/polls/tests.py deleted file mode 100644 index dd007626..00000000 --- a/assignments/teachers/week06/answers/mysite/polls/tests.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -This file demonstrates writing tests using the unittest module. These will pass -when you run "manage.py test". - -Replace this with more appropriate tests for your application. -""" -from datetime import timedelta - -from django.test import TestCase -from django.utils import timezone - -from polls.models import Poll - - -class PollTest(TestCase): - def setUp(self): - self.expected_question = "what is the question?" - self.expected_choice = "do you like spongecake?" - self.poll = Poll.objects.create(question=self.expected_question, - pub_date=timezone.now()) - self.choice = self.poll.choice_set.create( - choice=self.expected_choice) - - def test_published_today(self): - self.assertTrue(self.poll.published_today()) - delta = timedelta(hours=26) - self.poll.pub_date = self.poll.pub_date - delta - self.assertFalse(self.poll.published_today()) - - def test_poll_display(self): - self.assertEquals(unicode(self.poll), self.expected_question) - new_question = "What is the answer?" - self.poll.question = new_question - self.assertEquals(unicode(self.poll), new_question) - - def test_choice_display(self): - self.assertEquals(unicode(self.choice), self.expected_choice) - new_choice = "is left better than right?" - self.choice.choice = new_choice - self.assertEquals(unicode(self.choice), new_choice) \ No newline at end of file diff --git a/assignments/teachers/week06/answers/mysite/polls/urls.py b/assignments/teachers/week06/answers/mysite/polls/urls.py deleted file mode 100644 index 32da9a8d..00000000 --- a/assignments/teachers/week06/answers/mysite/polls/urls.py +++ /dev/null @@ -1,34 +0,0 @@ -from django.conf.urls import patterns, url -from django.views.generic import DetailView, ListView -from django.http import HttpResponse - -from polls.models import Poll - - -def stub(request, *args, **kwargs): - return HttpResponse('stub view', mimetype="text/plain") - - -urlpatterns = patterns('', - url(r'^$', - ListView.as_view( - queryset=Poll.objects.order_by('-pub_date')[:5], - context_object_name='polls', - template_name="polls/list.html" - ), - name="poll_list"), - url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/$', - DetailView.as_view( - model=Poll, - template_name="polls/detail.html" - ), - name="poll_detail"), - url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/vote/$', - 'polls.views.vote_view', - name="poll_vote"), - url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/result/$', - DetailView.as_view( - model=Poll, - template_name="polls/result.html"), - name="poll_result") -) \ No newline at end of file diff --git a/assignments/teachers/week06/answers/mysite/polls/views.py b/assignments/teachers/week06/answers/mysite/polls/views.py deleted file mode 100644 index d069db6b..00000000 --- a/assignments/teachers/week06/answers/mysite/polls/views.py +++ /dev/null @@ -1,26 +0,0 @@ -from django.shortcuts import get_object_or_404 -from django.core.urlresolvers import reverse -from django.contrib import messages -from django.http import HttpResponseRedirect -from polls.models import Poll, Choice - - -def vote_view(request, pk): - poll = get_object_or_404(Poll, pk=pk) - if request.method == "POST": - try: - choice = poll.choice_set.get(pk=request.POST.get('choice', 0)) - except Choice.DoesNotExist: - msg = "Ooops, pick a choice that exists, please" - messages.add_message(request, messages.ERROR, msg) - url = reverse('poll_detail', args=[pk, ]) - else: - choice.votes += 1 - choice.save() - messages.add_message(request, messages.INFO, - "You voted for %s" % choice) - url = reverse('poll_result', args=[pk]) - else: - url = reverse('poll_detail', args=[pk, ]) - - return HttpResponseRedirect(url) \ No newline at end of file diff --git a/assignments/teachers/week08/answers/wikitutorial/.coverage b/assignments/teachers/week08/answers/wikitutorial/.coverage deleted file mode 100644 index 8c9133a13e2831e2c1dbf9effe488c37d019e003..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73698 zcmd3PXLwXq*S4pZnW2e*B1HrYQbGq66a`c~-1LZTfDi@ZjdUflYwThgw((+7o)?S!(3W|;`EUL~_RTq|I=9ZREE3B-lm_h$y zbzx0aacMdK$?UlkD@!tkmGi5LXO<|99eoiYb!|%StEHAJj~*DDT;=Utx7=O{QyQ zamh^jZ&eo#o?bjFQJ;r9b&k45-J-&%d(KM}4BcQNO5vv|F@$G$`6L+AA6y z4T*+Edq?|3`$of}{h}xu8I6j@L`Bg7(IL^KXi8KXl}E=!E25RrxzTyi`O)RkmC@?x zs_35RzUcnwjp)tj-RS-318i-esex?_G&9h`z_tdqGqAmZb_P}(c)`F+23|4ns)4r+ zd~Dzg1HT$@OmsHU#YA@#y-f5qv8#!LOdMijf{79n3r$>N;xZFgnRwL1b0%Ie@sf!* zO#EV^sfBGVw6f5_LMIE|E%dW6z`{ri<1HL)VUmT6g=rS1TPU?K!@^7pvn-TbsIX9J zq1wW13v(@8YT;@N*IBs7!rKc=x3wI#&jFAY*gDg&BkgQSKGMThUcKI zgANYHIVg8(W}un(f830(a+Iu(eKe8(O)oWEgSF*_y$4)NdpZH zG?6_)yP>6l)&_Po(9yuo2D%y8)4&h|`x+Q#V7P$;4IE_PU;~F3m}sEbz+?ki1BV(o z+`v%=jxlhof#VD;GjP0t6Ahef;1mO=8aU0s=?1PfaJ_-`25vBLqk)?Y+-%?$1GgHu z-M}3N?lf?hfx8XdZ{R@#4;gsez>@}^GVqLnXAL}Gf1AE$;B^CU7-7mdplU6!v$Urn(?Z@Fgp-zcp8HwrWJN-~vvN>uZ0(;%H~SU`75W4ce&ZL(d|hBn5IbboZE zTcZcv7Q51q+&vnc$L~>IQJtavO!s4KNAn*RR+i14R$5+N7(28YrL&C-=ny(Ew=*Y2 zC3HQ_h-T7pR7J=^i(vfr-T~t>@*GAVxH%GrjzvlMopP8bg^7VcG#cfX& zKp%ehP14z|`KGtz?d#jTMbuJm@*Oip7w79C|IdqPB3CTMHT)}@rnB4d3gW6nt)UjV zT7)Z+U7|smqDA@o9hYp zSZ_)t`Hq2ibv;Sfl4tVu6Yvd`$zNf=>6cSdQ9iYFT4BxHOhz5G+o!Xw)OL5|HrZNg zky%t&-$bX=EmT$9A3YR3nkibAudlhe?NWQ~RToaLnI)gLbvoNdU4E+fP@RXmDOyn9 z!CeP0Q0_ZA&@$D%#V&Mf>`n#MXey+p($QRwSq3T$R7yQlZJ@@$Yy)!)%r!92z zq|Q0az(T2Zjxeyuz>-+CbCOg$E9w_KD-E1s;7kMO8@Ry0#Re`haH)aI3|wL0N@+W; zGO)(L)dsFHu-3pjDU+_#mC}u|8tFDEkf=KPNLJG)Qu9!?Lq*H}CKi}jY~myn=Sw5< zjftPBwz1I6$`l=)ua9=n$RT^lHQ&8Beu(fN7Y?0QSy5FpY!?47Z^X9g><$G~rZlSU z51ZE(yshM3-FkdB zCTSuEAosTF5Ns>!OLeqEq7l-aj+OqDi*zp0Cq>m%oX@4}e?fFXbak{YT2H_7F4|U4 zaIuc&(vWUvpp}6(My6=ofBfNdOJ|nW%qAqEw79IW-d{|dNB}|2#EJYH+NZM}^ik+W ziA>S)|M5SQJ5)9gD{O8vOCMBSICXZp^n}H-ojazpJJr>)8boLjgAVFo19eIM6L7$r zdp9ZyRfAX`LWrn?0(~F`5Jpoc#VunIHI3t?VvBcFlcc9AA#fo>N5r&fdajBqi}*~e zh$^YMtdfs9o2okgu=DBDa%HzLIy^dp>bphMiycj{#Nz1KXi0Qjv@}{qjp*^w3DJqs zNzus!SDX@^8l6UU;L7NX=uB!*&yLQ?0T`=jkz5#E6kQx$5?z|B6BVSfh8E8?(OOzS zTsK}%%jkya#@rdrTj%!N=DC}e*1ZCMJPK-$no1{zB|#-%rG$1K$*e!QhDrZsxt5| zZ>J;Wf}*DUXz9xrOKZMF?yIHJpf8sm{RC;#H+^@VW#DWB=NLHGzLI)EC0w8uXQ79N9;R=Ky?jkVaZYK6Hv6qRVCiXKi-oybW4itFt zU=x!}6q}eVAmdaM(@ab^QEFm_iJ2zK1e_>0Q6UgTR#1v+6E!Ago0wx_u7DQvr8GFy z#9;zp9B$$W69i){5+vhj6URv5aIA?XCXO?))Wk9q%T25>ajJ^+->4s6Azep(8OaVo;LA}iDv~Eecr^2CSEh~ zy1=9Fn0U{`*CrAcQWhFnXl$X0g{`@4L30Z&ENpL~jfHlCpB7ly*+ORvT?qFSEVYM) zo)&sp=qtGDt`-Jb7-V6vg}p5dvoKtc)-e`}EF2(s>jVqM7A6boN{}mot%S5@EmR52 zI>*AH7LK&A$ih(;j<#@&g<~x&v2dJ)r52W1SZ?8X3nyAwVc}E@r&&0|!kHG%vT(MA zb1a-|;XDhgEL>pWLJJpJxJ1y~%Pd@O;R*|@EnFpF?ll(HTDacAdJ8vNxXHpT7H+k0 zyM;R}+-2cz3-?-hz`}zT9vGAOQ=PkT!;S~$7T6oRE zTY?e4W8r-ZA6WR%!Y39!weXpR&nk^F&mHDc*4e0HlDWejExs< zylmqY8?W1V!^WF7-m&qnjrVMPVBB0 zg${Z<=;NTDgZ>V7aj>g{-5d;Xu)Bjj91L*Qx2YX@SKC^9lYS+MF%fAc-_H!4nA=3p@WYceC*&e z2cJ9m+QBytzIE`OgYO;u;NV9GKRNi>!7mPeb?}>m-yQtn;7 zmy3N|40iz+BV3GhG0Mdl7vo%1xtQx>zKaDe4s~&ui=$i|?cx|0$GKSMV!4YGU950% zii=ZSoay2$7w5V-&&7of#v}&%1cl#oI34aq+H;4_tiW;&T^YxcG)%m50zn!b1}eTYG5gVH*$4JT&*Py@wq= zwD+)+hXM~fd+6n%w}(C+`g+*K!vGHhJ?!COn1}s5L>`8FfQL~YMtd0JVXTL79%gzd z^DxUpxrZ7Lvpvl5FxSHZ4~Kd<%)>$tOFSIs;Uo{Idsyk=3=d~|IM>5@9?ti$%EJX7 zF7$Ajhs!-&;o(XTt36!fVXcSt9&Yh)n}^#y+~MI)5BGYw&%^y59`Nv>hle~o?BNj) zk9v5_!{Z*F@bHX>XFWXU;Uy2Rd3fE!8y?>D@RofOH1N^TMijZKDztp<)gQc zK0f;T=;x!qj{!dR^s%>(eSHk`v7e8~2Yih7F~-MOALD!!`PkpbcpnG&IMByIJ`VPA zh>x_72|gzJnB=3_$7CNRKBoA{_?YTrnvdx|N`1`mG1Etxk6Av-eN_0U^pW*Z<)hk1 zjgQ$r=J=TFW1f%sJ{I^m)W=~y7Wz2c#}Ph`^s>Q9h3Lag2|}K92RV#K&|W@@w|^0e7xx6B_A*Qc*V!-KHl*0rjNILyyN3tAMg42$j8S%KKJpJ zk8gZ@=i_@HKlu3B$1gs9_3@jJ-+lb$W2*pW04snUzzN_6@B;V&f&gKFM1W*~h5;G{ z*g8P70L=qz7ocT;?E|z4&^Ex10XhcgA7Ix2y9F2!VD|un0!#`pHNf-$r2%FHm>Hlv zKt+Jc0NDUl0jdMk1ehIQPJp=q<^`A^;P3!P2RJUk(g4c>EDvx}fKvjT9^lLXX9qYh z!1)1I1-Kx^rEa7BQt0;~zJHo&?7*9N#Q!1V!c3~*C`n*-bu;PwD_1-LuFJpt|y z@IZhE13VnykpNEycq+j20bU63YJk@QydB`30PhBPFTnc&J_zt>fG+}k8Q`k`-v;fib3h;A)UjqCZ;Ew=Xg>XW+A-oV_h(w5Fh*XG1AsUBh5@MSW%|bK}v0aFkA+`_E zCPdp1JA~LV%p>BoIYcA|Z&uHl#%N7JI@?L3n+*vwW2{L77^8^rU7kn2{y#izS#eEf z9zXBS>1=2HybXwNX-Z_kQ3QXisD%{XjlSjHy$bKu|ztP(tmIZNh97{a`k@F&KeZV}Xp09(SFm@|1qP^PB@UwT21rPuQK!8c8G z)MTn_NFT-PvwJ$*L!+Neax@Yeh$R;->2-Fgr65?9|@rY#+6xY?8vU5RM1@BcAC#b<(P4|d?c&)aS*$8uP^>AK z{^{&4YKic<7|_|>gmh6uqtZ;#q4|1mD4to-wL57db2=6gt<0i7EG(<2m^r(WU)rwe z>}~})A!LG-IE{p{=tdOd5IQ(k{3FI6NBETvB#!UD8U4UIttJ9>4>Ujk^TBj!9+9tK zx#`tWC#M*Y&JI+|gXN#Dtaqh6QluV}u3F;BVuns4X6R0W&Vh0xjim#0^4}PgIdqIJ ztH+C+Mtlg%^)4ai;|gNq*NH;rHloY!uH`hC(O_<#Sqx?`__+Ou7z*YkzR%;qwztd$slNigT zIIbUa8p^*|HMxy2wTfC&M3Q2WNC;9(A?+cw(LN%a{2NuIcp@T+6hm~72r4Itl(OWX z*dL;MW{V7gqz822A1&gN<1~Xq^o`V>3X5NiQXpqn;2kXPZNWMo1m&;q=|7R4i?>WIz~)ngqR>o zf;5tUV-^;hP_%;L6iyOO;S`}2PB(F;iL-=UIM>7~6Bn4cNDHYIzi@*v3pbm%MKcR` znz)PAmv#KYLna=kLT1Ygmt!>hUg_*$)mgA?POWV%LlOCVrs$IY+5H;V3k*qThZcw~ zpOrIw0R1zqUZ>30^m=Gc!bgn$_CJJcU#Sk+05ZQN+fJqPdyL6_X3AGS!vz12TNt@0ZR}f68W&I-3Z8 zgp^2no6#p|Pv^Z_Qc9;hls*Xy`s*|rtjt(Nx&^jyd>#Fm)2&ls)I$6lZH4!zFQv$R zI*w$}qXR zvV{fq>ZE(1W~){_PF+_MA%dGq`_)`d+HHjnrjxd9?6B>in=?9ZyO`)|g8H+*LIID` zv@a39l_m}~p}1N)LRXr&*u>=~t}sDo<7!cOspFA|SK>)`5cYGdu$)uHE3zO)UlLzQ zBqMQ)L><0q;YT6+8r#^~#uyuE8^uD{mD(WAjtIL-@sQNmm~CU8jl*mlp_#j-Lfa8x zceyZbw+PpEuZ{aP*Y>1PY|q*F*2a%SDLQ#9&NqeiOfIXK%!_b%It!&CuPZs~bZ6Vg z#6=2D=_Cr=ZnZ8XR+kSV>jfJx4xsa52FZQyi(X(4#kL|q+1Ws$fnElv4xlc6cLPI3 z2vRCbu*v`_ElwBx#A*Yiavi9uQ- zKzHzH6JzvEJW&Jztw`Ywf*Ab#i*>~cHM=gS+2W4o{#td`V+0;?Kl42GGjGau^hHc%#WmMqnMp%ds&vw16|G7zbd1!O$7*RSotw*K0UvLGYRwa++&s;| zS@rcm7yOeFh*mqDvupHGOC{;Ln6&j~*$a2XEI%aoxz7L{!QY8z=Xd&zG0ja#8j%eQ zJG5oC5!p=(6Li|r_GxXR_Q0jmw!Mkk1D9%C0>nD&Gq+IoR}ZoD^_C;JpH#iH<93xz zH_*iHx&j_zVs8`s2#lsMG}?)DUeit-E8^P&^w~|7@g$M#Ofiu$F;$A=(wJB$t7SS% zL~XN7q&6p*IMKw(a>Ud5ewD~;YR`AtxwpjRHL3`{Ti3z&nYdr1Hjjw=@Cn)GPi-K( zdCA1fT6y!9Z2xymyldhE6CcV^@TrN7Zbml_`}4XCjKHt z6x|;dYzvMB*Mesu6!{LFBwJf(Eqa}{awqL*p`(R8EesJk&OR3Q6;V!P0iw$pWnr`h zQs>asHBN4?{lylklsbo4NL!dF7Rh3f>`W2W4&89mHg1hMoSyp+h}d0 zjg7W8cCfLdjrKM=+9A+#Ws%B5+AA+mf2Wt<9Hh<*f`O~Nj6T7Nq?w} zSZU)78)w=$OKX76wQ-(kfG!sG57il0*jOVfpPOw^!BMO7xl`<|_lVGk>W>F)JYwTf zE%za<&$Bk3*K(iNwbtitE%fbJDsmsop$dkDKCZ()T3;)E zQZdC(69-KlY~!H0gBA|96VXpA(fzb_u!AUmIymU)U?&G%9P|*y&u$L(t}p9>XnID9 ztY@r)A_x16vgd&M%AN@^anEE2CG{mfr4D9jp-+W_%9z$?j)S=|xz9oehdWs0;3x-+ z9UQ9_Kg(l^pHm&2=HPTu{E*h?YzOCv;zwzHE)==XrK0sAp%3YMu6M9rWIZ>EvWH|n zw>x;;!K)756$uUrWk?@GnwY+#a3OiiFs)=6En=3jqGu^`vA>J)E)H;Uu!}=nq{XH@ z(ZwVe#V#hhC~+}GjLTD9Omi{aMX8H27qi&Pj0zW(F0vwxsdiE0Vz!GpB9oaXN*U6~ zEOc?Wiz8ed>0*(V%q-D*nd4oYqOcxO)!gFOuKu#c#ChR2jUMIQF|Fy6xf9uD$wu!ppV2_7bTDE2VLL&n2&52YSv zh{lHmJ{2CSMB_7$)jfGMNN%dNEiPeiYGrYi>TXA+v!it-+K_PFZ3z2rEu3s;Vts~C z7h6R9Y880`jwLSj##)Z_0aD{LL;9@Hgl|b-D^Bg4WNpa^Qw7(-z)sRwQ0+zl zo^)}zgKLj-Yq6+AxHSE((>Z6o_+dq z7k5B9dtd=UaV%+3N`{?@?A?vHJnh9fm}vInDa>OH8N%+%U!s6RjPf8ZNac1LApPHS;UI-6#% zU;QkYx_Arr`^EEMm@L$ZFkPa;JZ|cZyZNgr2Zsd-yg(5+WoeL=%G27;9kwZN>j`U_kMd;>ui} z#^iLiWJ89MV<&hq^d?2e0J_=7)cOYb8Zm4c^SD8^s{O$aNYYw{+YjY9Y|-IQ@J)I)M{K4P%V{6p;r z{!AiH2(fm>fkb!*0U3m1jMEk(!Xu`Mf2hnvxnRt6;LOz~p~J)#bd-ss#SgSpY(R9y zDqw;TXu_V?({;NzUu*7P+;hd%WO7xu{we8fM!AU_=dwXqe86N|N0J>d?AMEA2fL9Z zZZJvV#*hcMj3B$iY40is0^c4h zXb|B*rwcK9ju4|43M;zC#MJ`muGOw9h3u{uaQ8-WU=dJsyKtil6M8^kp+`*+8bt69 zA-cBzrK&1s=Qj1!baomaPA;t!mR<1e!)QMXRCXqbN;fLl zFO9y<FI2#CXShBf;_X+B$Yuy(dUUHl@3jPP-co2$7AwM7511sjlLG>FrrTo>9YrJP?wCk4QkFjDQc|v*NlTBVjW<&P za5r^@uSXx`QNOh5Et9+0t1{(NsJ~OP+46L@LVZg9H9BEReNNs=6vLKB-SnoPw^m#v zHArPTn^jNh(_7~!}5VgnQah$5gVGYG}i>nPc zgRYEnar#%&w>pxzo?~e1EtMAcWKu_;Mm*1%q~tu0y!y=YTp_yXwWQ{}nYxzSNz-|^ zD54(}P4r`=JbIeG@AKree~T1H?5+P$)J9+A{PdjG#!h;*wM`*;=(-_>hcE%!5e;;9 z;kE(}v=RETqqyC>3eQ7D29b~i6c7o%hw$J-#k5Yx!YFa0Q}L13rgCB?tF?&uSh=kf zy>pH>dS5E+&26Gij5f#)QK?PXCPzb|1VpX;EtpTtJ}n+{qtg*vB-#EVhq zNeNwRWb$p;MCYz;D+Eqk&6RhoPuFxeL0kpROo${Q^0v~#919D@xxCE6335%JBqrrk#H4(tIFyOy zxY`1-7IahJE1qKFB3>6_fgHg^EPP|(+n6tyc!objFc8>iWut?QonkaXXW zzSQ~GsSMIlbY1Y(a5P;7FVm6!J%^D{ySFEmV0laN+Z0Gm7NU}>(n^9csRl7Uhte z#Uy=LL85JyzFQ}4zm#%#Rb0)rRN!d&HeZ1sk_ta2`QC z*GLs`pWOQ|((?Eq`XrBXs7ijPsvz1V^ka<*@LQFy^(cr_I_05a#(ge&8m!4OzcNGmHbF& zh$HDnNsr>HRjK9UxlvD&HtFR&-aDI9g3T^3Rk~RISjVKZiwkl;T&1xwwyaX*7^vgU zUY~2d2)9*5|3KQTdx~X9oornCvpMU4SeWvpJVqSKP4sV4u0@gNsnRX4x~#iESKkcsJw2 z#O@YIVi`4X-K26*LgrqA828oOFTp&dE2Wl>kRHMs_tHEtwRd|7zah-Gd)BV_HD2EK|#WKnw; zibRj-trpVBwan#UBX0;r(+J_MlQ>2;7_i{ZdK+Eu;4S@;q*pjTal4 zc{PRcn)AeT_N2%t-co+Q>KfX#C49`DoX)N&pa#jNf>$52DpZwANLI*>CM@eH!bFzQ zE+CF)OU|jNVHh>1NH`^(Jyij4VeZgW>hHMuE}jmn>fv}fq^DBU35VFnv+gvgf&!+2UYy**tbJaI$) zzTKlynWA&^)r(aUn@-m_jYyEx*xZbSjfKP4{nPcf$I5i}42H?;3;LN(=B7qL`d#A# zMeJe%#o+BIMms>E+HMZg=PcESt3qCu}PG`^IC8w&>t%Z`~AuqkDHXWHMnxC&Fw(%N3 z_dw^Sv*#5^F6(i0b8`m&J@x9{$8!QKVjZ@YG}7kUZnT|@$!HY|A+2py|8_s`vq4lS zVXx|DPU`^BQ-t_ELjt1D-FUXlsEap+^8HwRN<{e*@cM;}wD>cYS=msa zRl15vL)9#2M#|$oyzy7ACnRL5sw%2V$|z@mm&W<&?5YBR&vU`Id5j0yR9iK9J`se) z<#QMY=3}C|KPT@=F5Q|%y(&{Yg}Wzd_b*FlFRxpg%0S8G82ecH(xW>fQ#ATN9;o$F z!t4D7SIn|cuSjRFRR3Mx5E_J5(==3&0aI)$1D$C$?z}atE^{n0MHl_Yr^>yT%_ofi zpMwdCr_3oWk)6LfoxQ3+xI!)o+sO;vkGi;3(e0U{GxPNW>WZ8HSPGR<0mX}VO*(tE zRts!XTg@qbgRUQR7ze{bg`$WVK(*^o!gWWGCWbSOit~tfY;Hs5%zcb@kiBmT|EO!y z*|oY*&VE-o=HExh4VUzH#xm8gFs0v8%B_sd>EVQT zo$g+TSjJP`U+8qkl-}a9z?m zbHjiBEm_@_Sze@+s4Z2t(O|kNRa)z?^malMcM+7KyEX;VNlp+$e>u;0)qp$U3xmbO zN+nDr=J$~~sW}Ur2wylbHU~`AGQ|c;B*45h7F}MU=V{dFVH)%G7>&aQ;JL$AiBWo7D0_ zOjP$t{W?pb9wbr!Mx47ph~)0)SaSI98`NUNfLq!>{x=>xQQy&6ONdk9*0eq?PGHLR zv0U+5mYkHt?dy9SJ89m$%LY!zp4#lFIP`w?{f+}fEJ&6|k|rx+odn8*O(=SOZ*6}h zl6^lDk*3;5NHEAK?Mogja>F7~HjkGu^MiF@$OID;>qnXsO;3_U#neyNGU!>NO|1AY zk>-mwo@7q?#S=ursA&BaCQgy~k<&zCN210vVmTxvw>wuyov)HW5|Z9sB-Z;&bn^M- z^*#9isLH!R6aq_hNH|gOC+n#2jkynrlqV@&ZCW^44=>fqx_>kst`i3TI-ML&?!z0! z;Qu!d;vE+5)G6Z1iFlud`|HPvlPi&QdXxWKF$aF|5f+7(T9IS-|Q*2bl0t)6xM!|eBBa)l&LJ17NQY?el=#cR1 zY+PSIDx9o@wLZc-BrW_d?Ixr&gZpeeB!LFxCVb51@NjYyJ|l+0=WM)W<5e54>HKhI zD11K_9!}1}Pi%ZDwn8!#Dl6e%Hnwtd$>C%xBtv1K!^3Ocgk&XDCc4@Af9`ui+#n>IDB)a z#sgg(B&No=olzMXYh8@B{zWn`&XH*ETEk*(x;MEMk8`oq1-TVZkc{uzbZ_!0o+BCG z=etmD#fv2ATX`0*_$RmG--5qyaB*WS{`*cBcg4($6a{|23$idi?BWrL1t%BdlM)X8 ztc&L)B0TPBe9gt1F;gSi8Og}_dCa`{y^9}Q{N&;n7k_B~;#OYH!f1JLJh)nBKjq=+Sd96L9$u9s^LUK;`;uY)v4>AReBt3s4_|rs z+QT;E(?ix4fy3Z6vh3c`UKKjgBjCCyC|lCA7Tb z2BGCWbYgiwAG`Y4O%luZ@G;28U>`$#43+fqeRP2Na7iy8r31{zNp$%^l2txYg33#D zK6$B5Ca=vTpDo$r@!)Yv9Y6Y?^2V3@INrwz5+G- zcu*3{ANA{nmOtg=Ss%~o-12y0`P;F$^7nOO`6oU;_3@cRmw(~oYe_HvRtK0G2v889Q-GZVbPmuZK-U1>1M~{eJ3yZRyGVff zKuIs(LjuhA46s*#!2yN@*e^g7V0Zuo7!hD(fN=qe0_-1Pe1Jm&qytO{Fi~R9ivvs! zFs*+0dD%b3o~z9B1p$r-aAbf*0gjUV^Tj&+e1(LcpBmt_0A~caI>4=xWPVS8djs4j zVdj)%{*Vqce>A}30iKXZ^QQwmC&A_~26!pJE0S&gdVn_qycyuF4MNU83h;4&PbBU9 zvjCsRGS9yb@QqGB|Gs|s`ELP!rjt43Q-WEQ;3~I zbPmxaMAs1ALi7mHGeoZty+iZ~(KkfD5dA|82r($co*{;Y*gM3q5K)NXArN9jh>;=2 zgcuuQT!`@@4hnH_h(ki8Lre%UF~p=0#UV;UWI{|0F)hUO5TzkzgeVI!D@0|8Y>285 zvqQ`YF)ze|5Qm32BE*p)7KJz_#NrUghFBV6S%~E!P7HBUh*LtG9%5yPGeVpl;+zoY zhgcQjf)JO6SRLZ35NkqQ9pai0*M_(*#PuQ8hqxicjUjFcac79TL);VMz7Y3^cqqif zAs!9!Scu0%JQ3o_5Ko18I>a*}o(=I_i04DR5aPuUFNJtH#490Q4e?rt*F(G&;_VRc zgm^c^dm-Kr@j-}>LwpkA(-5D9_&mfHA-)XpO^EM9{1oEn5Wj`^J;Yxjj0DUCoCN#? zf&{_@8YIv#fkp{5PM}EwTPM&ofo&3KmO%3aS|qS-0<98goj{ue+9j}K0v!|BDS?6n zIw#O2fx-m3C(t8--U;+gpkD(06WA?*0SOFDU~mFM5*V7m-U$p#V7~;S1V$tHw0`n4>pTL3y7AA0b0!JipR02mQa7+S=6F4@3B?%mtzzGSQlEA46oR+}p z39L-u%mmI!;M@exOW^zjE==I^1Xd@oCV^`bSeL+c39L`xh6HX(;MN3gOW@7~?n&U@ z1ny7Zfdn2-;IRZAPvD6Jo=o7W1fEUcxdfh1;H3m!PT-XUUQghS1l~;Gy#zi<;L`*? zOW^YazDVG!1int-n*_d1;JXCAPvD0HeoWw}1b$B7mjr%I;I{;RPvDOP{!HMn1dJq_ zCebp9R!Ou@qD>NQlW3R3j!CpnqC*lLlPE}H=Onr$(JhG{N%TshcM^S*=%2){NeoD0 zU=q70u}2bvlGrPWAxR8PVxJ`TO=4IQQ4+(GKoTR87@5SVBt|DOCW*00j7y>@iSbDs zlEj20CM7XBiIOCyBr!FKX-P~^VrCL$Nz6*3Jc)`Vs*=fptFfWA#DIA)@VJR$3;qVlWNa4s77Nu}h3P-1KObSa`2lBy_qeFBdc21%2xIb8KYeYI$j`h z-{quly*7G)CA?%#X;goDBk`r%#)dW$_PC>-(paE}GZOGPT;RlMLFTaoM2 z*&FKUEE>d+NBVbj6olk;^Vh#IoxMp@fpyXnt&ve%gsCCLaK*9;a23wmOP5~2e=M=-k#3hQ4ph7wZ@mnODh_WHNIViyyJNiyqxqHAa*Vu zAi9JqiJO>DdTv&u@?_zaq-el-(>xxzn`X9iqRa&)#k}e6OlR*>OUsTL zW{OV8*N6DG!t45e(!0~ydsK8R)2nT1^B0g=ygMzP-RT}2E}l`o3}zBzSVNwV#q{o1 zMi-FjgwhmkaZ3$G2{Fh(AC0BAzeo!TD-JT>EJ?P>YOH$P1DS+#KT8l4GrmUWEK<@G_V2u~5 zpSS$O>Fgs~nVX=6pwuKyXk+!F!)+qfRaa0Y^(@y%+-p-H-1{P zKD%=Mv{@uuRf0DDA&;iBkLe#0pMk=aHJ{!8TvzMzfiFvyLd-L}SgW9%I>ROVoIRdA zmtGkqC(sG6h9FI+lZK|x=kZeg7uvJTJkf?fp3XkO9wb)Fd7_t_NWO_O2|8jm_$gEp zUoCzIPB!3j_#rBX*+ukh^hO>-K{ge&5#K{krn66}(_QZ!$qUF7ou980>HjQQs;c0H z_jEe@j1v9vmTy57O>TT$t`b#>byjrO#axpNCXb6|(?@Omr9Yd_KF7|6ylDXc#rmat zsW9gIdp@0gLDwKGa#MQcxVBvFWo;Kwk}7TrJCPf^J1Ls`kaT_zY7FlNxfRha=*nor>B&irJG42#jK&k|a90)m~Cy(+oS&UOM zl~oyK(Gn3_&sYb?{{YP~s{IGz|35Fo7t`673gm)RSOV`J73-$jf&yBYY@+CqTZn3M z5x3AvleI62(0JBET~k!|ws^|VR8nKjm6>TrlQCy81vec}Q8DaQWPcSWZm5Y_%3!>n z48}@db-T=n;#ogDiSV&JA~Bm@_9eB25Y5MwO6cWu_7zznE9TbxeG2$njiM#$FF z;dP8@@e#$D45hU7SOR%!Zgkz5^ybbMgD?kjuA`0h7zNxtMa~l*y{6)9XnhsuH9_l*7{n+du6P_{W94=b#ISJY#%jnPZ@Yx6p7Tvy<*^11Fso)UAJ^` zMdEt~L_E(U4oC{vIyU8?oy3W%Wk%XRrSa=ai){;_8dbB)89L(I;q7$x9Y!@m@=-L9 zinxF_Wq+!5_n``xN2yGrWmZn6CLW@?m@td8DF=%)lvWdnx{g59TO<~YEl#}L^k7xa zOa7Q9w0*^sR7w7-z-QXXEhH0(R#$tm)OHt*D*>eg4D2T=))BHc#v7O1IOiY5tYROL| zRpF&_i{E78c}d>;+=OAFp~b^`+FRI_uJ%RwsxvozFI8oxv5{W#W!_C^->bWk0y zK$K7ie$idkz(B*;jkR^`Y$cY37JYxM-rkrKZLo|FzFxvaZ#O{4%7-$3=yQXOV_$0p zvs&C_79)|a662B*mt?r}DY{FNs(Q-^kC7H=D#rwwzLB*+!qcZLP=M467Ty!(D8)q$ zv$0l`mv>U$Q{Jc@%`j}7dZ=@Fe3;IDR6tc0mkK*6F!Ql@>;twT|; zx7Lq>eMoX(pO(0~XHC2yS#@ukcuVf5_e`GtL$}lyG6U!v84dQUiQi28E^~kA5b!Mo zGV3R4VH=%i*FrL6DbJ2>H5F+`d3HT4^pW(s{uT!7(7L@Pw{Dcqty9D5D7ubqg=Z{0s|W79SbxF}N!~xVKw@`_!23!h@1%6MMCR_;aBYy--M2vzcqDmG z*huE{WZN9E6~DhePiMaFif^H!B+m`Bqiv z3g4?;sJ<8|XeS4ZjidIXlv)lZ(x1-ViCu&x*+=TOL#13J6!-|))W=GG$?*aTQ-Q8Z z^D`wyn+O!D(Jzr{xT~qw*g`|IGju;G7v^G{&@`+L4V69DF zS@#?7hAZduI0w43c!7SO&i=p||BBOR({C4QQ08tyF@hwR@T2{h&ibfS2h7gv9YU1D@5+NeXqC98YcM<*TxdH8#h|N4X&f|07c?VuPE1 zPG^7N*Uq8MiiX!PFzZ0LC~HlyFV6@P>k_b z3OU;X93W9>D(C$7boLKTopIsYfGEpOw1E53a$H0w-wi|CqIw@AqGM?^0X}-Bb*XDM1G0_f~FIt#US3CXh9wq*1z~h zN>{{>@5|!{wcm#a5OCeO4Uq=S$#bNV8vH4)2Ag z@(#C=cUXsTdveM04MkWey-8jaT`36WI3oC%eR*Ew>aRwxiDdm}#-z6~KwvYyvvH!> zr?-_A(PFg(j8aohoj1L+izPX9oe)?AGk+{FGrg)`Bqx;EQp&p^0)-S0y(JVPV`7G& zTotjjhZ>njb*P@va16c6W&g1X%)O$`X9)d^Q;@|XHJMqJWh9H{ciK$eY4h55%GxJY zxF~Ex9guuw>eZ^w9gaupKpj^7{)#d)MbW@r70(e_Mcve;^cB_!R{BIPd5Z{u{-W}) zh4=>vBYLobVhLO+69SVyOO5 zuEM$P($%d}(A6Da+{JK{z;hzi3C-B}o^&pciK%ROev9T?rjS;yf)J(ow5D&Cn8a6U zq~5!E1cWwK)5q|Ws_o?Wx2*mB7Ku)kf{uJchvsXsZ|dpjs%N1^)%Nmat>nqLuH|x^ z?J#OJx5`~4d|oKs6HCkn5*s#{)Qc=C;DLzzJq{qYf?=&GBqx|5n#IEu}kSDY`6QOY#3K0IgpmwU@WnLEakQJ9S_cGl+^2=tu=02fr~g$m0;% zmNY{6!~4vackC?J2ArT|raj z3Zkp#DACOjzjnESYee<(s0dts5{`^WF}n4~naG-;JN^WTUZQ*@Vy{-4xY5KNChjru zu!+Y_5KHxKq}YD9GtT3l|GBMJY~~YjSFhg=;LVmE@-Dg*qpqil}p< zrM{MYrJrdKqs&;M6eJaaG*_~XF1JBRM$g;$%?2e0IZhsV-%ViWWwWQ1mRA>+RZJ_P zajCP_>C;ix;7+mz*;b__$E=Uw@iDA`dbf@uTxOuc|&LP~J?k|$VJx%l6I5qVLHQ0tW zP#`TxW4(>qiIua57PHOJ^0Rn39cQrT>FoYP#p3gxfghyjpb~m_8GJ?|Y!tt?zl5rh zOye*UM@SOdViU*7Akh;|tT1t!Y&9Z>*U0?PYlYNpW?@_5X-U>WBrQ!A8*X8LVPa`F zl*`(mXMq;}F|yt-k_CISObvTLriMMj!##QNzHH$Y3$IytLo^^C$|x}+QNOeBi-q4U z{6%7?!}E2fZrrsYx!W~W8M!5QmapDfzPhT|xn5`OE#EMV12Bf#oo;hw+vK?!Wkwrd3+J+BE_4GCOq>E5ViJR~A~TwGwJ;rU7g zYIMy0D&d2U$rFI7-J&Cxk_4NZpwW8WM6%XLhUfKO% z(+tVasjm5*-$^Lav6RRj_ZH=26jQKXY2aFVX?dFsyYb7TbXH|Wm2%@&b(a^{LtY%y znQ9I^v#>kS7UYteOBGFHC=yfosCD7TP&!Kz*&y}z(JjhHt#r&;Aw2agb~UN2t^q$$ ztg3HFA~A9=6T68pc0akDNEkcb#K9sfq_S_Gq;IY?ah7Cl zl6vV15iPAVah*t))=MpTw+SUzdP&4dADW;NkSae?BT?B$HJ@W4VIif5DY_2QYCnWFRZb?y9rcaT-;?wM? z;jVMHoRs81s!As2>Jl}CWGe-9rc0Ka6&;qqBe{8uvuRLh-3cW>SXByFnk*|VgkbPkP_MMZgOj&$5zUiu#L z(iL*hjOySvgtB&)*Gu}Wyp;(XudU)p`yhG3J>>~`F)%vZQ1rw4GsLG8K2ckFv#yvO z?=R-eNyKDu$~no2M;e$TxHusd$7%uL$p%OMzI zL_-25VmRJ_d&!#~EN}We5+A-E zy`RT%y#L*J8ox+}$g>WWXN_ZCq}9or;c3$++3YHw(NVRxJlH<+U_4%xb0mDCpS3ww z&!#M5Xl(~6o2W}`V`7v{C#M34MA>hc_}IjECJ5;Aq(kq(P5KsdEL3M|YD&we37fdD z{J>$gKhU8rr+FUV`o>R*7?rf2JX9nPr4I>i>sf;HcOl#kV%uT)%>=ruPm8|cRI;7L zYIq7+Y@}1BeL7mu69OT>65Tr$m2E62^UD|uMS>q@ED&0_UNDiH1iSk~Qqfa3S_p#I z*2a!DI@zGm^8u1(UM8vKvu!M}vCzheHcql}s*Tk;sr*_S6iR*@XOZVoowun9Nd-Gp z4VQNcd8b;|xjJ_%DjUab6y?C~&*!NLeOm?weIm(bJTmBq=udVv(ITfVy{Qn#^o|Mj zqBEFo#qkExy2mJ&2@$j9RHjaYzz^y)=wMzVXEOoG^jT^lkX7Qqy--+Y>O-y;jCn0L zwCuRNO`9(7iVe$pDrTj8k7p0D^XXdye^Te8eYNfI6IUu^9(+x|f-lrKcEFi6wBhpmPg_)FuxHo&C!MpgUfG@RRC~ zAvjn2IWE(d4ub5ilkVsS6E~T-#l(Fk?lI|-ZAm6337G3 zZ{j0a%U??q^{t#Of5_7Q%fwdXa*$Sv5Omc|Q7c8j;C2>h;csuDwSeek>F8u(XA51l zv7?{BhP%e>9s5|=Pf*11vPBNmDEkzF*r#fgT_Ni=0x-@MW5HcD;GurbpHodL6Kl-sDVQE4Na8)T420&e4nXg&K@)d<=1 zBW2IW;ZZIP`5a{^oS_I6=)gn#*bK>$4n>5(Od~LSF41pCQR&50+YfoP{rwBghEA@l z8YRDKwEU{L07fB-4E^)%+(LBSb#TA7DsZYwAq9Hys32v1)kDvfS6*fHaUf5YdJdM? z&ZoZPQ1WsdP2k-{L~q|lu<*0=M!t`J;?Mz-A@vhe8}$nZ$`Bobe>N5DN!CF}lW zQb>FBQ61jK=6KGMf4G|d;dl;Y)fo9aW99Sc`kwKRW^z#v7CiwYSgh)plH*(|3DVmT=q?!cgf_@^Px^)*6r2o{uYtX=k6lDhbqNE1GI8+`I13IDzGH!W@|u`GI(4 zX5H)j&r~1~WStO}j3DaRhH4irquRaxDDAy<_Z~?qE!8QbrBpdc68flMnIJq(v7U1^O=n2dZr53{ zL5Q?zsqLq_MlpDY>3vH;0I@qa3x)HHjcIXFCa&*j^h}cM#7i6+s>A@=I9Y z*jXD{3x!W2u(!7fVwL)t*hPTffx1vqRnk5t_BAm~21ZfEM78x;DVO#)age~mhnSck z;Bc`CDxETV9@LDOByg^{&=;6c1=J!TIgc^1!~_*kisU>+20EQ-;v5s_i!Jtom@`&Y zQmai|B`oOGLWHi>Rn>a2%ibkb6_r#EN>%l+2`a1}Gx3CpC+k~hpOa9B7eu2#r54E) zUNceaq`y^(mrON9kDmFRRsjk9mB^6d%3nW$`?3%j0j5f^1Va(nsvIstVgh_}jrTpDop5`;re|DzZq5GFTWP&f9So;sx5lqJ&6`rGKI} z;!YMXE){OmMg4Hx|7-3%!=xzlElzh=>gsC6$kkOA1s4P*s00xuF1Wx^6af(t2OI?j z24_IP2r5WaL=a4itBC3DDrPXCuCihdYmR`RD2mrCUh$syRKGLT42(SYKJ$1#!hGqj zu6pYq&N)BPtFD&H;o1zYlgi-+)n!Sc!xCv7Zj;>M4%u;8ul+-c2i9v#t>WRq47f&K zmcepczCB*dq zXjXh%)T*VarARn?<>@srtDPL|ssfNwjQS3Uv0^W`UvVYaSj8Z_yQY?H)mCjDYrw7! zx;gl>gYFI}ww6tPaJ$|VOgI$*y!L3QM0~w z@STJ29sJ zzqz=@#S#~{y1327?Ji;l*Ih2|cCpmOJ;e;JM_oMTBFW%dDfCv%-Fn%@D=uDj@tVbL zz3ZZqxD}JHT6k#bp_PY2JRIubFb}OgwDHi^Lpu+LduZ>0Nd{ zy*%{x01w9`C|LbG^!G5p!ypeQi+ok$VW@{;9?tME+yk*!qdbiEQ0Ae+1DRLjJWLe! z>Ov2fc$ng0s)rbOHN(S93%r`^fy}FU9_D+v+QR}53q4%pp^|@fg9jq878O&lZuLL} z)_;2VyN9J7?(uN1P*)FmSmt55hf3NNAy-d}a}`6bp7Zd$hnGAMa`kTyuX}jI!2FXq*!9yWOR!o!yyHhK8Q!?z+|{V4L)W)D9Lenr}q z@1qiR75T{f*x5&2AG`S2-A5(rYHuG&&Q(JnjS_gPraqeaXyK!!k3)PAaz(sVyX_OM zI$Ow9Hy=HG^cL!>kB{R-yXxzszmEYvPV_Oz$H_hh`ylPAM6|16K8E`!^KrHyR~0_S z`Z&i2X;%|{oa^H}A6qf6rudlZ<1!!9{377hJRkEd@akG0*ZH{K$6tLcstI>h+GK0s z)lxC9mibuj<53@v`B>qD@T(_$JmrJ@tCc=h6(g`-w*0F%eSF~KBOj}Mtnsnd$2uRM z_}C!w)#pAoZij#MqsUjk`lu5i6@c(7N7$=efP8?R0_+-Kw*d75{6~PjEcR-9%&W!$ znk2|q2L(7dK=S}C0<;W31Xk++Z346n&@RB?7K9a3usR3mQjEYtfMWt28=#Vc)jz<1 z0D}UYECg0bfS~~h!Wtf+EWp_T$^%pc7#rZ60OJEp3~*img0Ln9m|V=is*b&y8{nz{ z^8(DT5rIYW)y)AG2e>7`k^r{`xUCq0b#H=ywLHMX0g?!;n1A(*;8!mMcrgH(S1$*6 zJ;1vG-V5-4fDZzEDB2a-R$m6#R1IwPU4S0~{1{+!fS&`@$s&`5mqlKLt39&#LlzCh zup+C9SgIc4Q1#7XP!_|oI7?`$@mX9Tc+~VPt`IG1Q5LsmaaR`iXYsITQN%;Nlm&TE zgh9Pyc~B%lt;u3-79VG^K8qd4Kz&zCg4&!#41@Y5i!E8yAyz0vIz%Rf6T%DOhscHo z6_pQBH$jWqJ;WX%_6$)^?3|u{bGbvLs6t+gj6#Nk7`*B9@RF);UU_GI70lW zBSRb&qN4>#bqUcmL^n&6>Jj2-aiw~OTcf4=ggCAkFm+;xfeFmi5DSX- zMu#X9W2z#=STUvun3^cY)CCqZb#aJG5}2vWLQD${W@=W5*%mf6C&ZN@<|U9*3qxEZ z@YD?n@YLTz+!W&G5Q_z&S`y-Ri=z5Rh`SOHss}?nBnZ{=5D$lVB*cmkPg)e!(?U_L zO3Mc>HJ`i1Td;lNx0Le*RxDnh6Z$>Go( zS_?(hE{FC)Q5~7XQ8{$Vp|gNg-E%lvG^*Y?z@n&*6OHPG9Qx-lFo%;wqZ({cRHuqY zRcdKeBgLMo$YE>_a93~eNsABxo^c-g7Ff)f)IS@s4c@9_PFekyJ zT3Ae@T9m_$IV{fMmK>IdOm(~9RCkI`b(i>5ONFSqH-`s=sCp=eWjQ>O!=nOKtq`c{ zp9xmgsvMrp;kg`M&f)b0qUs$>sroR7k8)U@!yPT&{oi@ z!^N#Sq8MF8ZdF%{uIes&RnMq^t~%C2t72T$i4g{hST$JCs*(h>syeP}OoX$As~TsC zRTHW~t1gUiQH0AZrD|4$*~P4?xe>04FfYP(@LYuFBfJpd#R#uh&eaLZ zTjC&_TQ~-Ow%2pmRd(Q`ITf$9Ou`*lPS8|es(t#2`sf1-AKic_tTwBS|}v(c_n4EL5&=7bcMXqmtr>%A%5r<^>lS)Wx_?Ymm7az^>BTnRsMhHJ-*94vB| zx|b%2T&Fg!O@a9i-7n{iC>^gWev+>Epvo(5ZWogfU?4_DcHE8&tvK7WE8UF8(938d zx&{`UjHl~%n!|Xm+bIcqmoAS#NCMU)h5j1&Qc1KxR_JTAkhwu7avGs{#op8~m!n%= zsCZoaYYJ`}J899(5o!lXW;rcAR)P@DNl!?lpUfQt(l}A+vXukV!FFbPY8o7y4ozcN z@$htb8YASb?x~qYZw)Lax_HLLDi_aM4EIJCn_PV5;=e@J{>DWTuKlA6^0hZtLu|A8 zXXoF^LuU_NJjBiapFMQ<(BrqJ0Bp;zQ)}JWM=Q0XhY7NLj9-hAhZ>Yn-w$TQpK>6 z(W7Ho*D3l^L-eK0nYafxx%+UF+lV$wv%NJp`H)`2YEhH8Lyu>9*|@RsiFm3$aEU&! zIn3joU@Ye`Zu**uD%SN{NJ26}w>+O#%N4^V$gVtxuBtUPc&v3*;sD=Lqq!5^hUm5O z&qZ6%q59Ut3g0@;A@(S5H8FvMYSH1c{l{WhNrgO9r|FZG>XYp&KU^{X?qK;zJBeJ= zGa-~7PDklv`Mph|+$_qXl~`Mg-uCT(m-5nzaU&%&K3(7D41Jrb+`NM-1Mj)WuSFwB zO}eXLWo2iLh#!IB`j8{^AMntJfw9>yNjr2gwoKJfVU< z)K(JluC={PNJolFNx{Q0sw(V=eLxCX@x|VpQ#_@Ed3x=4(mAE!#D?v6Ds25^r|eOq-&=Q>x(J_Q%}B8`jUmT z!N}ye0^dbzZ`uU^V#VX9NeMDW%j4P7!Yx$F${mur@m$-GGWy~JWd$9V2KSd-Ony)E zpF-xT*P;ieeFmMi9i%j?PX=7+T`y}g6;s@(tySJF*JJxj+SFd_EAFnii{h$@D)cS-g6D~`RbJ5pDe-|ga7~-PT#c;C` z`TZ3aXPz_4yzNKoHyx$lG|q^!3ivqY(L|k9$$^>{s)4H1kyvX{1y`z`2j7zhHKSay z=CtAjcwDkUhBsC=rAS2z%#XG$gp6{{xrNK@Wa zDq9&J?BQ~{o@sSXN#VrVR`WDAA$y{T;yfGvd!gJElN4)nspO*5q!pc!0w0mf6$i{R ze7*|s>r-G2{?`;1NgZ`lLK=0qbffp!wq}`Ck3N>d3K;;NNa3F;Je9)Agr4--6rPjq z_60d_DKC9lyogs*cx^jEj`vlBtP_`UqXPH8tcI2NQEkCy=~CGi)JYpl9h(CdEuk`# z*jiDYyo*xB*jdFwzS&SwrRANHsh!?I;BBjMt7+) zV*5B-jpNm7u*slJ?-YqK*jTWoD77Sj(Gp`+2vBuVLVYnUjp^2CK2HLSs}s(?#d7u~ zMHhF=-1ng57LO?L;W3?Ck1P7&$%L%6QiHL|$}pb)EhWaAX}l%rYpln3uQ=bFs*E*O z54$dn^-{%tn#P7SKC{v1-|G1MLDA<_$kvfIHZ~guHu^lDLEQ{?lR}o_4JtPpO0&V^ zmTHYw8BmfzJ;o6k9A%H*9T8?6tK<2&435vBZw3@;^plE~@{Ch$M8$BWRGg`liZVr1 zP(?dFg9#Z-R8YlvQfpiw*Z!mosHnX}qS`4LOjT~hG+Fs)D7|7<2D3A`-0E$w%wVof zSD&8&#U2Z6szogMpbnQ}4~lSamGE{&29Mi-^`|memBF(aP_yw$2LIN(dQ3o6*d{ zK@JXf(A+@_z1*nSJ{Fa*QAS1O z?VKJxM&0C#gp{WgTfp~4^~#UsUGk;Su~<;oEkSBxMbp#1Ec)2ggXHUg?}Cv!@F(i1 zzedM0kJh(zc(TmlkckH)hb5GswbAj#Ba6zh%0URHAZ2NsC-x47VN=qWDi;S;VGGl^ zHjNu33A^3O=O5Ow!vp7OX}w;t3ND@!du2e873-#M8BjXKM{=;9yHQf9U#bWgK0!BR zaIe@WZz=ua9R*-~n*l{f-&@^L^p%S6F?wvy)?>3(mT4jW zr7C|lE&+>M-e#PfwCBTQ!fkqUKxmZV71VrBQ#Rn);$fB%8 zL-r2MSqO4GZ3J15aidwT3sF%xKg=Z5XC8_TJ&&`*W1gdt{+k*&PMAMJ`6z~b6vrZxqfvI7qQ87G=mt!uw{upOqvQmu2_D)fv9u^~NCEL)~sL3|zTe>XLUt!FUmT$ff-tt_M1>!Go0;PC79G;+J>>ZWaD(nVy{_z!46V`(2)o1 zUkXEzu>!EquSNO&|2lqPRLPhzbo80;bB?~xczquuI5$7Kan1dK%}=vJ)S8u+x987p z+MF&79q7r{rhl)&wb-7YTXx#eapfau9dDJeju-y7Xm~b3-(jM@Ly9Yu-D~kv)%=uI zln&!Z9;gg+T5N?zj`D&zN&8vc(3;d^Pn+iL5n_&-P1G3t6`3A3&Xps4cmb!{%twb?q7 zIeFHaqQwM?nMrk$WZY4s(cV0M%r!GG-Pr4ICScR)@xQ%b2Dyh(Im-(+kd-WF1cTM| z>t&8zVkG+8T;sf7n1z{DSyeP(Y*J7G#LLbjJU*3tb>MZiI6GKQgO>6(a*4+2R|lJs z+s{t6IM6Cl_d8y@p$BDDd{nTh73wpe6c_SeG6TG!isu6%+CI|cdac$*pQgag(bwWl z{gA@XS|PC>VxyR{a({M=l>4($tfw5725Ey9W)s*-uqoC|ROfe8``1~UCN_cHR7mwq zqqn-gIVzQ|k%0dCgogem`3;xbd_ERT?9E=3+3;iaQS~HeudiN+El^7t1LGE`g9%|l z#|%1Y2E~f1dj`~|Cnf29YSZ0ZQ%z8urFfxk%Zqed?#yM0NsgUK6W1Ng%~?(crSY-6 z%ZKuFrh5HiVwQLlaOlD*%YGW7u*l^^q_5nqtZhe_0Vc+1p26S#B26qVOJRm46L)If zz*)lQ8VRtx{e?GK8ck%UI6@OWE&_+hJ9@sDUpLCQz=oAJ0`{hCLz`sKLLFyMi_IFH z0sF!+Y7NU1>4oeFFSJeJWHp6x3&{SDUEPi9>Xt~J&kk%0e=rrBtS;H>oZ{dNIT*)F za!yhCEGr?We*6xp!k?A~oP$En1b-$f%SB#tY!;r4B)e|r;vg3XyJ(?7;h`?ta2oh~ zftf}d|G0SpPSS5aS-*LzSC+frBY(F~HFkVysYrU|7wc19QutIEey*I3L8i?9PT0&* zC1;fl85@US7ixz~^&zJeK4iSKG9_e0^@Sad+XzxqN4Kra>N;7`zqhd%G?>?=9C$8c zyZJ;dZXtI>l#xjIo~o~QS>^RF)@8&*f%ql9qdQ6SBJ04Hd@rRVo0h?3Hl4y^aX4RL z=A=2F)$_%yoG)hya5L97Pf@+`I+YvW^2NW!ynf;r&)yo`^2O891_}0NMZEa`?YlpL znk}EE%Q{_`wW{+fj!C!Tmg3IKtWzxB#zX)cuD1z5tBOC1`>_}(-%HtW$7)qSjz-bH z>Vg_-wOP#@W1{KKK2ad>*Nj19hZeu#ceiH4E{QZB?x;A>K3~Q?j+*Bv1MTlAP!w}t z3Vf44u0b)U#H%zJ=1e%A2Gi5`jdjm7bb zVklSb+)cM>-l}LlebyO6xF;$GIY?aL4!u@&Zx9zEcS4Vhb10jU&bBQ zn(+@0cP9)Q#lr+N@o``^FT>6O>IT@witKj}ut$JBt;l|#0Q&~0A0SrS?;oIHfJOlZ z2RJ3bkYWY=^Z+vg%nWc>fV%@M4RC*e2Le18;Lt3n0&kZ^lMn}nXc~fI=oTTQgsw$} zS~#_TJb(miZ*+)d14_tJhdYwJY$E%nOjBSso! zUr~#9xxU2}`W7aSKBj@}&T&mc&LrBiAvJWCfy~h~Y`b%LjvAK2VzmKxDZpzb%YMTL z`PnG84ph0;T)XP7mLZSgja6K>4>gs0ElzEI>tYma;zJTG`y5@1D|IcZ@&au>|F$A; z%=9MNR&9GXZQFdScrw8b)wi1VfQ|j+h9eg%qD%_AQOZ>hg zCOW|!)UlSTm`YfsBB_e)+!mK`J~yY1jf;o<&G`gOs;%Ro=EJO_ zw4#9OET60U{wm$~$!&)j!^Nrhds4&MhU3_6+*zgluBfdqFt)s8bVZ58A|~gsdCSDO zD)F}#LlXZmoyRnfp0jdX;zQ8ipwUT9`{`t(ssb3!2~R4&m+5+7_JbaQoO9 z$3QFB8Kz8<$qC%{RPE$vYaxG&g7vt`S*`RXZok>>vIyF&+K2OtcybXcG;de6z?@uk z&{Tq}X)dL?CPk8CkPk>XwV=IrlazPg4mv2rBG=jXHZU&I)bd)N(`F!{$huQGupA9F1J zeT=hW55R|?Pkv588GO$7u&LtvY6igvxTz#rEj5d3qoj+Y6gK~7t160ryna@0HN>XR z=uKyWe>u50Lo4)pUzxN(#<8UmvsK;IDHKmiOqXh0GT$f5y8Mn(lr zPEIj#Ai)ddFf%g)`Eo2Q!azQdBPb}Sz$wKF1QMLQK#sJuG@G&_7$~s=Ib0wh3I<>% w6A18w0hlQO2J+n8d=Qop8c;z43^FJH7?vVPfPvuvGXp~dBk4g5(gV^90E$0CbN~PV diff --git a/assignments/teachers/week08/answers/wikitutorial/wikitutorial/static/footerbg.png b/assignments/teachers/week08/answers/wikitutorial/wikitutorial/static/footerbg.png deleted file mode 100644 index 1fbc873daa930207b3a5a07a4d34a9478241d67e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 333 zcmV-T0kZyyP)x;P*EWNYZUli+~q;(eTbfe*U$baTG!fAgG=`DK4DzIF9EWa~YA`tJ9_ z8KSNH@Hyb?@aX8R^MT1t_v-D!{?^ltv3)o9> f@a++B;w^4}o%yp?Jw|+(00000NkvXXu0mjfL|da= diff --git a/assignments/teachers/week08/answers/wikitutorial/wikitutorial/static/headerbg.png b/assignments/teachers/week08/answers/wikitutorial/wikitutorial/static/headerbg.png deleted file mode 100644 index 0596f2020327efd97a4467c3025691844bb703d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 203 zcmV;+05t!JP)t-jh%+|_^FEwkAv~hm;c(PdXHHPSc-$gT+Ec53X`vdosFfm>3bJhR=002ovPDHLk FV1j%>T7Uom diff --git a/assignments/teachers/week08/answers/wikitutorial/wikitutorial/static/ie6.css b/assignments/teachers/week08/answers/wikitutorial/wikitutorial/static/ie6.css deleted file mode 100644 index b7c8493d..00000000 --- a/assignments/teachers/week08/answers/wikitutorial/wikitutorial/static/ie6.css +++ /dev/null @@ -1,8 +0,0 @@ -* html img, -* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none", -this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')", -this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("http://github.com/','').replace('")',''), -this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')", -this.runtimeStyle.backgroundImage = "none")),this.pngSet=true) -);} -#wrap{display:table;height:100%} diff --git a/assignments/teachers/week08/answers/wikitutorial/wikitutorial/static/middlebg.png b/assignments/teachers/week08/answers/wikitutorial/wikitutorial/static/middlebg.png deleted file mode 100644 index 2369cfb7da3e5052c2ad4932a6d56240c92654c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2797 zcmV4Tx0C)kNmUmQBSrfqTdoR7v5<-y@dJRoV0Fe@UkzPe5BmqJR7!t5oLbpCc6HqI?@={d8%D5al;0(=!Cz zYydD6nO!2_rJ!tuGDRE_#zA==00c_%EKZ!o62USwPXIWXSj`sE}8w<4jU*%sHzk2;U z$a?$5<7MdQoaVsz{O95^ejS$UX;36cb2fe1Y+3Y{{cC>d?Hh%b}~Geu0H=$|_LAH!zl zAj2Q0Uf9TEuaUC0Snjw2jC3cfEVxw!5{*}g2jLb zQa}a}gIur*tOxm^5bOYZKsl%aHJ}bOfD@nvoCX)bWpEwb1byH>7z88W8JGmG!3+dJ zc!&zoAT>xEGJwn=8;A|fhrFObC=7~)5};&A1WBP)&_<{bDu&9TgHRpxBXkP709}Q8 zpu5lzG!Fdvqf1r2MCzX|yZIz>xmnl~$ zpHUuUAPhr>A0wSn#5lp|XS`F#WweHcflJworSw_BrjROl77!Go4w=>|jpnXz2LrNOcbC zbnDFM8tF#rZqRMieW*v$W9ud9?bd78o7C6V57J+yU$1}9fM~!rNHN%J&}lGjXk-{| zxY@A9aLh>6$j@knQN7UvW2&*M@lxYz|7l}t!?UTdxjmOU*L&{Txvg_w*qYf2Z1>yVv7^}q*=@FKxBFo4U@x|B zupf8OcSvxkbQoaM*&*z0>?@8~M-Rufj;9^pI@vo(oK86X;mmSQb3W=kHqU6DU|!9< zVHaH&uFFA}!THSj3G)xkA9U4m<+@h8K6cY{%Av^?0i=GocG202Kesu9q`liwb@Yi zqU=@)9sQZ=k{U}lNr!Ug=Tzjp$&JcAxlD1HXj#{C)8$*2kFM}u@%>87O5V!$RXVHI zuNqqIzWU%AXiegp_O*Iz^VW{6^I3OfJ!yT~`d>C!Z7AOGYGd@qwmi+eb$P>^d^XkR z%jJvn2R1uzuG)gxBHYrwb?(-(tse{c1=k9#3QG##Z{uyd_MP>2rQdzpp0vHY$i8U* z4%`mWj{cplJC77A7OyBC-W9Z~c{g)+!R}Xkmh8D&Vp~$Rm$X;9cd#_Dw6#pXY)9Gq z@|5zv3Xh7$N{z~`mDBt9`+E1g?Qf{ktSYQ}cR+aH&Ox7p&DDn0C5Lc_at=MIiK^-R zp8b7Yt$J-??T5pn!-Ge{j&#&H)YTo;I9gN>*GucikHsIm`Ge;VtqrV(gN=;F!sFn$ z^!U>s6MpPJ5pbgYB>QB;PX<3#Hqn|2nxW?9&66!DErYGGtv#pwPqnu>w>AB2@$=!+ zI;ShnD4!`hOFEl(_S3l)=cdkQou9and||kKN&EeaF&A%lgm!da3b=ITviIeSo$j6I zuDDz|ebwpescYO08?84TZ?^T!>p9!&+I!)a=dH`P z{cd0HThQ0jAK8CrAbw!*4*$;B-SoRJ?&aK@xxelK_Cdizg@+}NG#*v|YVvF2p#9*P zAK5^Wa`oDjMp>M1#i^e9C^!r+xaf~-RMm2 zd;I&-4<;YlJ_dYz@G0Zdr@sILoAdna&gY5%000SaNLh0L01FcU01FcV0GgZ_0000` zNkl3M)`0?X^CI%pY5dZ)Ghq6c#BU2mL4m7>^xj0=#gtkGV1kD*#^bxk;#3qK# z1w@EpQ$noku{i^$7!@T*ax+fPAS4hh!X^U%5(tH;2fehL00000NkvXXu0mjf?v`T0 diff --git a/assignments/teachers/week08/answers/wikitutorial/wikitutorial/static/pylons.css b/assignments/teachers/week08/answers/wikitutorial/wikitutorial/static/pylons.css deleted file mode 100644 index 4b1c017c..00000000 --- a/assignments/teachers/week08/answers/wikitutorial/wikitutorial/static/pylons.css +++ /dev/null @@ -1,372 +0,0 @@ -html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td -{ - margin: 0; - padding: 0; - border: 0; - outline: 0; - font-size: 100%; /* 16px */ - vertical-align: baseline; - background: transparent; -} - -body -{ - line-height: 1; -} - -ol, ul -{ - list-style: none; -} - -blockquote, q -{ - quotes: none; -} - -blockquote:before, blockquote:after, q:before, q:after -{ - content: ''; - content: none; -} - -:focus -{ - outline: 0; -} - -ins -{ - text-decoration: none; -} - -del -{ - text-decoration: line-through; -} - -table -{ - border-collapse: collapse; - border-spacing: 0; -} - -sub -{ - vertical-align: sub; - font-size: smaller; - line-height: normal; -} - -sup -{ - vertical-align: super; - font-size: smaller; - line-height: normal; -} - -ul, menu, dir -{ - display: block; - list-style-type: disc; - margin: 1em 0; - padding-left: 40px; -} - -ol -{ - display: block; - list-style-type: decimal-leading-zero; - margin: 1em 0; - padding-left: 40px; -} - -li -{ - display: list-item; -} - -ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl -{ - margin-top: 0; - margin-bottom: 0; -} - -ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir -{ - list-style-type: circle; -} - -ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir -{ - list-style-type: square; -} - -.hidden -{ - display: none; -} - -p -{ - line-height: 1.5em; -} - -h1 -{ - font-size: 1.75em; - line-height: 1.7em; - font-family: helvetica, verdana; -} - -h2 -{ - font-size: 1.5em; - line-height: 1.7em; - font-family: helvetica, verdana; -} - -h3 -{ - font-size: 1.25em; - line-height: 1.7em; - font-family: helvetica, verdana; -} - -h4 -{ - font-size: 1em; - line-height: 1.7em; - font-family: helvetica, verdana; -} - -html, body -{ - width: 100%; - height: 100%; -} - -body -{ - margin: 0; - padding: 0; - background-color: #fff; - position: relative; - font: 16px/24px NobileRegular, "Lucida Grande", Lucida, Verdana, sans-serif; -} - -a -{ - color: #1b61d6; - text-decoration: none; -} - -a:hover -{ - color: #e88f00; - text-decoration: underline; -} - -body h1, body h2, body h3, body h4, body h5, body h6 -{ - font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif; - font-weight: 400; - color: #373839; - font-style: normal; -} - -#wrap -{ - min-height: 100%; -} - -#header, #footer -{ - width: 100%; - color: #fff; - height: 40px; - position: absolute; - text-align: center; - line-height: 40px; - overflow: hidden; - font-size: 12px; - vertical-align: middle; -} - -#header -{ - background: #000; - top: 0; - font-size: 14px; -} - -#footer -{ - bottom: 0; - background: #000 url(http://github.com/footerbg.png) repeat-x 0 top; - position: relative; - margin-top: -40px; - clear: both; -} - -.header, .footer -{ - width: 750px; - margin-right: auto; - margin-left: auto; -} - -.wrapper -{ - width: 100%; -} - -#top, #top-small, #bottom -{ - width: 100%; -} - -#top -{ - color: #000; - height: 230px; - background: #fff url(http://github.com/headerbg.png) repeat-x 0 top; - position: relative; -} - -#top-small -{ - color: #000; - height: 60px; - background: #fff url(http://github.com/headerbg.png) repeat-x 0 top; - position: relative; -} - -#bottom -{ - color: #222; - background-color: #fff; -} - -.top, .top-small, .middle, .bottom -{ - width: 750px; - margin-right: auto; - margin-left: auto; -} - -.top -{ - padding-top: 40px; -} - -.top-small -{ - padding-top: 10px; -} - -#middle -{ - width: 100%; - height: 100px; - background: url(http://github.com/middlebg.png) repeat-x; - border-top: 2px solid #fff; - border-bottom: 2px solid #b2b2b2; -} - -.app-welcome -{ - margin-top: 25px; -} - -.app-name -{ - color: #000; - font-weight: 700; -} - -.bottom -{ - padding-top: 50px; -} - -#left -{ - width: 350px; - float: left; - padding-right: 25px; -} - -#right -{ - width: 350px; - float: right; - padding-left: 25px; -} - -.align-left -{ - text-align: left; -} - -.align-right -{ - text-align: right; -} - -.align-center -{ - text-align: center; -} - -ul.links -{ - margin: 0; - padding: 0; -} - -ul.links li -{ - list-style-type: none; - font-size: 14px; -} - -form -{ - border-style: none; -} - -fieldset -{ - border-style: none; -} - -input -{ - color: #222; - border: 1px solid #ccc; - font-family: sans-serif; - font-size: 12px; - line-height: 16px; -} - -input[type=text], input[type=password] -{ - width: 205px; -} - -input[type=submit] -{ - background-color: #ddd; - font-weight: 700; -} - -/*Opera Fix*/ -body:before -{ - content: ""; - height: 100%; - float: left; - width: 0; - margin-top: -32767px; -} diff --git a/assignments/teachers/week08/answers/wikitutorial/wikitutorial/static/pyramid-small.png b/assignments/teachers/week08/answers/wikitutorial/wikitutorial/static/pyramid-small.png deleted file mode 100644 index a5bc0ade71d3da5eab67391e840ff20448c42cd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7044 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 - - - ${page.__name__} - Pyramid tutorial wiki (based on - TurboGears 20-Minute Wiki) - - - - - - - - -
    -
    -
    -
    - pyramid -
    -
    -
    -
    -
    -
    - - Viewing Page Name Goes - Here - -
    - -
    -
    -
    -
    - -
    -
    -
    - - - \ No newline at end of file diff --git a/assignments/teachers/week08/answers/wikitutorial/wikitutorial/templates/edit.pt b/assignments/teachers/week08/answers/wikitutorial/wikitutorial/templates/edit.pt deleted file mode 100644 index 70c95604..00000000 --- a/assignments/teachers/week08/answers/wikitutorial/wikitutorial/templates/edit.pt +++ /dev/null @@ -1,14 +0,0 @@ - - - Editing - Page Name Goes Here - - - -
    - -
    -
    - -
    - - {% endif %} -

    Posts

    -
      - {% for entry in entries %} -
    • -

      {{ entry.title }}

      -
      - {{ entry.text|safe }} -
      -
    • - {% else %} -
    • No entries here so far
    • - {% endfor %} -
    -{% endblock %} \ No newline at end of file diff --git a/assignments/week05/lab/type-along.txt b/assignments/week05/lab/type-along.txt deleted file mode 100644 index e8d4c740..00000000 --- a/assignments/week05/lab/type-along.txt +++ /dev/null @@ -1,761 +0,0 @@ -But First ---------- - -And Second ----------- - -And Now... ----------- - -A Moment to Reflect -------------------- - -We've built ------------ - -We've built ------------ - -We've built ------------ - -We've built ------------ - -Onward ------- - -From Now On ------------ - -The Abstraction Stack ---------------------- - -Plumbing --------- - -Tools ------ - -Small Frameworks ----------------- - -Full Stack Frameworks ---------------------- - -Systems -------- - -Frameworks ----------- - -What Does That *Mean*? ----------------------- - -Level of Abstraction --------------------- - -Python Web Frameworks ---------------------- - -Choosing a Framework --------------------- - -Cris' First Law of Frameworks ------------------------------ - -Cris' Second Law of Frameworks ------------------------------- - -Preparation ------------ - -Flask ------ - - from flask import Flask - app = Flask(__name__) - - @app.route('/') - def hello_world(): - return 'Hello World!' - - if __name__ == '__main__': - app.run() - - -Running our App ---------------- - - (flaskenv)$ python flask_intro.py - - -Debugging our App ------------------ - - @app.route('/') - def hello_world(): - bar = 1 / 0 - return 'Hello World!' - - if __name__ == '__main__': - app.run(debug=True) - - -What's Happening Here? ----------------------- - -URL Routing ------------ - -Routes Can Be Dynamic ---------------------- - - @app.route('/profile/') - def show_profile(username): - return "My username is %s" % username - - - @app.route('/div//') - def divide(val): - return "%0.2f divided by 2 is %0.2f" % (val, val / 2) - - -Routes Can Be Filtered ----------------------- - - @app.route('/blog/entry//', methods=['GET',]) - def read_entry(id): - return "reading entry %d" % id - - @app.route('/blog/entry//', methods=['POST', ]) - def write_entry(id): - return 'writing entry %d' % id - - -Routes Can Be Reversed ----------------------- - -Reversing URLs in Flask ------------------------ - - from flask import url_for - with app.test_request_context(): - print url_for('endpoint', **kwargs) - - -Reversing in Action -------------------- - - import flask_intro - from flask_intro import app - from flask import url_for - with app.test_request_context(): - print url_for('show_profile', username="cris") - print url_for('divide', val=23.7) - - '/profile/cris/' - '/div/23.7/' - - -Generating HTML ---------------- - -Templating ----------- - -Jinja2 Template Basics ----------------------- - -Advanced Jinja2 ---------------- - -Templates in Flask ------------------- - - from flask import render_template - - @app.route('/hello/') - @app.route('/hello/') - def hello(name=None): - return render_template('hello.html', name=name) - - -Flask Template Context ----------------------- - -Lab 1 ------ - -Lab 2 - Part 1 --------------- - -Data Persistence ----------------- - -Simple SQL ----------- - -Our Database ------------- - - drop table if exists entries; - create table entries ( - id integer primary key autoincrement, - title string not null, - text string not null - ); - - -Our App -------- - - # configuration goes here - DATABASE = '/tmp/flaskr.db' - SECRET_KEY = 'development key' - - app = Flask(__name__) # this is already in the file - app.config.from_object(__name__) - - -Creating the Database ---------------------- - - # add this at the very top - import sqlite3 - - # add the rest of this below the app.config statement - def connect_db(): - return sqlite3.connect(app.config['DATABASE']) - - -Tests and TDD -------------- - -Testing Setup -------------- - - import os - import flaskr - import unittest - import tempfile - - class FlaskrTestCase(unittest.TestCase): - - def setUp(self): - db_fd = tempfile.mkstemp() - self.db_fd, flaskr.app.config['DATABASE'] = db_fd - flaskr.app.config['TESTING'] = True - self.client = flaskr.app.test_client() - self.app = flaskr.app - - -Testing Teardown ----------------- - - class FlaskrTestCase(unittest.TestCase): - ... - - def tearDown(self): - os.close(self.db_fd) - os.unlink(flaskr.app.config['DATABASE']) - - -Make Tests Runnable -------------------- - - if __name__ == '__main__': - unittest.main() - - -Test Databse Setup ------------------- - - def test_database_setup(self): - con = flaskr.connect_db() - cur = con.execute('PRAGMA table_info(entries);') - rows = cur.fetchall() - self.assertEquals(len(rows), 3) - - -Run the Tests -------------- - - (flaskenv)$ python flaskr_tests.py - F - ====================================================================== - FAIL: test_database_setup (__main__.FlaskrTestCase) - ---------------------------------------------------------------------- - Traceback (most recent call last): - File "flaskr_tests.py", line 23, in test_database_setup - self.assertTrue(len(rows) == 3) - AssertionError: False is not True - - - ---------------------------------------------------------------------- - Ran 1 test in 0.011s - - - FAILED (failures=1) - - -Make the Test Pass ------------------- - - # add this import at the top - from contextlib import closing - - # add this function after the connect_db function - def init_db(): - with closing(connect_db()) as db: - with app.open_resource('schema.sql') as f: - db.cursor().executescript(f.read()) - db.commit() - - -Initialize the DB in Tests --------------------------- - - def setUp(self): - ... - flaskr.init_db() # <- add this at the end - - -Initialize the DB IRL ---------------------- - - import flaskr - flaskr.init_db() - ^D - - -Lab 2 - Part 2 --------------- - -Managing DB Connections ------------------------ - -Manage our DB -------------- - - # add this import at the top: - from flask import g - - # add these function after init_db - @app.before_request - def before_request(): - g.db = connect_db() - - @app.teardown_request - def teardown_request(exception): - g.db.close() - - -Test Writing Entries --------------------- - - def test_write_entry(self): - expected = ("My Title", "My Text") - with self.app.test_request_context('/'): - self.app.preprocess_request() - flaskr.write_entry(*expected) - con = flaskr.connect_db() - cur = con.execute("select * from entries;") - rows = cur.fetchall() - self.assertEquals(len(rows), 1) - for val in expected: - self.assertTrue(val in rows[0]) - - -Write an Entry --------------- - - def write_entry(title, text): - g.db.execute('insert into entries (title, text) values (?, ?)', - [title, text]) - g.db.commit() - - -Test Reading Entries --------------------- - - def test_get_all_entries_empty(self): - with self.app.test_request_context('/'): - self.app.preprocess_request() - entries = flaskr.get_all_entries() - self.assertEquals(len(entries), 0) - - - def test_get_all_entries(self): - expected = ("My Title", "My Text") - with self.app.test_request_context('/'): - self.app.preprocess_request() - flaskr.write_entry(*expected) - entries = flaskr.get_all_entries() - self.assertEquals(len(entries), 1) - for entry in entries: - self.assertEquals(expected[0], entry['title']) - self.assertEquals(expected[1], entry['text']) - - -Read Entries ------------- - - def get_all_entries(): - cur = g.db.execute('select title, text from entries order by id desc') - entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()] - return entries - - -Lab 2 - Part 3 --------------- - -Test the Front Page -------------------- - - def test_empty_listing(self): - rv = self.client.get('/') - assert 'No entries here so far' in rv.data - - - def test_listing(self): - expected = ("My Title", "My Text") - with self.app.test_request_context('/'): - self.app.preprocess_request() - flaskr.write_entry(*expected) - rv = self.client.get('/') - for value in expected: - assert value in rv.data - - -Template Inheritance --------------------- - -Creating Layout ---------------- - - - - - Flaskr - - -

    Flaskr

    -
    - {% block body %}{% endblock %} -
    - - - - -Extending Layout ----------------- - - {% extends "layout.html" %} - {% block body %} -

    Posts

    -
      - {% for entry in entries %} -
    • -

      {{ entry.title }}

      -
      - {{ entry.text|safe }} -
      -
    • - {% else %} -
    • No entries here so far
    • - {% endfor %} -
    - {% endblock %} - - -Creating a View ---------------- - - # at the top, import - from flask import render_template - - # and after our last functions: - @app.route('/') - def show_entries(): - entries = get_all_entries() - return render_template('show_entries.html', entries=entries) - - -Authentication --------------- - -Test Authentication -------------------- - - def test_login_passes(self): - with self.app.test_request_context('/'): - self.app.preprocess_request() - flaskr.do_login(flaskr.app.config['USERNAME'], - flaskr.app.config['PASSWORD']) - self.assertTrue(session.get('logged_in', False)) - - - def test_login_fails(self): - with self.app.test_request_context('/'): - self.app.preprocess_request() - self.assertRaises(ValueError, flaskr.do_login, - flaskr.app.config['USERNAME'], - 'incorrectpassword') - - -Set Up Authentication ---------------------- - - # add an import - from flask import session - - # and configuration - USERNAME = 'admin' - PASSWORD = 'default' - - # and a function - def do_login(usr, pwd): - if usr != app.config['USERNAME']: - raise ValueError - elif pwd != app.config['PASSWORD']: - raise ValueError - else: - session['logged_in'] = True - - -Login/Logout in Tests ---------------------- - - def login(self, username, password): - return self.client.post('/login', data=dict( - username=username, - password=password - ), follow_redirects=True) - - - def logout(self): - return self.client.get('/logout', - follow_redirects=True) - - -Test Authentication -------------------- - - def test_login_logout(self): - rv = self.login('admin', 'default') - assert 'You were logged in' in rv.data - rv = self.logout() - assert 'You were logged out' in rv.data - rv = self.login('adminx', 'default') - assert 'Invalid username' in rv.data - rv = self.login('admin', 'defaultx') - assert 'Invalid password' in rv.data - - -Add Login Template ------------------- - - {% extends "layout.html" %} - {% block body %} -

    Login

    - {% if error -%} -

    Error {{ error }} - {%- endif %} -

    -
    - - -
    -
    - - -
    -
    - -
    -
    - {% endblock %} - - -Add Login/Logout Views ----------------------- - - # at the top, new imports - from flask import request - from flask import redirect - from flask import flash - from flask import url_for - - -And the View Code ------------------ - - @app.route('/login', methods=['GET', 'POST']) - def login(): - error = None - if request.method == 'POST': - try: - do_login(request.form['username'], - request.form['password']) - except ValueError: - error = "Invalid Login" - else: - flash('You were logged in') - return redirect(url_for('show_entries')) - return render_template('login.html', error=error) - - - @app.route('/logout') - def logout(): - session.pop('logged_in', None) - flash('You were logged out') - return redirect(url_for('show_entries')) - - -About Flash ------------ - -

    Flaskr

    -
    - {% if not session.logged_in %} - log in - {% else %} - log_out - {% endif %} -
    - {% for message in get_flashed_messages() %} -
    {{ message }}
    - {% endfor %} -
    - - -Adding an Entry ---------------- - - def test_add_entries(self): - self.login('admin', 'default') - rv = self.client.post('/add', data=dict( - title='Hello', - text='This is a post' - ), follow_redirects=True) - assert 'No entries here so far' not in rv.data - assert 'Hello' in rv.data - assert 'This is a post' in rv.data - - -Add the View ------------- - - # add an import - from flask import abort - - - @app.route('/add', methods=['POST']) - def add_entry(): - if not session.get('logged_in'): - abort(401) - try: - write_entry(request.form['title'], request.form['text']) - flash('New entry was successfully posted') - except sqlite3.Error as e: - flash('There was an error: %s' % e.args[0]) - return redirect(url_for('show_entries')) - - -Where do Entries Come From --------------------------- - -Provide a Form --------------- - - {% block body %} - {% if session.logged_in %} -
    -
    - - -
    -
    - - -
    -
    - -
    -
    - {% endif %} -

    Posts

    - - -All Done --------- - - (flaskenv)$ python flaskr.py - * Running on http://127.0.0.1:5000/ - * Restarting with reloader - - -The Big Payoff --------------- - -Lab 2 - Part 4 --------------- - -Static Files ------------- - - - Flaskr - - - - -Deploying ---------- - - (flaskenv)$ cd ../ - (flaskenv)$ tar -czvf flaskr.tgz flaskr - (flaskenv)$ scp flaskr.tgz :~/ - (flaskenv)$ ssh - $ tar -zxvf flaskr.tgz - - -Deploying ---------- - - WSGIScriptAlias / /var/www/flaskr.wsgi - - -Deploying ---------- - - $ sudo touch /var/www/flaskr.wsgi - $ sudo vi /var/www/flasrk.wsgi - - - import sys - sys.path.insert(0, 'path/to/flaskr') # the flaskr app you uploaded - - from flaskr import app as application - - -Deploying ---------- - - $ sudo apache2ctl configtest - $ sudo /etc/init.d/apache2 graceful - - -Going Further -------------- - -But Instead ------------ - -Assignment ----------- - -Submitting The Assignment -------------------------- - diff --git a/assignments/week06/athome/assignment.txt b/assignments/week06/athome/assignment.txt deleted file mode 100644 index bf7b9f6f..00000000 --- a/assignments/week06/athome/assignment.txt +++ /dev/null @@ -1,59 +0,0 @@ -Assignment ----------- - -As described in class, we've divided into teams for Week 07. Our assignment -for week six is also divided. Each team has a team leader, they have one -assignment, described below. The remaining members of each team have a second -assignment, also described below. - -Team Leader Assignment ----------------------- - -If you are a team leader, your assignment is to formulate a plan to implement -one of the following features as an extension to the djangor micro-blog app -your team members are building. Please pick one feature and communicate your -plan to me before the start of class on Tuesday, Feb. 19: - -* User Registration (django-registration) -* 'Archive' views based on date or author (generic date-based views) -* WYSIWYG visual editor for entry posts. (django-ckeditor) -* Tagging (django-taggit) -* Theme (make it beautiful) - -Submitting the Team Leader Assignment -------------------------------------- - -Communicate with your team to decide a feature. Formulate a plan to implement -that feature. Research the tools you'll need to accomplish the job. -Communicate your plan to Cris (cris@crisewing.com) - -Team Member Assignment ----------------------- - -* Review the data structure and views required for the Flaskr app. - -* Start a new *app* in your same `mysite` project. Call it `djangor` - -* Build the required models to represent the data. Make two enhancements: - - * Add a column for 'pub_date' to the entry model - - * Allow each entry to be 'owned' by a User. Add a relation field to - represent this. - - * *HINT* ``django.contrib.auth.models`` defines a ``User`` model. - -* Build the urlconf required to present an entry list and a view for posting a - new entry. - -* Build views for each URL - -Submitting the Team Member Assignment -------------------------------------- - -* place your *app* package into the `athome` folder in ``assignments/week06/`` - -* Add any notes, comments or questions in the form of a README file in that - same folder - -* Commit your changes to your fork and make a pull request. diff --git a/assignments/week06/lab/src/base.html b/assignments/week06/lab/src/base.html deleted file mode 100644 index f89925eb..00000000 --- a/assignments/week06/lab/src/base.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - My Site - - -
    -
    - {% if messages %} - {% for message in messages %} -

    - {{ message }}

    - {% endfor %} - {% endif %} - {% block content %} - {% endblock %} -
    -
    - - diff --git a/assignments/week07/athome/assignment.rst b/assignments/week07/athome/assignment.rst deleted file mode 100644 index c26f0045..00000000 --- a/assignments/week07/athome/assignment.rst +++ /dev/null @@ -1,161 +0,0 @@ -Week 7 Assignment Instructions -============================== - -Prep ----- - -For this week, you have *no* code assignment. - -Instead I want you to focus on installing software and reading for next week. -Software we'll be installing uses C extensions, and so installing it on OS X -or Linux requires a compiler and python's development headers. - -**Ubuntu** (our vms): - - $ sudo apt-get install python-dev - -**OS X**: Ensure that you have XCode installed. It's free, but *big* expect it -to take a while if you don't already have it. Once you've downloaded it you'll -also need to install the command-line tools (Thanks to Jon Braam for this -pointer): - -* Open XCode -* Open the XCode menu, then click 'Preferences' > 'Downloads' > 'Install - Command Line Tools' -* Once this is done, you can close XCode again - -**Windows**: See the next section - -Windows Prep ------------- - -Although there are pre-compiled binaries available for Windows, you'll need -one `.bat` file to get them to work properly. To get that file, you'll need to -install Visual Studio 2008 Express: - -* Download the installer (894MB): - http://download.microsoft.com/download/8/B/5/8B5804AD-4990-40D0-A6AA-CE894CBBB3DC/VS2008ExpressENUX1397868.iso -* Extract the files to a folder (call it VS2008ExpressENUX1397868—it will be - 2.68GB) using something like 7zip -* Inside that folder double-click on Setup.hta -* On the screen that comes up, click on the installer for Visual C++ 2008 - Express Edition and follow the instructions. **Note**: It does work if you - include the following two options which are pre-selected for you: (1) MSDN - Express Library for Visual Studio 2008, and (2) Microsoft SQL Server 2005 - Express Edition (x86). - -Virtualenv ----------- - -With that prep work out of the way, you're ready to start. First, set up a -virtualenv: - - $ python2.6 virtualenv.py --distribute pyramidenv - ... - $ source pyramidenv/bin/activate - (pyramidenv)$ - -Remeber, Windows users: ``> pyramidenv\Scripts\activate`` - -Install Pyramid ---------------- - -Once you've got a virtualenv set up and ready to go, install Pyramid: - - (pyramidenv)$ easy_install pyramid - -This will install a number of dependency packages, do not be alarmed. - -Next, we'll install a different kind of Database, the ZODB. - -Install ZODB ------------- - -If you're on OS X or Linux: - - (pyramidenv)$ easy_install ZODB3==3.10.5 - -This will take some time. If you get errors, contact me directly or via the -Google Group. - -Windows users, you'll have it a bit easier here. You have to install a binary -egg: - - [pyramidenv]> pip install --egg ZODB3==3.10.5 - -Pause for Self Evaluation -------------------------- - -At this point, you can check your work. Fire up a python interpreter in your -virtualenv: - - (pyramidenv)$ python - >>> import ZODB - >>> ^D - (pyramidenv)$ - -If you get an ImportError when you try that, you're not done. Contact me. - -Extras ------- - -Next, we'll need to finish installing the bits we need for our work next -week: - - (pyramidenv)$ easy_install docutils nose coverage - ... - (pyramidenv)$ easy_install pyramid_zodbconn pyramid_tm - ... - (pyramidenv)$ easy_install pyramid_debugtoolbar - -These tools will allow us to manage ZODB connections, debug our app, and run -cool tests. - -Set Up Project --------------- - -And finally, we'll set up a project for ourselves. This is like running -'startproject' for django in a way: - - (pyramidenv)$ pcreate -s zodb wikitutorial - -Do not be alarmed by the 'sorry for the convenience' message. - -You get a folder called ``wikitutorial``. In it you should see files like -``setup.py`` and ``development.ini`` among others. - -This is an installable ``package``. You can install this package with -easy_install. - -Final Self Evaluation ---------------------- - -In fact, let's do that now, so we can prove to ourselves this all worked: - - (pyramidenv)$ cd wikitutorial - (pyramidenv)$ python setup.py develop - ... - -You'll see a bunch of output. When it's over, run tests: - - (pyramidenv)$ python setup.py test -q - -Congratulations ---------------- - -When you've made it this far, and you see 1 test run successfully, you're -done. - -If you like, you can see your work by running the new project:: - - (pyramidenv)$ pserve development.ini - Starting server in PID 3056. - serving on http://0.0.0.0:6543 - -Visit ``http://localhost:6543`` to see your work in action. then go grab a -beer and curl up with the reading for the week. There's a lot. - - - - -http://wiki.cython.org/64BitCythonExtensionsOnWindows \ No newline at end of file diff --git a/assignments/week08/athome/assignment.rst b/assignments/week08/athome/assignment.rst deleted file mode 100644 index be29364d..00000000 --- a/assignments/week08/athome/assignment.rst +++ /dev/null @@ -1,54 +0,0 @@ -Assignment -========== - -Begin work on your Final Project. The parameters are listed below: - -* Create a Website -* It can do anything you want it to. -* It should have some user interactions (forms users complete). -* It should look nice-ish -* It should show off some aspect of what you've learned -* It should take you about 15-20 hours to create (so small) -* It will be due Friday following the last day of class (March 15) - -Remember to check in with Dan or me before you begin work on the project to -ensure that you haven't bitten off more than you can chew in the time you -have. - -If you are having difficulty getting started, contact Dan or me. We are here -to help you get this done. - -We will be spending most of class in weeks 9 and 10 working on this. That will -be your opportunity to get help directly from Dan or me. Please prepare -yourselves to take advantage of this by working ahead so you have specific, -solvable problems we can address. - -Submitting The Assignment -========================= - -The assignment is due by Friday, March 15 at noon. I will not accept -assignments turned in later than that. - -Your assignment will be completed when you email me the following: - -* A Link to your site **running on your bluebox VM** -* A Link to **your project source code repository** in Github. -* Text describing **the goals and outcomes** of your project. (This can also - be in the form of a README in your repository) -* Instructions on **how I can run your project locally** on my laptop (Do I - need to install anything special in a virtualenv? Will I need a particular - database? Anything else I'll need to know?) - -Evaluating the Project -====================== - -For evaluation purposes, the site running on your VM is the vital part. I will -look there to see if you've gotten your site to run. I will judge the app -based on the text you write describing your goals. If that text is missing, I -will not be able to judge the completeness of your outcome. For this reason, -the text describing your project is a **vital** part of the submission. Do not -overlook it. - -I will *not* be grading you on the style of your code. That being said, neat, -clean, pep8 compliant code will keep me happy and can only help. Strive to be -as *pythonic* as you can. diff --git a/assignments/week08/lab/base.pt b/assignments/week08/lab/base.pt deleted file mode 100644 index 49e1e193..00000000 --- a/assignments/week08/lab/base.pt +++ /dev/null @@ -1,54 +0,0 @@ - - - - ${page.__name__} - Pyramid tutorial wiki (based on - TurboGears 20-Minute Wiki) - - - - - - - - -
    -
    -
    -
    - pyramid -
    -
    -
    -
    -
    -
    - Viewing Page Name Goes - Here -
    - -
    -
    -
    -
    - -
    -
    -
    - - - \ No newline at end of file From 084d104fe46e9d201e7235260417b1a0413bbf19 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 2 Aug 2013 13:04:35 -0700 Subject: [PATCH 176/487] remove remainin week-style presentations --- source/presentations/week06.rst | 273 ------- source/presentations/week07.rst | 448 ----------- source/presentations/week08.rst | 1277 ------------------------------- 3 files changed, 1998 deletions(-) delete mode 100644 source/presentations/week06.rst delete mode 100644 source/presentations/week07.rst delete mode 100644 source/presentations/week08.rst diff --git a/source/presentations/week06.rst b/source/presentations/week06.rst deleted file mode 100644 index 25f66e61..00000000 --- a/source/presentations/week06.rst +++ /dev/null @@ -1,273 +0,0 @@ -Internet Programming with Python -================================ - -blah blah blah - - - - - - -Detail View ------------ - -Back in our ``polls`` app, let's edit ``urls.py`` again: - -.. code-block:: python - :class: incremental small - - # add this import - from django.views.generic import ListView - - # and edit the detail url like so: - url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/$', - DetailView.as_view( - model=Poll, - template_name="polls/detail.html" - ), - name="poll_detail"), - -.. class:: incremental - -Again, we only need to add a template. - -Forms in Django ---------------- - -We want to be able to vote on a poll. - -.. class:: incremental - -Because doing so involves changing data on the server, we should do this with -a POST request. - -.. class:: incremental - -An html form is a simple way to allow us to force a POST request. - -.. class:: incremental - -Data-altering requests are vulnerable to Cross-Site Request Forgery, a common -attack vector. - -Danger: CSRF ------------- - -Django not only provides a convenient system to fight this, it *requires* it -for any POST requests. - -.. class:: incremental - -The Django middleware that does this is enabled by default. All you need to do -is include the {% csrf_token %} tag in your form template. - -.. class:: incremental - -Create a new file ``detail.html`` in your ``templates/polls`` directory - -Detail Template ---------------- - -.. code-block:: django - :class: small - - {% extends "base.html" %} - {% block content %} -

    {{ poll }}

    - {% if poll.choice_set.count > 0 %} -
    - {% csrf_token %} - {% for choice in poll.choice_set.all %} -
    -
    - {% endfor %} - -
    - {% else %} -

    No choices are available for this poll

    - {% endif %} - {% endblock %} - -Processing The Vote -------------------- - -We can now submit a form to the ``poll_vote`` url. We need to process that -vote - -.. class:: incremental - -Here, a class-based generic view is just going to get in our way. Let's use -an old-fashioned view function. - -.. class:: incremental - -How is our user's vote reaching the server? - -.. class:: incremental - -It gets there as POST data, the value for the key 'choice'. - -Django GET and POST Data ------------------------- - -Django provides the same type of Request/Response based interaction model that -most frameworks are based on. Views are called with the first argument being a -``request`` object. - -.. class:: incremental - -request.GET and request.POST are dictionary-like objects containing data -parsed from incoming HTTP request. - -.. class:: incremental - -You can use normal dictionary syntax to read values from these: - -.. code-block:: python - :class: incremental small - - bar = request.POST['bucko'] - foo = request.GET.get('somevar', None) - -Vote View Skeleton ------------------- - -In ``views.py`` from our ``polls`` app package: - -.. code-block:: python - :class: small - - from django.core.urlresolvers import reverse - from django.http import HttpResponseRedirect - - def vote_view(request, pk): - if request.method == "POST": - try: - # attempt to get a choice - except NoGoodChoice: # send back to detail - url = reverse('poll_detail', args=[pk, ]) - else: # vote and send to result - url = reverse('poll_result', args=[pk]) - else: # submitted via GET, ignore it - url = reverse('poll_detail', args=[pk, ]) - - return HttpResponseRedirect(url) - -Get the Choice --------------- - -Let's start by filling out the process of getting the choice: - -.. code-block:: python - :class: small - - # add imports - from django.shortcuts import get_object_or_404 - from django.contrib import messages - from polls.models import Poll, Choice - # and edit our skeleton - def vote_view(request, pk): - poll = get_object_or_404(Poll, pk=pk) - if request.method == "POST": - try: - choice = poll.choice_set.get( - pk=request.POST.get('choice', 0)) - except Choice.DoesNotExist: - msg = "Ooops, pick a choice that exists, please" - messages.add_message(request, messages.ERROR, msg) - url = reverse('poll_detail', args=[pk, ]) - -Add a Vote ----------- - -Next, let's record a vote on our choice: - -.. code-block:: python - :class: small - - def vote_view(request, pk): - ... - try: - # choice = ... - except Choice.DoesNotExist: - # ... - else: - choice.votes += 1 - choice.save() - messages.add_message(request, messages.INFO, - "You voted for %s" % choice) - url = reverse('poll_result', args=[pk]) - -Add the URL ------------ - -Finally, we need to add this view to our urlconf. Back in ``urls.py`` in the -``polls`` app package, edit the url for the voting view like so: - -.. code-block:: python - :class: small - - url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/vote/$', - 'polls.views.vote_view', - name="poll_vote"), - -.. class:: incremental - -Notice that the 'callable' in this pattern is a string. Django allows you to -use this sort of *dotted name* reference. It will resolve it (or throw an -error if it can't) - -Display Result --------------- - -The last view we need is the poll result. This can simply be a different -version of the Generic DetailView. Still in ``urls.py`` edit the pattern for -the results view: - -.. code-block:: python - :class: small - - url(http://github.com/r'%5E(?P%3Cpk%3E\d+)/result/$', - DetailView.as_view( - model=Poll, - template_name="polls/result.html"), - name="poll_result") - -.. class:: incremental - -And, of course, we will need to create that final template - -Result Template ---------------- - -In ``templates/polls`` create a new file, ``result.html``: - -.. code-block:: django - :class: small - - {% extends "base.html" %} - - {% block content %} -

    {{ poll }}

    -
      - {% for choice in poll.choice_set.all %} -
    • {{ choice }} ({{choice.votes}} votes)
    • - {% endfor %} -
    - Back to the polls, please - {% endblock %} - -Play a Bit ----------- - -Alright. You've done it. - -Take a few minutes to add some polls in the Admin. - -Then return to the public side and vote. See how it goes. - - - diff --git a/source/presentations/week07.rst b/source/presentations/week07.rst deleted file mode 100644 index ab37cf89..00000000 --- a/source/presentations/week07.rst +++ /dev/null @@ -1,448 +0,0 @@ -Internet Programming with Python -================================ - -.. image:: img/django-pony.png - :align: left - :width: 50% - -Week 7: Django - Part 2 - -.. class:: intro-blurb right - -Wherein we extend Django's built-in features - -.. class:: image-credit - -image: http://djangopony.com/ - -But First ---------- - -.. class:: big-centered - -Questions from the Reading? - -And Second ----------- - -A reminder of our task for today: - -.. class:: incremental - -Extend a basic micro-blog application with one of the following features: - -.. class:: incremental - -* User Registration -* 'Archive' views based on date or author -* WYSIWYG visual editor for entry posts. -* Tagging -* Theme (make it beautiful) - -Your Teams ----------- - -**Team 1**: - -.. class:: incremental - -**Leader**: Jon B - -.. class:: incremental - -**Members**: Tyler, Matt K, John C, Wilson, Divesh - -.. class:: incremental - -**Your Task**: User Registration with ``django-registration`` - -Your Teams ----------- - -**Team 2**: - -.. class:: incremental - -**Leader**: Matt O - -.. class:: incremental - -**Members**: David, Pho, Phil, Chris - -.. class:: incremental - -**Your Task**: Archive Views using Generic date-based views - -Your Teams ----------- - -**Team 3**: - -.. class:: incremental - -**Leader**: Austin - -.. class:: incremental - -**Members**: Edet, Eric, Allan - -.. class:: incremental - -**Your Task**: Content Tagging with ``django-taggit`` - -Your Teams ----------- - -**Team 4**: - -.. class:: incremental - -**Leader**: Jason - -.. class:: incremental - -**Members**: Daniel, Conor, Maria - -.. class:: incremental - -**Your Task**: WYSIWYG Editing with ``django-ckeditor`` - -My Guidelines -------------- - -Each team can work from a single *core* repository. - -.. class:: incremental - -Break the job into discreet tasks. - -.. class:: incremental - -Work in twos or threes, each small group take a task and complete it. - -.. class:: incremental - -Create a local branch. Complete your task then merge. - -.. class:: incremental - -Team leaders manage communications, keep an eye on the big picture. - -First Step - Setup ------------------- - -Get a 'core' repository (perhaps leaders fork mine):: - - https://github.com/cewing/training.django_microblog - -.. class:: incremental - -Add your teammates as **collaborators**: - -.. class:: incremental - -* In your browser, view the repo you'll be working from in github. -* Click on the 'settings' tab (in the grey bar below the repo name) -* Click on the 'collaborators' menu item on the left -* Add your teammates by github id to the list of collaborators - -.. class:: incremental - -Now you should **all** have read-write access to this *core* repo. - -Second Step - Workflow ----------------------- - -Each small group, pick a *driver* - -.. class:: incremental - -Each driver, clone the *core* repo to your local machine - -.. class:: incremental - -Pick a task. **Before** you start to work, make a local branch: - -.. class:: incremental - -:: - - $ git checkout -b - -.. class:: incremental - -Complete your task, making commits as you go (you're on a branch) - -Third Step - Cleanup --------------------- - -When you're finished with a task, you'll merge your branch: - -.. class:: incremental small - -:: - - $ git branch - master - * - $ git checkout master - Switched to branch 'master' - $ git pull origin master - From ... - * branch master -> FETCH_HEAD - Already up-to-date. - $ git merge - $ git push origin master - -.. class:: incremental - -Rinse and repeat - -In The End ----------- - -Leaders, make a copy of the *core* repository on your machine - -.. class:: incremental - -When your team is done, set up your machine to show off your results - -.. class:: incremental - -At 8:30 we'll come together. Each team will have 5 minutes to show a quick -demo of their work, and say something about what they learned along the way. - -Almost There ------------- - -.. class:: big-centered - -Any Questions? - -And Now -------- - -.. class:: big-centered - -**begin** - -Reference ---------- - -A Few useful git commands: - -.. class:: small - -:: - - $ git clone # make a clone - $ git checkout -b # make a new local branch - $ git checkout master # return to the master - $ git branch # list branches (and show current) - $ git commit -m "message" # make a commit locally - $ git pull [origin [branch]] # pull recent changes from remote - $ git push [origin [branch]] # push committed changes to remote - $ git merge # merge changes from other to current - -Assignment ----------- - -For this week, you have *no* code assignment. - -.. class:: incremental - -Instead I want you to focus on installing software and reading for next week. -Software we'll be installing uses C extensions, and so installing it on OS X -or Linux requires a compiler and python's development headers. - -.. class:: incremental - -There are a few steps here, so follow along carefully. - -Assignment - Linux Prep ------------------------ - -For Linux machines, we'll need to have ``gcc`` (a c compiler) and python's -development headers in order to complete our tasks. The VMs we have access to -already have ``gcc`` installed, so all we need there is:: - -:: - - $ sudo apt-get install python-dev - -Assignment - OSX Prep ---------------------- - -OS X does not come with a c compiler installed. You'll need to have XCode -installed. It's free, but *big* expect it to take a while if you don't already -have it. - -Once it is installed, there's one more step, you have to install the -'optional' command line tools: - -* Launch XCode -* From the XCode menu, click 'preferences' > 'Downloads' > 'Install Command - Line Tools' -* Once it completes, you can quit XCode again. - -Assignment - Windows Prep -------------------------- - -There are pre-compiled binaries available for Windows, but we need one -``.bat`` file in order to properly install them. We'll need to install Visual -Studio 2008 Express to get this file (if you already have another copy of VS, -you can probably skip this) - -.. class:: small - -* Download the installer (894MB): - http://download.microsoft.com/download/8/B/5/8B5804AD-4990-40D0-A6AA-CE894CBBB3DC/VS2008ExpressENUX1397868.iso -* Extract the files to a folder (call it VS2008ExpressENUX1397868—it will be - 2.68GB) using something like 7zip -* Inside that folder double-click on Setup.hta -* On the screen that comes up, click on the installer for Visual C++ 2008 - Express Edition and follow the instructions. **Note**: It does work if you - include the following two options which are pre-selected for you: (1) MSDN - Express Library for Visual Studio 2008, and (2) Microsoft SQL Server 2005 - Express Edition (x86). - -Assignment - Virtualenv ------------------------ - -With that prep work out of the way, you're ready to start. First, set up a -virtualenv: - -.. class:: incremental - -:: - - $ python2.6 virtualenv.py --distribute pyramidenv - ... - $ source pyramidenv/bin/activate - (pyramidenv)$ - -.. class:: incremental - -Remeber, Windows users: ``> pyramidenv\Scripts\activate`` - -Assignment - Install Pyramid ----------------------------- - -Once you've got a virtualenv set up and ready to go, install Pyramid: - -.. class:: incremental - -:: - - (pyramidenv)$ easy_install pyramid - -.. class:: incremental - -This will install a number of dependency packages, do not be alarmed. - -.. class:: incremental - -Next, we'll install a different kind of Database, the ZODB. - -Assignment - Install ZODB -------------------------- - -If you're on OS X or Linux:: - - (pyramidenv)$ easy_install ZODB3==3.10.5 - -This will take some time. If you get errors, contact me directly or via the -Google Group. - -Windows users, you'll have it a bit easier here. You have to install a binary -egg:: - - [pyramidenv]> pip install --egg ZODB3==3.10.5 - -Pause for Self Evaluation -------------------------- - -At this point, you can check your work. Fire up a python interpreter in your -virtualenv:: - - (pyramidenv)$ python - >>> import ZODB - >>> ^D - (pyramidenv)$ - -If you get an ImportError when you try that, you're not done. Contact me. - -Assignment - Extras -------------------- - -Next, we'll need to finish installing the bits we need for our work next -week:: - - (pyramidenv)$ easy_install docutils nose coverage - ... - (pyramidenv)$ easy_install pyramid_zodbconn pyramid_tm - ... - (pyramidenv)$ easy_install pyramid_debugtoolbar - -.. class:: incremental - -These tools will allow us to manage ZODB connections, debug our app, and run -cool tests. - -Assignment - Set Up Project ---------------------------- - -And finally, we'll set up a project for ourselves. This is like running -'startproject' for django in a way: - -.. class:: incremental small - - (pyramidenv)$ pcreate -s zodb wikitutorial - -.. class:: incremental small center - -Do not be alarmed by the 'sorry for the convenience' message. - -.. class:: incremental - -You get a folder called ``wikitutorial``. In it you should see files like -``setup.py`` and ``development.ini`` among others. - -.. class:: incremental - -This is an installable ``package``. You can install this package with -easy_install. - -Final Self Evaluation ---------------------- - -In fact, let's do that now, so we can prove to ourselves this all worked:: - - (pyramidenv)$ cd wikitutorial - (pyramidenv)$ python setup.py develop - ... - -.. class:: incremental - -You'll see a bunch of output. When it's over, run tests: - -.. class:: incremental - -:: - - (pyramidenv)$ python setup.py test -q - -Congratulations ---------------- - -When you've made it this far, and you see 1 test run successfully, you're -done. - -If you like, you can see your work by running the new project:: - - (pyramidenv)$ pserve development.ini - Starting server in PID 3056. - serving on http://0.0.0.0:6543 - -Visit ``http://localhost:6543`` to see your work in action. then go grab a -beer and curl up with the reading for the week. There's a lot. diff --git a/source/presentations/week08.rst b/source/presentations/week08.rst deleted file mode 100644 index 2ff6a3ce..00000000 --- a/source/presentations/week08.rst +++ /dev/null @@ -1,1277 +0,0 @@ -Internet Programming with Python -================================ - -.. image:: img/pyramid-medium.png - :align: left - :width: 50% - -Week 8: Pyramid - -.. class:: intro-blurb right - -| Wherein we learn -| it's not built by aliens - -But First ---------- - -.. class:: big-centered - -Questions from the Reading? - -And Now -------- - -.. image:: img/sheep_pyramid.jpg - :align: center - :width: 65% - -.. class:: image-credit - -image: Ionics http://www.flickr.com/photos/ionics/6337525967/ - CC_BY - -What is Pyramid? ----------------- - -A Web Framework - -.. class:: incremental - -"Its primary job is to make it easier for a developer to create an arbitrary -web application" - -.. class:: incremental - -Makes as few decisions as possible for you. - -.. class:: incremental - -Allows *you* to make decisions, and provides tools to support you when you do - -.. class:: incremental - -"Pay only for what you eat" - -Why is Pyramid? ---------------- - -Micro-frameworks are great for lightweight apps - -.. class:: incremental - -Micro-frameworks do not scale up or change specs easily - -.. class:: incremental - -Full-stack frameworks have lots of opinions. *Bending* them can be difficult. - -.. class:: incremental - -Pyramid can build a lightweight app easily, but it can also scale and bend - -History - Zope and Repoze -------------------------- - -Many of the core developers of Pyramid started as Zope developers. - -.. class:: incremental - -Born in 1996, Zope was the first Python web framework, and possibly the first -in any language. - -.. class:: incremental - -After 14 years, the developers of Zope had seen and learned *a lot*. - -.. class:: incremental - -Repoze was a short-lived (2008-2010) framework intended to embody the lessons -learned from Zope. - -History - Pylons ----------------- - -Pylons was released in 2005. - -.. class:: incremental - -It was among the first frameworks to fully embrace the WSGI specification. - -.. class:: incremental - -The creators of Pylons build WebTest, WebError and WebOb (abstracted HTTP -request and response objects) - -History - 2010 --------------- - -In 2010, the authors of Repoze and Pylons got together and made an unusual -decision. - -.. class:: incremental - -Why duplicate efforts when there are already so many other frameworks? - -.. class:: incremental - -Repoze was re-named 'Pyramid' and the 'Pylons Project' was born to shepherd -this new combined project. - -Implications ------------- - -Pylons was a framework predicated largely on relational persistence and URL -Dispatch. - -.. class:: incremental - -Zope/Repoze was based on the ZODB and Object Traversal. - -.. class:: incremental - -Each of these approaches has strengths and weaknesses. - -.. class:: incremental - -Pyramid supports neither, both and even combinations of the two. - -Relational DB / URL Dispatch ----------------------------- - -You've seen this before, both in Flask and Django - -.. class:: incremental - -SQLite3, the Django ORM, both are examples of relational persistence models - -.. class:: incremental - -Routes/urlpatterns, both are examples of URL Dispatch - -.. class:: incremental - -Pyramid can work this way too. SQLAlchemy, Route-based views. - -.. class:: incremental - -Been there, done that. Let's see something else. - -ZODB ----- - -ORMs allow developers to pretend that Objects are like DB Tables. - -.. class:: incremental - -But Objects are *not* tables, so there's a `conceptual mismatch -`_ between -the two. - -.. class:: incremental - -The ZODB is an *object store*, rather than a relational database. - -.. class:: incremental - -If your data is best represented by *heterogenous* objects, it's a better -persistence solution. - -Traversal - Object Graphs -------------------------- - -Python objects can *contain* other objects. - -.. class:: incremental - -Using *dict*-like structures, you can build a *graph* of objects: - -.. class:: incremental - -:: - - Family - ├── Parents - │ ├── Cris - │ ├── Kristina - ├── Children - │ ├── Kieran - │ ├── Finnian - -Traversal - Path Lookup ------------------------ - -You can *traverse* across the object graph by treating a URL as a series of -*node names* - -.. class:: incremental small - -:: - - http://family/parents/cris -> family['parents']['cris'] - -.. class:: incremental - -Further path segments can be view names or information passed to the view - -.. class:: incremental small - -:: - - http://family/parents/cris/edit -> edit view - http://family/parents/cris/next/steps -> subpath = /next/steps - -Break Time ----------- - -We've got the concept of object stores and traversal - -.. class:: incremental - -The next step is to see how those work in real life. - -.. class:: incremental - -Take the next few minutes here to ensure that you have a working Pyramid setup -with the ZODB and a project created with ``pcreate -s zodb``. - -Lab - Part One --------------- - -.. class:: big-centered - -Getting To Know Pyramid - -Scaffolds and Opinions ----------------------- - -Pyramid uses what it calls *scaffolds* to get you started on a new project. - -.. class:: incremental - -When you ran ``pcreate -s zodb wikitutorial`` you were invoking the *zodb -scaffold* - -.. class:: incremental - -Pyramid the framework is highly un-opinionated. - -.. class:: incremental - -*Scaffolds*, conversely, can be quite opinionated. The one we used has chosen -our persistence mechanism (ZODB) and how we will reach our code (Traversal). - -Project Layout --------------- - -Running ``pcreate`` has set up a file structure for us: - -.. class:: small - -:: - - wikitutorial/ - CHANGES.txt - development.ini - MANIFEST.in - production.ini - README.txt - setup.cfg - setup.py - wikitutorial/ - __init__.py - models.py - static/ - templates/ - tests.py - views.py - -Similarities to Django ----------------------- - -Our project is organized with an outer *project* folder and an inner *package* -folder (see the ``__init__.py``?) - -.. class:: incremental - -The name of that outer directory is not really important. - -.. class:: incremental - -Our inner *package* folder has a models.py, tests.py and views.py module - -.. class:: incremental - -Our inner *package* folder has a ``static/`` and ``templates/`` directory - -Differences from Django ------------------------ - -Our *outer* module has a ``setup.py`` file, which allows it to be installed -with ``pip`` or ``easy_install`` - -.. class:: incremental - -There is no ``manage.py`` file. Pyramid commands are console scripts. - -.. class:: incremental - -There is nothing magical in Pyramid about the name of the ``models.py`` -module. - -.. class:: incremental - -There is nothing magical in Pyramid about the names of the ``static/`` or -``templates/`` directories. - -Pyramid System Configuration ----------------------------- - -Pyramid keeps configuration intended for an entire installation in ``.ini`` -files at the top of a project. - -.. class:: incremental - -When you deploy an app to some wsgi server, you'll reference one of these files - -.. class:: incremental - -Settings there affect the environment of all apps that are running in that -wsgi server. - -.. class:: incremental - -It is much like Django's ``settings.py`` but is not a python module. - -Pyramid is Python ------------------ - -Running a Pyramid application is really just like running a Python module. In -the ``__init__.py`` file of your app *package*, you'll find a ``main`` -function: - -.. code-block:: python - :class: small incremental - - def main(global_config, **settings): - """ This function returns a Pyramid WSGI application. - """ - config = Configurator(root_factory=root_factory, - settings=settings) - config.add_static_view('static', 'static', cache_max_age=3600) - config.scan() - return config.make_wsgi_app() - -.. class:: incremental - -App-level configuration is done here. - -App Configuration ------------------ - -.. code-block:: python - :class: small - - def main(global_config, **settings): - -.. class:: incremental - -``global_config`` will be a dictionary of the settings from your ``.ini`` file -that come in the [DEFAULT] section (if there is one). These settings will be -shared across all apps that are involved in the system. - -.. class:: incremental - -The ``settings`` passed in here are the settings from your ``.ini`` file that -come in the section that corresponds to your application. They will be used -only by your app. - -App Configuration ------------------ - -.. code-block:: python - :class: small - - config = Configurator(root_factory=root_factory, - settings=settings) - config.add_static_view('static', 'static', cache_max_age=3600) - config.scan() - -.. class:: incremental - -Pyramid does configuration work when an app is run using the ``Configurator`` -class. - -.. class:: incremental - -The ``Configurator`` provides an extensible API for configuring just about -everything. - -.. class:: incremental - -You can read more in `the pyramid.config documentation -`_ - -The Application Root --------------------- - -The ``Configurator`` constructor can take a ``root_factory`` keyword argument. - -.. class:: incremental - -The ``root_factory`` of your app returns the router that determines how to -dispatch individual requests. - -.. class:: incremental - -If you do not provide this argument, the default root factory, which uses URL -Dispatch, will be used. - -.. class:: incremental - -In our case, we want to use Traversal for our app, so we provide a custom -``root_factory``. - -Our Root Factory ----------------- - -.. code-block:: python - :class: small - - from pyramid_zodbconn import get_connection - from .models import appmaker - - def root_factory(request): - conn = get_connection(request) - return appmaker(conn.root()) - -.. class:: incremental - -We grab a connection to the ZODB and pass that into a call to ``appmaker``, -the result is returned (and becomes our app root). - -.. class:: incremental - -So what exactly does ``appmaker`` do? - -The appmaker ------------- - -.. code-block:: python - :class: small - - def appmaker(zodb_root): - if not 'app_root' in zodb_root: - app_root = MyModel() - zodb_root['app_root'] = app_root - import transaction - transaction.commit() - return zodb_root['app_root'] - -.. class:: incremental - -We ensure that there is an ``app_root`` object stored in the ZODB, and return -it. That simple Python object will manage our *Traversal* based application. - -Seeing It Live --------------- - -You've done this at home, but let's repeat the exercise here. - -.. class:: incremental - -In a terminal, change directories into your ``wikitutorial`` *project* folder -(where you see ``development.ini``). Fire up your pyramid virtualenv and serve -our app: - -.. class:: incremental - -:: - - (pyramidenv)$ pserve development.ini - Starting server in PID 16698. - serving on http://0.0.0.0:6543 - -.. class:: incremental - -Load http://localhost:6543 and view your app root. - -Why is it Pretty? ------------------ - -If we understand correctly what is happening so far, we are looking at an -instance of ``MyModel``. - -.. class:: incremental - -What makes it look like this? - -.. class:: incremental - -The secret sauce lies in *view configuration* - -Pyramid Views -------------- - -.. code-block:: python - :class: small - - from pyramid.view import view_config - from .models import MyModel - - @view_config(context=MyModel, renderer='templates/mytemplate.pt') - def my_view(request): - return {'project': 'wikitutorial'} - -.. class:: incremental - -Pyramid views can be configured with the ``@view_config()`` decorator. - -.. class:: incremental - -Or call ``config.add_view()`` method in your app ``main``. - -.. class:: incremental - -``config.scan()`` in ``main`` picks up all config decorators. - -View Configuration ------------------- - -.. class:: small - -The ``view_config`` decorator (and the ``add_view`` method) take a number of -interesting arguments. In our case there are two. - -.. class:: incremental small - -``renderer`` is used to designate how the results returned by the view -callable will be handled. In our case, it's a template that will render to an -HTML page. - -.. class:: incremental small - -``context`` determines the *type* of object for which this view may be used. It -is an example of a ``predicate`` argument, which can be used to place -restrictions on when and how a view may be called. - -.. class:: incremental small - -Predicates are a very powerful system for choosing views. Read more about them -in `view configuration -`_ - -Lab - Part Two --------------- - -.. class:: big-centered - -Data Models and Tests - -Wiki Models ------------ - -Now that we have a basic idea of what's going on in the code generated for us, -it's time to build our wiki models. - -.. class:: incremental - -We'll need to have a Python class that corresponds to a *page* in our wiki. - -.. class:: incremental - -This will be the type of object we view when we are looking at the wiki. - -.. class:: incremental - -We'll also need to have a *root* object, which will be a container for all the -*pages* we create for the wiki. - -Persistence Magic ------------------ - -In an SQL database, data *about* an object is written to tables. In the ZODB, -the *object itself* is saved in the database. - -.. class:: incremental - -The ZODB provides base classes that will *automatically save themselves*. We -will use two of these: - -.. class:: incremental - -* **Persistent** - a class that automatically tracks changes to class - attributes and saves them. - -* **PersistentMapping** - roughly equivalent to a Python *dictionary*, this - class will save changes to itself *and its keys and values*. - -.. class:: incremental small - -The ZODB also provides lists and more complex persistent data structures like -BTrees. - -Traversal Magic ---------------- - -Traversal is supported by two object properties: ``__name__`` and -``__parent__``. - -.. class:: incremental - -Every object in a system which is going to use Traversal **must** provide -these two attributes. - -.. class:: incremental - -The *root* object in a Traversal system will have both of these attributes set -to ``None``. - -The Wiki Class --------------- - -Open ``models.py`` from our ``wikitutorial`` *package* directory. - -.. class:: incremental - -First, delete the ``MyModel`` class. We won't need it. - -.. class:: incremental - -Add the following in its place: - -.. code-block:: python - :class: incremental - - class Wiki(PersistentMapping): - __name__ = None - __parent__ = None - -The Page Class --------------- - -To that same file (models.py) add one import and a second class definition: - -.. code-block:: python - - from persistent import Persistent - - class Page(Persistent): - def __init__(self, data): - self.data = data - -.. class:: incremental - -What about ``__name__`` and ``__parent__``? - -.. class:: incremental - -We'll add those to each instance when we create it. - -Update Appmaker ---------------- - -The existing ``appmaker`` function needs to be updated for our new models: - -.. code-block:: python - - def appmaker(zodb_root): - if not 'app_root' in zodb_root: - app_root = Wiki() - frontpage = Page('This is the front page') - app_root['FrontPage'] = frontpage - frontpage.__name__ = 'FrontPage' - frontpage.__parent__ = app_root - zodb_root['app_root'] = app_root - import transaction - transaction.commit() - return zodb_root['app_root'] - -A Last Bit of Cleanup ---------------------- - -We've deleted the ``MyModel`` class. But we still have *views* that -reference the class. - -.. class:: incremental - -Open the ``views.py`` file in your *package* directory and comment out -everything **except** the first line: - -.. code-block:: python - :class: incremental - - from pyramid.view import view_config - -.. class:: incremental - -Next, we'll test our models. - -Test the Wiki Model -------------------- - -Open ``tests.py`` from the *package* directory. Delete the ``ViewTests`` -class and replace it with the following: - -.. code-block:: python - :class: small - - class WikiModelTests(unittest.TestCase): - - def _getTargetClass(self): - from wikitutorial.models import Wiki - return Wiki - - def _makeOne(self): - return self._getTargetClass()() - - def test_it(self): - wiki = self._makeOne() - self.assertEqual(wiki.__parent__, None) - self.assertEqual(wiki.__name__, None) - -Test the Page Model -------------------- - -Add the following test class as well: - -.. code-block:: python - :class: small - - class PageModelTests(unittest.TestCase): - - def _getTargetClass(self): - from wikitutorial.models import Page - return Page - - def _makeOne(self, data=u'some data'): - return self._getTargetClass()(data=data) - - def test_constructor(self): - instance = self._makeOne() - self.assertEqual(instance.data, u'some data') - -Test Appmaker -------------- - -One more test class: - -.. code-block:: python - :class: small - - class AppmakerTests(unittest.TestCase): - - def _callFUT(self, zodb_root): - from .models import appmaker - return appmaker(zodb_root) - - def test_it(self): - root = {} - self._callFUT(root) - self.assertEqual(root['app_root']['FrontPage'].data, - 'This is the front page') - -A Quick Interlude ------------------ - -In your *package* directory you should see a file: ``Data.fs``. - -.. class:: incremental - -This is the ZODB. It contains references to a class that doesn't exist -anymore (MyModel). This means it is broken. - -.. class:: incremental - -Make sure Pyramid is not running. - -.. class:: incremental - -Delete Data.fs. It will be re-created as needed. - -.. class:: incremental - -You can also delete Data.fs.* (.tmp, .index, .lock) - -Run our Tests -------------- - -Finally, let's run our tests:: - - (pyramidenv)$ python setup.py test - ... - Ran 3 tests in 0.000s - - OK - -.. class:: incremental - -We can also run tests to tell us our code-coverage: - -.. class:: incremental small - -:: - - (pyramidenv)$ nosetests --cover-package=tutorial --cover-erase --with-coverage - -Break ------ - -.. class:: big-centered - -Take a few minutes to breathe - -Lab - Part Three ----------------- - -.. class:: big-centered - -Views and Templates - -Preparing for Views -------------------- - -Our ``Page`` model has a ``data`` attribute, which represents the text in the -page. - -.. class:: incremental - -Our pages will use ReStructuredText, a plain-text format that can be rendered -to HTML with a Python module called ``docutils``. - -.. class:: incremental - -Our project is installable as a python package. It declares its own -*dependencies* so that they will also be installed. - -.. class:: incremental - -We need to add the ``docutils`` package to this list. - -Package Dependencies --------------------- - -Open the ``setup.py`` file from our *project* directory. Add ``docutils`` to -the list ``requires``: - -.. code-block:: python - - requires = [ - 'pyramid', - 'pyramid_zodbconn', - 'transaction', - 'pyramid_tm', - 'pyramid_debugtoolbar', - 'ZODB3', - 'waitress', - 'docutils', # <- ADD THIS - ] - -Complete the Change -------------------- - -Any time you make a change to ``setup.py`` for a package you are working on, -you need to re-install that package to pick up the changes:: - - (pyramidenv)$ python setup.py develop - -.. class:: incremental - -You'll see a whole bunch of stuff flicker by. In it will be a reference to -``Searching for docutils``. - -Adding Views ------------- - -Open ``views.py`` again. Add the following: - -.. code-block:: python - :class: small - - from docutils.core import publish_parts - import re - - from pyramid.httpexceptions import HTTPFound - from pyramid.view import view_config # <- ALREADY THERE - - from wikitutorial.models import Page - - # regular expression used to find WikiWords - wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") - - @view_config(context='.models.Wiki') - def view_wiki(context, request): - return HTTPFound(location=request.resource_url(context, - 'FrontPage')) - -Some Notes ----------- - -New pages in a typical wiki are added by writing *WikiWords* into the page. - -.. class:: incremental - -``r"\b([A-Z]\w+[A-Z]+\w+)"`` is a regular expression that will locate -WikiWords. - -.. class:: incremental - -Note that the ``@view_config`` for the ``view_wiki`` function has no -``renderer`` argument. It will never be *shown* - -.. class:: incremental - -Instead, it returns ``HTTPFound``, (``302 Found``). Calling -``request.resource_url`` provides a URL for the redirect. - -Add a Page View ---------------- - -.. code-block:: python - :class: small - - @view_config(context='.models.Page', renderer='templates/view.pt') - def view_page(context, request): - wiki = context.__parent__ - - def check(match): - word = match.group(1) - if word in wiki: - page = wiki[word] - view_url = request.resource_url(http://github.com/page) - return '%s' % (view_url, word) - else: - add_url = request.application_url + '/add_page/' + word - return '%s' % (add_url, word) - - content = publish_parts( - context.data, writer_name='html')['html_body'] - content = wikiwords.sub(check, content) - edit_url = request.resource_url(http://github.com/context,%20'edit_page') - return dict(page=context, content=content, edit_url=edit_url) - -Adding Templates ----------------- - -What will the page template for the ``view_page`` function need to be called? - -.. class:: incremental - -Go ahead and create ``view.pt`` in your ``templates`` directory. - -.. class:: incremental - -While you're there, also copy the file ``base.pt`` from -``assignments/week08/lab`` in the class repo. - -.. class:: incremental - -Like Django templates, Chameleon templates can extend other templates. Our -``base.pt`` template will be the master, and our ``view.pt`` and ``edit.pt`` -templates will extend it. - -The view.pt Template --------------------- - -Type this code into your ``view.pt`` file: - -.. code-block:: xml - - - -
    - Page text goes here. -
    -

    - - Edit this page - -

    -
    -
    - -A Few Notes ------------ - -Chameleon page templates are valid XML. The templating language uses ``tal``/``metal`` -namespace XML tag attributes. - -.. class:: incremental - -```` tells us we will be using -``base.pt`` as our main template *macro*. - -.. class:: incremental - -Template *macros* can define one or more *slots*. These are like the *blocks* -in Jinja2 or Django templates. - -.. class:: incremental - -```` tells us that everything -here will go in the ``main-content`` slot. - -More Notes ----------- - -.. code-block:: xml - -
    - Page text goes here. -
    - -This uses the ``tal`` directive ``replace`` to completely replace the -``
    `` tag with whatever html is in ``content``. - -.. code-block:: xml - :class: incremental - - - Edit this page - - -.. class:: incremental - -Here, we use the ``tal`` directive ``attributes`` to set the ``href`` for our -anchor to the value passed into our template as ``edit_url``. - -View Your Work --------------- - -We've created the following: - -.. class:: incremental small - -* A wiki view that redirects to the automatically-created FrontPage page -* A page view that will render the ``data`` from a page, along with a url for - editing that page -* A page template to show a wiki page. - -.. class:: incremental - -That's all we need to be able to see our work. Start Pyramid: - -.. class:: incremental small - -:: - - (pyramidenv)$ pserve development.ini - Starting server in PID 43925. - serving on http://0.0.0.0:6543 - -.. class:: incremental - -Load http://localhost:6543/ - -What You Should See -------------------- - -.. image:: img/wiki_frontpage.png - :align: center - :width: 95% - -Editing a Page --------------- - -Back in ``views.py`` add the following: - -.. code-block:: python - :class: small - - @view_config(name='edit_page', context='.models.Page', - renderer='templates/edit.pt') - def edit_page(context, request): - if 'form.submitted' in request.params: - context.data = request.params['body'] - return HTTPFound(location = request.resource_url(http://github.com/context)) - - return dict(page=context, - save_url=request.resource_url(http://github.com/context,%20'edit_page')) - -The Edit Template ------------------ - -Create and fill ``edit.pt`` in ``templates``: - -.. code-block:: xml - :class: small - - - - Editing - Page Name Goes Here - - - -
    - +
    +
    + +
    + +

    Posts

    +
      + {% for entry in entries %} +
    • +

      {{ entry.title }}

      +
      + {{ entry.text|safe }} +
      +
    • + {% else %} +
    • No entries here so far
    • + {% endfor %} +
    +{% endblock %} diff --git a/assignments/session05/tasks.txt b/assignments/session05/tasks.txt new file mode 100644 index 00000000..ea269d25 --- /dev/null +++ b/assignments/session05/tasks.txt @@ -0,0 +1,64 @@ +Session 5 Homework +================== + +Required Tasks +-------------- + +1. Add authentication so a user can log in and log out. +2. Add flash messaging so the app can inform a user about events that happen + + +Authentication Specifications +----------------------------- + +Writing new entries should be restricted to users who have logged in. This +means that: + +.. class:: incremental + +* The form to create a new entry should only be visible to logged in users +* There should be a visible link to allow a user to log in +* This link should display a login form that expects a username and password +* If the user provides incorrect login information, this form should tell her + so. +* If the user provides correct login information, she should end up at the + list page +* Once logged in, the user should see a link to log out. +* Upon clicking that link, the system should no longer show the entry form and + the log in link should re-appear. + + +Flash Messaging Specifications +------------------------------ + +A flask app provides a method called `flash` that allows passing messages from +a view function into a template context so that they can be viewed by a user. + +.. class:: incremental + +Use this method to provide the following messages to users: + +.. class:: incremental + +* Upon a successful login, display the message "You are logged in" +* Upon a successful logout, display the message "You have logged out" +* Upon posting a successful new entry, display the message "New entry posted" +* If adding an entry causes an error, instead of returning a 500 response, + alert the user to the error by displaying the error message to the user. + + +Resources to Use +---------------- + +The microblog we created today comes from the tutorial on the `flask` website. +I've modified that tutorial to omit authentication and flash messaging. You can +refer to the tutorial and to the flask api documentation to learn what you need +to accomplish these tasks. + +`The Flask Tutorial `_ + +`Flask API Documentation `_ + +Both features depend on *sessions*, so you will want to pay particular +attention to how a session is enabled and what you can do with it once it +exists. From b3f6cc398fd7b3fb0b0ce247e02ddd415544ffaf Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 26 Jan 2014 14:29:27 -0800 Subject: [PATCH 257/487] re-organized session 5 to build the basic flask app. login and flash messaging saved for homework --- source/presentations/session05.rst | 1729 +++++++++++++++------------- 1 file changed, 958 insertions(+), 771 deletions(-) diff --git a/source/presentations/session05.rst b/source/presentations/session05.rst index b93f525d..efb1775d 100644 --- a/source/presentations/session05.rst +++ b/source/presentations/session05.rst @@ -99,6 +99,14 @@ This last part is important when it comes to choosing a framework * *Every* framework makes *different* choices +Impedance Mismatch +------------------ + +.. class:: big-centered + +Don't Fight the Framework + + Python Web Frameworks --------------------- @@ -171,85 +179,11 @@ You can't know unless you try so let's try -Practice Safe Development -------------------------- - -We are going to install Flask, and the packages it requires, into a -virtualenv. - -.. class:: incremental - -This will ensure that it is isolated from everything else we do in class (and -vice versa) - -.. container:: incremental - - Remember the basic format for creating a virtualenv: - - .. class:: small - - :: - - $ python virtualenv.py [options] - - $ virtualenv [options] - - -Set Up a VirtualEnv -------------------- - -Start by creating your virtualenv:: - - $ python virtualenv.py flaskenv - - $ virtualenv flaskenv - ... - -.. container:: incremental - - Then, activate it:: - - $ source flaskenv/bin/activate - - C:\> flaskenv\Scripts\activate - - -Install Flask -------------- - -Finally, install Flask using `setuptools` or `pip`:: - - (flaskenv)$ pip install flask - Downloading/unpacking flask - Downloading Flask-0.10.1.tar.gz (544kB): 544kB downloaded - ... - Installing collected packages: flask, Werkzeug, Jinja2, - itsdangerous, markupsafe - ... - Successfully installed flask Werkzeug Jinja2 itsdangerous - markupsafe - - -Kicking the Tires ------------------ - -We've installed the Flask microframework and all of its dependencies. - -.. class:: incremental - -Now, let's see what it can do - -.. class:: incremental - -In your class working directory, create a file called ``flask_intro.py`` and -open it in your text editor. - - -Flask ------ +From Your Homework +------------------ -Getting started with Flask is pretty straightforward. Here's a complete, -simple app. Type it into `flask_intro.py`: +During the week, you walked through an introduction to the *Flask* web +framework. You wrote a file that looked like this: .. code-block:: python :class: small @@ -265,41 +199,15 @@ simple app. Type it into `flask_intro.py`: app.run() -Running our App ---------------- - -As you might expect by now, the last block in our ``flask_intro.py`` file -allows us to run this as a python program. Save your file, and in your -terminal try this:: - - (flaskenv)$ python flask_intro.py - -.. class:: incremental - -Load ``http://localhost:5000`` in your browser to see it in action. - - -Debugging our App ------------------ - -Last week, ``cgitb`` provided us with useful feedback when building an app. -Flask has similar functionality. Make the following changes to your -``flask_intro.py`` file: - -.. code-block:: python - :class: small - - def hello_world(): - bar = 1 / 0 - return 'Hello World!' - - if __name__ == '__main__': - app.run(debug=True) +The outcome +----------- -.. class:: incremental +When you ran this file, you should have seen something like this in your +browser: -Restart your app and then reload your browser to see what happens (clean up -the error when you're done). +.. image:: img/flask_hello.png + :align: center + :width: 80% What's Happening Here? @@ -310,7 +218,7 @@ functions as a single *application* in the WSGI sense. .. class:: incremental -Remember, a WSGI application must be a *callable* that takes the arguments +We know a WSGI application must be a *callable* that takes the arguments *environ* and *start_response*. .. class:: incremental @@ -412,1055 +320,1334 @@ thing that really matters to you. Getting input from a request, and returning a response. -Popping Back Up the Stack -------------------------- +A Quick Reminder +---------------- -Returning up to the level where we will be working, remember what you've done: +Over the week, in addition to walking through a Flask intro you did two other +tasks: .. class:: incremental -* You instantiated a `Flask` app with a name that represents the package or - module containing the app - - * Because our app is a single Python module, this should be ``__name__`` - * This is used to help the `Flask` app figure out where to look for - *resources* - -* You defined a function that returned a response body -* You told the app which requests should use that function with a *route* +You walked through a tutorial on the Python DB API2, and learned how +to use ``sqlite3`` to store and retrieve data. .. class:: incremental -Let's take a look at how that last bit works for a moment... +You also read a bit about ``Jinja2``, the templating language Flask +uses out of the box, and ran some code to explore its abilities. -URL Routing ------------ +Moving On +--------- -Remember our bookdb exercise? How did you end up solving the problem of -mapping an HTTP request to the right function? +Now it is time to put all that together. .. class:: incremental -Flask solves this problem by using the `route` decorator from your app. +We'll spend this session building a "microblog" application. .. class:: incremental -A 'route' takes a URL rule (more on that in a minute) and maps it to an -*endpoint* and a *function*. +Let's dive right in. .. class:: incremental -When a request arrives at a URL that matches a known rule, the function is -called. +Start by activating your Flask virtualenv -URL Rules ---------- +Our Database +------------ -URL Rules are strings that represent what environ['PATH_INFO'] will look like. +We need first to define what an *entry* for our microblog might look like. .. class:: incremental -They are added to a *mapping* on the Flask object called the *url_map* +Let's keep it a simple as possible for now. .. class:: incremental -You can call ``app.add_url_rule()`` to add a new one +Create a new directory ``microblog``, and open a new file in it: +``schema.sql`` -.. class:: incremental +.. code-block:: sql + :class: incremental small -Or you can use what we've used, the ``app.route()`` decorator + drop table if exists entries; + create table entries ( + id integer primary key autoincrement, + title string not null, + text string not null + ); -Function or Decorator ---------------------- +App Configuration +----------------- -.. code-block:: python - :class: small +For any but the most trivial applications, you'll need some configuration. - def index(): - """some function that returns something""" - # ... - - app.add_url_rule('/', 'homepage', index) +.. class:: incremental -.. container:: incremental +Flask provides a number of ways of loading configuration. We'll be using a +config file + +.. class:: incremental - is identical to +Create a new file ``microblog.cfg`` in the same directory. - .. code-block:: python - :class: small +.. code-block:: python + :class: small incremental - @app.route('/', 'homepage') - def index(): - """some function that returns something""" - # ... + # application configuration for a Flask microblog + DATABASE = 'microblog.db' -Routes Can Be Dynamic ---------------------- +Our App Skeleton +---------------- -A *placeholder* in a URL rule becomes a named arg to your function (add these -to ``flask_intro.py``): +Finally, we'll need a basic app skeleton to work from. + +.. class:: incremental + +Create one more file ``microblog.py`` in the same directory, and enter the +following: .. code-block:: python - :class: incremental small + :class: small incremental - @app.route('/profile/') - def show_profile(username): - return "My username is %s" % username + from flask import Flask -.. class:: incremental + app = Flask(__name__) -And *converters* ensure the incoming argument is of the correct type. + app.config.from_pyfile('microblog.cfg') -.. code-block:: python - :class: incremental small + if __name__ == '__main__': + app.run(debug=True) - @app.route('/div//') - def divide(val): - return "%0.2f divided by 2 is %0.2f" % (val, val / 2) +Test Your Work +-------------- -Routes Can Be Filtered ----------------------- +This is enough to get us off the ground. -You can also determine which HTTP *methods* a given route will accept: +.. container:: incremental -.. code-block:: python - :class: small + From a terminal in the ``microblog`` directory, run the app: + + .. class:: small + + :: + + (flaskenv)$ python microblog.py + * Running on http://127.0.0.1:5000/ + * Restarting with reloader - @app.route('/blog/entry//', methods=['GET',]) - def read_entry(id): - return "reading entry %d" % id +.. class:: incremental - @app.route('/blog/entry//', methods=['POST', ]) - def write_entry(id): - return 'writing entry %d' % id +Then point your browser at http://localhost:5000/ .. class:: incremental -After adding that to ``flask_intro.py`` and saving, try loading -``http://localhost:5000/blog/entry/23/`` into your browser. Which was called? +What do you see in your browser? In the terminal? Why? -Routes Can Be Reversed ----------------------- -Reversing a URL means the ability to generate the url that would result in a -given endpoint being called. +Creating the Database +--------------------- + +Quit the app with ``^C``. Then return to ``microblog.py`` and add the +following: + +.. code-block:: python + :class: incremental small + + # add this up at the top + import sqlite3 + + # add the rest of this below the app.config statement + def connect_db(): + return sqlite3.connect(app.config['DATABASE']) .. class:: incremental -This means *you don't have to hard-code your URLs when building links* +This should look familiar. What will happen? .. class:: incremental -That means *you can change the URLs for your app without changing code or -templates* +This convenience method allows us to write our very first test. + + +Tests and TDD +------------- + +.. class:: center + +**If it isn't tested, it's broken** .. class:: incremental -This is called **decoupling** and it is a good thing +We are going to write tests at every step of this exercise using the +``unittest`` module. -Reversing URLs in Flask ------------------------ +.. class:: incremental -In Flask, you reverse a url with the ``url_for`` function. +In your ``microblog`` folder create a ``microblog_tests.py`` file. .. class:: incremental -* ``url_for`` requires an HTTP request context to work -* You can fake an HTTP request when working in a terminal (or testing) -* Use the ``test_request_context`` method of your app object -* This is a great chance to use the Python ``with`` statement -* **Don't type this** +Open it in your editor. + + +Testing Setup +------------- + +Add the following to provide minimal test setup. .. code-block:: python - :class: small incremental + :class: small - from flask import url_for - with app.test_request_context(): - print url_for('endpoint', **kwargs) + import os + import tempfile + import unittest + + import microblog -Reversing in Action -------------------- + class MicroblogTestCase(unittest.TestCase): + + def setUp(self): + db_fd = tempfile.mkstemp() + self.db_fd, microblog.app.config['DATABASE'] = db_fd + microblog.app.config['TESTING'] = True + self.client = microblog.app.test_client() + self.app = microblog.app + + +Testing Teardown +---------------- -Quit your Flask app with ``^C``. Then start a python interpreter in that same -terminal and import your ``flask_intro.py`` module: +**Add** this method to your existing test case class to tear down after each +test: .. code-block:: python - >>> from flask_intro import app - >>> from flask import url_for - >>> with app.test_request_context(): - ... print url_for('show_profile', username="cris") - ... print url_for('divide', val=23.7) - ... - '/profile/cris/' - '/div/23.7/' - >>> + class MicroblogTestCase(unittest.TestCase): + # ... + def tearDown(self): + os.close(self.db_fd) + os.unlink(microblog.app.config['DATABASE']) -Break Time ----------- -Now's a good time to take a rest. +Make Tests Runnable +------------------- + +Finally, we make our tests runnable by adding a ``main`` block: + +.. container:: incremental + + Add the following at the end of ``microblog_tests.py``: + + .. code-block:: python + :class: small + + if __name__ == '__main__': + unittest.main() .. class:: incremental -When we return, we'll take a look at templating and data persistence. +Now, we're ready to add our first actual test.. -Generating HTML ---------------- +Test Database Setup +------------------- -.. class:: big-centered +We'd like to test that our database is correctly initialized. The schema has +one table with three columns. Let's test that. -"I enjoy writing HTML in Python" +.. container:: incremental -.. class:: incremental right + **Add** the following method to your test class in ``microblog_tests.py``: --- nobody, ever + .. code-block:: python + :class: small + def test_database_setup(self): + con = microblog.connect_db() + cur = con.execute('PRAGMA table_info(entries);') + rows = cur.fetchall() + self.assertEquals(len(rows), 3) -Templating ----------- -A good framework will provide some way of generating HTML with a templating -system. +Run the Tests +------------- -.. class:: incremental +We can now run our test module: -There are nearly as many templating systems as there are frameworks +.. class:: small -.. class:: incremental +:: -Each has advantages and disadvantages + (flaskenv)$ python microblog_tests.py + F + ====================================================================== + FAIL: test_database_setup (__main__.MicroblogTestCase) + ---------------------------------------------------------------------- + Traceback (most recent call last): + File "microblog_tests.py", line 23, in test_database_setup + self.assertEquals(len(rows) == 3) + AssertionError: 0 != 3 -.. class:: incremental + ---------------------------------------------------------------------- + Ran 1 test in 0.011s -Flask includes the *Jinja2* templating system (perhaps because it's built by -the same folks) + FAILED (failures=1) -Jinja2 Template Basics ----------------------- +Make the Test Pass +------------------ -Let's start with the absolute basics. +This is an expected failure. Why? .. container:: incremental - Fire up a Python interpreter, using your flask virtualenv: - + Let's add some code to ``microblog.py`` that will actually create our + database schema: + .. code-block:: python :class: small - - (flaskenv)$ python - >>> from jinja2 import Template + + # add this import at the top + from contextlib import closing + + # add this function after the connect_db function + def init_db(): + with closing(connect_db()) as db: + with app.open_resource('schema.sql') as f: + db.cursor().executescript(f.read()) + db.commit() + + +Initialize the DB in Tests +-------------------------- + +We also need to call that function in our ``microblog_tests.py`` to set up the +database schema for each test. .. container:: incremental - A template is built of a simple string: - + Add the following line at the end of that ``setUp`` method: + .. code-block:: python :class: small - >>> t1 = Template("Hello {{ name }}, how are you?") + def setUp(self): + # ... + microblog.init_db() # <- add this at the end +.. class:: incremental -Rendering a Template --------------------- +:: + + (flaskenv)$ python microblog_tests.py + + +Success? +-------- + +.. class:: big-centered incremental -Call the ``render`` method, providing some *context*: + \\o/ Wahoooo! + + +Initialize the DB IRL +--------------------- + +Our test passed, so we have confidence that ``init_db`` does what it should + +.. class:: incremental + +We'll need to have a working database for our app, so let's go ahead and do +this "in real life" + +.. class:: incremental + + (flaskenv)$ python .. code-block:: python - :class: incremental small + :class: incremental + + >>> import microblog + >>> microblog.init_db() + >>> ^D + + +First Break +----------- - >>> t1.render(name="Freddy") - u'Hello Freddy, how are you?' - >>> t1.render({'name': "Roberto"}) - u'Hello Roberto, how are you?' - >>> +After you quit the interpreter, you should see ``microblog.db`` in your +directory. .. class:: incremental -*Context* can either be keyword arguments, or a dictionary +Let's take a few minutes here to rest and consider what we've done. +.. class:: incremental -Dictionaries in Context ------------------------ +When we return, we'll start writing data to our database, and reading it back +out. -Dictionaries passed in as part of the *context* can be addressed with *either* -subscript or dotted notation: -.. code-block:: python - :class: incremental small +Reading and Writing Data +------------------------ - >>> person = {'first_name': 'Frank', - ... 'last_name': 'Herbert'} - >>> t2 = Template("{{ person.last_name }}, {{ person['first_name'] }}") - >>> t2.render(person=person) - u'Herbert, Frank' +Before the break, we created a function that would initialize our database. .. class:: incremental -* Jinja2 will try the *correct* way first (attr for dotted, item for - subscript). -* If nothing is found, it will try the opposite. -* If nothing is found, it will return an *undefined* object. +It's time now to think about writing and reading data for our blog. +.. class:: incremental -Objects in Context ------------------- +We'll start by writing tests. -The exact same is true of objects passed in as part of *context*: +.. class:: incremental + +But first, a word or two about the circle of life. -.. code-block:: python - :class: incremental small - >>> t3 = Template("{{ obj.x }} + {{ obj['y'] }} = Fun!") - >>> class Game(object): - ... x = 'babies' - ... y = 'bubbles' - ... - >>> bathtime = Game() - >>> t3.render(obj=bathtime) - u'babies + bubbles = Fun!' +The Request/Response Cycle +-------------------------- + +Every interaction in HTTP is bounded by the interchange of one request and one +response. .. class:: incremental -This means your templates can be a bit agnostic as to the nature of the things -in *context* +No HTTP application can do anything until some client makes a request. +.. class:: incremental -Filtering values in Templates ------------------------------ +And no action by an application is complete until a response has been sent +back to the client. -You can apply *filters* to the data passed in *context* with the pipe ('|') -operator: +.. class:: incremental -.. code-block:: python - :class: incremental small +This is the lifecycle of an http web application. - t4 = Template("shouted: {{ phrase|upper }}") - >>> t4.render(phrase="this is very important") - u'shouted: THIS IS VERY IMPORTANT' -.. container:: incremental +Managing DB Connections +----------------------- - You can also chain filters together: - - .. code-block:: python - :class: small - - t5 = Template("confusing: {{ phrase|upper|reverse }}") - >>> t5.render(phrase="howdy doody") - u'confusing: YDOOD YDWOH' +It makes sense to bind the lifecycle of a database connection to this same +border. +.. class:: incremental -Control Flow ------------- +Flask does not dictate that we write an application that uses a database. -Logical control structures are also available: +.. class:: incremental -.. code-block:: python - :class: incremental small +Because of this, managing the lifecycle of database connection so that they +are connected to the request/response cycle is up to us. + +.. class:: incremental + +Happily, Flask *does* have a way to help us. - tmpl = """ - ... {% for item in list %}{{ item }}, {% endfor %} - ... """ - >>> t6 = Template(tmpl) - >>> t6.render(list=[1,2,3,4,5,6]) - u'\n1, 2, 3, 4, 5, 6, ' + +Request Boundary Decorators +--------------------------- + +The Flask *app* provides decorators we can use on our database lifecycle +functions: .. class:: incremental -Any control structure introduced in a template **must** be paired with an -explicit closing tag ({% for %}...{% endfor %}) +* ``@app.before_request``: any method decorated by this will be called before + the cycle begins +* ``@app.after_request``: any method decorated by this will be called after + the cycle is complete. If an unhandled exception occurs, these functions are + skipped. -Template Tests --------------- +* ``@app.teardown_request``: any method decorated by this will be called at + the end of the cycle, *even if* an unhandled exception occurs. -There are a number of specialized *tests* available for use with the -``if...elif...else`` control structure: + +Managing our DB +--------------- + +Consider the following functions: .. code-block:: python - :class: incremental small + :class: small - >>> tmpl = """ - ... {% if phrase is upper %} - ... {{ phrase|lower }} - ... {% elif phrase is lower %} - ... {{ phrase|upper }} - ... {% else %}{{ phrase }}{% endif %}""" - >>> t7 = Template(tmpl) - >>> t7.render(phrase="FOO") - u'\n\n foo\n' - >>> t7.render(phrase="bar") - u'\n\n BAR\n' - >>> t7.render(phrase="This should print as-is") - u'\nThis should print as-is' - - -Basic Python Expressions ------------------------- + def get_database_connection(): + db = connect_db() + return db -Basic Python expressions are also supported: + @app.teardown_request + def teardown_request(exception): + db.close() -.. code-block:: python - :class: incremental small +.. class:: incremental - tmpl = """ - ... {% set sum = 0 %} - ... {% for val in values %} - ... {{ val }}: {{ sum + val }} - ... {% set sum = sum + val %} - ... {% endfor %} - ... """ - >>> t8 = Template(tmpl) - >>> t8.render(values=range(1,11)) - u'\n\n\n1: 1\n \n\n2: 3\n \n\n3: 6\n \n\n4: 10\n - \n\n5: 15\n \n\n6: 21\n \n\n7: 28\n \n\n8: 36\n - \n\n9: 45\n \n\n10: 55\n \n' - - -Much, Much More ---------------- +How does the ``db`` object get from one place to the other? -There's more that Jinja2 templates can do, and we'll see more in the next -session when we write templates for our Flask app. -.. container:: incremental +Global Context in Flask +----------------------- - Make sure that you bookmark the Jinja2 documentation for later use:: - - http://jinja.pocoo.org/docs/templates/ +Our flask ``app`` is only really instantiated once +.. class:: incremental -Data Persistence ----------------- +This means that anything we tie to it will be shared across all requests. + +.. class:: incremental -There are many models for persistance of data. +This is what we call ``global`` context. .. class:: incremental -* Flat files -* Relational Database (SQL RDBMs like PostgreSQL, MySQL, SQLServer, Oracle) -* Object Stores (Pickle, ZODB) -* NoSQL Databases (CouchDB, MongoDB, etc) +What happens if two clients make a request at the same time? + + +Local Context in Flask +---------------------- + +Flask provides something it calls a ``local global``: "g". .. class:: incremental -It's also one of the most contentious issues in app design. +This is an object that *looks* global (you can import it anywhere) .. class:: incremental -For this reason, it's one of the things that most Small Frameworks leave -undecided, Flask included. +But in reality, it is *local* to a single request. +.. class:: incremental -Simple SQL ----------- +Resources tied to this object are *not* shared among requests. Perfect for +things like a database connection. -`PEP 249 `_ describes a -common API for database connections called DB-API 2. -.. container:: incremental +Working DB Functions +-------------------- - The goal was to +Add the following, working methods to ``microblog.py``: - achieve a consistency leading to more easily understood modules, code - that is generally more portable across databases, and a broader reach - of database connectivity from Python +.. code-block:: python + :class: small - .. class:: image-credit + # add this import at the top: + from flask import g - source: http://www.python.org/dev/peps/pep-0248/ + # add these function after init_db + def get_database_connection(): + db = getattr(g, 'db', None) + if db is None: + g.db = db = connect_db() + return db + @app.teardown_request + def teardown_request(exception): + db = getattr(g, 'db', None) + if db is not None: + db.close() -A Note on DB API ----------------- -.. class:: incremental center +Writing Blog Entries +-------------------- -It is important to remember that PEP 249 is **only a specification**. +Our microblog will have *entries*. We've set up a simple database schema to +represent them. .. class:: incremental -There is no code or package for DB-API 2 on it's own. +To write an entry, what would we need to do? .. class:: incremental -Since 2.5, the Python Standard Library has provided a `reference -implementation of the api `_ -based on SQLite3 +* Provide a title +* Provide some body text +* Write them to a row in the database .. class:: incremental -Before Python 2.5, this package was available as ``pysqlite`` +Let's write a test of a function that would do that. -Using DB API ------------- +Test Writing Entries +-------------------- -To use the DB API with any database other than SQLite3, you must have an -underlying API package available. +The database connection is bound by a request. We'll need to mock one (in +``microblog_tests.py``) .. container:: incremental - Implementations are available for: + Flask provides ``app.test_request_context`` to do just that - * PostgreSQL (**psycopg2**, txpostgres, ...) - * MySQL (**mysql-python**, PyMySQL, ...) - * MS SQL Server (**adodbapi**, pymssql, mxODBC, pyodbc, ...) - * Oracle (**cx_Oracle**, mxODBC, pyodbc, ...) - * and many more... + .. code-block:: python + :class: small - .. class:: image-credit + def test_write_entry(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + microblog.write_entry(*expected) + con = microblog.connect_db() + cur = con.execute("select * from entries;") + rows = cur.fetchall() + self.assertEquals(len(rows), 1) + for val in expected: + self.assertTrue(val in rows[0]) - source: http://wiki.python.org/moin/DatabaseInterfaces +Run Your Test +------------- -Installing API Packages ------------------------ +.. class:: small -Most db api packages can be installed using typical Pythonic methods:: +:: - $ easy_install psycopg2 - $ pip install mysql-python - ... + (flaskenv)$ python microblog_tests.py + .E + ====================================================================== + ERROR: test_write_entry (__main__.MicroblogTestCase) + ---------------------------------------------------------------------- + Traceback (most recent call last): + File "microblog_tests.py", line 30, in test_write_entry + microblog.write_entry(*expected) + AttributeError: 'module' object has no attribute 'write_entry' -.. class:: incremental + ---------------------------------------------------------------------- + Ran 2 tests in 0.018s -Most api packages will require that the development headers for the underlying -database system be available. Without these, the C symbols required for -communication with the db are not present and the wrapper cannot work. + FAILED (errors=1) +.. class:: incremental -Not Today ---------- +Great. Two tests, one passing. -We don't want to spend the next hour getting a package installed, so let's use -``sqlite3`` instead. -.. class:: incremental +Make It Pass +------------ -I **do not** recommend using sqlite3 for production web applications, there are -too many ways in which it falls short +Now we are ready to write an entry to our database. Add this function to +``microblog.py``: -.. class:: incremental +.. code-block:: python + :class: small incremental -But it will provide a solid learning tool + def write_entry(title, text): + con = get_database_connection() + con.execute('insert into entries (title, text) values (?, ?)', + [title, text]) + con.commit() +.. class:: incremental small -Getting Started ---------------- +:: -In the class resources folder, you'll find an ``sql`` directory. Copy that to -your working directory. + (flaskenv)$ python microblog_tests.py + .. + ---------------------------------------------------------------------- + Ran 2 tests in 0.146s -.. class:: incremental + OK -Open the file ``createdb.py`` in your text editor. Edit ``main`` like so: -.. code-block:: python - :class: incremental small +Reading Entries +--------------- - def main(): - conn = sqlite3.connect(DB_FILENAME) - if DB_IS_NEW: - print 'Need to create database and schema' - else: - print 'Database exists, assume schema does, too.' - conn.close() +We'd also like to be able to read the entries in our blog +.. container:: incremental -Try It Out ----------- + We need a method that returns all of them for a listing page -Run the ``createdb.py`` script to see it in effect:: + .. class:: incremental - $ python createdb.py - Need to create database and schema - $ python createdb.py - Database exists, assume schema does, too. - $ ls - books.db - ... + * The return value should be a list of entries + * If there are none, it should return an empty list + * Each entry in the list should be a dictionary of 'title' and 'text' .. class:: incremental -Sqlite3 will automatically create a new database when you connect for the -first time, if one does not exist. +Let's begin by writing tests. -Set Up A Schema ---------------- +Test Reading Entries +-------------------- -Make the following changes to ``createdb.py``: +In ``microblog_tests.py``: .. code-block:: python :class: small - DB_FILENAME = 'books.db' - SCHEMA_FILENAME = 'ddl.sql' # <- this is new - DB_IS_NEW = not os.path.exists(DB_FILENAME) + def test_get_all_entries_empty(self): + with self.app.test_request_context('/'): + entries = microblog.get_all_entries() + self.assertEquals(len(entries), 0) + + def test_get_all_entries(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + microblog.write_entry(*expected) + entries = microblog.get_all_entries() + self.assertEquals(len(entries), 1) + for entry in entries: + self.assertEquals(expected[0], entry['title']) + self.assertEquals(expected[1], entry['text']) + + +Run Your Tests +-------------- + +.. class:: small - def main(): - with sqlite3.connect(DB_FILENAME) as conn: # <- context mgr - if DB_IS_NEW: # A whole new if clause: - print 'Creating schema' - with open(SCHEMA_FILENAME, 'rt') as f: - schema = f.read() - conn.executescript(schema) - else: - print 'Database exists, assume schema does, too.' - # delete the `conn.close()` that was here. +:: + (flaskenv)$ python microblog_tests.py + .EE. + ====================================================================== + ERROR: test_get_all_entries (__main__.MicroblogTestCase) + ---------------------------------------------------------------------- + Traceback (most recent call last): + File "microblog_tests.py", line 47, in test_get_all_entries + entries = microblog.get_all_entries() + AttributeError: 'module' object has no attribute 'get_all_entries' -Verify Your Work ----------------- + ====================================================================== + ERROR: test_get_all_entries_empty (__main__.MicroblogTestCase) + ---------------------------------------------------------------------- + Traceback (most recent call last): + File "microblog_tests.py", line 40, in test_get_all_entries_empty + entries = microblog.get_all_entries() + AttributeError: 'module' object has no attribute 'get_all_entries' -Quit your python interpreter and delete the file ``books.db`` + ---------------------------------------------------------------------- + Ran 4 tests in 0.021s -.. container:: incremental + FAILED (errors=2) - Then run the script from the command line again to try it out:: +Make Them Pass +-------------- - $ python createdb.py - Creating schema - $ python createdb.py - Database exists, assume schema does, too. +Now we have 4 tests, and two fail. -Introspect the Database ------------------------ +.. class:: incremental -Add the following to ``createdb.py``: +add the ``get_all_entries`` function to ``microblog.py``: .. code-block:: python - :class: small + :class: small incremental + + def get_all_entries(): + con = get_database_connection() + cur = con.execute('SELECT title, text FROM entries ORDER BY id DESC') + return [dict(title=row[0], text=row[1]) for row in cur.fetchall()] + +.. container:: incremental + + And back in your terminal: + + .. class:: small + + :: + + (flaskenv)$ python microblog_tests.py + .... + ---------------------------------------------------------------------- + Ran 4 tests in 0.021s - # in the imports, add this line: - from utils import show_table_metadata + OK - else: - # in the else clause, replace the print statement with this: - print "Database exists, introspecting:" - tablenames = ['author', 'book'] - cursor = conn.cursor() - for name in tablenames: - print "\n" - show_table_metadata(cursor, name) + +Where We Stand +-------------- + +We've moved quite a ways in implementing our microblog: .. class:: incremental -Then try running ``python createdb.py`` again +* We've created code to initialize our database schema +* We've added functions to manage the lifecycle of our database connection +* We've put in place functions to write and read blog entries +* And, since it's tested, we are reasonably sure our code does what we think + it does. -My Results ----------- +.. class:: incremental -.. class:: small +We're ready now to put a face on it, so we can see what we're doing! -:: - $ python createdb.py - Table Metadata for 'author': - cid | name | type | notnull | dflt_value | pk | - -----------+------------+------------+------------+------------+------------+- - 0 | authorid | INTEGER | 1 | None | 1 | - -----------+------------+------------+------------+------------+------------+- - 1 | name | TEXT | 0 | None | 0 | - -----------+------------+------------+------------+------------+------------+- +Second Break +------------ + +But first, let's take a quick break to clear our heads. - Table Metadata for 'book': - cid | name | type | notnull | dflt_value | pk | - -----------+------------+------------+------------+------------+------------+- - 0 | bookid | INTEGER | 1 | None | 1 | - -----------+------------+------------+------------+------------+------------+- - 1 | title | TEXT | 0 | None | 0 | - -----------+------------+------------+------------+------------+------------+- - 2 | author | INTEGER | 1 | None | 0 | - -----------+------------+------------+------------+------------+------------+- +Templates In Flask +------------------ +We'll start with a detour into templates as they work in Flask -Inserting Data --------------- +.. container:: incremental -Let's load up some data. Fire up your interpreter and type: + Jinja2 templates use the concept of an *Environment* to: + + .. class:: incremental + + * Figure out where to look for templates + * Set configuration for the templating system + * Add some commonly used functionality to the template *context* -.. code-block:: python - :class: small +.. class:: incremental + +Flask sets up a proper Jinja2 Environment when you instantiate your ``app``. + + +Flask Environment +----------------- - >>> import sqlite3 - >>> insert = """ - ... INSERT INTO author (name) VALUES("Iain M. Banks");""" - >>> with sqlite3.connect("books.db") as conn: - ... cur = conn.cursor() - ... cur.execute(insert) - ... cur.rowcount - ... cur.close() - ... - - 1 - >>> +Flask uses the value you pass to the ``app`` constructor to calculate the root +of your application on the filesystem. .. class:: incremental -Did that work? +From that root, it expects to find templates in a directory name ``templates`` + +.. container:: incremental + + This allows you to use the ``render_template`` command from ``flask`` like + so: + + .. code-block:: python + :class: small + + from flask import render_template + page_html = render_template('hello_world.html', name="Cris") -Querying Data +Flask Context ------------- -Let's query our database to find out: +Keyword arguments you pass to ``render_template`` become the *context* passed +to the template for rendering. -.. code-block:: python - :class: small +.. class:: incremental - >>> query = """ - ... SELECT * from author;""" - >>> with sqlite3.connect("books.db") as conn: - ... cur = conn.cursor() - ... cur.execute(query) - ... rows = cur.fetchall() - ... for row in rows: - ... print row - ... - - (1, u'Iain M. Banks') +Flask will add a few things to this context. .. class:: incremental -Alright! We've got data in there. Let's make it more efficient +* **config**: contains the current configuration object +* **request**: contains the current request object +* **session**: any session data that might be available +* **g**: the request-local object to which global variables are bound +* **url_for**: so you can easily *reverse* urls from within your templates +* **get_flashed_messages**: a function that returns messages you flash to your + users (more on this later). -Parameterized Statements +Setting Up Our Templates ------------------------ -Try this: +In your ``microblog`` directory, add a new ``templates`` directory -.. code-block:: python - :class: small +.. container:: incremental - >>> insert = """ - ... INSERT INTO author (name) VALUES(?);""" - >>> authors = [["China Mieville"], ["Frank Herbert"], - ... ["J.R.R. Tolkien"], ["Susan Cooper"], ["Madeline L'Engle"]] - >>> with sqlite3.connect("books.db") as conn: - ... cur = conn.cursor() - ... cur.executemany(insert, authors) - ... print cur.rowcount - ... cur.close() - ... - - 5 - - -Check Your Work ---------------- + In this directory create a new file ``layout.html`` + + .. code-block:: jinja + :class: small + + + + + Microblog! + + +

    My Microblog

    +
    + {% block body %}{% endblock %} +
    + + + +Template Inheritance +-------------------- -Again, query the database: +You can combine templates in a number of different ways. -.. code-block:: python +.. class:: incremental + +* you can make replaceable blocks in templates with blocks + + * ``{% block foo %}{% endblock %}`` + +* you can build on a template in a second template by extending + + * ``{% extends "layout.html" %}`` + * this *must* be the first text in the template + +* you can re-use common structure with *include*: + + * ``{% include "footer.html" %}`` + + +Displaying an Entries List +-------------------------- + +Create a new file, ``show_entries.html`` in ``templates``: + +.. code-block:: jinja :class: small - >>> query = """ - ... SELECT * from author;""" - >>> with sqlite3.connect("books.db") as conn: - ... cur = conn.cursor() - ... cur.execute(query) - ... rows = cur.fetchall() - ... for row in rows: - ... print row - ... - - (1, u'Iain M. Banks') - ... - (4, u'J.R.R. Tolkien') - (5, u'Susan Cooper') - (6, u"Madeline L'Engle") - - -Transactions ------------- + {% extends "layout.html" %} + {% block body %} +

    Posts

    +
      + {% for entry in entries %} +
    • +

      {{ entry.title }}

      +
      + {{ entry.text|safe }} +
      +
    • + {% else %} +
    • No entries here so far
    • + {% endfor %} +
    + {% endblock %} + + +Viewing Entries +--------------- -Transactions group operations together, allowing you to verify them *before* -the results hit the database. +We just need a Python function that will: .. class:: incremental -In SQLite3, data-altering statements require an explicit ``commit`` unless -auto-commit has been enabled. +* build a list of entries +* pass the list to our template to be rendered +* return the result to a client's browser .. class:: incremental -The ``with`` statements we've used take care of committing when the context -manager closes. +As usual, we'll start by writing tests for this new function -.. class:: incremental -Let's change that so we can see what happens explicitly +Test Viewing Entries +-------------------- +Add the following two tests to ``microblog_tests.py``: -Populating the Database ------------------------ +.. code-block:: python + :class: small -Let's start by seeing what happens when you try to look for newly added data -before the ``insert`` transaction is committed. + def test_empty_listing(self): + actual = self.client.get('/').data + expected = 'No entries here so far' + self.assertTrue(expected in actual) + + def test_listing(self): + expected = ("My Title", "My Text") + with self.app.test_request_context('/'): + microblog.write_entry(*expected) + actual = self.client.get('/').data + for value in expected: + self.assertTrue(value in actual) .. class:: incremental -Begin by quitting your interpreter and deleting ``books.db``. +``app.test_client()`` creates a mock http client for us. -.. container:: incremental - Then re-create the database, empty:: +Run Your Tests +-------------- - $ python createdb.py - Creating schema +.. class:: small +:: -Setting Up the Test -------------------- + (flaskenv)$ python microblog_tests.py + .F..F. + ====================================================================== + FAIL: test_empty_listing (__main__.MicroblogTestCase) + ---------------------------------------------------------------------- + Traceback (most recent call last): + File "microblog_tests.py", line 55, in test_empty_listing + assert 'No entries here so far' in response.data + AssertionError + ====================================================================== + FAIL: test_listing (__main__.MicroblogTestCase) + ---------------------------------------------------------------------- + Traceback (most recent call last): + File "microblog_tests.py", line 63, in test_listing + assert value in response.data + AssertionError + ---------------------------------------------------------------------- + Ran 6 tests in 0.138s + + FAILED (failures=2) -.. class:: small -Open ``populatedb.py`` in your editor, replace the final ``print``: +Make Them Pass +-------------- + +In ``microblog.py``: .. code-block:: python :class: small - conn1 = sqlite3.connect(DB_FILENAME) - conn2 = sqlite3.connect(DB_FILENAME) - print "\nOn conn1, before insert:" - show_authors(conn1) - authors = ([author] for author in AUTHORS_BOOKS.keys()) - cur = conn1.cursor() - cur.executemany(author_insert, authors) - print "\nOn conn1, after insert:" - show_authors(conn1) - print "\nOn conn2, before commit:" - show_authors(conn2) - conn1.commit() - print "\nOn conn2, after commit:" - show_authors(conn2) - conn1.close() - conn2.close() - - -Running the Test ----------------- - -.. class:: small + # at the top, import + from flask import render_template -Quit your python interpreter and run the ``populatedb.py`` script: + # and after our last functions: + @app.route('/') + def show_entries(): + entries = get_all_entries() + return render_template('show_entries.html', entries=entries) -.. class:: small incremental +.. class:: incremental small :: - On conn1, before insert: - no rows returned - On conn1, after insert: - (1, u'China Mieville') - (2, u'Frank Herbert') - (3, u'Susan Cooper') - (4, u'J.R.R. Tolkien') - (5, u"Madeline L'Engle") - - On conn2, before commit: - no rows returned - On conn2, after commit: - (1, u'China Mieville') - (2, u'Frank Herbert') - (3, u'Susan Cooper') - (4, u'J.R.R. Tolkien') - (5, u"Madeline L'Engle") - - -Rollback --------- + (flaskenv)$ python microblog_tests.py + ...... + ---------------------------------------------------------------------- + Ran 6 tests in 0.100s -That's all well and good, but what happens if an error occurs? + OK -.. class:: incremental -Transactions can be rolled back in order to wipe out partially completed work. +Creating Entries +---------------- + +We still lack a way to add an entry. We need a view that will: .. class:: incremental -Like with commit, using ``connect`` as a context manager in a ``with`` -statement will automatically rollback for exceptions. +* Accept incoming form data from a request +* Get the data for ``title`` and ``text`` +* Create a new entry in the database +* Throw an appropriate HTTP error if that fails +* Show the user the list of entries when done. .. class:: incremental -Let's rewrite our populatedb script so it explicitly commits or rolls back a -transaction depending on exceptions occurring +Again, first come the tests. -Edit populatedb.py (slide 1) ----------------------------- - -.. class:: small +Testing Add an Entry +-------------------- -First, add the following function above the ``if __name__ == '__main__'`` -block: +Add this to ``microblog_tests.py``: .. code-block:: python :class: small - def populate_db(conn): - authors = ([author] for author in AUTHORS_BOOKS.keys()) - cur = conn.cursor() - cur.executemany(author_insert, authors) + def test_add_entries(self): + actual = self.client.post('/add', data=dict( + title='Hello', + text='This is a post' + ), follow_redirects=True).data + self.assertFalse('No entries here so far' in actual) + self.assertTrue('Hello' in actual) + self.assertTrue('This is a post' in actual) - for author in AUTHORS_BOOKS.keys(): - params = ([book, author] for book in AUTHORS_BOOKS[author]) - cur.executemany(book_insert, params) +Run Your Tests +-------------- -Edit populatedb.py (slide 2) ----------------------------- +Verify that our test fails as expected: .. class:: small -Then, in the runner: +:: + + (flaskenv)$ python microblog_tests.py + F...... + ====================================================================== + FAIL: test_add_entries (__main__.MicroblogTestCase) + ---------------------------------------------------------------------- + Traceback (most recent call last): + File "microblog_tests.py", line 72, in test_add_entries + self.assertTrue('Hello' in actual) + AssertionError: False is not true + + ---------------------------------------------------------------------- + Ran 7 tests in 0.050s + + FAILED (failures=1) + + +Make Them Pass +-------------- + +We have all we need to write entries, all we lack is an endpoint (in +``microblog.py``): .. code-block:: python :class: small - with sqlite3.connect(DB_FILENAME) as conn1: - with sqlite3.connect(DB_FILENAME) as conn2: - try: - populate_db(conn1) - print "\nauthors and books on conn2 before commit:" - show_authors(conn2) - show_books(conn2) - except sqlite3.Error: - conn1.rollback() - print "\nauthors and books on conn2 after rollback:" - show_authors(conn2) - show_books(conn2) - raise - else: - conn1.commit() - print "\nauthors and books on conn2 after commit:" - show_authors(conn2) - show_books(conn2) - - -Try it Out ----------- + # add imports + from flask import abort + from flask import request + from flask import url_for + from flask import redirect + + @app.route('/add', methods=['POST']) + def add_entry(): + try: + write_entry(request.form['title'], request.form['text']) + except sqlite3.Error: + abort(500) + return redirect(url_for('show_entries')) -Remove ``books.db`` and recrete the database, then run our script: + +And...? +------- .. class:: small :: - $ rm books.db - $ python createdb.py - Creating schema - $ python populatedb.py + (flaskenv)$ python microblog_tests.py + ....... + ---------------------------------------------------------------------- + Ran 7 tests in 0.047s -.. class:: small incremental + OK -:: +.. class:: incremental center - authors and books on conn2 after rollback: - no rows returned - no rows returned - Traceback (most recent call last): - File "populatedb.py", line 57, in - populate_db(conn1) - File "populatedb.py", line 46, in populate_db - cur.executemany(book_insert, params) - sqlite3.InterfaceError: Error binding parameter 0 - probably unsupported type. +**Hooray!** + + +Where do Entries Come From +-------------------------- + +Finally, we're almost done. We can add entries and view them. But look at that +last view. Do you see a call to ``render_template`` in there at all? + +.. class:: incremental + +There isn't one. That's because that view is never meant to be be visible. +Look carefully at the logic. What happens? + +.. class:: incremental + +So where do the form values come from? + +.. class:: incremental + +Let's add a form to the main view. Open ``show_entries.html`` -Oooops, Fix It + +Provide a Form -------------- -.. class:: small +.. code-block:: jinja + :class: small -Okay, we got an error, and the transaction was rolled back correctly. + {% block body %} +
    +
    + + +
    +
    + + +
    +
    + +
    +
    +

    Posts

    + + +All Done +-------- -.. container:: incremental small +Okay. That's it. We've got an app all written. - Open ``utils.py`` and find this: +.. class:: incremental - .. code-block:: python +So far, we haven't actually touched our browsers at all, but we have +reasonable certainty that this works because of our tests. Let's try it. - 'Susan Cooper': ["The Dark is Rising", ["The Greenwitch"]], -.. container:: incremental small +.. class:: incremental - Fix it like so: +In the terminal where you've been running tests, run our microblog app: - .. code-block:: python +.. class:: incremental - 'Susan Cooper': ["The Dark is Rising", "The Greenwitch"], +:: + + (flaskenv)$ python microblog.py + * Running on http://127.0.0.1:5000/ + * Restarting with reloader + + +The Big Payoff +-------------- + +Now load ``http://localhost:5000/`` in your browser and enjoy your reward. -.. class:: small incremental -It appears that we were attempting to bind a list as a parameter. Ooops. +Making It Pretty +---------------- +What we've got here is pretty ugly. -Try It Again +.. class:: incremental + +If you've fallen behind, or want to start fresh, you can find the finished +``microblog`` directory in the class resources. + +.. class:: incremental + +In that directory inside the ``static`` directory you will find +``styles.css``. Open it in your editor. It contains basic CSS for this app. + +.. class:: incremental + +We'll need to include this file in our ``layout.html``. + + +Static Files ------------ -.. container:: small +Like page templates, Flask locates static resources like images, css and +javascript by looking for a ``static`` directory relative to the app root. - Now that the error in our data is repaired, let's try again:: +.. class:: incremental - $ python populatedb.py +You can use the special url endpoint ``static`` to build urls that point here. +Open ``layout.html`` and add the following: -.. class:: small incremental +.. code-block:: jinja + :class: small incremental -:: + + Flaskr + + - Reporting authors and books on conn2 before commit: - no rows returned - no rows returned - Reporting authors and books on conn2 after commit: - (1, u'China Mieville') - (2, u'Frank Herbert') - (3, u'Susan Cooper') - (4, u'J.R.R. Tolkien') - (5, u"Madeline L'Engle") - (1, u'Perdido Street Station', 1) - (2, u'The Scar', 1) - (3, u'King Rat', 1) - (4, u'Dune', 2) - (5, u"Hellstrom's Hive", 2) - (6, u'The Dark is Rising', 3) - (7, u'The Greenwitch', 3) - (8, u'The Hobbit', 4) - (9, u'The Silmarillion', 4) - (10, u'A Wrinkle in Time', 5) - (11, u'A Swiftly Tilting Planet', 5) - - -Next Steps ----------- -We've learned a bit about the basics of using Flask, writing templates and -using DB API to persist data. +Reap the Rewards +---------------- + +Make sure that your `microblog` folder has a `static` folder inside it, and +that the `styles.css` file is in it. + +.. class:: incremental + +Then, reload your web browser and see the difference a bit of style can make. + +Homework +-------- + +We've built a simple microblog application in the *Flask* web framework. .. class:: incremental -This afternoon, we'll put this to use by writing a small application in Flask +For your homework this week I'd like you to add two features to this app. .. class:: incremental -By the end of the day, we'll have a fully-tested microblog ready to go. +1. Authentication +2. Flash messaging -Lunch Time ----------- +Authentication Specifications +----------------------------- -.. class:: big-centered +Writing new entries should be restricted to users who have logged in. This +means that: + +.. class:: incremental + +* The form to create a new entry should only be visible to logged in users +* There should be a visible link to allow a user to log in +* This link should display a login form that expects a username and password +* If the user provides incorrect login information, this form should tell her + so. +* If the user provides correct login information, she should end up at the + list page +* Once logged in, the user should see a link to log out. +* Upon clicking that link, the system should no longer show the entry form and + the log in link should re-appear. + + +Flash Messaging Specifications +------------------------------ + +A flask app provides a method called `flash` that allows passing messages from +a view function into a template context so that they can be viewed by a user. + +.. class:: incremental + +Use this method to provide the following messages to users: + +.. class:: incremental + +* Upon a successful login, display the message "You are logged in" +* Upon a successful logout, display the message "You have logged out" +* Upon posting a successful new entry, display the message "New entry posted" +* If adding an entry causes an error, instead of returning a 500 response, + alert the user to the error by displaying the error message to the user. + + +Resources to Use +---------------- + +The microblog we created today comes from the tutorial on the `flask` website. +I've modified that tutorial to omit authentication and flash messaging. You can +refer to the tutorial and to the flask api documentation to learn what you need +to accomplish these tasks. + +`The Flask Tutorial `_ + +`Flask API Documentation `_ + +Both features depend on *sessions*, so you will want to pay particular +attention to how a session is enabled and what you can do with it once it +exists. + + +Next Week +--------- + +Next week we are going to mix things up a little and do something quite +different. + +.. class:: incremental + +We'll be starting from the app you have just built (with the additional +features you complete over the week). + +.. class:: incremental + +We will divide into pairs and each pair will select one feature from a list I +will provide. + +.. class:: incremental + +We'll spend the entire class implementing this feature, and at 8:15, each pair +will show their work to the class. + + +Wrap-Up +------- + +For educational purposes you might try taking a look at the source code for +Flask and Werkzeug. Neither is too large a package. + +.. class:: incremental -We'll see you back here in an hour. Enjoy! +In particular seeing how Werkzeug sets up a Request and Response--and how +these relate to the WSGI specification--can be very enlightening. From 02e5db2249172ce0e597cd0f03cf215dd19d2e23 Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 26 Jan 2014 14:30:30 -0800 Subject: [PATCH 258/487] add image of flask helloworld app in browser for session 5 slides --- source/img/flask_hello.png | Bin 0 -> 51023 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 source/img/flask_hello.png diff --git a/source/img/flask_hello.png b/source/img/flask_hello.png new file mode 100644 index 0000000000000000000000000000000000000000..7d02322ffa836456c3c55b13aebcab3a4c8375e3 GIT binary patch literal 51023 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 ZH{u2T1Mzh;StktiBMVlPtQI#8`fog88 Date: Sun, 26 Jan 2014 14:31:06 -0800 Subject: [PATCH 259/487] break three portions of the former session 5 lecture out into tutorials to be walked through during the week before session 5 --- source/additional/flask_walkthrough.rst | 334 ++++++++++ .../additional/sql_persistence_tutorial.rst | 617 ++++++++++++++++++ source/additional/template_tutorial.rst | 235 +++++++ 3 files changed, 1186 insertions(+) create mode 100644 source/additional/flask_walkthrough.rst create mode 100644 source/additional/sql_persistence_tutorial.rst create mode 100644 source/additional/template_tutorial.rst diff --git a/source/additional/flask_walkthrough.rst b/source/additional/flask_walkthrough.rst new file mode 100644 index 00000000..4b4ed6c8 --- /dev/null +++ b/source/additional/flask_walkthrough.rst @@ -0,0 +1,334 @@ +A Quick Flask Walkthrough +========================= + +If you've already set up your virtualenv and installed flask, you can simply +activate it and skip down to **Kicking the Tires** + +If not... + +Practice Safe Development +------------------------- + +We are going to install Flask, and the packages it requires, into a +virtualenv. + +.. class:: incremental + +This will ensure that it is isolated from everything else we do in class (and +vice versa) + +.. container:: incremental + + Remember the basic format for creating a virtualenv: + + .. class:: small + + :: + + $ python virtualenv.py [options] + + $ virtualenv [options] + + +Set Up a VirtualEnv +------------------- + +Start by creating your virtualenv:: + + $ python virtualenv.py flaskenv + + $ virtualenv flaskenv + ... + +.. container:: incremental + + Then, activate it:: + + $ source flaskenv/bin/activate + + C:\> flaskenv\Scripts\activate + + +Install Flask +------------- + +Finally, install Flask using `setuptools` or `pip`:: + + (flaskenv)$ pip install flask + Downloading/unpacking flask + Downloading Flask-0.10.1.tar.gz (544kB): 544kB downloaded + ... + Installing collected packages: flask, Werkzeug, Jinja2, + itsdangerous, markupsafe + ... + Successfully installed flask Werkzeug Jinja2 itsdangerous + markupsafe + + +Kicking the Tires +----------------- + +We've installed the Flask microframework and all of its dependencies. + +.. class:: incremental + +Now, let's see what it can do + +.. class:: incremental + +With your flaskenv activated, create a file called ``flask_intro.py`` and +open it in your text editor. + + +Flask +----- + +Getting started with Flask is pretty straightforward. Here's a complete, +simple app. Type it into `flask_intro.py`: + +.. code-block:: python + :class: small + + from flask import Flask + app = Flask(__name__) + + @app.route('/') + def hello_world(): + return 'Hello World!' + + if __name__ == '__main__': + app.run() + + +Running our App +--------------- + +As you might expect by now, the last block in our ``flask_intro.py`` file +allows us to run this as a python program. Save your file, and in your +terminal try this:: + + (flaskenv)$ python flask_intro.py + +.. class:: incremental + +Load ``http://localhost:5000`` in your browser to see it in action. + + +Debugging our App +----------------- + +Last week, ``cgitb`` provided us with useful feedback when building an app. +Flask has similar functionality. Make the following changes to your +``flask_intro.py`` file: + +.. code-block:: python + :class: small + + def hello_world(): + bar = 1 / 0 + return 'Hello World!' + + if __name__ == '__main__': + app.run(debug=True) + +.. class:: incremental + +Restart your app and then reload your browser to see what happens. + +Click in the stack trace that appears in your browser. Notice anything fun? + +(clean up the error when you're done playing). + + +Your work so far +---------------- + +.. class:: incremental + +* You instantiated a `Flask` app with a name that represents the package or + module containing the app + + * Because our app is a single Python module, this should be ``__name__`` + * This is used to help the `Flask` app figure out where to look for + *resources* + +* You defined a function that returned a response body +* You told the app which requests should use that function with a *route* + +.. class:: incremental + +Let's take a look at how that last bit works for a moment... + + +URL Routing +----------- + +Remember our bookdb exercise? How did you end up solving the problem of +mapping an HTTP request to the right function? + +.. class:: incremental + +Flask solves this problem by using the `route` decorator from your app. + +.. class:: incremental + +A 'route' takes a URL rule (more on that in a minute) and maps it to an +*endpoint* and a *function*. + +.. class:: incremental + +When a request arrives at a URL that matches a known rule, the function is +called. + + +URL Rules +--------- + +URL Rules are strings that represent what environ['PATH_INFO'] will look like. + +.. class:: incremental + +They are added to a *mapping* on the Flask object called the *url_map* + +.. class:: incremental + +You can call ``app.add_url_rule()`` to add a new one + +.. class:: incremental + +Or you can use what we've used, the ``app.route()`` decorator + + +Function or Decorator +--------------------- + +.. code-block:: python + :class: small + + def index(): + """some function that returns something""" + # ... + + app.add_url_rule('/', 'homepage', index) + +.. container:: incremental + + is identical to + + .. code-block:: python + :class: small + + @app.route('/', 'homepage') + def index(): + """some function that returns something""" + # ... + + +Routes Can Be Dynamic +--------------------- + +A *placeholder* in a URL rule becomes a named arg to your function (add these +to ``flask_intro.py``): + +.. code-block:: python + :class: incremental small + + @app.route('/profile/') + def show_profile(username): + return "My username is %s" % username + +.. class:: incremental + +And *converters* ensure the incoming argument is of the correct type. + +.. code-block:: python + :class: incremental small + + @app.route('/div//') + def divide(val): + return "%0.2f divided by 2 is %0.2f" % (val, val / 2) + + +Routes Can Be Filtered +---------------------- + +You can also determine which HTTP *methods* a given route will accept: + +.. code-block:: python + :class: small + + @app.route('/blog/entry//', methods=['GET',]) + def read_entry(id): + return "reading entry %d" % id + + @app.route('/blog/entry//', methods=['POST', ]) + def write_entry(id): + return 'writing entry %d' % id + +.. class:: incremental + +After adding that to ``flask_intro.py`` and saving, try loading +``http://localhost:5000/blog/entry/23/`` into your browser. Which was called? + +Routes Can Be Reversed +---------------------- + +Reversing a URL means the ability to generate the url that would result in a +given endpoint being called. + +.. class:: incremental + +This means *you don't have to hard-code your URLs when building links* + +.. class:: incremental + +That means *you can change the URLs for your app without changing code or +templates* + +.. class:: incremental + +This is called **decoupling** and it is a good thing + +Reversing URLs in Flask +----------------------- + +In Flask, you reverse a url with the ``url_for`` function. + +.. class:: incremental + +* ``url_for`` requires an HTTP request context to work +* You can fake an HTTP request when working in a terminal (or testing) +* Use the ``test_request_context`` method of your app object +* This is a great chance to use the Python ``with`` statement +* **Don't type this** + +.. code-block:: python + :class: small incremental + + from flask import url_for + with app.test_request_context(): + print url_for('endpoint', **kwargs) + +Reversing in Action +------------------- + +Quit your Flask app with ``^C``. Then start a python interpreter in that same +terminal and import your ``flask_intro.py`` module: + +.. code-block:: python + + >>> from flask_intro import app + >>> from flask import url_for + >>> with app.test_request_context(): + ... print url_for('show_profile', username="cris") + ... print url_for('divide', val=23.7) + ... + '/profile/cris/' + '/div/23.7/' + >>> + +Enough for Now +-------------- + +That will give you plenty to think about before class. We'll put this all to +good use building a real flask app in our next session. diff --git a/source/additional/sql_persistence_tutorial.rst b/source/additional/sql_persistence_tutorial.rst new file mode 100644 index 00000000..07ff3fd2 --- /dev/null +++ b/source/additional/sql_persistence_tutorial.rst @@ -0,0 +1,617 @@ +SQL Persistence in Python +========================= + +In this tutorial, you'll walk through some basic concepts of data persistence +using the Python stdlib implementation of DB API 2, `sqlite3` + +Data Persistence +---------------- + +There are many models for persistance of data. + +.. class:: incremental + +* Flat files +* Relational Database (SQL RDBMs like PostgreSQL, MySQL, SQLServer, Oracle) +* Object Stores (Pickle, ZODB) +* NoSQL Databases (CouchDB, MongoDB, etc) + +.. class:: incremental + +It's also one of the most contentious issues in app design. + +.. class:: incremental + +For this reason, it's one of the things that most Small Frameworks leave +undecided. + + +Simple SQL +---------- + +`PEP 249 `_ describes a +common API for database connections called DB-API 2. + +.. container:: incremental + + The goal was to + + achieve a consistency leading to more easily understood modules, code + that is generally more portable across databases, and a broader reach + of database connectivity from Python + + .. class:: image-credit + + source: http://www.python.org/dev/peps/pep-0248/ + + +A Note on DB API +---------------- + +.. class:: incremental center + +It is important to remember that PEP 249 is **only a specification**. + +.. class:: incremental + +There is no code or package for DB-API 2 on it's own. + +.. class:: incremental + +Since 2.5, the Python Standard Library has provided a `reference +implementation of the api `_ +based on SQLite3 + +.. class:: incremental + +Before Python 2.5, this package was available as ``pysqlite`` + + +Using DB API +------------ + +To use the DB API with any database other than SQLite3, you must have an +underlying API package available. + +.. container:: incremental + + Implementations are available for: + + * PostgreSQL (**psycopg2**, txpostgres, ...) + * MySQL (**mysql-python**, PyMySQL, ...) + * MS SQL Server (**adodbapi**, pymssql, mxODBC, pyodbc, ...) + * Oracle (**cx_Oracle**, mxODBC, pyodbc, ...) + * and many more... + + .. class:: image-credit + + source: http://wiki.python.org/moin/DatabaseInterfaces + + +Installing API Packages +----------------------- + +Most db api packages can be installed using typical Pythonic methods:: + + $ easy_install psycopg2 + $ pip install mysql-python + ... + +.. class:: incremental + +Most api packages will require that the development headers for the underlying +database system be available. Without these, the C symbols required for +communication with the db are not present and the wrapper cannot work. + + +Not Today +--------- + +We don't want to spend the next hour getting a package installed, so let's use +``sqlite3`` instead. + +.. class:: incremental + +I **do not** recommend using sqlite3 for production web applications, there are +too many ways in which it falls short + +.. class:: incremental + +But it will provide a solid learning tool + + +Getting Started +--------------- + +In the class resources folder, you'll find an ``sql`` directory. Copy that to +your working directory. + +.. class:: incremental + +Open the file ``createdb.py`` in your text editor. Edit ``main`` like so: + +.. code-block:: python + :class: incremental small + + def main(): + conn = sqlite3.connect(DB_FILENAME) + if DB_IS_NEW: + print 'Need to create database and schema' + else: + print 'Database exists, assume schema does, too.' + conn.close() + + +Try It Out +---------- + +Run the ``createdb.py`` script to see it in effect:: + + $ python createdb.py + Need to create database and schema + $ python createdb.py + Database exists, assume schema does, too. + $ ls + books.db + ... + +.. class:: incremental + +Sqlite3 will automatically create a new database when you connect for the +first time, if one does not exist. + + +Set Up A Schema +--------------- + +Make the following changes to ``createdb.py``: + +.. code-block:: python + :class: small + + DB_FILENAME = 'books.db' + SCHEMA_FILENAME = 'ddl.sql' # <- this is new + DB_IS_NEW = not os.path.exists(DB_FILENAME) + + def main(): + with sqlite3.connect(DB_FILENAME) as conn: # <- context mgr + if DB_IS_NEW: # A whole new if clause: + print 'Creating schema' + with open(SCHEMA_FILENAME, 'rt') as f: + schema = f.read() + conn.executescript(schema) + else: + print 'Database exists, assume schema does, too.' + # delete the `conn.close()` that was here. + + +Verify Your Work +---------------- + +Quit your python interpreter and delete the file ``books.db`` + +.. container:: incremental + + Then run the script from the command line again to try it out:: + + $ python createdb.py + Creating schema + $ python createdb.py + Database exists, assume schema does, too. + +Introspect the Database +----------------------- + +Add the following to ``createdb.py``: + +.. code-block:: python + :class: small + + # in the imports, add this line: + from utils import show_table_metadata + + else: + # in the else clause, replace the print statement with this: + print "Database exists, introspecting:" + tablenames = ['author', 'book'] + cursor = conn.cursor() + for name in tablenames: + print "\n" + show_table_metadata(cursor, name) + +.. class:: incremental + +Then try running ``python createdb.py`` again + +My Results +---------- + +.. class:: small + +:: + + $ python createdb.py + Table Metadata for 'author': + cid | name | type | notnull | dflt_value | pk | + -----------+------------+------------+------------+------------+------------+- + 0 | authorid | INTEGER | 1 | None | 1 | + -----------+------------+------------+------------+------------+------------+- + 1 | name | TEXT | 0 | None | 0 | + -----------+------------+------------+------------+------------+------------+- + + + Table Metadata for 'book': + cid | name | type | notnull | dflt_value | pk | + -----------+------------+------------+------------+------------+------------+- + 0 | bookid | INTEGER | 1 | None | 1 | + -----------+------------+------------+------------+------------+------------+- + 1 | title | TEXT | 0 | None | 0 | + -----------+------------+------------+------------+------------+------------+- + 2 | author | INTEGER | 1 | None | 0 | + -----------+------------+------------+------------+------------+------------+- + + +Inserting Data +-------------- + +Let's load up some data. Fire up your interpreter and type: + +.. code-block:: python + :class: small + + >>> import sqlite3 + >>> insert = """ + ... INSERT INTO author (name) VALUES("Iain M. Banks");""" + >>> with sqlite3.connect("books.db") as conn: + ... cur = conn.cursor() + ... cur.execute(insert) + ... cur.rowcount + ... cur.close() + ... + + 1 + >>> + +.. class:: incremental + +Did that work? + + +Querying Data +------------- + +Let's query our database to find out: + +.. code-block:: python + :class: small + + >>> query = """ + ... SELECT * from author;""" + >>> with sqlite3.connect("books.db") as conn: + ... cur = conn.cursor() + ... cur.execute(query) + ... rows = cur.fetchall() + ... for row in rows: + ... print row + ... + + (1, u'Iain M. Banks') + +.. class:: incremental + +Alright! We've got data in there. Let's make it more efficient + + +Parameterized Statements +------------------------ + +Try this: + +.. code-block:: python + :class: small + + >>> insert = """ + ... INSERT INTO author (name) VALUES(?);""" + >>> authors = [["China Mieville"], ["Frank Herbert"], + ... ["J.R.R. Tolkien"], ["Susan Cooper"], ["Madeline L'Engle"]] + >>> with sqlite3.connect("books.db") as conn: + ... cur = conn.cursor() + ... cur.executemany(insert, authors) + ... print cur.rowcount + ... cur.close() + ... + + 5 + + +Check Your Work +--------------- + +Again, query the database: + +.. code-block:: python + :class: small + + >>> query = """ + ... SELECT * from author;""" + >>> with sqlite3.connect("books.db") as conn: + ... cur = conn.cursor() + ... cur.execute(query) + ... rows = cur.fetchall() + ... for row in rows: + ... print row + ... + + (1, u'Iain M. Banks') + ... + (4, u'J.R.R. Tolkien') + (5, u'Susan Cooper') + (6, u"Madeline L'Engle") + + +Transactions +------------ + +Transactions group operations together, allowing you to verify them *before* +the results hit the database. + +.. class:: incremental + +In SQLite3, data-altering statements require an explicit ``commit`` unless +auto-commit has been enabled. + +.. class:: incremental + +The ``with`` statements we've used take care of committing when the context +manager closes. + +.. class:: incremental + +Let's change that so we can see what happens explicitly + + +Populating the Database +----------------------- + +Let's start by seeing what happens when you try to look for newly added data +before the ``insert`` transaction is committed. + +.. class:: incremental + +Begin by quitting your interpreter and deleting ``books.db``. + +.. container:: incremental + + Then re-create the database, empty:: + + $ python createdb.py + Creating schema + + +Setting Up the Test +------------------- + +.. class:: small + +Open ``populatedb.py`` in your editor, replace the final ``print``: + +.. code-block:: python + :class: small + + conn1 = sqlite3.connect(DB_FILENAME) + conn2 = sqlite3.connect(DB_FILENAME) + print "\nOn conn1, before insert:" + show_authors(conn1) + authors = ([author] for author in AUTHORS_BOOKS.keys()) + cur = conn1.cursor() + cur.executemany(author_insert, authors) + print "\nOn conn1, after insert:" + show_authors(conn1) + print "\nOn conn2, before commit:" + show_authors(conn2) + conn1.commit() + print "\nOn conn2, after commit:" + show_authors(conn2) + conn1.close() + conn2.close() + + +Running the Test +---------------- + +.. class:: small + +Quit your python interpreter and run the ``populatedb.py`` script: + +.. class:: small incremental + +:: + + On conn1, before insert: + no rows returned + On conn1, after insert: + (1, u'China Mieville') + (2, u'Frank Herbert') + (3, u'Susan Cooper') + (4, u'J.R.R. Tolkien') + (5, u"Madeline L'Engle") + + On conn2, before commit: + no rows returned + On conn2, after commit: + (1, u'China Mieville') + (2, u'Frank Herbert') + (3, u'Susan Cooper') + (4, u'J.R.R. Tolkien') + (5, u"Madeline L'Engle") + + +Rollback +-------- + +That's all well and good, but what happens if an error occurs? + +.. class:: incremental + +Transactions can be rolled back in order to wipe out partially completed work. + +.. class:: incremental + +Like with commit, using ``connect`` as a context manager in a ``with`` +statement will automatically rollback for exceptions. + +.. class:: incremental + +Let's rewrite our populatedb script so it explicitly commits or rolls back a +transaction depending on exceptions occurring + + +Edit populatedb.py (slide 1) +---------------------------- + +.. class:: small + +First, add the following function above the ``if __name__ == '__main__'`` +block: + +.. code-block:: python + :class: small + + def populate_db(conn): + authors = ([author] for author in AUTHORS_BOOKS.keys()) + cur = conn.cursor() + cur.executemany(author_insert, authors) + + for author in AUTHORS_BOOKS.keys(): + params = ([book, author] for book in AUTHORS_BOOKS[author]) + cur.executemany(book_insert, params) + + +Edit populatedb.py (slide 2) +---------------------------- + +.. class:: small + +Then, in the runner: + +.. code-block:: python + :class: small + + with sqlite3.connect(DB_FILENAME) as conn1: + with sqlite3.connect(DB_FILENAME) as conn2: + try: + populate_db(conn1) + print "\nauthors and books on conn2 before commit:" + show_authors(conn2) + show_books(conn2) + except sqlite3.Error: + conn1.rollback() + print "\nauthors and books on conn2 after rollback:" + show_authors(conn2) + show_books(conn2) + raise + else: + conn1.commit() + print "\nauthors and books on conn2 after commit:" + show_authors(conn2) + show_books(conn2) + + +Try it Out +---------- + +Remove ``books.db`` and recrete the database, then run our script: + +.. class:: small + +:: + + $ rm books.db + $ python createdb.py + Creating schema + $ python populatedb.py + +.. class:: small incremental + +:: + + authors and books on conn2 after rollback: + no rows returned + no rows returned + Traceback (most recent call last): + File "populatedb.py", line 57, in + populate_db(conn1) + File "populatedb.py", line 46, in populate_db + cur.executemany(book_insert, params) + sqlite3.InterfaceError: Error binding parameter 0 - probably unsupported type. + +Oooops, Fix It +-------------- + +.. class:: small + +Okay, we got an error, and the transaction was rolled back correctly. + +.. container:: incremental small + + Open ``utils.py`` and find this: + + .. code-block:: python + + 'Susan Cooper': ["The Dark is Rising", ["The Greenwitch"]], + +.. container:: incremental small + + Fix it like so: + + .. code-block:: python + + 'Susan Cooper': ["The Dark is Rising", "The Greenwitch"], + +.. class:: small incremental + +It appears that we were attempting to bind a list as a parameter. Ooops. + + +Try It Again +------------ + +.. container:: small + + Now that the error in our data is repaired, let's try again:: + + $ python populatedb.py + +.. class:: small incremental + +:: + + Reporting authors and books on conn2 before commit: + no rows returned + no rows returned + Reporting authors and books on conn2 after commit: + (1, u'China Mieville') + (2, u'Frank Herbert') + (3, u'Susan Cooper') + (4, u'J.R.R. Tolkien') + (5, u"Madeline L'Engle") + (1, u'Perdido Street Station', 1) + (2, u'The Scar', 1) + (3, u'King Rat', 1) + (4, u'Dune', 2) + (5, u"Hellstrom's Hive", 2) + (6, u'The Dark is Rising', 3) + (7, u'The Greenwitch', 3) + (8, u'The Hobbit', 4) + (9, u'The Silmarillion', 4) + (10, u'A Wrinkle in Time', 5) + (11, u'A Swiftly Tilting Planet', 5) + +Congratulations +--------------- + +You've just created a small database of books and authors. The transactional +protections you've used let you rest comfortable, knowing that so long as the +process completed, you've got the data you sent. + +We'll see more of this when we build our flask app. diff --git a/source/additional/template_tutorial.rst b/source/additional/template_tutorial.rst new file mode 100644 index 00000000..ac7fa024 --- /dev/null +++ b/source/additional/template_tutorial.rst @@ -0,0 +1,235 @@ +Jinja2 Template Introduction +============================ + +When you installed ``flask`` into your virtualenv, along with it came a +Python-based templating engine called ``Jinja2``. + +In this walkthrough, you'll see some basics about how templates work, and get +to know what sorts of options they provide you for creating HTML from a Python +process. + +Generating HTML +--------------- + +.. class:: big-centered + +"I enjoy writing HTML in Python" + +.. class:: incremental right + +-- nobody, ever + + +Templating +---------- + +A good framework will provide some way of generating HTML with a templating +system. + +.. class:: incremental + +There are nearly as many templating systems as there are frameworks + +.. class:: incremental + +Each has advantages and disadvantages + +.. class:: incremental + +Flask includes the *Jinja2* templating system (perhaps because it's built by +the same folks) + + +Jinja2 Template Basics +---------------------- + +Let's start with the absolute basics. + +.. container:: incremental + + Fire up a Python interpreter, using your flask virtualenv: + + .. code-block:: python + :class: small + + (flaskenv)$ python + >>> from jinja2 import Template + +.. container:: incremental + + A template is built of a simple string: + + .. code-block:: python + :class: small + + >>> t1 = Template("Hello {{ name }}, how are you?") + + +Rendering a Template +-------------------- + +Call the ``render`` method, providing some *context*: + +.. code-block:: python + :class: incremental small + + >>> t1.render(name="Freddy") + u'Hello Freddy, how are you?' + >>> t1.render({'name': "Roberto"}) + u'Hello Roberto, how are you?' + >>> + +.. class:: incremental + +*Context* can either be keyword arguments, or a dictionary + + +Dictionaries in Context +----------------------- + +Dictionaries passed in as part of the *context* can be addressed with *either* +subscript or dotted notation: + +.. code-block:: python + :class: incremental small + + >>> person = {'first_name': 'Frank', + ... 'last_name': 'Herbert'} + >>> t2 = Template("{{ person.last_name }}, {{ person['first_name'] }}") + >>> t2.render(person=person) + u'Herbert, Frank' + +.. class:: incremental + +* Jinja2 will try the *correct* way first (attr for dotted, item for + subscript). +* If nothing is found, it will try the opposite. +* If nothing is found, it will return an *undefined* object. + + +Objects in Context +------------------ + +The exact same is true of objects passed in as part of *context*: + +.. code-block:: python + :class: incremental small + + >>> t3 = Template("{{ obj.x }} + {{ obj['y'] }} = Fun!") + >>> class Game(object): + ... x = 'babies' + ... y = 'bubbles' + ... + >>> bathtime = Game() + >>> t3.render(obj=bathtime) + u'babies + bubbles = Fun!' + +.. class:: incremental + +This means your templates can be a bit agnostic as to the nature of the things +in *context* + + +Filtering values in Templates +----------------------------- + +You can apply *filters* to the data passed in *context* with the pipe ('|') +operator: + +.. code-block:: python + :class: incremental small + + t4 = Template("shouted: {{ phrase|upper }}") + >>> t4.render(phrase="this is very important") + u'shouted: THIS IS VERY IMPORTANT' + +.. container:: incremental + + You can also chain filters together: + + .. code-block:: python + :class: small + + t5 = Template("confusing: {{ phrase|upper|reverse }}") + >>> t5.render(phrase="howdy doody") + u'confusing: YDOOD YDWOH' + + +Control Flow +------------ + +Logical control structures are also available: + +.. code-block:: python + :class: incremental small + + tmpl = """ + ... {% for item in list %}{{ item }}, {% endfor %} + ... """ + >>> t6 = Template(tmpl) + >>> t6.render(list=[1,2,3,4,5,6]) + u'\n1, 2, 3, 4, 5, 6, ' + +.. class:: incremental + +Any control structure introduced in a template **must** be paired with an +explicit closing tag ({% for %}...{% endfor %}) + + +Template Tests +-------------- + +There are a number of specialized *tests* available for use with the +``if...elif...else`` control structure: + +.. code-block:: python + :class: incremental small + + >>> tmpl = """ + ... {% if phrase is upper %} + ... {{ phrase|lower }} + ... {% elif phrase is lower %} + ... {{ phrase|upper }} + ... {% else %}{{ phrase }}{% endif %}""" + >>> t7 = Template(tmpl) + >>> t7.render(phrase="FOO") + u'\n\n foo\n' + >>> t7.render(phrase="bar") + u'\n\n BAR\n' + >>> t7.render(phrase="This should print as-is") + u'\nThis should print as-is' + + +Basic Python Expressions +------------------------ + +Basic Python expressions are also supported: + +.. code-block:: python + :class: incremental small + + tmpl = """ + ... {% set sum = 0 %} + ... {% for val in values %} + ... {{ val }}: {{ sum + val }} + ... {% set sum = sum + val %} + ... {% endfor %} + ... """ + >>> t8 = Template(tmpl) + >>> t8.render(values=range(1,11)) + u'\n\n\n1: 1\n \n\n2: 3\n \n\n3: 6\n \n\n4: 10\n + \n\n5: 15\n \n\n6: 21\n \n\n7: 28\n \n\n8: 36\n + \n\n9: 45\n \n\n10: 55\n \n' + + +Much, Much More +--------------- + +There's more that Jinja2 templates can do, and you'll see more in class +when we write templates for our Flask app. + +.. container:: incremental + + Make sure that you bookmark the Jinja2 documentation for later use:: + + http://jinja.pocoo.org/docs/templates/ From 8873ba12de2032c9d7f827f97c89085dec51155c Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 26 Jan 2014 14:36:10 -0800 Subject: [PATCH 260/487] basic starting point for the session 5 flask app. --- .../session05/microblog/static/style.css | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 resources/session05/microblog/static/style.css diff --git a/resources/session05/microblog/static/style.css b/resources/session05/microblog/static/style.css new file mode 100644 index 00000000..80218c4f --- /dev/null +++ b/resources/session05/microblog/static/style.css @@ -0,0 +1,20 @@ +body { font-family: 'Helvetica', sans-serif; background: #eaeced; } +a, h1, h2 { color: #1E727F; } +h1, h2 { font-family: 'Helvetica', sans-serif; margin: 0; } +h1 { font-size: 2em; border-bottom: 2px solid #1E727F; padding-bottom: 0.25em; margin-bottom: 0.5em;} +h2 { font-size: 1.4em; } +.page { margin: 2em auto; width: 35em; border: 5px solid #1E727F; + padding: 0.8em; background: white; } +.entries { list-style: none; margin: 0; padding: 0; } +.entries li { margin: 0.8em 1.2em; } +.entries li h2 { margin-left: -1em; } +.add_entry { float: right; clear: right; width: 50%; font-size: 0.9em; + border: 1px solid #1E727F; padding: 1em; background: #fafafa;} +.add_entry dl { font-weight: bold; } +.add_entry label {display: block; } +.add_entry .field {margin-bottom: 0.25em;} +.metanav { text-align: left; font-size: 0.8em; padding: 0.3em; + margin-bottom: 1em; background: #fafafa; border: 1px solid #1E727F} +.flash { width: 30%; background: #00B0CC; padding: 1em; + border: 1px solid #1E727F; margin-bottom: 1em;} +.error { background: #F0D6D6; padding: 0.5em; } From 0278afbfbea6666b480b5df0d7f0704e12b6f0df Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 26 Jan 2014 15:42:39 -0800 Subject: [PATCH 261/487] add slide to take time to fix git with folks --- source/presentations/session04.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/presentations/session04.rst b/source/presentations/session04.rst index ae4f1434..f8214583 100644 --- a/source/presentations/session04.rst +++ b/source/presentations/session04.rst @@ -22,6 +22,13 @@ But First A look at some of the cool mashups you built over the week. + +But First +--------- + +Clean up the git situation. + + But First --------- From 75a8462a9ba7fbd9e85921fbe02ce3ba3c110439 Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 26 Jan 2014 16:12:11 -0800 Subject: [PATCH 262/487] starting to build the session 6 slides --- source/presentations/session06.rst | 1624 +--------------------------- 1 file changed, 33 insertions(+), 1591 deletions(-) diff --git a/source/presentations/session06.rst b/source/presentations/session06.rst index 8d0b3dd3..18e617e5 100644 --- a/source/presentations/session06.rst +++ b/source/presentations/session06.rst @@ -5,7 +5,7 @@ Python Web Programming :align: left :width: 50% -Session 6: A Flask Application +Session 6: Extending Flask .. class:: intro-blurb right @@ -17,1641 +17,83 @@ Session 6: A Flask Application image: Flask Logo (http://flask.pocoo.org/community/logos/) -A Quick Reminder ----------------- - -In our last session we set up a virtualenv in which we have installed the -microframework Flask - -.. class:: incremental - -We spent a few minutes exploring how Flask works, and how it is similar to the -wsgi app we wrote ourselves. - -.. class:: incremental - -We then took a detour to introduce ``Jinja2``, the templating language Flask -uses out of the box. - -.. class:: incremental - -Finally, we learned about the Python DB API 2 by seeing how we can set up a -sqlite3 database and work with it safely. - - -Moving On +Last Week --------- -Now it is time to put all that together. - -.. class:: incremental - -We'll spend this session building a "microblog" application. +Last week, we created a nice, simple flask microblog application. .. class:: incremental -Let's dive right in. - -.. class:: incremental - -Start by activating your Flask virtualenv - - -Our Database ------------- - -We need first to define what an *entry* for our microblog might look like. - -.. class:: incremental - -Let's keep it a simple as possible for now. - -.. class:: incremental - -Create a new directory ``microblog``, and open a new file in it: -``schema.sql`` - -.. code-block:: sql - :class: incremental small - - drop table if exists entries; - create table entries ( - id integer primary key autoincrement, - title string not null, - text string not null - ); - - -App Configuration ------------------ - -For any but the most trivial applications, you'll need some configuration. +Over the week, as your homework, you added in authentication and flash +messaging. .. class:: incremental -Flask provides a number of ways of loading configuration. We'll be using a -config file +There's still quite a bit more we can do to improve this application. .. class:: incremental -Create a new file ``microblog.cfg`` in the same directory. - -.. code-block:: python - :class: small incremental - - # application configuration for a Flask microblog - DATABASE = 'microblog.db' +And today, that's what we are going to do. -Our App Skeleton +Pair Programming ---------------- -Finally, we'll need a basic app skeleton to work from. - -.. class:: incremental - -Create one more file ``microblog.py`` in the same directory, and enter the -following: - -.. code-block:: python - :class: small incremental - - from flask import Flask - - app = Flask(__name__) - - app.config.from_pyfile('microblog.cfg') - - if __name__ == '__main__': - app.run(debug=True) - - -Test Your Work --------------- - -This is enough to get us off the ground. - -.. container:: incremental - - From a terminal in the ``microblog`` directory, run the app: - - .. class:: small - - :: - - (flaskenv)$ python microblog.py - * Running on http://127.0.0.1:5000/ - * Restarting with reloader - -.. class:: incremental - -Then point your browser at http://localhost:5000/ - -.. class:: incremental - -What do you see in your browser? In the terminal? Why? - - -Creating the Database ---------------------- - -Quit the app with ``^C``. Then return to ``microblog.py`` and add the -following: - -.. code-block:: python - :class: incremental small - - # add this up at the top - import sqlite3 - - # add the rest of this below the app.config statement - def connect_db(): - return sqlite3.connect(app.config['DATABASE']) - -.. class:: incremental - -This should look familiar. What will happen? +`Pair programming `_ is a +technique used in agile development. .. class:: incremental -This convenience method allows us to write our very first test. - - -Tests and TDD -------------- - -.. class:: center - -**If it isn't tested, it's broken** - -.. class:: incremental - -Test-Driven Development means writing the tests before writing the code. -As your tests pass, you know you're building what you want. - -.. class:: incremental - -We are going to write tests at every step of this exercise using the -``unittest`` module. +The basic idea is that two heads are better than one. .. class:: incremental -You'll want to read more about this module. See the reading list for -suggestions. - - -Testing Environment -------------------- - -The Python ``unittest`` module defines a class called a ``TestCase``. It -serves as a container for a set of tests and the code needed to run them. +A pair of developers work together at one computer. One *drives* and the other +*navigates* .. class:: incremental -This class provides ``setUp`` and ``tearDown`` methods to control the -environment for each test. - -.. class:: incremental +The driver can focus on the tactics of completing a function, while the +navigator can catch typos, think strategically, and find answers to questions +that arise. -These methods are run before and after *each test*, and may be used to provide -*isolation* between tests. -.. class:: incremental +Pair Up +------- -In your ``microblog`` folder create a ``microblog_tests.py`` file. +We are going to employ this technique for todays class. .. class:: incremental -Open it in your editor. - - -Testing Setup -------------- - -Add the following to provide minimal test setup. - -.. code-block:: python - :class: small - - import os - import tempfile - import unittest - - import microblog - - class MicroblogTestCase(unittest.TestCase): - - def setUp(self): - db_fd = tempfile.mkstemp() - self.db_fd, microblog.app.config['DATABASE'] = db_fd - microblog.app.config['TESTING'] = True - self.client = microblog.app.test_client() - self.app = microblog.app - - -Testing Teardown ----------------- - -Add this method to your test case class to tear down after each test: - -.. code-block:: python - - class MicroblogTestCase(unittest.TestCase): - # ... - - def tearDown(self): - os.close(self.db_fd) - os.unlink(microblog.app.config['DATABASE']) - - -Make Tests Runnable -------------------- - -To make the test module runnable, we need a ``__main__`` block. +So take the next few minutes to find a partner and pair up. You must end up +sitting next to your partner, so get up and move. .. class:: incremental -Calling the ``unittest.main()`` function here will find test cases and run -their tests. - -.. container:: incremental - - Add the following at the end of ``microblog_tests.py``: - - .. code-block:: python - :class: small - - if __name__ == '__main__': - unittest.main() +One of you will start as the driver, the other as the observer. .. class:: incremental -Now, we're ready to add our first actual test.. - -Test Database Setup -------------------- - -We'd like to test that our database is correctly initialized. The schema has -one table with three columns. Let's test that. - -.. container:: incremental - - Add the following method to your test class in ``microblog_tests.py``: - - .. code-block:: python - :class: small - - def test_database_setup(self): - con = microblog.connect_db() - cur = con.execute('PRAGMA table_info(entries);') - rows = cur.fetchall() - self.assertEquals(len(rows), 3) - - -Run the Tests -------------- +About every 20 minutes, we will switch, so that each of you can take a turn +driving. -We can now run our test module: -.. class:: small - -:: - - (flaskenv)$ python microblog_tests.py - F - ====================================================================== - FAIL: test_database_setup (__main__.MicroblogTestCase) - ---------------------------------------------------------------------- - Traceback (most recent call last): - File "microblog_tests.py", line 23, in test_database_setup - self.assertEquals(len(rows) == 3) - AssertionError: 0 != 3 - - ---------------------------------------------------------------------- - Ran 1 test in 0.011s - - FAILED (failures=1) - - -Make the Test Pass ------------------- - -This is an expected failure. Why? - -.. container:: incremental - - Let's add some code to ``microblog.py`` that will actually create our - database schema: - - .. code-block:: python - :class: small - - # add this import at the top - from contextlib import closing - - # add this function after the connect_db function - def init_db(): - with closing(connect_db()) as db: - with app.open_resource('schema.sql') as f: - db.cursor().executescript(f.read()) - db.commit() - - -Initialize the DB in Tests --------------------------- +Preparation +----------- -We also need to call that function in our ``microblog_tests.py`` to set up the -database schema for each test. +In order for this to work properly, we'll need to have a few things in place. .. container:: incremental - Add the following line at the end of that ``setUp`` method: + First, you'll all need to make sure that you have the very latest code from the + class repository available on your local machine:: - .. code-block:: python - :class: small - - def setUp(self): - # ... - microblog.init_db() # <- add this at the end - -.. class:: incremental - -:: - - (flaskenv)$ python microblog_tests.py - - -Success? --------- - -.. class:: big-centered incremental - - \\o/ Wahoooo! - - -Initialize the DB IRL ---------------------- - -Our test passed, so we have confidence that ``init_db`` does what it should - -.. class:: incremental - -We'll need to have a working database for our app, so let's go ahead and do -this "in real life" - -.. class:: incremental - - (flaskenv)$ python - -.. code-block:: python - :class: incremental - - >>> import microblog - >>> microblog.init_db() - >>> ^D - - -Reading and Writing Data ------------------------- - -After you quit the interpreter, you should see ``microblog.db`` in your -directory. - -.. class:: incremental - -It's time now to think about writing and reading data for our blog. - -.. class:: incremental - -We'll start by writing tests. - -.. class:: incremental - -But first, a word or two about the circle of life. - - -The Request/Response Cycle --------------------------- - -Every interaction in HTTP is bounded by the interchange of one request and one -response. - -.. class:: incremental - -No HTTP application can do anything until some client makes a request. - -.. class:: incremental - -And no action by an application is complete until a response has been sent -back to the client. - -.. class:: incremental - -This is the lifecycle of an http web application. - - -Managing DB Connections ------------------------ - -It makes sense to bind the lifecycle of a database connection to this same -border. - -.. class:: incremental - -Flask does not dictate that we write an application that uses a database. - -.. class:: incremental - -Because of this, managing the lifecycle of database connection so that they -are connected to the request/response cycle is up to us. - -.. class:: incremental - -Happily, Flask *does* have a way to help us. - - -Request Boundary Decorators ---------------------------- - -The Flask *app* provides decorators we can use on our database lifecycle -functions: - -.. class:: incremental - -* ``@app.before_request``: any method decorated by this will be called before - the cycle begins - -* ``@app.after_request``: any method decorated by this will be called after - the cycle is complete. If an unhandled exception occurs, these functions are - skipped. - -* ``@app.teardown_request``: any method decorated by this will be called at - the end of the cycle, *even if* an unhandled exception occurs. - - -Managing our DB ---------------- - -Think about the following functions: - -.. code-block:: python - :class: small - - def get_database_connection(): - db = connect_db() - return db - - @app.teardown_request - def teardown_request(exception): - db.close() - -.. class:: incremental - -How does the ``db`` object get from one place to the other? - - -Global Context in Flask ------------------------ - -Our flask ``app`` is only really instantiated once - -.. class:: incremental - -This means that anything we tie to it will be shared across all requests. - -.. class:: incremental - -This is what we call ``global`` context. - -.. class:: incremental - -What happens if two clients make a request at the same time? - - -Local Context in Flask ----------------------- - -Flask provides something it calls a ``local global``: "g". - -.. class:: incremental - -This is an object that *looks* global (you can import it anywhere) - -.. class:: incremental - -But in reality, it is *local* to a single request. - -.. class:: incremental - -Resources tied to this object are *not* shared among requests. Perfect for -things like a database connection. - - -Working DB Functions --------------------- - -Add the following, working methods to ``microblog.py``: - -.. code-block:: python - :class: small - - # add this import at the top: - from flask import g - - # add these function after init_db - def get_database_connection(): - db = getattr(g, 'db', None) - if db is None: - g.db = db = connect_db() - return db - - @app.teardown_request - def teardown_request(exception): - db = getattr(g, 'db', None) - if db is not None: - db.close() - - -Writing Blog Entries --------------------- - -Our microblog will have *entries*. We've set up a simple database schema to -represent them. - -.. class:: incremental - -To write an entry, what would we need to do? - -.. class:: incremental - -* Provide a title -* Provide some body text -* Write them to a row in the database - -.. class:: incremental - -Let's write a test of a function that would do that. - - -Test Writing Entries --------------------- - -The database connection is bound by a request. We'll need to mock one (in -``microblog_tests.py``) + $ git add remote uwpce git@github.com:UWPCE-PythonCert/training.python_web.git .. container:: incremental - Flask provides ``app.test_request_context`` to do just that - - .. code-block:: python - :class: small - - def test_write_entry(self): - expected = ("My Title", "My Text") - with self.app.test_request_context('/'): - microblog.write_entry(*expected) - con = microblog.connect_db() - cur = con.execute("select * from entries;") - rows = cur.fetchall() - self.assertEquals(len(rows), 1) - for val in expected: - self.assertTrue(val in rows[0]) - - -Run Your Test -------------- - -.. class:: small - -:: - - (flaskenv)$ python microblog_tests.py - .E - ====================================================================== - ERROR: test_write_entry (__main__.MicroblogTestCase) - ---------------------------------------------------------------------- - Traceback (most recent call last): - File "microblog_tests.py", line 30, in test_write_entry - microblog.write_entry(*expected) - AttributeError: 'module' object has no attribute 'write_entry' - - ---------------------------------------------------------------------- - Ran 2 tests in 0.018s - - FAILED (errors=1) - -.. class:: incremental - -Great. Two tests, one passing. - - -Make It Pass ------------- - -Now we are ready to write an entry to our database. Add this function to -``microblog.py``: - -.. code-block:: python - :class: small incremental - - def write_entry(title, text): - con = get_database_connection() - con.execute('insert into entries (title, text) values (?, ?)', - [title, text]) - con.commit() - -.. class:: incremental small - -:: - - (flaskenv)$ python microblog_tests.py - .. - ---------------------------------------------------------------------- - Ran 2 tests in 0.146s - - OK - - -Reading Entries ---------------- - -We'd also like to be able to read the entries in our blog - -.. container:: incremental - - We need a method that returns all of them for a listing page - - .. class:: incremental - - * The return value should be a list of entries - * If there are none, it should return an empty list - * Each entry in the list should be a dictionary of 'title' and 'text' - -.. class:: incremental - -Let's begin by writing tests. - - -Test Reading Entries --------------------- - -In ``microblog_tests.py``: - -.. code-block:: python - :class: small - - def test_get_all_entries_empty(self): - with self.app.test_request_context('/'): - entries = microblog.get_all_entries() - self.assertEquals(len(entries), 0) - - def test_get_all_entries(self): - expected = ("My Title", "My Text") - with self.app.test_request_context('/'): - microblog.write_entry(*expected) - entries = microblog.get_all_entries() - self.assertEquals(len(entries), 1) - for entry in entries: - self.assertEquals(expected[0], entry['title']) - self.assertEquals(expected[1], entry['text']) - - -Run Your Tests --------------- - -.. class:: small - -:: - - (flaskenv)$ python microblog_tests.py - .EE. - ====================================================================== - ERROR: test_get_all_entries (__main__.MicroblogTestCase) - ---------------------------------------------------------------------- - Traceback (most recent call last): - File "microblog_tests.py", line 47, in test_get_all_entries - entries = microblog.get_all_entries() - AttributeError: 'module' object has no attribute 'get_all_entries' - - ====================================================================== - ERROR: test_get_all_entries_empty (__main__.MicroblogTestCase) - ---------------------------------------------------------------------- - Traceback (most recent call last): - File "microblog_tests.py", line 40, in test_get_all_entries_empty - entries = microblog.get_all_entries() - AttributeError: 'module' object has no attribute 'get_all_entries' - - ---------------------------------------------------------------------- - Ran 4 tests in 0.021s - - FAILED (errors=2) - -Make Them Pass --------------- - -Now we have 4 tests, and two fail. - -.. class:: incremental - -add the ``get_all_entries`` function to ``microblog.py``: - -.. code-block:: python - :class: small incremental - - def get_all_entries(): - con = get_database_connection() - cur = con.execute('SELECT title, text FROM entries ORDER BY id DESC') - return [dict(title=row[0], text=row[1]) for row in cur.fetchall()] - -.. container:: incremental - - And back in your terminal: - - .. class:: small - - :: - - (flaskenv)$ python microblog_tests.py - .... - ---------------------------------------------------------------------- - Ran 4 tests in 0.021s - - OK - - -Where We Stand --------------- - -We've moved quite a ways in implementing our microblog: - -.. class:: incremental - -* We've created code to initialize our database schema -* We've added functions to manage the lifecycle of our database connection -* We've put in place functions to write and read blog entries -* And, since it's tested, we are reasonably sure our code does what we think - it does. - -.. class:: incremental - -We're ready now to put a face on it, so we can see what we're doing! - - -Break Time ----------- - -But first, let's take a quick break to clear our heads. - - -Templates In Flask ------------------- - -We'll start with a detour into templates as they work in Flask - -.. container:: incremental - - Jinja2 templates use the concept of an *Environment* to: - - .. class:: incremental - - * Figure out where to look for templates - * Set configuration for the templating system - * Add some commonly used functionality to the template *context* - -.. class:: incremental - -Flask sets up a proper Jinja2 Environment when you instantiate your ``app``. - - -Flask Environment ------------------ - -Flask uses the value you pass to the ``app`` constructor to calculate the root -of your application on the filesystem. - -.. class:: incremental - -From that root, it expects to find templates in a directory name ``templates`` - -.. container:: incremental - - This allows you to use the ``render_template`` command from ``flask`` like - so: - - .. code-block:: python - :class: small - - from flask import render_template - page_html = render_template('hello_world.html', name="Cris") - - -Flask Context -------------- - -Keyword arguments you pass to ``render_template`` become the *context* passed -to the template for rendering. - -.. class:: incremental - -Flask will add a few things to this context. - -.. class:: incremental - -* **config**: contains the current configuration object -* **request**: contains the current request object -* **session**: any session data that might be available -* **g**: the request-local object to which global variables are bound -* **url_for**: so you can easily *reverse* urls from within your templates -* **get_flashed_messages**: a function that returns messages you flash to your - users (more on this later). - - -Setting Up Our Templates ------------------------- - -In your ``microblog`` directory, add a new ``templates`` directory - -.. container:: incremental - - In this directory create a new file ``layout.html`` - - .. code-block:: jinja - :class: small - - - - - Microblog! - - -

    My Microblog

    -
    - {% block body %}{% endblock %} -
    - - - -Template Inheritance --------------------- - -You can combine templates in a number of different ways. - -.. class:: incremental - -* you can make replaceable blocks in templates with blocks - - * ``{% block foo %}{% endblock %}`` - -* you can build on a template in a second template by extending - - * ``{% extends "layout.html" %}`` - * this *must* be the first text in the template - -* you can re-use common structure with *include*: - - * ``{% include "footer.html" %}`` - - -Template Inheritance --------------------- - -You can even build libraries of template *macros* and import them: - -.. code-block:: jinja - :class: small incremental - - {% macro input(label, name='input', value='', type='text') -%} - - {%- endmacro %} - -.. code-block:: jinja - :class: small incremental - - {% import "forms.html" as forms %} -
    - {{ forms.input("Username", name="username") }} - {{ forms.input("Password", name="password" type="password") }} - {{ forms.input("", type="submit" name="submit" value="Log in") }} -
    - - -Displaying an Entries List --------------------------- - -Create a new file, ``show_entries.html`` in ``templates``: - -.. code-block:: jinja - :class: small - - {% extends "layout.html" %} - {% block body %} -

    Posts

    -
      - {% for entry in entries %} -
    • -

      {{ entry.title }}

      -
      - {{ entry.text|safe }} -
      -
    • - {% else %} -
    • No entries here so far
    • - {% endfor %} -
    - {% endblock %} - - -Viewing Entries ---------------- - -We just need a Python function that will: - -.. class:: incremental - -* build a list of entries -* pass the list to our template to be rendered -* return the result to a client's browser - -.. class:: incremental - -As usual, we'll start by writing tests for this new function - - -Test Viewing Entries --------------------- - -Add the following two tests to ``microblog_tests.py``: - -.. code-block:: python - :class: small - - def test_empty_listing(self): - response = self.client.get('/') - assert 'No entries here so far' in response.data - - def test_listing(self): - expected = ("My Title", "My Text") - with self.app.test_request_context('/'): - microblog.write_entry(*expected) - response = self.client.get('/') - for value in expected: - assert value in response.data - -.. class:: incremental - -``app.test_client()`` creates a mock http client for us. - - -Run Your Tests --------------- - -.. class:: small - -:: - - (flaskenv)$ python microblog_tests.py - .F..F. - ====================================================================== - FAIL: test_empty_listing (__main__.MicroblogTestCase) - ---------------------------------------------------------------------- - Traceback (most recent call last): - File "microblog_tests.py", line 55, in test_empty_listing - assert 'No entries here so far' in response.data - AssertionError - ====================================================================== - FAIL: test_listing (__main__.MicroblogTestCase) - ---------------------------------------------------------------------- - Traceback (most recent call last): - File "microblog_tests.py", line 63, in test_listing - assert value in response.data - AssertionError - ---------------------------------------------------------------------- - Ran 6 tests in 0.138s - - FAILED (failures=2) - - -Make Them Pass --------------- - -In ``microblog.py``: - -.. code-block:: python - :class: small - - # at the top, import - from flask import render_template - - # and after our last functions: - @app.route('/') - def show_entries(): - entries = get_all_entries() - return render_template('show_entries.html', entries=entries) - -.. class:: incremental small - -:: - - (flaskenv)$ python microblog_tests.py - ...... - ---------------------------------------------------------------------- - Ran 6 tests in 0.100s - - OK - - -Authentication --------------- - -We don't want just anyone to be able to add new entries. So we want to be able -to authenticate a user. - -.. class:: incremental - -Flask provides *session* concept as a way to store and access data for a given -client. - -.. class:: incremental - -The session in Flask uses encrypted HTTP *Cookies* - -.. class:: incremental - -We will require a few changes to our app configuration to use this session. - - -Additional Config ------------------ - -In ``microblog.cfg`` add the following lines: - -.. code-block:: python - :class: small - - SECRET_KEY = "sooperseekritvaluenooneshouldknow" - USERNAME = "admin" - PASSWORD = "secret" - -.. class:: incremental - -``SECRET_KEY`` is a value that will be used to encrypt the session cookie. If -it isn't set, sessions won't be created. - -.. class:: incremental - -``USERNAME`` and ``PASSWORD`` are our admin credentials. - -.. class:: small center incremental - -obviously this is not a robust login system, do not do this in real life - - -Test Authentication -------------------- - -Back in ``microblog_tests.py`` add new test methods: - -.. code-block:: python - :class: small - - # up with the imports - from flask import session - - # at the end of our list of test methods - def test_login_passes(self): - with self.app.test_request_context('/'): - microblog.do_login(microblog.app.config['USERNAME'], - microblog.app.config['PASSWORD']) - self.assertTrue(session.get('logged_in', False)) - - def test_login_fails(self): - with self.app.test_request_context('/'): - self.assertRaises(ValueError, - microblog.do_login, - microblog.app.config['USERNAME'], - 'incorrectpassword') - - -Run Your Tests --------------- - -.. class:: small - -:: - - (flaskenv)$ python microblog_tests.py - .....EE. - ====================================================================== - ERROR: test_login_fails (__main__.MicroblogTestCase) - ---------------------------------------------------------------------- - Traceback (most recent call last): - File "microblog_tests.py", line 76, in test_login_fails - microblog.do_login, - AttributeError: 'module' object has no attribute 'do_login' - ====================================================================== - ERROR: test_login_passes (__main__.MicroblogTestCase) - ---------------------------------------------------------------------- - Traceback (most recent call last): - File "microblog_tests.py", line 69, in test_login_passes - microblog.do_login(microblog.app.config['USERNAME'], - AttributeError: 'module' object has no attribute 'do_login' - ---------------------------------------------------------------------- - Ran 8 tests in 0.082s - - FAILED (errors=2) - - -Make Them Pass --------------- - -In ``microblog.py``: - -.. code-block:: python - :class: small - - # add an import - from flask import session - - # and a function - def do_login(usr, pwd): - if usr != app.config['USERNAME']: - raise ValueError - elif pwd != app.config['PASSWORD']: - raise ValueError - else: - session['logged_in'] = True - -.. class:: incremental - -Re-run your tests, you should now be 8 for 8 - - -Creating Login/Logout ---------------------- - -We need to have the ability to log in and out of our application. - -.. container:: incremental - - This means we need views that will - - .. class:: incremental - - * Allow a user to provide credentials and attempt to login - * Redirect to the listing page if they succeed - * Give appropriate feedback if they fail - * Allow a user to log out if they are logged in - * Redirect to the listing page after logging out - -.. class:: incremental - -Let's begin as usual by writing some tests - - -Helper Methods in Tests ------------------------ - -We will need to log in or out a few times in our test. - -.. container:: incremental - - Add helper methods to our ``microblog_tests.py`` TestCase: - - .. code-block:: python - :class: small - - def login(self, username, password): - return self.client.post('/login', data=dict( - username=username, - password=password - ), follow_redirects=True) - - def logout(self): - return self.client.get('/logout', - follow_redirects=True) - -.. class:: incremental small - -**Note:** Methods that do not begin with ``test`` will not be run as tests. - - -Testing Login/Logout --------------------- - -And now the test itself: - -.. code-block:: python - :class: small - - def test_login_logout(self): - # verify we can log in - response = self.login('admin', 'secret') - assert 'You were logged in' in response.data - # verify we can log back out - response = self.logout() - assert 'You were logged out' in response.data - # verify that incorrect credentials get a proper message - response = self.login('notadmin', 'secret') - assert 'Invalid Login' in response.data - response = self.login('admin', 'notsosecret') - assert 'Invalid Login' in response.data - - -Run Your Tests --------------- - -You should now have nine tests, with one failure: - -.. class:: small - -:: - - (flaskenv)$ python microblog_tests.py - ......F.. - ====================================================================== - FAIL: test_login_logout (__main__.MicroblogTestCase) - ---------------------------------------------------------------------- - Traceback (most recent call last): - File "microblog_tests.py", line 93, in test_login_logout - assert 'You were logged in' in response.data - AssertionError - - ---------------------------------------------------------------------- - Ran 9 tests in 0.047s - - FAILED (failures=1) - - -Login Form Template -------------------- - -Add ``login.html`` to the ``templates`` directory: - -.. code-block:: jinja - :class: tiny - - {% extends "layout.html" %} - {% block body %} -

    Login

    - {% if error -%} -

    Error {{ error }} - {%- endif %} -

    -
    - - -
    -
    - - -
    -
    - -
    -
    - {% endblock %} - - -Required Imports ----------------- - -Back in ``microblog.py``, we need to import some symbols from flask: - -.. code-block:: python - - # at the top, new imports - from flask import request - from flask import redirect - from flask import flash - from flask import url_for - -.. class:: incremental - -And finally, we'll add the view functions we need to fix our tests - - -Make the Test Pass ------------------- - -.. code-block:: python - :class: small - - @app.route('/login', methods=['GET', 'POST']) - def login(): - error = None - if request.method == 'POST': - try: - do_login(request.form['username'], - request.form['password']) - except ValueError: - error = "Invalid Login" - else: - flash('You were logged in') - return redirect(url_for('show_entries')) - return render_template('login.html', error=error) - - @app.route('/logout') - def logout(): - session.pop('logged_in', None) - flash('You were logged out') - return redirect(url_for('show_entries')) - - -About Flash ------------ - -.. class:: small - -``flash`` allows sending messages to clients. We need a place to show these -messages. Add it to ``layout.html`` (along with links to log in and out) - -.. code-block:: jinja - :class: small - -

    My Microblog

    -
    - {% if not session.logged_in %} - log in - {% else %} - log_out - {% endif %} -
    - {% for message in get_flashed_messages() %} -
    {{ message }}
    - {% endfor %} -
    - - -Nine For Nine -------------- - -At this point, we are displaying the messages we sent from the view code, so -our tests should pass: - -.. class:: small - -:: - - (flaskenv)$ python microblog_tests.py - ......... - ---------------------------------------------------------------------- - Ran 9 tests in 0.064s - - OK - - -Creating Entries ----------------- - -We still lack a way to add an entry. We need a view that will: - -.. class:: incremental - -* Verify that the user is authenticated -* Accept incoming form data from a request -* Get the data for ``title`` and ``text`` -* Create a new entry in the database -* Provide feedback to the user on success or failure - -.. class:: incremental - -Again, first come the tests. - - -Testing Add an Entry --------------------- - -Add this to ``microblog_tests.py``: - -.. code-block:: python - :class: small - - def test_add_entries(self): - self.login('admin', 'secret') - response = self.client.post('/add', data=dict( - title='Hello', - text='This is a post' - ), follow_redirects=True) - assert 'No entries here so far' not in response.data - assert 'Hello' in response.data - assert 'This is a post' in response.data - - -Run Your Tests --------------- - -Verify that our test fails as expected: - -.. class:: small - -:: - - (flaskenv)$ python microblog_tests.py - F......... - ====================================================================== - FAIL: test_add_entries (__main__.MicroblogTestCase) - ---------------------------------------------------------------------- - Traceback (most recent call last): - File "microblog_tests.py", line 110, in test_add_entries - assert 'Hello' in response.data - AssertionError - - ---------------------------------------------------------------------- - Ran 10 tests in 0.071s - - FAILED (failures=1) - - -Make Them Pass --------------- - -We have all we need to write entries, all we lack is an endpoint (in -``microblog.py``): - -.. code-block:: python - :class: small - - # add an import - from flask import abort - - @app.route('/add', methods=['POST']) - def add_entry(): - if not session.get('logged_in'): - abort(401) - try: - write_entry(request.form['title'], request.form['text']) - flash('New entry was successfully posted') - except sqlite3.Error as e: - flash('There was an error: %s' % e.args[0]) - return redirect(url_for('show_entries')) - - -And...? -------- - -.. class:: small - -:: - - (flaskenv)$ python microblog_tests.py - .......... - ---------------------------------------------------------------------- - Ran 10 tests in 0.075s - - OK - -.. class:: incremental center - -**Hooray!** - - -Where do Entries Come From --------------------------- - -Finally, we're almost done. We can log in and log out. We can add entries and -view them. But look at that last view. Do you see a call to -``render_template`` in there at all? - -.. class:: incremental - -There isn't one. That's because that view is never meant to be be visible. -Look carefully at the logic. What happens? - -.. class:: incremental - -So where do the form values come from? - -.. class:: incremental - -Let's add a form to the main view. Open ``show_entries.html`` - - -Provide a Form --------------- - -.. code-block:: jinja - :class: small - - {% block body %} - {% if session.logged_in %} -
    -
    - - -
    -
    - - -
    -
    - -
    -
    - {% endif %} -

    Posts

    - - -All Done --------- - -Okay. That's it. We've got an app all written. - -.. class:: incremental - -So far, we haven't actually touched our browsers at all, but we have -reasonable certainty that this works because of our tests. Let's try it. - - -.. class:: incremental - -In the terminal where you've been running tests, run our microblog app: - -.. class:: incremental - -:: - - (flaskenv)$ python microblog.py - * Running on http://127.0.0.1:5000/ - * Restarting with reloader - - -The Big Payoff --------------- - -Now load ``http://localhost:5000/`` in your browser and enjoy your reward. - - -Making It Pretty ----------------- - -What we've got here is pretty ugly. - -.. class:: incremental - -If you've fallen behind, or want to start fresh, you can find the finished -``microblog`` directory in the class resources. - -.. class:: incremental - -In that directory inside the ``static`` directory you will find -``styles.css``. Open it in your editor. It contains basic CSS for this app. - -.. class:: incremental - -We'll need to include this file in our ``layout.html``. - - -Static Files ------------- - -Like page templates, Flask locates static resources like images, css and -javascript by looking for a ``static`` directory relative to the app root. - -.. class:: incremental - -You can use the special url endpoint ``static`` to build urls that point here. -Open ``layout.html`` and add the following: - -.. code-block:: jinja - :class: small incremental - - - Flaskr - - - - -Going Further -------------- - -It's not too hard to see ways you could improve this. - -.. class:: incremental - -* For my part, I made a version with styles from Bootstrap.js. -* You could limit the number of posts shown on the front page and add - pagination. -* You could add *created date* to the entry schema and provide archived views - for older posts. -* You could add the ability to edit existing posts (and add a modified date to - the schema) -* You could support multi-user blogging by providing a more complex - authentication system and some more views. - - -Wrap-Up -------- - -For educational purposes you might try taking a look at the source code for -Flask and Werkzeug. Neither is too large a package. - -.. class:: incremental - -In particular seeing how Werkzeug sets up a Request and Response--and how -these relate to the WSGI specification--can be very enlightening. + First, you both will need to make a branch of the class repository that you + can work on:: -.. class:: incremental center + $ git checkout -b session06-class -**See You Tomorrow!** From 7dfca294bdfed8fc6d86528da41e1be25d920fe0 Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 26 Jan 2014 16:37:57 -0800 Subject: [PATCH 263/487] adding the instructions for getting back to a clean master branch for students. --- source/additional/git_cleanup.rst | 211 ++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 source/additional/git_cleanup.rst diff --git a/source/additional/git_cleanup.rst b/source/additional/git_cleanup.rst new file mode 100644 index 00000000..a077173c --- /dev/null +++ b/source/additional/git_cleanup.rst @@ -0,0 +1,211 @@ +Steps to get a clean master branch for your git fork +==================================================== + +Command line instructions for getting back to a pristine master branch + + +1. Make sure that you have the UWPCE repostitory set up as an additional + remote for your local repository:: + + $ git remote add uwpce git@github.com:UWPCE-PythonCert/training.python_web.git + +This will give you direct access to the original copy of the repository from +the command line. + +2. Verify this worked by checking your remotes:: + + $ git remote + origin + uwpce + +Now you have *two* remote repositories connected to your local repository. + +* *Origin* represents the copy of your fork of the UW PCE repository *on + github's servers*. +* *Uwpce* is the original UW PCE repository *on github's servers*. + +State the Problem +----------------- + +You have a series of changes *you* have made to the *master* branch of your +repository, both the local and the *origin* remote. + +Every time you make new changes for a homework and then submit a pull request, +all these old changes are included in the pull request. + +State the Goal +-------------- + +You would like to get a *master* branch of your repository that exactly matches +the *master* branch of the UW PCE remote (*uwpce*). + +Once you have this, you can then keep that branch up to date with the UW PCE +copy + +And you can continue to make clean branches for each homework *starting from +that clean master*. + +Steps to get there +------------------ + +Preserve your Old Work +++++++++++++++++++++++ + +First, make a branch on your local machine of your current *master*, this will +be a branch you keep that contains all your homework up until today:: + + $ git branch -a + * master + remotes/origin/HEAD -> origin/master + remotes/origin/gh-pages + remotes/origin/instructor + remotes/origin/master + remotes/origin/week-long-format + remotes/uwpce/master + $ git branch keep-old-work + $ git branch -a + keep-old-work + * master + remotes/origin/HEAD -> origin/master + remotes/origin/gh-pages + remotes/origin/instructor + remotes/origin/master + remotes/origin/week-long-format + remotes/uwpce/master + +Now, you have a copy of all the work you've done to date. It's on the +*keep-old-work* branch. You have not yet pushed this branch up to your github +account, so let's do that next, making it safe:: + + $ git push -u origin keep-old-work + Total 0 (delta 0), reused 0 (delta 0) + To git@github.com:cewing/training.python_web.git + * [new branch] keep-old-work -> keep-old-work + Branch keep-old-work set up to track remote branch keep-old-work from origin. + +Okay, now there's a copy of your old work safe in a branch on *your* github +repository. + +Revert Your Master +++++++++++++++++++ + +The next step is to *roll back your master* to a point *before you made any +changes to it*. + +The key here is understanding that every change you commit to a repository in +git is associated with a *hash*, which is a big, unique identification number +you can use to refer to that specific change. You can see these numbers when +you look at the list of commits in github. + +You need to find the number of a commit by me that happened before you began +making changes. + +First, open the 'commits' page on github of your fork of the class repository. + +Then, scroll down until you find your first commit, which should be part of +work for session01 homework. + +Then, find the last commit *before* that commit, and click on the number in the +far right of that commit listing (it should be something like `b60ea2bb70`) + +This will open up that specific commit, and in the URL for that commit you will +find the full hash: `b60ea2bb7052a5bd300772d7d9d40b19b27f7a1b`. Copy that value. + +Now, we are going to reset your local *master* branch to that commit, +abandoning all the changes you (and I) have made between then and now:: + + $ git branch + keep-old-work + * master + $ git reset --hard b60ea2bb7052a5bd300772d7d9d40b19b27f7a1b + +Now, your *local master* has been reverted to a state before you did any work. +All your changes have been deleted, but so have all the changes I've made since +the start of class. + +Luckily, we can fix that. Our next step is to fetch the *uwpce* *master* +branch, which contains all those changes I've made, but none of the changes you +made: + + $ git fetch uwpce master + remote: Counting objects: 10, done. + remote: Compressing objects: 100% (10/10), done. + remote: Total 10 (delta 3), reused 7 (delta 0) + Unpacking objects: 100% (10/10), done. + From github.com:UWPCE-PythonCert/training.python_web + * branch master -> FETCH_HEAD + 8873ba1..75a8462 master -> uwpce/master + +And finally, we can merge the changes in the *uwpce* master into our local +*master*:: + + $ git branch + keep-old-work + * master + $ git merge uwpce/master + Merge made by the 'recursive' strategy. + source/presentations/session04.rst | 7 + + source/presentations/session06.rst | 1624 +----------------------------------- + 2 files changed, 40 insertions(+), 1591 deletions(-) + + +Forcibly Update ++++++++++++++++ + +Now, what we have is a situation where your local master has a history that is +completely different from the *origin* to which it is attached. Your +*origin/master* still has your work on it, interleaved with the changes I've +made along the way, but your *local* master contains only my work. + +If you were to try to push these changes up to *origin* (your repository) it would +fail because there's no way to reconcile the two histories. + +But we don't care about the history on your *origin*, we only want to keep the +history that is represented by what is currently in your *local* master branch. +To do that, we can push with the `--force` option:: + + $ git push --force origin master + Counting objects: 25, done. + Delta compression using up to 8 threads. + Compressing objects: 100% (11/11), done. + Writing objects: 100% (11/11), 2.04 KiB | 0 bytes/s, done. + Total 11 (delta 7), reused 0 (delta 0) + To git@github.com:cewing/training.python_web.git + + 782d17e...5fb97f3 master -> master (forced update) + +Okay. This means that now *master* both on your local machine and on the +*origin* remote (your github repository) is identical to (and up to date with) +the master in the *uwpce* repository. + + +Going Forward +------------- + +From now on, when you want to get the very latest copies of the *uwpce* +repository, you can issue these commands:: + + $ git checkout master + $ git fetch uwpce master + $ git merge uwpce/master + $ git push origin master + +That will fetch the changes from the *uwpce* remote *master* branch, merge them +into your *local* repository *master* branch, and then push those changes up to +your *origin* repository *master* branch. + +And when you are ready to start work on a new homework assignment, you can +simply start a new branch:: + + $ git checkout -b session05-homework + +Once you've completed your homework, and committed all the changes to your +*local* homework branch, you can push that branch up to your *origin* +repository:: + + $ git push origin session05-homework + +And then, when you open a pull request for me to review your homework, you can +select your *homework branch* as the source of the pull request, and my +*master* branch as the destination. The request will contain only those changes +that are germane to your homework. + From 3cd635ea9947ff1db505f501d77d2f59abd48569 Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 26 Jan 2014 17:28:58 -0800 Subject: [PATCH 264/487] add tutorials to list of stuff for session 4 homework --- source/main/outline.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/main/outline.rst b/source/main/outline.rst index 8455df3e..db8315b8 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -109,6 +109,15 @@ using WSGI and see what benefits and drawbacks it confers. * `Lecture Slides `_ * `As Plain HTML `_ +Homework Tutorials +++++++++++++++++++ + +Please walk through all three of these tutorials before session 5 begins. + +* `Jinja2 Template Tutorial `_ +* `SQL Persistence Tutorial `_ +* `Flask Walkthrough `_ + Session 5 - Frameworks and Flask -------------------------------- From 8fa860853d9f78f86dab021faddf3a570534dc09 Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 26 Jan 2014 17:29:28 -0800 Subject: [PATCH 265/487] reorganize session 5&6 reading list to include and emphasize the three tutorials --- source/main/readings.rst | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/source/main/readings.rst b/source/main/readings.rst index e9f362df..a27a7eca 100644 --- a/source/main/readings.rst +++ b/source/main/readings.rst @@ -174,8 +174,16 @@ more minimal and may be easier to comprehend off the bat. Sessions 5 & 6 - Flask ---------------------- -* `Web Application Frameworks - `_ +In order to properly prepare for class, you *must* work through the three +tutorials linked below. You will be expected to know this material before +session 5 begins. The documentation readings associated with these tutorials +are there for further reference, and to help you find answers to questions that +arise while you do the tutorials themselves. + +Jinja2 +++++++ + +* `Jinja2 Template Tutorial `_ * `Jinja2 - Python page templates `_ - We'll learn something about templating in Python, starting with the Jinja2 @@ -183,14 +191,31 @@ Sessions 5 & 6 - Flask `_, which provides a reasonable, non-technical introduction to the language and how it is used. +SQLite3 ++++++++ + +* `SQL Persistence Tutorial `_ + * `sqlite3 - DB API for sqlite3 `_ - We'll need a bit of familiarity with the sqlite3 module. How to open connections, execute queries, and read the results from a cursor. Just read the first two sections ('Creating a Database' and 'Retrieving Data'). +Flask ++++++ + +* `Flask Walkthrough `_ + * `Flask Documentation `_ - Read the Foreward, Installation and Quickstart sections. + +Additional Readings ++++++++++++++++++++ + +* `Web Application Frameworks + `_ + * `Unittest - Unit Testing Framework `_ - Starting in this module we'll begin writing tests to cover our code. Start learning how. For more, From cb6161ce4cbad3b4698c4e79fa27959f23f9ee81 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 8 Feb 2014 11:20:53 -0800 Subject: [PATCH 266/487] pep8 fixes --- resources/session06/microblog/microblog_tests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/session06/microblog/microblog_tests.py b/resources/session06/microblog/microblog_tests.py index 2363655d..3e910226 100644 --- a/resources/session06/microblog/microblog_tests.py +++ b/resources/session06/microblog/microblog_tests.py @@ -6,6 +6,7 @@ import microblog + class MicroblogTestCase(unittest.TestCase): def setUp(self): @@ -82,7 +83,7 @@ def test_login_passes(self): def test_login_fails(self): with self.app.test_request_context('/'): - self.assertRaises(ValueError, + self.assertRaises(ValueError, microblog.do_login, microblog.app.config['USERNAME'], 'incorrectpassword') From 0a744473d19111f12cd1d59a563af3d6cb1e41ba Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 8 Feb 2014 11:21:29 -0800 Subject: [PATCH 267/487] complete the minimal slides for session06 --- source/presentations/session06.rst | 55 ++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/source/presentations/session06.rst b/source/presentations/session06.rst index 18e617e5..068fb965 100644 --- a/source/presentations/session06.rst +++ b/source/presentations/session06.rst @@ -74,7 +74,7 @@ One of you will start as the driver, the other as the observer. .. class:: incremental -About every 20 minutes, we will switch, so that each of you can take a turn +About every 20-30 minutes, we will switch, so that each of you can take a turn driving. @@ -85,15 +85,56 @@ In order for this to work properly, we'll need to have a few things in place. .. container:: incremental - First, you'll all need to make sure that you have the very latest code from the - class repository available on your local machine:: + First, we'll start from a canonical copy of the microblog. Make a fork of + the following repository to your github account:: - $ git add remote uwpce git@github.com:UWPCE-PythonCert/training.python_web.git + https://github.com/UWPCE-PythonCert/training.sample-flask-app .. container:: incremental - First, you both will need to make a branch of the class repository that you - can work on:: + Then, clone that repository to your local machine:: - $ git checkout -b session06-class + $ git clone https://github.com//training.sample-flask-app.git + or + $ git clone git@github.com:/training.sample-flask-app.git +Connect to Your Partner +----------------------- + +Finally, you'll want to connect to your partner's repository, so that you can +each work on your own laptop and still share the changes you make. + +.. container:: incremental + + First, add your partner's repository as ``upstream`` to yours:: + + $ git remote add upstream https://github.com//training.sample-flask-app.git + or + $ git remote add upstream git@github.com:/training.sample-flask-app.git + +.. container:: incremental + + Then, fetch their copy so that you can easily merge their changes later:: + + $ git fetch upstream + +While You Work +-------------- + +Now, when you switch roles during your work, here's the workflow you can use: + +1. The current driver commits all changes and pushes to their repository:: + + $ git commit -a -m "Time to switch roles" + $ git push origin master + +2. The new driver fetches and merges changes made upstream. + + $ git fetch upstream master + $ git branch -a + * master + remotes/origin/master + remotes/upstream/master + $ git merge upstream/master + +3. The new driver continues working from where their partner left off. From 4c0d97950704a05f284ecff81fb84fa664efab85 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 8 Feb 2014 12:42:03 -0800 Subject: [PATCH 268/487] more updates --- source/main/outline.rst | 36 ++++++++++++----------- source/presentations/session06.rst | 46 +++++++++++++++++++++++------- source/presentations/session07.rst | 16 ++++------- 3 files changed, 62 insertions(+), 36 deletions(-) diff --git a/source/main/outline.rst b/source/main/outline.rst index db8315b8..8fefabf8 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -110,7 +110,7 @@ using WSGI and see what benefits and drawbacks it confers. * `As Plain HTML `_ Homework Tutorials -++++++++++++++++++ +****************** Please walk through all three of these tutorials before session 5 begins. @@ -131,9 +131,15 @@ implementation of a *microframework*, `Flask `_. We'll install the framework and take a look at how it works. What does it have in common with work we've already done? -Along the way we'll learn about Jinja2, the templating language that Flask -uses, and a bit about the DBAPI2 and communicating with SQL databases from -within Python. +Finally, we'll spend our class implementing a simple application using Flask. +We'll decide the functionality we need, write tests to demonstrate that it +works, and then write the code to make the tests pass. When we finish, we'll +have a tested, simple app that we can view through the browser. + +Along the way, we'll learn a bit about how flask operates in a real +application. We'll learn some more about the Jinja2 templating language, and +we'll learn to tie the transactions of our database interaction to the cycles +of request and response. `Lecture Slides `_ @@ -141,20 +147,18 @@ within Python. Session 6 - A Flask Application ------------------------------- -In this class we will exercise our new-won knowledge by building a small -application using Flask. We'll write templates and forms, persist data, -implement login and logout. When we're done, we'll have a fully-functional -microblog. +During this class, we will explore the technique of `pair programming`_ in the +process of extending and improving our Flask application. Students will divide +into pairs and each pair will work together to implement one or more new +features for the Flask app we finished in the previous class. -We'll use a test-driven development style as we go. We'll decide the -functionality we need, write tests to prove it works, and then write the code -to make those tests pass. We'll be using the ``unittest`` module from the -Python Standard Library. +Along the way, we'll gain insight into how to build a more complex Flask +application, how to integrate with existing front-end design frameworks, and +even how to use alternate storage strategies. Most importantly, we'll gain a +bit of experience in the workflow of a small team as we explore how to share +our work quickly across different environments. -Along the way, we'll learn a bit more about how flask operates in a real -application. We'll learn some more about the Jinja2 templating language, and -we'll learn to tie the transactions of our database interaction to the cycles -of request and response. +.. _pair programming: http://en.wikipedia.org/wiki/Pair_programming `Lecture Slides `_ diff --git a/source/presentations/session06.rst b/source/presentations/session06.rst index 068fb965..636b608e 100644 --- a/source/presentations/session06.rst +++ b/source/presentations/session06.rst @@ -83,16 +83,22 @@ Preparation In order for this to work properly, we'll need to have a few things in place. -.. container:: incremental +.. container:: incremental small First, we'll start from a canonical copy of the microblog. Make a fork of - the following repository to your github account:: + the following repository to your github account: + + .. code-block:: + :class: small https://github.com/UWPCE-PythonCert/training.sample-flask-app -.. container:: incremental +.. container:: incremental small + + Then, clone that repository to your local machine: - Then, clone that repository to your local machine:: + .. code-block:: bash + :class: small $ git clone https://github.com//training.sample-flask-app.git or @@ -104,31 +110,49 @@ Connect to Your Partner Finally, you'll want to connect to your partner's repository, so that you can each work on your own laptop and still share the changes you make. -.. container:: incremental +.. container:: incremental small + + First, add your partner's repository as ``upstream`` to yours: - First, add your partner's repository as ``upstream`` to yours:: + .. code-block:: bash + :class: small $ git remote add upstream https://github.com//training.sample-flask-app.git or $ git remote add upstream git@github.com:/training.sample-flask-app.git -.. container:: incremental +.. container:: incremental small - Then, fetch their copy so that you can easily merge their changes later:: + Then, fetch their copy so that you can easily merge their changes later: + + .. code-block:: bash + :class: small $ git fetch upstream While You Work -------------- +.. class:: small + Now, when you switch roles during your work, here's the workflow you can use: -1. The current driver commits all changes and pushes to their repository:: +.. class:: small + +1. The current driver commits all changes and pushes to their repository: + +.. code-block:: bash + :class: small $ git commit -a -m "Time to switch roles" $ git push origin master -2. The new driver fetches and merges changes made upstream. +.. class:: small + +2. The new driver fetches and merges changes made upstream: + +.. code-block:: bash + :class: small $ git fetch upstream master $ git branch -a @@ -137,4 +161,6 @@ Now, when you switch roles during your work, here's the workflow you can use: remotes/upstream/master $ git merge upstream/master +.. class:: small + 3. The new driver continues working from where their partner left off. diff --git a/source/presentations/session07.rst b/source/presentations/session07.rst index 77d7975b..85692503 100644 --- a/source/presentations/session07.rst +++ b/source/presentations/session07.rst @@ -108,20 +108,16 @@ Popularity translates into: Active Development ------------------ -Django releases in the last 12+ months: +Django releases in the last 12+ months (a short list): .. class:: incremental -* 1.5.1 (March 2013) +* 1.6.2 (February 2014) +* 1.6.1 (December 2013) +* 1.6 (November 2013) +* 1.4.10 (Novermber 2013) +* 1.5.5 (October 2013) * 1.5 (February 2013) -* 1.4.5 (February 2013) -* 1.3.7 (February 2013) -* 1.4.3 (December 2012) -* 1.3.5 (December 2012) -* 1.4.2 (November 2012) -* 1.3.3 (August 2012) -* 1.4.1 (July 2012) -* 1.3.2 (July 2012) * 1.4 (March 2012) From 261b3535fb60d6240e51affe90721f6c5eab7850 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 8 Feb 2014 15:48:07 -0800 Subject: [PATCH 269/487] updates --- source/img/admin_index.png | Bin 18633 -> 27949 bytes source/main/outline.rst | 50 +- source/presentations/session06.rst | 13 + source/presentations/session07.rst | 1608 +--------------------------- 4 files changed, 47 insertions(+), 1624 deletions(-) diff --git a/source/img/admin_index.png b/source/img/admin_index.png index 55a8919f5fb77f12d5af16b607a08229fd637def..ae7a19f986880cac0b47c2ea4cb48a722851c260 100644 GIT binary patch literal 27949 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 literal 18633 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 TaXvnw00000NkvXXu0mjfP)V4v diff --git a/source/main/outline.rst b/source/main/outline.rst index 8fefabf8..0585da80 100644 --- a/source/main/outline.rst +++ b/source/main/outline.rst @@ -162,36 +162,36 @@ our work quickly across different environments. `Lecture Slides `_ +Homework Tutorials +****************** + +Please walk through this tutorial before session 7 begins. + +* `An Introduction to Django `_ -Session 7 - Intro to Django ---------------------------- + +Session 7 - Basic Django +------------------------ In this class we'll get introduced to arguably the most popular full-stack Python web framework, Django. We'll install the framework, learn about how to get it running and how to get started creating your very own app. We'll be learning about the Django ORM and how Django Models can help shield -developers from much of the complexity of SQL. We'll learn how to use the -tools Django provides to explore and interact with your models while designing -them. We'll also get a brief introduction to the Django admin, Django's -*killer feature*. +developers from much of the complexity of SQL. -Along the way, we'll continue our test-driven development style: writing tests -to demonstrate the functionality we desire and then implementing code to make -them pass. We'll get a chance to see how to build tests within the framework -offered by Django's testrunner. +During the week leading up to this session, we'll `get started building`_ a +blog app in Django. We'll learn how to use the tools Django provides to explore +and interact with your models while designing them. We'll also get a brief +introduction to the Django admin, Django's *killer feature*. -`Lecture Slides `_ +.. _get started building: presentations/django_intro-plain.html -Session 8 - A Django Application --------------------------------- - -In this class we'll complete our exploration of Django. We'll customize the -Django admin to help us most efficiently administer our Blog application. -We'll create and test view functions that present our application to the world -and we'll provide front-end access to forms that allow us to create, edit and -publish blog entries without needing to use the admin. +Along the way, we'll build a nicely functional blog application. We'll learn +about model relationships, customizing the Django admin, and adding front-end +views so users can see our work. We'll even learn how we can update our +database code and keep it in sync with our progressing development work. Along the way we'll learn that the Django template language is quite similar to the Jinja2 language (in fact, Jinja2 was modelled on the Django version). @@ -199,7 +199,17 @@ We'll also get a chance to learn a bit more about the features that the Django test framework provides over and above the standard Python ``unittest`` library. -Finally, we'll discuss some of the strengths and weaknesses of Django. What +`Lecture Slides `_ + + +Session 8 - Extending Django +---------------------------- + +During this session, we will continue our exploration of Django, and of pair +programming. Students will once again pair up and work together to implement +one or more feature extending the basic Django app we created previously. + +Finally, we'll discuss some of the strengths and weaknesses of Django. What makes it a good choice for some projects but not for others. `Lecture Slides `_ diff --git a/source/presentations/session06.rst b/source/presentations/session06.rst index 636b608e..3bc546f1 100644 --- a/source/presentations/session06.rst +++ b/source/presentations/session06.rst @@ -164,3 +164,16 @@ Now, when you switch roles during your work, here's the workflow you can use: .. class:: small 3. The new driver continues working from where their partner left off. + + +Homework +-------- + +For this week, please read and complete the Introduction to Django tutorial +linked from the class website and from the course outline. + +You will be expected to have successfully completed that tutorial upon arrival +in class for our next session. + +We will begin our work starting from where it leaves off. + diff --git a/source/presentations/session07.rst b/source/presentations/session07.rst index 85692503..7cfabd08 100644 --- a/source/presentations/session07.rst +++ b/source/presentations/session07.rst @@ -145,1648 +145,48 @@ that documentation for every commit **this is awesome** -Django Organization -------------------- - -A Django *project* represents a whole website: - -.. class:: incremental - -* global configuration settings -* inclusion points for additional functionality -* master list of URL endpoints - -.. class:: incremental - -A Django *app* encapsulates a unit of functionality: - -.. class:: incremental - -* A blog section -* A discussion forum -* A content tagging system - - -Apps Make Up a Project ----------------------- - -.. class:: big-centered - -One *project* can (and likely will) consist of many *apps* - - -Practice Safe Development -------------------------- - -We'll install Django and any other packages we use with it in a virtualenv. - -.. class:: incremental - -This will ensure that it is isolated from everything else we do in class (and -vice versa) - -.. container:: incremental - - Remember the basic format for creating a virtualenv: - - .. class:: small - - :: - - $ python virtualenv.py [options] - - $ virtualenv [options] - - -Set Up a VirtualEnv -------------------- - -Start by creating your virtualenv:: - - $ python virtualenv.py djangoenv - - $ virtualenv djangoenv - ... - -.. container:: incremental - - Then, activate it:: - - $ source djangoenv/bin/activate - - C:\> djangoenv\Scripts\activate - - -Install Django --------------- - -Finally, install Django 1.5.1 using `setuptools` or `pip`: - -.. class:: small - -:: - - (djangoenv)$ pip install Django==1.5.1 - Downloading/unpacking Django==1.5.1 - Downloading Django-1.5.1.tar.gz (8.0MB): 8.0MB downloaded - Running setup.py egg_info for package Django - changing mode of /path/to/djangoenv/bin/django-admin.py to 755 - Successfully installed Django - Cleaning up... - (djangoenv)$ - - -Starting a Project ------------------- - -Everything in Django stems from the *project* - -.. class:: incremental - -To get started learning, we'll create one - -.. class:: incremental - -We'll use a script installed by Django, ``django-admin.py``: - -.. code-block:: - :class: incremental - - (djangoenv)$ django-admin.py startproject mysite - -.. class:: incremental - -This will create a folder called 'mysite'. Let's take a look at it: - - -Project Layout --------------- - -The folder created by ``django-admin.py`` contains the following structure: - -.. code-block:: - - mysite/ - manage.py - mysite/ - __init__.py - settings.py - urls.py - wsgi.py - -.. class:: incremental - -If what you see doesn't match that, you're using an older version of Django. -Make sure you've installed 1.5.1. - - -What Got Created ----------------- - -.. class:: incremental - -* **outer *mysite* folder**: this is just a container and can be renamed or - moved at will -* **inner *mysite* folder**: this is your project directory. It should not be - renamed. -* **__init__.py**: magic file that makes *mysite* a python package. -* **settings.py**: file which holds configuration for your project, more soon. -* **urls.py**: file which holds top-level URL configuration for your project, - more soon. -* **wsgi.py**: binds a wsgi application created from your project to the - symbol ``application`` -* **manage.py**: a management control script. - - -Django and WSGI ---------------- - -If you open ``wsgi.py``, you'll see the following: - -.. code-block:: python - :class: small - - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") - - from django.core.wsgi import get_wsgi_application - application = get_wsgi_application() - -.. container:: incremental - - Django is pointing the python environment at your settings file and then - getting a wsgi application: - - .. code-block:: python - :class: small - - def get_wsgi_application(): - return WSGIHandler() - - -The Django WSGIHandler ----------------------- -.. code-block:: python - :class: small - - class WSGIHandler(base.BaseHandler): - #... - def __call__(self, environ, start_response): - #... set up django middleware - try: - #... build a request - request = self.request_class(environ) - except UnicodeDecodeError: - #... handle request errors - else: - # build a response - response = self.get_response(request) - #... determine response status - status = '%s %s' % (response.status_code, status_text) - #... build response headers - response_headers = [(str(k), str(v)) for k, v in response.items()] - #... start a response with status and headers - start_response(force_str(status), response_headers) - return response - - -*django-admin.py* and *manage.py* ---------------------------------- - -*django-admin.py* provides a hook for administrative tasks and abilities: - -.. class:: incremental - -* creating a new project or app -* running the development server -* executing tests -* entering a python interpreter -* entering a database shell session with your database -* much much more (run ``django-admin.py`` without an argument) - -.. class:: incremental - -*manage.py* wraps this functionality, adding the full environment of your -project. - - -Development Server ------------------- - -At this point, you should be ready to use the development server:: - - (djangoenv)$ cd mysite - (djangoenv)$ python manage.py runserver - ... - -.. class:: incremental - -Load ``http://localhost:8000`` in your browser. - - -A Blank Slate -------------- - -You should see this: - -.. image:: img/django-start.png - :align: center - :width: 98% - -.. class:: incremental center - -**Do you?** - - -Connecting A Database ---------------------- - -Django supplies its own ORM (Object-Relational Mapper) - -.. class:: incremental - -This ORM sits on top of the DB-API implementation you choose. - -.. class:: incremental - -You must provide connection information through Django configuration. - -.. class:: incremental - -All Django configuration takes place in ``settings.py`` in your project -folder. - - -Your Database Settings ----------------------- - -Edit your ``settings.py`` to match: - -.. code-block:: python - :class: small - - DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': 'mysite.db', - # The following settings are not used with sqlite3: - 'USER': '', - 'PASSWORD': '', - 'HOST': '', - 'PORT': '', - } - } - - -Django and Your Database ------------------------- - -Django's ORM provides a layer of *abstraction* between you and SQL - -.. class:: incremental - -You write Python *models* describing the object that make up your system. - -.. class:: incremental - -The ORM handles converting data from these objects into SQL statements (and -back) - -.. class:: incremental - -We'll learn much more about this in a bit - - -Core Django *Apps* ------------------- - -Django already includes some *apps* for you. - -.. container:: incremental - - They're in ``settings.py`` in the ``INSTALLED_APPS`` setting: - - .. code-block:: python - :class: small - - INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.messages', - 'django.contrib.staticfiles', - # Uncomment the next line to enable the admin: - # 'django.contrib.admin', - # Uncomment the next line to enable admin documentation: - # 'django.contrib.admindocs', - ) - - -Creating the Database ---------------------- - -These *apps* define models of their own, tables must be created. - -.. container:: incremental - - You make them by running the ``syncdb`` management command: - - .. class:: small - - :: - - (djangoenv)$ python manage.py syncdb - Creating tables ... - Creating table auth_permission - Creating table auth_group_permissions - Creating table auth_group - ... - You just installed Django's auth system, ... - Would you like to create one now? (yes/no): - -.. class:: incremental - -Add your first user at this prompt (remember the password) - - -Our Class App -------------- - -We are going to build an *app* to add to our *project*. To start with our app -will: - -.. class:: incremental - -* allow a user to create and edit blog posts -* allow a user to define categories -* allow a user to place a post in one or more categories - -.. class:: incremental - -As stated above, an *app* represents a unit within a system, the *project*. We -have a project, we need to create an *app* - - -Create an App -------------- - -This is accomplished using ``manage.py``. - -.. class:: incremental - -In your terminal, make sure you are in the *outer* mysite directory, where the -file ``manage.py`` is located. Then: - -.. class:: incremental - -:: - - (djangoenv)$ python manage.py startapp myblog - - -What is Created ---------------- - -This should leave you with the following structure: - -.. class:: small - -:: - - mysite/ - manage.py - mysite/ - ... - myblog/ - __init__.py - models.py - tests.py - views.py - -.. class:: incremental - -We'll start by defining the main Python class in our blog system, a ``Post``. - - -Django Models -------------- - -Any Python class in Django that is meant to be persisted *must* inherit from -the Django ``Model`` class. - -.. class:: incremental - -This base class hooks in to the ORM functionality converting Python code to -SQL. - -.. class:: incremental - -You can override methods from the base ``Model`` class to alter how this works -or write new methods to add functionality. - -.. class:: incremental - -Learn more about `models -`_ - - -Our Post Model --------------- - -Open the ``models.py`` file created in our ``myblog`` package. Add the -following: - -.. code-block:: python - :class: small - - from django.db import models - from django.contrib.auth.models import User - - class Post(models.Model): - title = models.CharField(max_length=128) - text = models.TextField(blank=True) - author = models.ForeignKey(User) - created_date = models.DateTimeField(auto_now_add=True) - modified_date = models.DateTimeField(auto_now=True) - published_date = models.DateTimeField(blank=True, null=True) - - -Model Fields ------------- - -We've created a subclass of the Django ``Model`` class and added a bunch of -attributes. - -.. class:: incremental - -* These attributes are all instances of ``Field`` classes defined in Django -* Field attributes on a model map to columns in a database table -* The arguments you provide to each Field customize how it works - - * This means *both* how it operates in Django *and* how it is defined in SQL - -* There are arguments shared by all Field types -* There are also arguments specific to individual types - -.. class:: incremental - -You can read much more about `Model Fields and options -`_ - - -Field Details -------------- - -There are some features of our fields worth mentioning in specific: - -.. class:: incremental - -Notice we have no field that is designated as the *primary key* - -.. class:: incremental - -* You *can* make a field the primary key by adding ``primary_key=True`` in the - arguments -* If you do not, Django will automatically create one. This field is always - called ``id`` -* No matter what the primary key field is called, its value is always - available on a model instance as ``pk`` - - -Field Details -------------- - -.. code-block:: python - :class: small - - title = models.CharField(max_length=128) - -.. class:: incremental - -The required ``max_length`` argument is specific to ``CharField`` fields. - -.. class:: incremental - -It affects *both* the Python and SQL behavior of a field. - -.. class:: incremental - -In python, it is used to *validate* supplied values during *model validation* - -.. class:: incremental - -In SQL it is used in the column definition: ``VARCHAR(128)`` - - -Field Details -------------- - -.. code-block:: python - :class: small - - text = models.TextField(blank=True) - # ... - published_date = models.DateTimeField(blank=True, null=True) - -.. class:: incremental - -The argument ``blank`` is shared across all field types. The default is -``False`` - -.. class:: incremental - -This argument affects only the Python behavior of a field, determining if the -field is *required* - -.. class:: incremental - -The related ``null`` argument affects the SQL definition of a field: is the -column NULL or NOT NULL - - -Field Details -------------- - -.. code-block:: python - :class: small - - created_date = models.DateTimeField(auto_now_add=True) - modified_date = models.DateTimeField(auto_now=True) - -.. class:: incremental - -``auto_now_add`` is available on all date and time fields. It sets the value -of the field to *now* when an instance is first saved. - -.. class:: incremental - -``auto_now`` is similar, but sets the value anew each time an instance is -saved. - -.. class:: incremental - -Setting either of these will cause the ``editable`` attribute of a field to be -set to ``False``. - - -Field Details -------------- - -.. code-block:: python - :class: small - - author = models.ForeignKey(User) - -.. class:: incremental - -Django also models SQL *relationships* as specific field types. - -.. class:: incremental - -The required positional argument is the class of the related Model. - -.. class:: incremental - -By default, the reverse relation is implemented as the attribute -``_set``. - -.. class:: incremental - -You can override this by providing the ``related_name`` argument. - - -Our Category Model ------------------- - -Our app specification says that a user should be able to place a post in one -or more categories. - -.. class:: incremental - -We'll create a second Model to represent this. It should: - -.. class:: incremental - -* Have a unique name -* Have a description -* Be in a many-to-many relationship with our ``Post`` model -* Instances of ``Category`` should have a ``posts`` attribute that provides - access to all posts in that category -* Instances of ``Post`` should have a ``categories`` attribute that provides - access to all the categories it has been placed in. - - -My Solution ------------ - -Add this new Model class to ``models.py``. - -.. class:: incremental small - -https://docs.djangoproject.com/en/1.5/ref/models/fields/ - -.. container:: incremental - - Here's my model code: - - .. code-block:: python - :class: small - - class Category(models.Model): - name = models.CharField(max_length=128) - description = models.TextField(blank=True) - posts = models.ManyToManyField(Post, - blank=True, - null=True, - related_name='categories' - ) - - -A Word About Development ------------------------- - -These models we've created are not going to change often. This is unusual for -a development cycle. - -.. class:: incremental - -The ``syncdb`` management command only creates tables that *do not yet exist*. -It **does not update tables**. - -.. class:: incremental - -The ``sqlclear `` command will print the ``DROP TABLE`` statements to -remove the tables for your app. - -.. class:: incremental - -Or ``sql `` will show the ``CREATE TABLE`` statements, and you can work -out the differences and update manually. - - -ACK!!! ------- - -That doesn't sound very nice, does it? - -.. class:: incremental - -Luckily, there is an app available for Django that helps with this: ``South`` - -.. class:: incremental - -South allows you to incrementally update your database in a simplified way. - -.. class:: incremental - -South supports forward, backward and data migrations. - -.. class:: incremental - -We won't have time to `cover it `_ in -this class, but know it's there. - - -Hooking it Up -------------- - -In order to use our new models, we need Django to know about our *app* - -.. class:: incremental - -This is accomplished by configuration in the ``settings.py`` file. - -.. class:: incremental - -Open that file now, in your editor, and find the INSTALLED_APPS setting. - - -Installing Apps ---------------- - -You extend Django functionality by *installing apps*. This is pretty simple: - -.. code-block:: python - :class: small - - INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.messages', - 'django.contrib.staticfiles', - # Uncomment the next line to enable the admin: - # 'django.contrib.admin', - # Uncomment the next line to enable admin documentation: - # 'django.contrib.admindocs', - 'myblog', # <- YOU ADD THIS PART - ) - - -Setting Up the Database ------------------------ - -You know what the next step will be: - -.. code-block:: - :class: incremental - - (djangoenv)$ python manage.py syncdb - Creating tables ... - Creating table myblog_post - Creating table myblog_category_posts - Creating table myblog_category - Installing custom SQL ... - Installing indexes ... - Installed 0 object(s) from 0 fixture(s) - -.. class:: incremental - -Django has now created tables for our app. How many did it create? - - -ORM and SQL ------------ - -That third table is the SQL mechanism by which a ``Post`` is related to a -``Category``. - -.. class:: incremental - -The ORM shields us, as Python developers, from SQL intricacies. - -.. class:: incremental - -We don't need to know that a join table is needed for a ManyToMany relation. - -.. class:: incremental - -This is but one of the ways that the ORM helps us. More soon. - - -Break Time ----------- - -.. class:: big-centered - -Let's take a break here and return in 10 minutes. - - -The Django Shell ----------------- - -Django provides a management command ``shell``: - -.. class:: incremental - -* Shares the same ``sys.path`` as your project, so all installed python - packages are present. -* Imports the ``settings.py`` file from your project, and so shares all - installed apps and other settings. -* Handles connections to your database, so you can interact with live data - directly. - -.. class:: incremental - -Let's explore the Model Instance API directly using this shell: - -.. class:: incremental - -:: - - (djangoenv)$ python manage.py shell - - -Creating Instances ------------------- - -Instances of our model can be created by simple instantiation: - -.. code-block:: python - :class: small - - >>> from myblog.models import Post - >>> p1 = Post(title="My first post", - ... text="This is the first post I've written") - >>> p1 - - -.. container:: incremental - - We can also validate that our new object is okay before we try to save it: - - .. code-block:: python - :class: small - - >>> p1.full_clean() - Traceback (most recent call last): - ... - ValidationError: {'author': [u'This field cannot be null.']} - - -Django Model Managers ---------------------- - -We have to hook our ``Post`` to an author, which must be a ``User``. - -.. class:: incremental - -To do this, we need to have an instance of the ``User`` class. - -.. class:: incremental - -We can use the ``User`` *model manager* to run table-level operations like -``SELECT``: - -.. class:: incremental - -All Django models have a *manager*. By default it is accessed through the -``objects`` class attribute. - - -Making a ForeignKey Relation ----------------------------- - -Let's use the *manager* to get an instance of the ``User`` class: - -.. code-block:: python - :class: small - - >>> from django.contrib.auth.models import User - >>> all_users = User.objects.all() - >>> all_users - [] - >>> u1 = all_users[0] - >>> p1.author = u1 - -.. container:: incremental - - And now our instance should validate properly: - - .. code-block:: python - :class: small - - >>> p1.full_clean() - >>> - - -Saving New Objects ------------------- - -Our model has three date fields, two of which are supposed to be -auto-populated: - -.. class:: python - :class: small - - >>> print(p1.created_date) - None - >>> print(p1.modified_date) - None - -.. container:: incremental - - When we save our post, these fields will get values assigned: - - .. code-block:: python - :class: small - - >>> p1.save() - >>> p1.created_date - datetime.datetime(2013, 7, 26, 20, 2, 38, 104217, tzinfo=) - >>> p1.modified_date - datetime.datetime(2013, 7, 26, 20, 2, 38, 104826, tzinfo=) - - -Updating An Instance --------------------- - -Models operate much like 'normal' python objects. - -.. container:: incremental - - To change the value of a field, simply set the instance attribute to a new - value. Call ``save()`` to persist the change: - - .. code-block:: python - :class: small - - >>> p1.title = p1.title + " (updated)" - >>> p1.save() - >>> p1.title - 'My first post (updated)' - - -Create a Few Posts ------------------- - -Let's create a few more posts so we can explore the Django model manager query -API: - -.. code-block:: python - :class: small - - >>> p2 = Post(title="Another post", - ... text="The second one created", - ... author=u1).save() - >>> p3 = Post(title="The third one", - ... text="With the word 'heffalump'", - ... author=u1).save() - >>> p4 = Post(title="Posters are great decoration", - ... text="When you are a poor college student", - ... author=u1).save() - >>> Post.objects.count() - 4 - - -The Django Query API --------------------- - -The *manager* on each model class supports a full-featured query API. - -.. class:: incremental - -API methods take keyword arguments, where the keywords are special -constructions combining field names with field *lookups*: - -.. class:: incremental small - -* title__exact="The exact title" -* text__contains="decoration" -* id__in=range(1,4) -* published_date__lte=datetime.datetime.now() - -.. class:: incremental - -Each keyword argument generates an SQL clause. - - -QuerySets ---------- - -API methods can be divided into two basic groups: methods that return -``QuerySets`` and those that do not. - -.. class:: incremental - -The former may be chained without hitting the database: - -.. code-block:: python - :class: small incremental - - >>> a = Post.objects.all() #<-- no query yet - >>> b = a.filter(title__icontains="post") #<-- not yet - >>> c = b.exclude(text__contains="created") #<-- nope - >>> [(p.title, p.text) for p in c] #<-- This will issue the query - -.. container:: incremental - - Conversely, the latter will issue an SQL query when executed. - - .. code-block:: python - :class: small - - >>> a.count() # immediately executes an SQL query - - -QuerySets and SQL ------------------ - -If you are curious, you can see the SQL that a given QuerySet will use: - -.. code-block:: python - :class: small incremental - - >>> print(c.query) - SELECT "myblog_post"."id", "myblog_post"."title", - "myblog_post"."text", "myblog_post"."author_id", - "myblog_post"."created_date", "myblog_post"."modified_date", - "myblog_post"."published_date" - FROM "myblog_post" - WHERE ("myblog_post"."title" LIKE %post% ESCAPE '\' - AND NOT ("myblog_post"."text" LIKE %created% ESCAPE '\' ) - ) - -.. class:: incremental - -The SQL will vary depending on which DBAPI backend you use (yay ORM!!!) - - -Exploring the QuerySet API --------------------------- - -See https://docs.djangoproject.com/en/1.5/ref/models/querysets - - -.. code-block:: python - :class: small - - >>> [p.pk for p in Post.objects.all().order_by('created_date')] - [1, 2, 3, 4] - >>> [p.pk for p in Post.objects.all().order_by('-created_date')] - [4, 3, 2, 1] - >>> [p.pk for p in Post.objects.filter(title__contains='post')] - [1, 2, 4] - >>> [p.pk for p in Post.objects.exclude(title__contains='post')] - [3] - >>> qs = Post.objects.exclude(title__contains='post') - >>> qs = qs.exclude(id__exact=3) - >>> [p.pk for p in qs] - [] - >>> qs = Post.objects.exclude(title__contains='post', id__exact=3) - >>> [p.pk for p in qs] - [1, 2, 3, 4] - - -Updating via QuerySets ----------------------- -You can update all selected objects at the same time. - -.. class:: incremental - -Changes are persisted without needing to call ``save``. - -.. code-block:: python - :class: small incremental - - >>> qs = Post.objects.all() - >>> [p.published_date for p in qs] - [None, None, None, None] - >>> from datetime import datetime - >>> from django.utils.timezone import UTC - >>> utc = UTC() - >>> now = datetime.now(utc) - >>> qs.update(published_date=now) - 4 - >>> [p.published_date for p in qs] - [datetime.datetime(2013, 7, 27, 1, 20, 30, 505307, tzinfo=), - ...] - - -Testing Our Models ------------------- - -As with any project, we want to test our work. Django provides a testing -framework to allow this. - -.. class:: incremental - -Django supports both *unit tests* and *doctests*. I strongly suggest using -*unit tests*. - -.. class:: incremental - -You add tests for your *app* to the file ``tests.py``, which should be at the -same package level as ``models.py``. - -.. class:: incremental - -Locate and open this file in your editor. - - -Django TestCase Classes ------------------------ - -**SimpleTestCase** is for basic unit testing with no ORM requirements - -.. class:: incremental - -**TransactionTestCase** is useful if you need to test transactional -actions (commit and rollback) in the ORM - -.. class:: incremental - -**TestCase** is used when you require ORM access and a test client - -.. class:: incremental - -**LiveServerTestCase** launches the django server during test runs for -front-end acceptance tests. - - -Testing Data ------------- - -Sometimes testing requires base data to be present. We need a User for ours. - -.. class:: incremental - -Django provides *fixtures* to handle this need. - -.. class:: incremental - -Create a directory called ``fixtures`` inside your ``myblog`` app directory. - -.. class:: incremental - -Copy the file ``myblog_test_fixture.json`` from the class resources into this -directory, it contains users for our tests. - - -Setting Up Our Tests --------------------- - -Now that we have a fixture, we need to instruct our tests to use it. - -.. container:: incremental - - Edit ``tests.py`` (which comes with one test already) to look like this: - - .. code-block:: python - :class: small - - from django.test import TestCase - from django.contrib.auth.models import User - - class PostTestCase(TestCase): - fixtures = ['myblog_test_fixture.json', ] - - def setUp(self): - self.user = User.objects.get(pk=1) - - -Our First Enhancement +DEPARTING FROM SCRIPT --------------------- -Look at the way our Post represents itself in the Django shell: - -.. code-block:: python - :class: small - - >>> [p for p in Post.objects.all()] - [, , - , ] - -.. class:: incremental - -Wouldn't it be nice if the posts showed their titles instead? - -.. class:: incremental - -In Django, the ``__unicode__`` method is used to determine how a Model -instance represents itself. - -.. class:: incremental - -Then, calling ``unicode(instance)`` gives the desired result. - - -Write The Test --------------- - -Let's write a test that demonstrates our desired outcome: - -.. code-block:: python - :class: small - - # add this import at the top - from myblog.models import Post - - # and this test method to the PostTestCase - test_unicode(self): - expected = "This is a title" - p1 = Post(title=expected) - actual = unicode(p1) - self.assertEqual(expected, actual) - - -Run The Test ------------- - -To run tests, use the ``test`` management command - -.. class:: incremental - -Without arguments, it will run all TestCases it finds in all installed *apps* - -.. class:: incremental - -You can pass the name of a single app to focus on those tests - -.. class:: incremental - -Quit your Django shell and in your terminal run the test we wrote: - -.. code-block:: bash - :class: small incremental - - (djangoenv)$ python manage.py test myblog - - -The Result ----------- - -We have yet to implement this enhancement, so our test should fail: - -.. class:: small - -:: - - Creating test database for alias 'default'... - F - ====================================================================== - FAIL: test_unicode (myblog.tests.PostTestCase) - ---------------------------------------------------------------------- - Traceback (most recent call last): - File "/Users/cewing/projects/training/uw_pce/training.python_web/scripts/session07/mysite/myblog/tests.py", line 15, in test_unicode - self.assertEqual(expected, actual) - AssertionError: 'This is a title' != u'Post object' - - ---------------------------------------------------------------------- - Ran 1 test in 0.007s - - FAILED (failures=1) - Destroying test database for alias 'default'... - - -Make it Pass ------------- - -Let's add an appropriate ``__unicode__`` method to our Post class - -.. class:: incremental - -It will take ``self`` as its only argument - -.. class:: incremental - -And it should return its own title as the result - -.. class:: incremental - -Go ahead and take a stab at this in ``models.py`` - -.. code-block:: python - :class: small incremental - - class Post(models.Model): - #... - - def __unicode__(self): - return self.title - - -Did It Work? ------------- - -Re-run the tests to see: - -.. code-block:: bash - :class: small - - (djangoenv)$ python manage.py test myblog - Creating test database for alias 'default'... - . - ---------------------------------------------------------------------- - Ran 1 test in 0.007s - - OK - Destroying test database for alias 'default'... - -.. class:: incremental center - -**YIPEEEE!** - - -Repeat the Exercise -------------------- - -Although we haven't played with it yet, our Category class could use the same -treatment, using the ``name`` field. - -.. class:: incremental - -Add a CategoryTestCase to ``tests.py`` with one test that shows this. - -.. class:: incremental - -Run the tests, demonstrating that you have two tests and one failure - -.. class:: incremental - -Add the appropriate method to the appropriate class in ``models.py`` and -re-run the tests. - - -My Test -------- - -.. code-block:: python - :class: incremental - - # another import - from myblog.models import Category - - # and the test case and test - class CategoryTestCase(TestCase): - - def test_unicode(self): - expected = "A Category" - c1 = Category(name=expected) - actual = unicode(c1) - self.assertEqual(expected, actual) - - -My Method ---------- - -.. code-block:: python - class Category(models.Model): - #... - - def __unicode__(self): - return self.name -What to Test ------------- -In any framework, the question arises of what to test. Much of your app's -functionality is provided by framework tools. Does that need testing? -.. class:: incremental - -I *usually* don't write tests covering features provided directly by the -framework. -.. class:: incremental -I *do* write tests for functionality I add, and for places where I make -changes to how the default functionality works. -.. class:: incremental -This is largely a matter of style and taste (and of budget). -More Later +Break Time ---------- -We've only begun to test our blog app. - -.. class:: incremental - -We'll be adding many more tests later - -.. class:: incremental - -In between, you might want to take a look at the Django testing documentation: - -.. class:: incremental center - -https://docs.djangoproject.com/en/1.5/topics/testing/ - - -The Django Admin ----------------- - -As I stated earlier, the Django admin is really Django's *killer feature* - -.. class:: incremental - -To demonstrate this, we are going to set up the admin for our blog - - -Install the Admin ------------------ - -The Django Admin is, itself, an *app*. It is not installed by default. - -.. class:: incremental - -Open the ``settings.py`` file from our ``mysite`` project package and -uncomment the admin bit: - -.. code-block:: python - :class: incremental small - - INSTALLED_APPS = ( - # ... - 'django.contrib.staticfiles', - # Uncomment the next line to enable the admin: - 'django.contrib.admin', # <- THIS LINE HERE - # Uncomment the next line to enable admin documentation: - # 'django.contrib.admindocs', - 'myblog', - ) - - -Add the Admin Tables --------------------- - -As you might expect, enabling the admin alters our DB. We'll need to run -the ``syncdb`` management command:: - - (djangoenv)$ python manage.py syncdb - Creating tables ... - Creating table django_admin_log - Installing custom SQL ... - Installing indexes ... - Installed 0 object(s) from 0 fixture(s) - -.. class:: incremental - -All set. Now let's make it visitable - - -Django URL Resolution ---------------------- - -Django too has a system for routing URLs to code: the *urlconf*. - -.. class:: incremental - -* A urlconf is a list of calls to the ``django.conf.urls.url`` function -* This function takes: - - * a regexp *rule*, representing the URL - - * a ``callable`` to be invoked (or a name identifying one) - - * an optional *name* kwarg, used to *reverse* the URL - - * other optional arguments we will skip for now - -* The function returns a *resolver* that matches the request path to the - callable -* django will load the urlconf named ``urlpatterns`` that it finds in the file - named in ``settings.ROOT_URLCONF``. - - -Including URLs --------------- - -Many Django add-on *apps*, like the Django Admin, come with their own urlconf - -.. class:: incremental - -It is standard to include these urlconfs by rooting them at some path in your -site. - -.. container:: incremental - - You can do this by using the ``include`` function as the callable in a - ``url`` call: - - .. code-block:: python - :class: small - - url(http://github.com/r'%5Eforum/',%20include('random.forum.app.urls')) - - -Including the Admin -------------------- - -We can use this to add *all* the URLs provided by the Django admin in one -stroke. - -.. container:: incremental - - Uncomment three lines in ``urls.py``: - - .. code-block:: python - :class: small - - from django.contrib import admin #<- Uncomment these two - admin.autodiscover() #<- - - urlpatterns = patterns('', - - # Uncomment the next line to enable the admin: - url(http://github.com/r'%5Eadmin/',%20include(admin.site.urls)), #<- and this - ) - - -Using the Development Server ----------------------------- - -We can now view the admin. We'll use the Django development server. - -.. class:: incremental - -In your terminal, use the ``runserver`` management command to start the -development server: - -.. class:: incremental - -:: - - (djangoenv)$ python manage.py runserver - Validating models... - - 0 errors found - Django version 1.4.3, using settings 'mysite.settings' - Development server is running at http://127.0.0.1:8000/ - Quit the server with CONTROL-C. - - -Viewing the Admin ------------------ - -Load ``http://localhost:8000/admin/``. You should see this: - -.. image:: img/django-admin-login.png - :align: center - :width: 50% - -.. class:: incremental - -Login with the name and password you created before. - - -The Admin Index ---------------- - -The index will provide a list of all the installed *apps* and each model -registered. You should see this: - -.. image:: img/admin_index.png - :align: center - :width: 90% - -.. class:: incremental - -Click on ``Users``. Find yourself? Edit yourself, but **don't** uncheck -``superuser``. - - -Add Posts to the Admin ----------------------- - -Okay, let's add our app models to the admin. - -.. class:: incremental - -Add a new file to the ``myblog`` app package: ``admin.py``. Open it and add -the following: - -.. code-block:: python - :class: incremental - - from django.contrib import admin - from myblog.models import Post, Category - - admin.site.register(Post) - admin.site.register(Category) - -.. class:: incremental - -Restart your Development server and reload the admin index - +.. class:: big-centered -Play A Bit ----------- +Let's take a break here and return in 10 minutes. -Visit the admin page for Posts. You should see the posts we created earlier in -the Django shell. -.. class:: incremental -Look at the listing of Posts. Because of our ``__unicode__`` method we see a -nice title. -.. class:: incremental -Are there other fields you'd like to see listed? -.. class:: incremental -Click on a Post, note what is and is not shown. -.. class:: incremental -Poke at the Category admin a bit too. -Next Steps ----------- -We've learned a great deal about Django's ORM and Models. -.. class:: incremental -We've also spent some time getting to know the Query API provided by model -managers and QuerySets. -.. class:: incremental -We've also hooked up the Django Admin and noted some shortcomings. -.. class:: incremental -In our next session we'll improve how the admin works for us. -.. class:: incremental -Then we'll put a front-end on this blog. -Break Time ----------- -.. class:: big-centered -See you back soon. From a0b0a969cb3bdb8fabeec7e9e582db1e6bf7811f Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 8 Feb 2014 15:48:37 -0800 Subject: [PATCH 270/487] set up homework for session 6, add django tutorial --- assignments/session06/django_intro-plain.html | 1246 ++++++++++++++ assignments/session06/img/admin_index.png | Bin 0 -> 27949 bytes .../session06/img/django-admin-login.png | Bin 0 -> 7749 bytes assignments/session06/img/django-start.png | Bin 0 -> 31371 bytes assignments/session06/tasks.txt | 7 + source/presentations/django_intro.rst | 1453 +++++++++++++++++ 6 files changed, 2706 insertions(+) create mode 100644 assignments/session06/django_intro-plain.html create mode 100644 assignments/session06/img/admin_index.png create mode 100644 assignments/session06/img/django-admin-login.png create mode 100644 assignments/session06/img/django-start.png create mode 100644 assignments/session06/tasks.txt create mode 100644 source/presentations/django_intro.rst diff --git a/assignments/session06/django_intro-plain.html b/assignments/session06/django_intro-plain.html new file mode 100644 index 00000000..ca60c56a --- /dev/null +++ b/assignments/session06/django_intro-plain.html @@ -0,0 +1,1246 @@ + + + + + + +An Introduction To Django + + + +
    +

    An Introduction To Django

    + +

    In this tutorial, you'll walk through creating a very simple microblog +application using Django.

    +
    +

    Practice Safe Development

    +

    We'll install Django and any other packages we use with it in a virtualenv.

    +

    This will ensure that it is isolated from everything else we do in class (and +vice versa)

    +
    +

    Remember the basic format for creating a virtualenv:

    +
    +$ python virtualenv.py [options] <ENV>
    +<or>
    +$ virtualenv [options] <ENV>
    +
    +
    +
    +
    +

    Set Up a VirtualEnv

    +

    Start by creating your virtualenv:

    +
    +$ python virtualenv.py djangoenv
    +<or>
    +$ virtualenv djangoenv
    +...
    +
    +
    +

    Then, activate it:

    +
    +$ source djangoenv/bin/activate
    +<or>
    +C:\> djangoenv\Scripts\activate
    +
    +
    +
    +
    +

    Install Django

    +

    Finally, install Django 1.6.2 using pip:

    +
    +(djangoenv)$ pip install Django==1.6.2
    +Downloading/unpacking Django==1.5.2
    +  Downloading Django-1.6.2.tar.gz (8.0MB): 8.0MB downloaded
    +  Running setup.py egg_info for package Django
    +     changing mode of /path/to/djangoenv/bin/django-admin.py to 755
    +Successfully installed Django
    +Cleaning up...
    +(djangoenv)$
    +
    +
    +
    +

    Starting a Project

    +

    Everything in Django stems from the project

    +

    To get started learning, we'll create one

    +

    We'll use a script installed by Django, django-admin.py:

    +
    +(djangoenv)$ django-admin.py startproject mysite
    +
    +

    This will create a folder called 'mysite'. Let's take a look at it:

    +
    +
    +

    Project Layout

    +

    The folder created by django-admin.py contains the following structure:

    +
    +mysite
    +├── manage.py
    +└── mysite
    +    ├── __init__.py
    +    ├── settings.py
    +    ├── urls.py
    +    └── wsgi.py
    +
    +

    If what you see doesn't match that, you're using an older version of Django. +Make sure you've installed 1.6.2.

    +
    +
    +

    What Got Created

    +
      +
    • outer *mysite* folder: this is just a container and can be renamed or +moved at will
    • +
    • inner *mysite* folder: this is your project directory. It should not be +renamed.
    • +
    • __init__.py: magic file that makes mysite a python package.
    • +
    • settings.py: file which holds configuration for your project, more soon.
    • +
    • urls.py: file which holds top-level URL configuration for your project, +more soon.
    • +
    • wsgi.py: binds a wsgi application created from your project to the +symbol application
    • +
    • manage.py: a management control script.
    • +
    +
    +
    +

    django-admin.py and manage.py

    +

    django-admin.py provides a hook for administrative tasks and abilities:

    +
      +
    • creating a new project or app
    • +
    • running the development server
    • +
    • executing tests
    • +
    • entering a python interpreter
    • +
    • entering a database shell session with your database
    • +
    • much much more (run django-admin.py without an argument)
    • +
    +

    manage.py wraps this functionality, adding the full environment of your +project.

    +
    +
    +

    How manage.py Works

    +

    Look in the manage.py script Django created for you. You'll see this:

    +
    +#!/usr/bin/env python
    +import os
    +import sys
    +
    +if __name__ == "__main__":
    +    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
    +    ...
    +
    +

    The environmental var DJANGO_SETTINGS_MODULE is how the manage.py +script is made aware of your project's environment. This is why you shouldn't +rename the project package.

    +
    +
    +

    Development Server

    +

    At this point, you should be ready to use the development server:

    +
    +(djangoenv)$ cd mysite
    +(djangoenv)$ python manage.py runserver
    +...
    +
    +

    Load http://localhost:8000 in your browser.

    +
    +
    +

    A Blank Slate

    +

    You should see this:

    +img/django-start.png +

    Do you?

    +
    +
    +

    Connecting A Database

    +

    Django supplies its own ORM (Object-Relational Mapper)

    +

    This ORM sits on top of the DB-API implementation you choose.

    +

    You must provide connection information through Django configuration.

    +

    All Django configuration takes place in settings.py in your project +folder.

    +
    +
    +

    Your Database Settings

    +

    Edit your settings.py to match:

    +
    +DATABASES = {
    +    'default': {
    +        'ENGINE': 'django.db.backends.sqlite3',
    +        'NAME': 'mysite.db',
    +    }
    +}
    +
    +

    There are other database settings, but they are not used with sqlite3, we'll +ignore them for now.

    +
    +
    +

    Django and Your Database

    +

    Django's ORM provides a layer of abstraction between you and SQL

    +

    You write Python classes called models describing the object that make up +your system.

    +

    The ORM handles converting data from these objects into SQL statements (and +back)

    +

    We'll learn much more about this in a bit

    +
    +
    +

    Django Organization

    +

    We've created a Django project. In Django a project represents a whole +website:

    +
      +
    • global configuration settings
    • +
    • inclusion points for additional functionality
    • +
    • master list of URL endpoints
    • +
    +

    A Django app encapsulates a unit of functionality:

    +
      +
    • A blog section
    • +
    • A discussion forum
    • +
    • A content tagging system
    • +
    +
    +
    +

    Apps Make Up a Project

    +

    One project can (and likely will) consist of many apps

    +
    +
    +

    Core Django Apps

    +

    Django already includes some apps for you.

    +
    +

    They're in settings.py in the INSTALLED_APPS setting:

    +
    +INSTALLED_APPS = (
    +    'django.contrib.auth',
    +    'django.contrib.contenttypes',
    +    'django.contrib.sessions',
    +    'django.contrib.sites',
    +    'django.contrib.messages',
    +    'django.contrib.staticfiles',
    +    # Uncomment the next line to enable the admin:
    +    # 'django.contrib.admin',
    +    # Uncomment the next line to enable admin documentation:
    +    # 'django.contrib.admindocs',
    +)
    +
    +
    +
    +
    +

    Creating the Database

    +

    These apps define models of their own, tables must be created.

    +
    +

    You make them by running the syncdb management command:

    +
    +(djangoenv)$ python manage.py syncdb
    +Creating tables ...
    +Creating table auth_permission
    +Creating table auth_group_permissions
    +Creating table auth_group
    +...
    +You just installed Django's auth system, ...
    +Would you like to create one now? (yes/no):
    +
    +
    +

    Add your first user at this prompt. I strongly suggest you use the username +'admin' and give it the password 'admin'. If you don't, make sure you remember +the values you use.

    +
    +
    +

    Our Class App

    +

    We are going to build an app to add to our project. To start with our app +will be a lot like the Flask app we finished last time.

    +

    As stated above, an app represents a unit within a system, the project. We +have a project, we need to create an app

    +
    +
    +

    Create an App

    +

    This is accomplished using manage.py.

    +

    In your terminal, make sure you are in the outer mysite directory, where the +file manage.py is located. Then:

    +
    +(djangoenv)$ python manage.py startapp myblog
    +
    +
    +
    +

    What is Created

    +

    This should leave you with the following structure:

    +
    +mysite
    +├── manage.py
    +├── myblog
    +│   ├── __init__.py
    +│   ├── admin.py
    +│   ├── models.py
    +│   ├── tests.py
    +│   └── views.py
    +└── mysite
    +    ├── __init__.py
    +    ...
    +
    +

    We'll start by defining the main Python class for our blog system, a Post.

    +
    +
    +

    Django Models

    +

    Any Python class in Django that is meant to be persisted must inherit from +the Django Model class.

    +

    This base class hooks in to the ORM functionality converting Python code to +SQL.

    +

    You can override methods from the base Model class to alter how this works +or write new methods to add functionality.

    +

    Learn more about models

    +
    +
    +

    Our Post Model

    +

    Open the models.py file created in our myblog package. Add the +following:

    +
    +from django.db import models #<-- This is already in the file
    +from django.contrib.auth.models import User
    +
    +class Post(models.Model):
    +    title = models.CharField(max_length=128)
    +    text = models.TextField(blank=True)
    +    author = models.ForeignKey(User)
    +    created_date = models.DateTimeField(auto_now_add=True)
    +    modified_date = models.DateTimeField(auto_now=True)
    +    published_date = models.DateTimeField(blank=True, null=True)
    +
    +
    +
    +

    Model Fields

    +

    We've created a subclass of the Django Model class and added a bunch of +attributes.

    +
      +
    • These attributes are all instances of Field classes defined in Django
    • +
    • Field attributes on a model map to columns in a database table
    • +
    • The arguments you provide to each Field customize how it works
        +
      • This means both how it operates in Django and how it is defined in SQL
      • +
      +
    • +
    • There are arguments shared by all Field types
    • +
    • There are also arguments specific to individual types
    • +
    +

    You can read much more about Model Fields and options

    +
    +
    +

    Field Details

    +

    There are some features of our fields worth mentioning in specific:

    +

    Notice we have no field that is designated as the primary key

    +
      +
    • You can make a field the primary key by adding primary_key=True in the +arguments
    • +
    • If you do not, Django will automatically create one. This field is always +called id
    • +
    • No matter what the primary key field is called, its value is always +available on a model instance as the pk attribute.
    • +
    +
    +
    +

    Field Details

    +
    +title = models.CharField(max_length=128)
    +
    +

    The required max_length argument is specific to CharField fields.

    +

    It affects both the Python and SQL behavior of a field.

    +

    In python, it is used to validate supplied values during model validation

    +

    In SQL it is used in the column definition: VARCHAR(128)

    +
    +
    +

    Field Details

    +
    +author = models.ForeignKey(User)
    +
    +

    Django also models SQL relationships as specific field types.

    +

    The required positional argument is the class of the related Model.

    +

    By default, the reverse relation is implemented as the attribute +<fieldname>_set.

    +

    You can override this by providing the related_name argument.

    +
    +
    +

    Field Details

    +
    +created_date = models.DateTimeField(auto_now_add=True)
    +modified_date = models.DateTimeField(auto_now=True)
    +
    +

    auto_now_add is available on all date and time fields. It sets the value +of the field to now when an instance is first saved.

    +

    auto_now is similar, but sets the value anew each time an instance is +saved.

    +

    Setting either of these will cause the editable attribute of a field to be +set to False.

    +
    +
    +

    Field Details

    +
    +text = models.TextField(blank=True)
    +# ...
    +published_date = models.DateTimeField(blank=True, null=True)
    +
    +

    The argument blank is shared across all field types. The default is +False

    +

    This argument affects only the Python behavior of a field, determining if the +field is required

    +

    The related null argument affects the SQL definition of a field: is the +column NULL or NOT NULL

    +
    +
    +

    Hooking it Up

    +

    In order to use our new model, we need Django to know about our app

    +

    This is accomplished by configuration in the settings.py file.

    +

    Open that file now, in your editor, and find the INSTALLED_APPS setting.

    +
    +
    +

    Installing Apps

    +

    You extend Django functionality by installing apps. This is pretty simple:

    +
    +INSTALLED_APPS = (
    +    'django.contrib.auth',
    +    'django.contrib.contenttypes',
    +    'django.contrib.sessions',
    +    'django.contrib.sites',
    +    'django.contrib.messages',
    +    'django.contrib.staticfiles',
    +    'myblog', # <- YOU ADD THIS PART
    +)
    +
    +
    +
    +

    Setting Up the Database

    +

    You know what the next step will be:

    +
    +(djangoenv)$ python manage.py syncdb
    +Creating tables ...
    +Creating table myblog_post
    +Installing custom SQL ...
    +Installing indexes ...
    +Installed 0 object(s) from 0 fixture(s)
    +
    +

    Django has now created a table for our model.

    +

    Notice that the table name is a combination of the name of our app and the +name of our model.

    +
    +
    +

    The Django Shell

    +

    Django provides a management command shell:

    +
      +
    • Shares the same sys.path as your project, so all installed python +packages are present.
    • +
    • Imports the settings.py file from your project, and so shares all +installed apps and other settings.
    • +
    • Handles connections to your database, so you can interact with live data +directly.
    • +
    +

    Let's explore the Model Instance API directly using this shell:

    +
    +(djangoenv)$ python manage.py shell
    +
    +
    +
    +

    Creating Instances

    +

    Instances of our model can be created by simple instantiation:

    +
    +>>> from myblog.models import Post
    +>>> p1 = Post(title="My first post",
    +...           text="This is the first post I've written")
    +>>> p1
    +<Post: Post object>
    +
    +
    +

    We can also validate that our new object is okay before we try to save it:

    +
    +>>> p1.full_clean()
    +Traceback (most recent call last):
    +  ...
    +ValidationError: {'author': [u'This field cannot be null.']}
    +
    +
    +
    +
    +

    Django Model Managers

    +

    We have to hook our Post to an author, which must be a User.

    +

    To do this, we need to have an instance of the User class.

    +

    We can use the User model manager to run table-level operations like +SELECT:

    +

    All Django models have a manager. By default it is accessed through the +objects class attribute.

    +
    +
    +

    Making a ForeignKey Relation

    +

    Let's use the manager to get an instance of the User class:

    +
    +>>> from django.contrib.auth.models import User
    +>>> all_users = User.objects.all()
    +>>> all_users
    +[<User: cewing>]
    +>>> u1 = all_users[0]
    +>>> p1.author = u1
    +
    +
    +

    And now our instance should validate properly:

    +
    +>>> p1.full_clean()
    +>>>
    +
    +
    +
    +
    +

    Saving New Objects

    +

    Our model has three date fields, two of which are supposed to be +auto-populated:

    +
    +>>> print(p1.created_date)
    +None
    +>>> print(p1.modified_date)
    +None
    +
    +
    +

    When we save our post, these fields will get values assigned:

    +
    +>>> p1.save()
    +>>> p1.created_date
    +datetime.datetime(2013, 7, 26, 20, 2, 38, 104217, tzinfo=<UTC>)
    +>>> p1.modified_date
    +datetime.datetime(2013, 7, 26, 20, 2, 38, 104826, tzinfo=<UTC>)
    +
    +
    +
    +
    +

    Updating An Instance

    +

    Models operate much like 'normal' python objects.

    +
    +

    To change the value of a field, simply set the instance attribute to a new +value. Call save() to persist the change:

    +
    +>>> p1.title = p1.title + " (updated)"
    +>>> p1.save()
    +>>> p1.title
    +'My first post (updated)'
    +
    +
    +
    +
    +

    Create a Few Posts

    +

    Let's create a few more posts so we can explore the Django model manager query +API:

    +
    +>>> p2 = Post(title="Another post",
    +...           text="The second one created",
    +...           author=u1).save()
    +>>> p3 = Post(title="The third one",
    +...           text="With the word 'heffalump'",
    +...           author=u1).save()
    +>>> p4 = Post(title="Posters are great decoration",
    +...           text="When you are a poor college student",
    +...           author=u1).save()
    +>>> Post.objects.count()
    +4
    +
    +
    +
    +

    The Django Query API

    +

    The manager on each model class supports a full-featured query API.

    +

    API methods take keyword arguments, where the keywords are special +constructions combining field names with field lookups:

    +
      +
    • title__exact="The exact title"
    • +
    • text__contains="decoration"
    • +
    • id__in=range(1,4)
    • +
    • published_date__lte=datetime.datetime.now()
    • +
    +

    Each keyword argument generates an SQL clause.

    +
    +
    +

    QuerySets

    +

    API methods can be divided into two basic groups: methods that return +QuerySets and those that do not.

    +

    The former may be chained without hitting the database:

    +
    +>>> a = Post.objects.all() #<-- no query yet
    +>>> b = a.filter(title__icontains="post") #<-- not yet
    +>>> c = b.exclude(text__contains="created") #<-- nope
    +>>> [(p.title, p.text) for p in c] #<-- This will issue the query
    +
    +
    +

    Conversely, the latter will issue an SQL query when executed.

    +
    +>>> a.count() # immediately executes an SQL query
    +
    +
    +
    +
    +

    QuerySets and SQL

    +

    If you are curious, you can see the SQL that a given QuerySet will use:

    +
    +>>> print(c.query)
    +SELECT "myblog_post"."id", "myblog_post"."title",
    +    "myblog_post"."text", "myblog_post"."author_id",
    +    "myblog_post"."created_date", "myblog_post"."modified_date",
    +    "myblog_post"."published_date"
    +FROM "myblog_post"
    +WHERE ("myblog_post"."title" LIKE %post% ESCAPE '\'
    +       AND NOT ("myblog_post"."text" LIKE %created% ESCAPE '\' )
    +)
    +
    +

    The SQL will vary depending on which DBAPI backend you use (yay ORM!!!)

    +
    +
    +

    Exploring the QuerySet API

    +

    See https://docs.djangoproject.com/en/1.6/ref/models/querysets

    +
    +>>> [p.pk for p in Post.objects.all().order_by('created_date')]
    +[1, 2, 3, 4]
    +>>> [p.pk for p in Post.objects.all().order_by('-created_date')]
    +[4, 3, 2, 1]
    +>>> [p.pk for p in Post.objects.filter(title__contains='post')]
    +[1, 2, 4]
    +>>> [p.pk for p in Post.objects.exclude(title__contains='post')]
    +[3]
    +>>> qs = Post.objects.exclude(title__contains='post')
    +>>> qs = qs.exclude(id__exact=3)
    +>>> [p.pk for p in qs]
    +[]
    +>>> qs = Post.objects.exclude(title__contains='post', id__exact=3)
    +>>> [p.pk for p in qs]
    +[1, 2, 3, 4]
    +
    +
    +
    +

    Updating via QuerySets

    +

    You can update all selected objects at the same time.

    +

    Changes are persisted without needing to call save.

    +
    +>>> qs = Post.objects.all()
    +>>> [p.published_date for p in qs]
    +[None, None, None, None]
    +>>> from datetime import datetime
    +>>> from django.utils.timezone import UTC
    +>>> utc = UTC()
    +>>> now = datetime.now(utc)
    +>>> qs.update(published_date=now)
    +4
    +>>> [p.published_date for p in qs]
    +[datetime.datetime(2013, 7, 27, 1, 20, 30, 505307, tzinfo=<UTC>),
    + ...]
    +
    +
    +
    +

    Testing Our Model

    +

    As with any project, we want to test our work. Django provides a testing +framework to allow this.

    +

    Django supports both unit tests and doctests. I strongly suggest using +unit tests.

    +

    You add tests for your app to the file tests.py, which should be at the +same package level as models.py.

    +

    Locate and open this file in your editor.

    +
    +
    +

    Django TestCase Classes

    +

    SimpleTestCase is for basic unit testing with no ORM requirements

    +

    TransactionTestCase is useful if you need to test transactional +actions (commit and rollback) in the ORM

    +

    TestCase is used when you require ORM access and a test client

    +

    LiveServerTestCase launches the django server during test runs for +front-end acceptance tests.

    +
    +
    +

    Testing Data

    +

    Sometimes testing requires base data to be present. We need a User for ours.

    +

    Django provides fixtures to handle this need.

    +

    Create a directory called fixtures inside your myblog app directory.

    +

    Copy the file myblog_test_fixture.json from the class resources into this +directory, it contains users for our tests.

    +
    +
    +

    Setting Up Tests

    +

    Now that we have a fixture, we need to instruct our tests to use it.

    +
    +

    Edit tests.py (which comes with one test already) to look like this:

    +
    +from django.test import TestCase
    +from django.contrib.auth.models import User
    +
    +class PostTestCase(TestCase):
    +    fixtures = ['myblog_test_fixture.json', ]
    +
    +    def setUp(self):
    +        self.user = User.objects.get(pk=1)
    +
    +
    +
    +
    +

    Our First Enhancement

    +

    Look at the way our Post represents itself in the Django shell:

    +
    +>>> [p for p in Post.objects.all()]
    +[<Post: Post object>, <Post: Post object>,
    + <Post: Post object>, <Post: Post object>]
    +
    +

    Wouldn't it be nice if the posts showed their titles instead?

    +

    In Django, the __unicode__ method is used to determine how a Model +instance represents itself.

    +

    Then, calling unicode(instance) gives the desired result.

    +
    +
    +

    Write The Test

    +

    Let's write a test that demonstrates our desired outcome:

    +
    +# add this import at the top
    +from myblog.models import Post
    +
    +# and this test method to the PostTestCase
    +def test_unicode(self):
    +    expected = "This is a title"
    +    p1 = Post(title=expected)
    +    actual = unicode(p1)
    +    self.assertEqual(expected, actual)
    +
    +
    +
    +

    Run The Test

    +

    To run tests, use the test management command

    +

    Without arguments, it will run all TestCases it finds in all installed apps

    +

    You can pass the name of a single app to focus on those tests

    +

    Quit your Django shell and in your terminal run the test we wrote:

    +
    +(djangoenv)$ python manage.py test myblog
    +
    +
    +
    +

    The Result

    +

    We have yet to implement this enhancement, so our test should fail:

    +
    +Creating test database for alias 'default'...
    +F
    +======================================================================
    +FAIL: test_unicode (myblog.tests.PostTestCase)
    +----------------------------------------------------------------------
    +Traceback (most recent call last):
    +  File "/Users/cewing/projects/training/uw_pce/training.python_web/scripts/session07/mysite/myblog/tests.py", line 15, in test_unicode
    +    self.assertEqual(expected, actual)
    +AssertionError: 'This is a title' != u'Post object'
    +
    +----------------------------------------------------------------------
    +Ran 1 test in 0.007s
    +
    +FAILED (failures=1)
    +Destroying test database for alias 'default'...
    +
    +
    +
    +

    Make it Pass

    +

    Let's add an appropriate __unicode__ method to our Post class

    +

    It will take self as its only argument

    +

    And it should return its own title as the result

    +

    Go ahead and take a stab at this in models.py

    +
    +class Post(models.Model):
    +    #...
    +
    +    def __unicode__(self):
    +        return self.title
    +
    +
    +
    +

    Did It Work?

    +

    Re-run the tests to see:

    +
    +(djangoenv)$ python manage.py test myblog
    +Creating test database for alias 'default'...
    +.
    +----------------------------------------------------------------------
    +Ran 1 test in 0.007s
    +
    +OK
    +Destroying test database for alias 'default'...
    +
    +

    YIPEEEE!

    +
    +
    +

    What to Test

    +

    In any framework, the question arises of what to test. Much of your app's +functionality is provided by framework tools. Does that need testing?

    +

    I usually don't write tests covering features provided directly by the +framework.

    +

    I do write tests for functionality I add, and for places where I make +changes to how the default functionality works.

    +

    This is largely a matter of style and taste (and of budget).

    +
    +
    +

    More Later

    +

    We've only begun to test our blog app.

    +

    We'll be adding many more tests later

    +

    In between, you might want to take a look at the Django testing documentation:

    +

    https://docs.djangoproject.com/en/1.6/topics/testing/

    +
    +
    +

    The Django Admin

    +

    There are some who believe that Django has been Python's killer app

    +

    And without doubt the Django Admin is a killer feature for Django.

    +

    To demonstrate this, we are going to set up the admin for our blog

    +
    +
    +

    Using the Admin

    +

    The Django Admin is, itself, an app, installed by default (as of 1.6).

    +

    Open the settings.py file from our mysite project package and +verify that you see it in the list:

    +
    +INSTALLED_APPS = (
    +    'django.contrib.admin', # <- already present
    +    # ...
    +    'django.contrib.staticfiles', # <- already present
    +    'myblog', # <- already present
    +)
    +
    +
    +
    +

    Accessing the Admin

    +

    What we need now is to allow the admin to be seen through a web browser.

    +

    To do that, we'll have to add some URLs to our project.

    +
    +
    +

    Django URL Resolution

    +

    Django too has a system for dispatching requests to code: the urlconf.

    +
      +
    • A urlconf is a an iterable of calls to the django.conf.urls.url function
    • +
    • This function takes:
        +
      • a regexp rule, representing the URL
      • +
      • a callable to be invoked (or a name identifying one)
      • +
      • an optional name kwarg, used to reverse the URL
      • +
      • other optional arguments we will skip for now
      • +
      +
    • +
    • The function returns a resolver that matches the request path to the +callable
    • +
    +
    +
    +

    urlpatterns

    +

    I said above that a urlconf is an iterable.

    +

    That iterable is generally built by calling the django.conf.urls.patterns +function.

    +

    It's best to build it that way, but in reality, any iterable will do.

    +

    However, the name you give this iterable is not flexible.

    +

    Django will load the urlconf named urlpatterns that it finds in the file +named in settings.ROOT_URLCONF.

    +
    +
    +

    Including URLs

    +

    Many Django add-on apps, like the Django Admin, come with their own urlconf

    +

    It is standard to include these urlconfs by rooting them at some path in your +site.

    +
    +

    You can do this by using the django.conf.urls.include function as the +callable in a url call:

    +
    +url(r'^forum/', include('random.forum.app.urls'))
    +
    +
    +
    +
    +

    Including the Admin

    +

    We can use this to add all the URLs provided by the Django admin in one +stroke.

    +
    +

    verify the following lines in urls.py:

    +
    +from django.contrib import admin #<- make sure these two are
    +admin.autodiscover()             #<- present and uncommented
    +
    +urlpatterns = patterns('',
    +    ...
    +    url(r'^admin/', include(admin.site.urls)), #<- and this
    +)
    +
    +
    +
    +
    +

    Using the Development Server

    +

    We can now view the admin. We'll use the Django development server.

    +

    In your terminal, use the runserver management command to start the +development server:

    +
    +(djangoenv)$ python manage.py runserver
    +Validating models...
    +
    +0 errors found
    +Django version 1.4.3, using settings 'mysite.settings'
    +Development server is running at http://127.0.0.1:8000/
    +Quit the server with CONTROL-C.
    +
    +
    +
    +

    Viewing the Admin

    +

    Load http://localhost:8000/admin/. You should see this:

    +img/django-admin-login.png +

    Login with the name and password you created before.

    +
    +
    +

    The Admin Index

    +

    The index will provide a list of all the installed apps and each model +registered. You should see this:

    +img/admin_index.png +

    Click on Users. Find yourself? Edit yourself, but don't uncheck +superuser.

    +
    +
    +

    Add Posts to the Admin

    +

    Okay, let's add our app model to the admin.

    +

    Find the admin.py file in the myblog package. Open it, add the +following and save the file:

    +
    +from django.contrib import admin # <- this is already there.
    +from myblog.models import Post
    +
    +admin.site.register(Post)
    +
    +

    Reload the admin index page.

    +
    +
    +

    Play A Bit

    +

    Visit the admin page for Posts. You should see the posts we created earlier in +the Django shell.

    +

    Look at the listing of Posts. Because of our __unicode__ method we see a +nice title.

    +

    Are there other fields you'd like to see listed?

    +

    Click on a Post, note what is and is not shown.

    +
    +
    +

    Next Steps

    +

    We've learned a great deal about Django's ORM and Models.

    +

    We've also spent some time getting to know the Query API provided by model +managers and QuerySets.

    +

    We've also hooked up the Django Admin and noted some shortcomings.

    +

    In class we'll learn how to put a front end on this, add new models, and +customize the admin experience.

    +
    +
    + + + diff --git a/assignments/session06/img/admin_index.png b/assignments/session06/img/admin_index.png new file mode 100644 index 0000000000000000000000000000000000000000..ae7a19f986880cac0b47c2ea4cb48a722851c260 GIT binary patch literal 27949 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 literal 0 HcmV?d00001 diff --git a/assignments/session06/img/django-admin-login.png b/assignments/session06/img/django-admin-login.png new file mode 100644 index 0000000000000000000000000000000000000000..4ceb5f54b92922f5f82b8896c8dccfbcd1ad6bdf GIT binary patch literal 7749 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 literal 0 HcmV?d00001 diff --git a/assignments/session06/tasks.txt b/assignments/session06/tasks.txt new file mode 100644 index 00000000..9cb9b211 --- /dev/null +++ b/assignments/session06/tasks.txt @@ -0,0 +1,7 @@ +Session 6 Homework +================== + +For your homework this week, walk through the Introduction to Django tutorial. + +Make sure to save your work and bring it to class. We'll be using it as a +starting point for our work in Session 7. diff --git a/source/presentations/django_intro.rst b/source/presentations/django_intro.rst new file mode 100644 index 00000000..0951003c --- /dev/null +++ b/source/presentations/django_intro.rst @@ -0,0 +1,1453 @@ +************************* +An Introduction To Django +************************* + +In this tutorial, you'll walk through creating a very simple microblog +application using Django. + +Practice Safe Development +------------------------- + +We'll install Django and any other packages we use with it in a virtualenv. + +.. class:: incremental + +This will ensure that it is isolated from everything else we do in class (and +vice versa) + +.. container:: incremental + + Remember the basic format for creating a virtualenv: + + .. class:: small + + :: + + $ python virtualenv.py [options] + + $ virtualenv [options] + + +Set Up a VirtualEnv +------------------- + +Start by creating your virtualenv:: + + $ python virtualenv.py djangoenv + + $ virtualenv djangoenv + ... + +.. container:: incremental + + Then, activate it:: + + $ source djangoenv/bin/activate + + C:\> djangoenv\Scripts\activate + + +Install Django +-------------- + +Finally, install Django 1.6.2 using ``pip``: + +.. class:: small + +:: + + (djangoenv)$ pip install Django==1.6.2 + Downloading/unpacking Django==1.5.2 + Downloading Django-1.6.2.tar.gz (8.0MB): 8.0MB downloaded + Running setup.py egg_info for package Django + changing mode of /path/to/djangoenv/bin/django-admin.py to 755 + Successfully installed Django + Cleaning up... + (djangoenv)$ + + +Starting a Project +------------------ + +Everything in Django stems from the *project* + +.. class:: incremental + +To get started learning, we'll create one + +.. class:: incremental + +We'll use a script installed by Django, ``django-admin.py``: + +.. code-block:: + :class: incremental + + (djangoenv)$ django-admin.py startproject mysite + +.. class:: incremental + +This will create a folder called 'mysite'. Let's take a look at it: + + +Project Layout +-------------- + +The folder created by ``django-admin.py`` contains the following structure: + +.. code-block:: + + mysite + ├── manage.py + └── mysite + ├── __init__.py + ├── settings.py + ├── urls.py + └── wsgi.py + +.. class:: incremental + +If what you see doesn't match that, you're using an older version of Django. +Make sure you've installed 1.6.2. + + +What Got Created +---------------- + +.. class:: incremental + +* **outer *mysite* folder**: this is just a container and can be renamed or + moved at will +* **inner *mysite* folder**: this is your project directory. It should not be + renamed. +* **__init__.py**: magic file that makes *mysite* a python package. +* **settings.py**: file which holds configuration for your project, more soon. +* **urls.py**: file which holds top-level URL configuration for your project, + more soon. +* **wsgi.py**: binds a wsgi application created from your project to the + symbol ``application`` +* **manage.py**: a management control script. + + +*django-admin.py* and *manage.py* +--------------------------------- + +*django-admin.py* provides a hook for administrative tasks and abilities: + +.. class:: incremental + +* creating a new project or app +* running the development server +* executing tests +* entering a python interpreter +* entering a database shell session with your database +* much much more (run ``django-admin.py`` without an argument) + +.. class:: incremental + +*manage.py* wraps this functionality, adding the full environment of your +project. + + +How *manage.py* Works +--------------------- + +Look in the ``manage.py`` script Django created for you. You'll see this: + +.. code-block:: python + :class: small + + #!/usr/bin/env python + import os + import sys + + if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + ... + +.. class:: incremental + +The environmental var ``DJANGO_SETTINGS_MODULE`` is how the ``manage.py`` +script is made aware of your project's environment. This is why you shouldn't +rename the project package. + + +Development Server +------------------ + +At this point, you should be ready to use the development server:: + + (djangoenv)$ cd mysite + (djangoenv)$ python manage.py runserver + ... + +.. class:: incremental + +Load ``http://localhost:8000`` in your browser. + + +A Blank Slate +------------- + +You should see this: + +.. image:: img/django-start.png + :align: center + :width: 98% + +.. class:: incremental center + +**Do you?** + + +Connecting A Database +--------------------- + +Django supplies its own ORM (Object-Relational Mapper) + +.. class:: incremental + +This ORM sits on top of the DB-API implementation you choose. + +.. class:: incremental + +You must provide connection information through Django configuration. + +.. class:: incremental + +All Django configuration takes place in ``settings.py`` in your project +folder. + + +Your Database Settings +---------------------- + +Edit your ``settings.py`` to match: + +.. code-block:: python + :class: small + + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': 'mysite.db', + } + } + +.. class:: incremental + +There are other database settings, but they are not used with sqlite3, we'll +ignore them for now. + + +Django and Your Database +------------------------ + +Django's ORM provides a layer of *abstraction* between you and SQL + +.. class:: incremental + +You write Python classes called *models* describing the object that make up +your system. + +.. class:: incremental + +The ORM handles converting data from these objects into SQL statements (and +back) + +.. class:: incremental + +We'll learn much more about this in a bit + + +Django Organization +------------------- + +We've created a Django *project*. In Django a project represents a whole +website: + +.. class:: incremental + +* global configuration settings +* inclusion points for additional functionality +* master list of URL endpoints + +.. class:: incremental + +A Django *app* encapsulates a unit of functionality: + +.. class:: incremental + +* A blog section +* A discussion forum +* A content tagging system + + +Apps Make Up a Project +---------------------- + +.. class:: big-centered + +One *project* can (and likely will) consist of many *apps* + + +Core Django *Apps* +------------------ + +Django already includes some *apps* for you. + +.. container:: incremental + + They're in ``settings.py`` in the ``INSTALLED_APPS`` setting: + + .. code-block:: python + :class: small + + INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + # Uncomment the next line to enable the admin: + # 'django.contrib.admin', + # Uncomment the next line to enable admin documentation: + # 'django.contrib.admindocs', + ) + + +Creating the Database +--------------------- + +These *apps* define models of their own, tables must be created. + +.. container:: incremental + + You make them by running the ``syncdb`` management command: + + .. class:: small + + :: + + (djangoenv)$ python manage.py syncdb + Creating tables ... + Creating table auth_permission + Creating table auth_group_permissions + Creating table auth_group + ... + You just installed Django's auth system, ... + Would you like to create one now? (yes/no): + +.. class:: incremental + +Add your first user at this prompt. I strongly suggest you use the username +'admin' and give it the password 'admin'. If you don't, make sure you remember +the values you use. + + +Our Class App +------------- + +We are going to build an *app* to add to our *project*. To start with our app +will be a lot like the Flask app we finished last time. + +.. class:: incremental + +As stated above, an *app* represents a unit within a system, the *project*. We +have a project, we need to create an *app* + + +Create an App +------------- + +This is accomplished using ``manage.py``. + +.. class:: incremental + +In your terminal, make sure you are in the *outer* mysite directory, where the +file ``manage.py`` is located. Then: + +.. class:: incremental + +:: + + (djangoenv)$ python manage.py startapp myblog + + +What is Created +--------------- + +This should leave you with the following structure: + +.. class:: small + +:: + + mysite + ├── manage.py + ├── myblog + │   ├── __init__.py + │   ├── admin.py + │   ├── models.py + │   ├── tests.py + │   └── views.py + └── mysite + ├── __init__.py + ... + +.. class:: incremental + +We'll start by defining the main Python class for our blog system, a ``Post``. + + +Django Models +------------- + +Any Python class in Django that is meant to be persisted *must* inherit from +the Django ``Model`` class. + +.. class:: incremental + +This base class hooks in to the ORM functionality converting Python code to +SQL. + +.. class:: incremental + +You can override methods from the base ``Model`` class to alter how this works +or write new methods to add functionality. + +.. class:: incremental + +Learn more about `models +`_ + + +Our Post Model +-------------- + +Open the ``models.py`` file created in our ``myblog`` package. Add the +following: + +.. code-block:: python + :class: small + + from django.db import models #<-- This is already in the file + from django.contrib.auth.models import User + + class Post(models.Model): + title = models.CharField(max_length=128) + text = models.TextField(blank=True) + author = models.ForeignKey(User) + created_date = models.DateTimeField(auto_now_add=True) + modified_date = models.DateTimeField(auto_now=True) + published_date = models.DateTimeField(blank=True, null=True) + + +Model Fields +------------ + +We've created a subclass of the Django ``Model`` class and added a bunch of +attributes. + +.. class:: incremental + +* These attributes are all instances of ``Field`` classes defined in Django +* Field attributes on a model map to columns in a database table +* The arguments you provide to each Field customize how it works + + * This means *both* how it operates in Django *and* how it is defined in SQL + +* There are arguments shared by all Field types +* There are also arguments specific to individual types + +.. class:: incremental + +You can read much more about `Model Fields and options +`_ + + +Field Details +------------- + +There are some features of our fields worth mentioning in specific: + +.. class:: incremental + +Notice we have no field that is designated as the *primary key* + +.. class:: incremental + +* You *can* make a field the primary key by adding ``primary_key=True`` in the + arguments +* If you do not, Django will **automatically** create one. This field is always + called ``id`` +* No matter what the primary key field is called, its value is always + available on a model instance as the ``pk`` attribute. + + +Field Details +------------- + +.. code-block:: python + :class: small + + title = models.CharField(max_length=128) + +.. class:: incremental + +The required ``max_length`` argument is specific to ``CharField`` fields. + +.. class:: incremental + +It affects *both* the Python and SQL behavior of a field. + +.. class:: incremental + +In python, it is used to *validate* supplied values during *model validation* + +.. class:: incremental + +In SQL it is used in the column definition: ``VARCHAR(128)`` + + +Field Details +------------- + +.. code-block:: python + :class: small + + author = models.ForeignKey(User) + +.. class:: incremental + +Django also models SQL *relationships* as specific field types. + +.. class:: incremental + +The required positional argument is the class of the related Model. + +.. class:: incremental + +By default, the reverse relation is implemented as the attribute +``_set``. + +.. class:: incremental + +You can override this by providing the ``related_name`` argument. + + +Field Details +------------- + +.. code-block:: python + :class: small + + created_date = models.DateTimeField(auto_now_add=True) + modified_date = models.DateTimeField(auto_now=True) + +.. class:: incremental + +``auto_now_add`` is available on all date and time fields. It sets the value +of the field to *now* when an instance is first saved. + +.. class:: incremental + +``auto_now`` is similar, but sets the value anew each time an instance is +saved. + +.. class:: incremental + +Setting either of these will cause the ``editable`` attribute of a field to be +set to ``False``. + + +Field Details +------------- + +.. code-block:: python + :class: small + + text = models.TextField(blank=True) + # ... + published_date = models.DateTimeField(blank=True, null=True) + +.. class:: incremental + +The argument ``blank`` is shared across all field types. The default is +``False`` + +.. class:: incremental + +This argument affects only the Python behavior of a field, determining if the +field is *required* + +.. class:: incremental + +The related ``null`` argument affects the SQL definition of a field: is the +column NULL or NOT NULL + + +Hooking it Up +------------- + +In order to use our new model, we need Django to know about our *app* + +.. class:: incremental + +This is accomplished by configuration in the ``settings.py`` file. + +.. class:: incremental + +Open that file now, in your editor, and find the INSTALLED_APPS setting. + + +Installing Apps +--------------- + +You extend Django functionality by *installing apps*. This is pretty simple: + +.. code-block:: python + :class: small + + INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'myblog', # <- YOU ADD THIS PART + ) + + +Setting Up the Database +----------------------- + +You know what the next step will be: + +.. code-block:: + :class: incremental + + (djangoenv)$ python manage.py syncdb + Creating tables ... + Creating table myblog_post + Installing custom SQL ... + Installing indexes ... + Installed 0 object(s) from 0 fixture(s) + +.. class:: incremental + +Django has now created a table for our model. + +.. class:: incremental + +Notice that the table name is a combination of the name of our app *and* the +name of our model. + + +The Django Shell +---------------- + +Django provides a management command ``shell``: + +.. class:: incremental + +* Shares the same ``sys.path`` as your project, so all installed python + packages are present. +* Imports the ``settings.py`` file from your project, and so shares all + installed apps and other settings. +* Handles connections to your database, so you can interact with live data + directly. + +.. class:: incremental + +Let's explore the Model Instance API directly using this shell: + +.. class:: incremental + +:: + + (djangoenv)$ python manage.py shell + + +Creating Instances +------------------ + +Instances of our model can be created by simple instantiation: + +.. code-block:: python + :class: small + + >>> from myblog.models import Post + >>> p1 = Post(title="My first post", + ... text="This is the first post I've written") + >>> p1 + + +.. container:: incremental + + We can also validate that our new object is okay before we try to save it: + + .. code-block:: python + :class: small + + >>> p1.full_clean() + Traceback (most recent call last): + ... + ValidationError: {'author': [u'This field cannot be null.']} + + +Django Model Managers +--------------------- + +We have to hook our ``Post`` to an author, which must be a ``User``. + +.. class:: incremental + +To do this, we need to have an instance of the ``User`` class. + +.. class:: incremental + +We can use the ``User`` *model manager* to run table-level operations like +``SELECT``: + +.. class:: incremental + +All Django models have a *manager*. By default it is accessed through the +``objects`` class attribute. + + +Making a ForeignKey Relation +---------------------------- + +Let's use the *manager* to get an instance of the ``User`` class: + +.. code-block:: python + :class: small + + >>> from django.contrib.auth.models import User + >>> all_users = User.objects.all() + >>> all_users + [] + >>> u1 = all_users[0] + >>> p1.author = u1 + +.. container:: incremental + + And now our instance should validate properly: + + .. code-block:: python + :class: small + + >>> p1.full_clean() + >>> + + +Saving New Objects +------------------ + +Our model has three date fields, two of which are supposed to be +auto-populated: + +.. class:: python + :class: small + + >>> print(p1.created_date) + None + >>> print(p1.modified_date) + None + +.. container:: incremental + + When we save our post, these fields will get values assigned: + + .. code-block:: python + :class: small + + >>> p1.save() + >>> p1.created_date + datetime.datetime(2013, 7, 26, 20, 2, 38, 104217, tzinfo=) + >>> p1.modified_date + datetime.datetime(2013, 7, 26, 20, 2, 38, 104826, tzinfo=) + + +Updating An Instance +-------------------- + +Models operate much like 'normal' python objects. + +.. container:: incremental + + To change the value of a field, simply set the instance attribute to a new + value. Call ``save()`` to persist the change: + + .. code-block:: python + :class: small + + >>> p1.title = p1.title + " (updated)" + >>> p1.save() + >>> p1.title + 'My first post (updated)' + + +Create a Few Posts +------------------ + +Let's create a few more posts so we can explore the Django model manager query +API: + +.. code-block:: python + :class: small + + >>> p2 = Post(title="Another post", + ... text="The second one created", + ... author=u1).save() + >>> p3 = Post(title="The third one", + ... text="With the word 'heffalump'", + ... author=u1).save() + >>> p4 = Post(title="Posters are great decoration", + ... text="When you are a poor college student", + ... author=u1).save() + >>> Post.objects.count() + 4 + + +The Django Query API +-------------------- + +The *manager* on each model class supports a full-featured query API. + +.. class:: incremental + +API methods take keyword arguments, where the keywords are special +constructions combining field names with field *lookups*: + +.. class:: incremental small + +* title__exact="The exact title" +* text__contains="decoration" +* id__in=range(1,4) +* published_date__lte=datetime.datetime.now() + +.. class:: incremental + +Each keyword argument generates an SQL clause. + + +QuerySets +--------- + +API methods can be divided into two basic groups: methods that return +``QuerySets`` and those that do not. + +.. class:: incremental + +The former may be chained without hitting the database: + +.. code-block:: python + :class: small incremental + + >>> a = Post.objects.all() #<-- no query yet + >>> b = a.filter(title__icontains="post") #<-- not yet + >>> c = b.exclude(text__contains="created") #<-- nope + >>> [(p.title, p.text) for p in c] #<-- This will issue the query + +.. container:: incremental + + Conversely, the latter will issue an SQL query when executed. + + .. code-block:: python + :class: small + + >>> a.count() # immediately executes an SQL query + + +QuerySets and SQL +----------------- + +If you are curious, you can see the SQL that a given QuerySet will use: + +.. code-block:: python + :class: small incremental + + >>> print(c.query) + SELECT "myblog_post"."id", "myblog_post"."title", + "myblog_post"."text", "myblog_post"."author_id", + "myblog_post"."created_date", "myblog_post"."modified_date", + "myblog_post"."published_date" + FROM "myblog_post" + WHERE ("myblog_post"."title" LIKE %post% ESCAPE '\' + AND NOT ("myblog_post"."text" LIKE %created% ESCAPE '\' ) + ) + +.. class:: incremental + +The SQL will vary depending on which DBAPI backend you use (yay ORM!!!) + + +Exploring the QuerySet API +-------------------------- + +See https://docs.djangoproject.com/en/1.6/ref/models/querysets + + +.. code-block:: python + :class: small + + >>> [p.pk for p in Post.objects.all().order_by('created_date')] + [1, 2, 3, 4] + >>> [p.pk for p in Post.objects.all().order_by('-created_date')] + [4, 3, 2, 1] + >>> [p.pk for p in Post.objects.filter(title__contains='post')] + [1, 2, 4] + >>> [p.pk for p in Post.objects.exclude(title__contains='post')] + [3] + >>> qs = Post.objects.exclude(title__contains='post') + >>> qs = qs.exclude(id__exact=3) + >>> [p.pk for p in qs] + [] + >>> qs = Post.objects.exclude(title__contains='post', id__exact=3) + >>> [p.pk for p in qs] + [1, 2, 3, 4] + + +Updating via QuerySets +---------------------- + +You can update all selected objects at the same time. + +.. class:: incremental + +Changes are persisted without needing to call ``save``. + +.. code-block:: python + :class: small incremental + + >>> qs = Post.objects.all() + >>> [p.published_date for p in qs] + [None, None, None, None] + >>> from datetime import datetime + >>> from django.utils.timezone import UTC + >>> utc = UTC() + >>> now = datetime.now(utc) + >>> qs.update(published_date=now) + 4 + >>> [p.published_date for p in qs] + [datetime.datetime(2013, 7, 27, 1, 20, 30, 505307, tzinfo=), + ...] + + +Testing Our Model +----------------- + +As with any project, we want to test our work. Django provides a testing +framework to allow this. + +.. class:: incremental + +Django supports both *unit tests* and *doctests*. I strongly suggest using +*unit tests*. + +.. class:: incremental + +You add tests for your *app* to the file ``tests.py``, which should be at the +same package level as ``models.py``. + +.. class:: incremental + +Locate and open this file in your editor. + + +Django TestCase Classes +----------------------- + +**SimpleTestCase** is for basic unit testing with no ORM requirements + +.. class:: incremental + +**TransactionTestCase** is useful if you need to test transactional +actions (commit and rollback) in the ORM + +.. class:: incremental + +**TestCase** is used when you require ORM access and a test client + +.. class:: incremental + +**LiveServerTestCase** launches the django server during test runs for +front-end acceptance tests. + + +Testing Data +------------ + +Sometimes testing requires base data to be present. We need a User for ours. + +.. class:: incremental + +Django provides *fixtures* to handle this need. + +.. class:: incremental + +Create a directory called ``fixtures`` inside your ``myblog`` app directory. + +.. class:: incremental + +Copy the file ``myblog_test_fixture.json`` from the class resources into this +directory, it contains users for our tests. + + +Setting Up Tests +---------------- + +Now that we have a fixture, we need to instruct our tests to use it. + +.. container:: incremental + + Edit ``tests.py`` (which comes with one test already) to look like this: + + .. code-block:: python + :class: small + + from django.test import TestCase + from django.contrib.auth.models import User + + class PostTestCase(TestCase): + fixtures = ['myblog_test_fixture.json', ] + + def setUp(self): + self.user = User.objects.get(pk=1) + + +Our First Enhancement +--------------------- + +Look at the way our Post represents itself in the Django shell: + +.. code-block:: python + :class: small + + >>> [p for p in Post.objects.all()] + [, , + , ] + +.. class:: incremental + +Wouldn't it be nice if the posts showed their titles instead? + +.. class:: incremental + +In Django, the ``__unicode__`` method is used to determine how a Model +instance represents itself. + +.. class:: incremental + +Then, calling ``unicode(instance)`` gives the desired result. + + +Write The Test +-------------- + +Let's write a test that demonstrates our desired outcome: + +.. code-block:: python + :class: small + + # add this import at the top + from myblog.models import Post + + # and this test method to the PostTestCase + def test_unicode(self): + expected = "This is a title" + p1 = Post(title=expected) + actual = unicode(p1) + self.assertEqual(expected, actual) + + +Run The Test +------------ + +To run tests, use the ``test`` management command + +.. class:: incremental + +Without arguments, it will run all TestCases it finds in all installed *apps* + +.. class:: incremental + +You can pass the name of a single app to focus on those tests + +.. class:: incremental + +Quit your Django shell and in your terminal run the test we wrote: + +.. code-block:: bash + :class: small incremental + + (djangoenv)$ python manage.py test myblog + + +The Result +---------- + +We have yet to implement this enhancement, so our test should fail: + +.. class:: small + +:: + + Creating test database for alias 'default'... + F + ====================================================================== + FAIL: test_unicode (myblog.tests.PostTestCase) + ---------------------------------------------------------------------- + Traceback (most recent call last): + File "/Users/cewing/projects/training/uw_pce/training.python_web/scripts/session07/mysite/myblog/tests.py", line 15, in test_unicode + self.assertEqual(expected, actual) + AssertionError: 'This is a title' != u'Post object' + + ---------------------------------------------------------------------- + Ran 1 test in 0.007s + + FAILED (failures=1) + Destroying test database for alias 'default'... + + +Make it Pass +------------ + +Let's add an appropriate ``__unicode__`` method to our Post class + +.. class:: incremental + +It will take ``self`` as its only argument + +.. class:: incremental + +And it should return its own title as the result + +.. class:: incremental + +Go ahead and take a stab at this in ``models.py`` + +.. code-block:: python + :class: small incremental + + class Post(models.Model): + #... + + def __unicode__(self): + return self.title + + +Did It Work? +------------ + +Re-run the tests to see: + +.. code-block:: bash + :class: small + + (djangoenv)$ python manage.py test myblog + Creating test database for alias 'default'... + . + ---------------------------------------------------------------------- + Ran 1 test in 0.007s + + OK + Destroying test database for alias 'default'... + +.. class:: incremental center + +**YIPEEEE!** + + +What to Test +------------ + +In any framework, the question arises of what to test. Much of your app's +functionality is provided by framework tools. Does that need testing? + +.. class:: incremental + +I *usually* don't write tests covering features provided directly by the +framework. + +.. class:: incremental + +I *do* write tests for functionality I add, and for places where I make +changes to how the default functionality works. + +.. class:: incremental + +This is largely a matter of style and taste (and of budget). + + +More Later +---------- + +We've only begun to test our blog app. + +.. class:: incremental + +We'll be adding many more tests later + +.. class:: incremental + +In between, you might want to take a look at the Django testing documentation: + +.. class:: incremental center + +https://docs.djangoproject.com/en/1.6/topics/testing/ + + +The Django Admin +---------------- + +There are some who believe that Django has been Python's *killer app* + +.. class:: incremental + +And without doubt the Django Admin is a *killer feature* for Django. + +.. class:: incremental + +To demonstrate this, we are going to set up the admin for our blog + + +Using the Admin +--------------- + +The Django Admin is, itself, an *app*, installed by default (as of 1.6). + +.. class:: incremental + +Open the ``settings.py`` file from our ``mysite`` project package and +verify that you see it in the list: + +.. code-block:: python + :class: incremental small + + INSTALLED_APPS = ( + 'django.contrib.admin', # <- already present + # ... + 'django.contrib.staticfiles', # <- already present + 'myblog', # <- already present + ) + + +Accessing the Admin +------------------- + +What we need now is to allow the admin to be seen through a web browser. + +.. class:: incremental + +To do that, we'll have to add some URLs to our project. + + +Django URL Resolution +--------------------- + +Django too has a system for dispatching requests to code: the *urlconf*. + +.. class:: incremental + +* A urlconf is a an iterable of calls to the ``django.conf.urls.url`` function +* This function takes: + + * a regexp *rule*, representing the URL + + * a ``callable`` to be invoked (or a name identifying one) + + * an optional *name* kwarg, used to *reverse* the URL + + * other optional arguments we will skip for now + +* The function returns a *resolver* that matches the request path to the + callable + + +*urlpatterns* +------------- + +I said above that a urlconf is an iterable. + +.. class:: incremental + +That iterable is generally built by calling the ``django.conf.urls.patterns`` +function. + +.. class:: incremental + +It's best to build it that way, but in reality, any iterable will do. + +.. class:: incremental + +However, the name you give this iterable is **not flexible**. + +.. class:: incremental + +Django will load the urlconf named ``urlpatterns`` that it finds in the file +named in ``settings.ROOT_URLCONF``. + + +Including URLs +-------------- + +Many Django add-on *apps*, like the Django Admin, come with their own urlconf + +.. class:: incremental + +It is standard to include these urlconfs by rooting them at some path in your +site. + +.. container:: incremental + + You can do this by using the ``django.conf.urls.include`` function as the + callable in a ``url`` call: + + .. code-block:: python + :class: small + + url(http://github.com/r'%5Eforum/',%20include('random.forum.app.urls')) + + +Including the Admin +------------------- + +We can use this to add *all* the URLs provided by the Django admin in one +stroke. + +.. container:: incremental + + verify the following lines in ``urls.py``: + + .. code-block:: python + :class: small + + from django.contrib import admin #<- make sure these two are + admin.autodiscover() #<- present and uncommented + + urlpatterns = patterns('', + ... + url(http://github.com/r'%5Eadmin/',%20include(admin.site.urls)), #<- and this + ) + + +Using the Development Server +---------------------------- + +We can now view the admin. We'll use the Django development server. + +.. class:: incremental + +In your terminal, use the ``runserver`` management command to start the +development server: + +.. class:: incremental + +:: + + (djangoenv)$ python manage.py runserver + Validating models... + + 0 errors found + Django version 1.4.3, using settings 'mysite.settings' + Development server is running at http://127.0.0.1:8000/ + Quit the server with CONTROL-C. + + +Viewing the Admin +----------------- + +Load ``http://localhost:8000/admin/``. You should see this: + +.. image:: img/django-admin-login.png + :align: center + :width: 50% + +.. class:: incremental + +Login with the name and password you created before. + + +The Admin Index +--------------- + +The index will provide a list of all the installed *apps* and each model +registered. You should see this: + +.. image:: img/admin_index.png + :align: center + :width: 90% + +.. class:: incremental + +Click on ``Users``. Find yourself? Edit yourself, but **don't** uncheck +``superuser``. + + +Add Posts to the Admin +---------------------- + +Okay, let's add our app model to the admin. + +.. class:: incremental + +Find the ``admin.py`` file in the ``myblog`` package. Open it, add the +following and save the file: + +.. code-block:: python + :class: incremental + + from django.contrib import admin # <- this is already there. + from myblog.models import Post + + admin.site.register(Post) + +.. class:: incremental + +Reload the admin index page. + + +Play A Bit +---------- + +Visit the admin page for Posts. You should see the posts we created earlier in +the Django shell. + +.. class:: incremental + +Look at the listing of Posts. Because of our ``__unicode__`` method we see a +nice title. + +.. class:: incremental + +Are there other fields you'd like to see listed? + +.. class:: incremental + +Click on a Post, note what is and is not shown. + + +Next Steps +---------- + +We've learned a great deal about Django's ORM and Models. + +.. class:: incremental + +We've also spent some time getting to know the Query API provided by model +managers and QuerySets. + +.. class:: incremental + +We've also hooked up the Django Admin and noted some shortcomings. + +.. class:: incremental + +In class we'll learn how to put a front end on this, add new models, and +customize the admin experience. + + From 0c1ccfc905cbc4758c347c0cc831ba9f948f603b Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 8 Feb 2014 18:51:25 -0800 Subject: [PATCH 271/487] fix up session 7, gut session 8, move css resource to session 7 resources --- .../{session08 => session07}/django_blog.css | 0 source/presentations/session07.rst | 1559 ++++++++++++++- source/presentations/session08.rst | 1746 +---------------- 3 files changed, 1554 insertions(+), 1751 deletions(-) rename resources/{session08 => session07}/django_blog.css (100%) diff --git a/resources/session08/django_blog.css b/resources/session07/django_blog.css similarity index 100% rename from resources/session08/django_blog.css rename to resources/session07/django_blog.css diff --git a/source/presentations/session07.rst b/source/presentations/session07.rst index 7cfabd08..66bdf5b0 100644 --- a/source/presentations/session07.rst +++ b/source/presentations/session07.rst @@ -5,11 +5,11 @@ Python Web Programming :align: left :width: 50% -Session 7: Introducing Django +Session 7: A Django Application .. class:: intro-blurb right -Wherein we become 'perfectionists with deadlines' +Wherein we build a simple blogging app. .. class:: image-credit @@ -62,7 +62,7 @@ You write the models, it provides the UI .. class:: incremental center -**Really** +You've seen this in action. Pretty neat, eh? The Pareto Principle @@ -145,48 +145,1593 @@ that documentation for every commit **this is awesome** +Where We Stand +-------------- -DEPARTING FROM SCRIPT +For your homework this week, you created a ``Post`` model to serve as the heart +of our blogging app. + +.. class:: incremental + +You also took some time to get familiar with the basic workings of the Django +ORM. + +.. class:: incremental + +You made a minor modification to our model class and wrote a test for it. + +.. class:: incremental + +And you installed the Django Admin site and added your app to it. + + +Going Further +------------- + +One of the most common features in a blog is the ability to categorize posts. + +.. class:: incremental + +Let's add this feature to our blog! + +.. class:: incremental + +To do so, we'll be adding a new model, and making some changes to existing code. + +.. class:: incremental + +This means that we'll need to *change our database schema*. + + +Changing a Database +------------------- + +You've seen how to add new tables to a database using the ``syncdb`` command. + +.. class:: incremental + +The ``syncdb`` management command only creates tables that *do not yet exist*. +It **does not update tables**. + +.. class:: incremental + +The ``sqlclear `` command will print the ``DROP TABLE`` statements to +remove the tables for your app. + +.. class:: incremental + +Or ``sql `` will show the ``CREATE TABLE`` statements, and you can work +out the differences and update manually. + +ACK!!! +------ + +That doesn't sound very nice, does it? + +.. class:: incremental + +Luckily, there is an app available for Django that helps with this: ``South`` + +.. class:: incremental + +South allows you to incrementally update your database in a simplified way. + +.. class:: incremental + +South supports forward, backward and data migrations. + +.. class:: incremental + + +Adding South +------------ + +South is so useful, that in Django 1.7 it will become part of the core +distribution of Django. + +.. class:: incremental + +But now it is not. We need to add it, and set up our project to use it. + +.. class:: incremental + +Activate your django virtualenv and install South: + +.. code-block:: bash + + $ source djagnoenv/bin/activate + (djangoenv)$ pip install south + ... + Successfully installed south + Cleaning up... + + +Installing South +---------------- + +Like other Django apps, South provides models of its own. We need to enable them. + +.. container:: incremental + + First, add ``south`` to your list of installed apps in ``settings.py``: + + .. code-block:: python + + INSTALLED_APPS = ( + ... + 'south', #< -add this line + 'myblog', + ) + + +Setting Up South +---------------- + +Then, run ``syncdb`` to pick up the tables it provides: + +.. code-block:: bash + + (djangoenv)$ python manage.py syncdb + Syncing... + Creating tables ... + Creating table south_migrationhistory + ... + + Synced: + ... + > south + > myblog + + Not synced (use migrations): + - + (use ./manage.py migrate to migrate these) + + +Hang On, What Just Happened? +---------------------------- + +You might have noticed that the output from ``syncdb`` looks a bit different +this time. + +.. class:: incremental + +This is because Django apps that use South do not use the normal ``syncdb`` +command to initialize their SQL. + +.. class:: incremental + +Instead they use a new command that South provides: ``migrate``. + +.. class:: incremental + +This command ensures that only incremental changes are made, rather than +creating all of the SQL for an app every time. + + +Adding South to an App +---------------------- + +If you notice, our ``myblog`` app is still in the ``sync`` list. We need to add +South to it. + +.. class:: incremental + +Adding South to an existing Django project is quite simple. The trick is to do +it **before** you make any new changes to your models. + +.. container:: incremental + + Simply use the ``convert_to_south`` management command, providing the name of + your app as an argument: + + .. code-block:: bash + + (djangoenv)$ python manage.py convert_to_south myblog + ... + + +What You Get +------------ + +After running this command, South will automatically create a first migration +for you that sets up tables looking exactly like what your app has now:: + + myblog/ + ├── __init__.py + ... + ├── migrations + │   ├── 0001_initial.py + │   ├── 0001_initial.pyc + │   ├── __init__.py + │   └── __init__.pyc + ├── models.py + ... + +.. class:: incremental + +South also automatically applies this first migration using the ``--fake`` +argument, since the database is already in the proposed state. + + +Adding a Model +-------------- + +We want to add a new model to represent the categories our blog posts might +fall into. + +.. class:: incremental + +This model will need to have a name for the category, a longer description and +will need to be related to the Post model. + +.. code-block:: python + :class: small + + # in models.py + class Category(models.Model): + name = models.CharField(max_length=128) + description = models.TextField(blank=True) + posts = models.ManyToManyField(Post, blank=True, null=True, + related_name='categories') + + +Strange Relationships +--------------------- + +In our ``Post`` model, we used a ``ForeignKeyField`` field to match an author +to her posts. + +.. class:: incremental + +This models the situatin in which a single author can have many posts, while +each post has only one author. + +.. class:: incremental + +But any given ``Post`` might belong in more than one ``Category``. + +.. class:: incremental + +And it would be a waste to allow only one ``Post`` for each ``Category``. + +.. class:: incremental + +Enter the ManyToManyField + + +Add a Migration +--------------- + +To get these changes set up, we now have to add a migration. + +.. class:: incremental + +We use the ``schemamigration`` management command to do so: + +.. code-block:: bash + + (djangoenv)$ python manage.py schemamigration myblog --auto + + Added model myblog.Category + + Added M2M table for posts on myblog.Category + Created 0002_auto__add_category.py. You can now apply this + migration with: ./manage.py migrate myblog + + +Apply A Migration +----------------- + +And south, along with making the migration, helpfully tells us what to do next: + +.. code-block:: bash + + (djangoenv)$ python manage.py migrate myblog + Running migrations for myblog: + - Migrating forwards to 0002_auto__add_category. + > myblog:0002_auto__add_category + - Loading initial data for myblog. + Installed 0 object(s) from 0 fixture(s) + +.. class:: incremental + +You can even look at the migration file you just applied, +``myblog/migrations/0002.py`` to see what happened. + + +Make Categories Look Nice +------------------------- + +Let's make ``Category`` object look nice the same way we did with ``Post``. +Start with a test: + +.. container:: incremental + + add this to ``tests.py``: + + .. code-block:: python + :class: incremental + + # another import + from myblog.models import Category + + # and the test case and test + class CategoryTestCase(TestCase): + + def test_unicode(self): + expected = "A Category" + c1 = Category(name=expected) + actual = unicode(c1) + self.assertEqual(expected, actual) + +Make it Pass +------------ + +Do you remember how you made that change for a ``Post``? + +.. code-block:: python + :class: incremental + + class Category(models.Model): + #... + + def __unicode__(self): + return self.name + + +Admin for Categories +-------------------- + +Adding our new model to the Django admin is equally simple. + +.. container:: incremental + + Simply add the following line to ``myblog/admin.py`` + + .. code-block:: python + + # a new import + from myblog.models import Category + + # and a new admin registration + admin.site.register(Category) + + +Test It Out +----------- + +Fire up the Django development server and see what you have in the admin: + +.. code-block:: bash + + (djangoenv)$ python manage.py runserver + Validating models... + ... + Starting development server at http://127.0.0.1:8000/ + Quit the server with CONTROL-C. + +.. class:: incremental + +Point your browser at ``http://localhost:8000/admin/``, log in and play. + +.. class:: incremental + +Add a few categories, put some posts in them. Visit your posts, add new ones +and then categorize them. + + +A Public Face +------------- + +Point your browser at http://localhost:8000/ + +.. class:: incremental + +What do you see? + +.. class:: incremental + +Why? + +.. class:: incremental + +We need to add some public pages for our blog. + +.. class:: incremental + +In Django, the code that builds a page that you can see is called a *view*. + +Django Views +------------ + +A *view* can be defined as a *callable* that takes a request and returns a +response. + +.. class:: incremental + +This should sound pretty familiar to you. + +.. class:: incremental + +Classically, Django views were functions. + +.. class:: incremental + +Version 1.3 added support for Class-based Views (a class with a ``__call__`` +method is a callable) + + +A Basic View +------------ + +Let's add a really simple view to our app. + +.. class:: incremental + +It will be a stub for our public UI. Add this to ``views.py`` in ``myblog`` + +.. code-block:: python + :class: small incremental + + from django.http import HttpResponse, HttpResponseRedirect, Http404 + + def stub_view(request, *args, **kwargs): + body = "Stub View\n\n" + if args: + body += "Args:\n" + body += "\n".join(["\t%s" % a for a in args]) + if kwargs: + body += "Kwargs:\n" + body += "\n".join(["\t%s: %s" % i for i in kwargs.items()]) + return HttpResponse(body, content_type="text/plain") + + +Hooking It Up +------------- + +In your homework tutorial, you learned about Django **urlconfs** + +.. class:: incremental + +We used our project urlconf to hook the Django admin into our project. + +.. class:: incremental + +We want to do the same thing for our new app. + +.. class:: incremental + +In general, an *app* that serves any sort of views should contain its own +urlconf. + +.. class:: incremental + +The project urlconf should mainly *include* these where possible. + + +Adding A Urlconf +---------------- + +Create a new file ``urls.py`` inside the ``myblog`` app package. + +.. container:: incremental + + Open it in your editor and add the following code: + + .. code-block:: python + :class: small + + from django.conf.urls import patterns, url + + urlpatterns = patterns('myblog.views', + url(r'^$', + 'stub_view', + name="blog_index"), + ) + + +A Word On Prefixes +------------------ + +The ``patterns`` function takes a first argument called the *prefix* + +.. class:: incremental + +When it is not empty, it is added to any view names in ``url()`` calls in the +same ``patterns``. + +.. class:: incremental + +In a root urlconf like the one in ``mysite``, this isn't too useful + +.. class:: incremental + +But in ``myblog.urls`` it lets us refer to views by simple function name + +.. class:: incremental + +No need to import every view. + + +Include Blog Urls +----------------- + +In order for our new urls to load, we'll need to include them in our project +urlconf + +.. container:: incremental + + Open ``urls.py`` from the ``mysite`` project package and add this: + + .. code-block:: python + :class: small + + urlpatterns = patterns('', + url(http://github.com/r'%5E',%20include('myblog.urls')), #<- add this + #... other included urls + ) + +.. class:: incremental + +Try reloading http://localhost:8000/ + +.. class:: incremental + +You should see some output now. + + +Project URL Space +----------------- + +A project is defined by the urls a user can visit. + +.. class:: incremental + +What should our users be able to see when they visit our blog? + +.. class:: incremental + +* A list view that shows blog posts, most recent first. +* An individual post view, showing a single post (a permalink). + +.. class:: incremental + +Let's add urls for each of these, use the stub view for now. + + +Our URLs +-------- + +We've already got a good url for the list page: ``blog_index`` at '/' + +.. container:: incremental + + For the view of a single post, we'll need to capture the id of the post. + Add this to ``urlpatterns`` in ``myblog/urls.py``: + + .. code-block:: python + :class: small incremental + + url(http://github.com/r'%5Eposts/(/d+)/$', + 'stub_view', + name="blog_detail"), + +.. class:: incremental + +``(\d+)`` captures one or more digits as the post_id. + +.. class:: incremental + +Load http://localhost:8000/posts/1234/ and see what you get. + + +A Word on Capture in URLs +------------------------- + +When you load the above url, you should see ``1234`` listed as an *arg* + +.. container:: incremental + + Try changing the route like so: + + .. code-block:: python + :class: small + + r'^posts/(?P\d+)/$' + +.. class:: incremental + +Reload the same url. Notice the change. + + +Regular Expression URLS +----------------------- + +Django, unlike Flask, uses Python regular expressions to build routes. + +.. class:: incremental + +When we built our WSGI book app, we did too. + +.. class:: incremental + +There we learned about regular expression *capture groups*. We just changed an +unnamed group to a named one. + +.. class:: incremental + +How you declare a capture group in your url pattern regexp influences how it +will be passed to the view callable. + + +Full Urlconf +------------ + +.. code-block:: python + :class: small + + from django.conf.urls import patterns, url + + urlpatterns = patterns('myblog.views', + url(r'^$', + 'stub_view', + name="blog_index"), + url(http://github.com/r'%5Eposts/(?P%3Cpost_id%3E\d+)/$', + 'stub_view', + name="blog_detail"), + ) + + +Testing Views +------------- + +Before we begin writin real views, we need to add some tests for the views we +are about to create. + +.. class:: incremental + +We'll need tests for a list view and a detail view + +.. container:: incremental + + add the following *imports* at the top of ``myblog/tests.py``: + + .. code-block:: python + + import datetime + from django.utils.timezone import utc + + +Add a Test Case +--------------- + +.. code-block:: python + :class: small + + class FrontEndTestCase(TestCase): + """test views provided in the front-end""" + fixtures = ['myblog_test_fixture.json', ] + + def setUp(self): + self.now = datetime.datetime.utcnow().replace(tzinfo=utc) + self.timedelta = datetime.timedelta(15) + author = User.objects.get(pk=1) + for count in range(1,11): + post = Post(title="Post %d Title" % count, + text="foo", + author=author) + if count < 6: + # publish the first five posts + pubdate = self.now - self.timedelta * count + post.published_date = pubdate + post.save() + + +Our List View +------------- + +We'd like our list view to show our posts. + +.. class:: incremental + +But in this blog, we have the ability to publish posts. + +.. class:: incremental + +Unpublished posts should not be seen in the front-end views. + +.. class:: incremental + +We set up our tests to have 5 published, and 5 unpublished posts + +.. class:: incremental + +Let's add a test to demonstrate that the right ones show up. + + +Testing the List View --------------------- +.. code-block:: python + + Class FrontEndTestCase(TestCase): # already here + # ... + def test_list_only_published(self): + resp = self.client.get('/') + self.assertTrue("Recent Posts" in resp.content) + for count in range(1,11): + title = "Post %d Title" % count + if count < 6: + self.assertContains(resp, title, count=1) + else: + self.assertNotContains(resp, title) + +.. class:: incremental + +Note that we also test to ensure that the unpublished posts are *not* visible. + + +Run Your Tests +-------------- + +.. code-block:: bash + + (djangoenv)$ python manage.py test myblog + Creating test database for alias 'default'... + .F. + ====================================================================== + FAIL: test_list_only_published (myblog.tests.FrontEndTestCase) + ... + Ran 3 tests in 0.024s + + FAILED (failures=1) + Destroying test database for alias 'default'... + + +Now Fix That Test! +------------------ + +Add the view for listing blog posts to ``views.py``. + +.. code-block:: python + :class: small + + # add these imports + from django.template import RequestContext, loader + from myblog.models import Post + + # and this view + def list_view(request): + published = Post.objects.exclude(published_date__exact=None) + posts = published.order_by('-published_date') + template = loader.get_template('list.html') + context = RequestContext(request, { + 'posts': posts, + }) + body = template.render(context) + return HttpResponse(body, content_type="text/html") + + +Getting Posts +------------- + +.. code-block:: python + :class: small + + published = Post.objects.exclude(published_date__exact=None) + posts = published.order_by('-published_date') + +.. class:: incremental + +We begin by using the QuerySet API to fetch all the posts that have +``published_date`` set + +.. class:: incremental + +Using the chaining nature of the API we order these posts by +``published_date`` + +.. class:: incremental + +Remember, at this point, no query has actually been issued to the database. + + +Getting a Template +------------------ + +.. code-block:: python + :class: small + + template = loader.get_template('list.html') + +.. class:: incremental + +Django uses configuration to determine how to find templates. + +.. class:: incremental + +By default, Django looks in installed *apps* for a ``templates`` directory + +.. class:: incremental + +It also provides a place to list specific directories. + +.. class:: incremental + +Let's set that up in ``settings.py`` + + +Project Templates +----------------- + +In ``settings.py`` add ``TEMPLATE_DIRS`` and add the absolute path to your +``mysite`` project package: + +.. code-block:: python + :class: small + + TEMPLATE_DIRS = ('/absolute/path/to/mysite/mysite/templates', ) + +.. class:: incremental + +Then add a ``templates`` directory to your ``mysite`` project package + +.. class:: incremental + +Finally, in that directory add a new file ``base.html`` and populate it with +the following: + + +base.html +--------- + +.. code-block:: jinja + :class: small + + + + + My Django Blog + + +

    +
    + {% block content %} + [content will go here] + {% endblock %} +
    +
    + + + + +Templates in Django +------------------- + +Before we move on, a quick word about Django templates. + +.. class:: incremental + +We've seen Jinja2 which was "inspired by Django's templating system". + +.. class:: incremental + +Basically, you already know how to write Django templates. + +.. class:: incremental + +Django templates **do not** allow any python expressions. + +.. class:: incremental center small + +https://docs.djangoproject.com/en/1.5/ref/templates/builtins/ + + +Blog Templates +-------------- + +Our view tries to load ``list.html``. + +.. class:: incremental + +This template is probably specific to the blog functionality of our site + +.. class:: incremental + +It is common to keep shared templates in your project directory and +specialized ones in app directories. + +.. class:: incremental + +Add a ``templates`` directory to your ``myblog`` app, too. + +.. class:: incremental + +In it, create a new file ``list.html`` and add this: + + +list.html +--------- + +.. code-block:: jinja + :class: tiny + + {% extends "base.html" %} + + {% block content %} +

    Recent Posts

    + + {% comment %} here is where the query happens {% endcomment %} + {% for post in posts %} +
    +

    {{ post }}

    + +
    + {{ post.text }} +
    +
      + {% for category in post.categories.all %} +
    • {{ category }}
    • + {% endfor %} +
    +
    + {% endfor %} + {% endblock %} + + +Template Context +---------------- + +.. code-block:: python + :class: small + + context = RequestContext(request, { + 'posts': posts, + }) + body = template.render(context) + +.. class:: incremental + +Like Jinja2, django templates are rendered by passing in a *context* + +.. class:: incremental + +Django's RequestContext provides common bits, similar to the global context in +Flask + +.. class:: incremental + +We add our posts to that context so they can be used by the template. +Return a Response +----------------- +.. code-block:: python + :class: small + return HttpResponse(body, content_type="text/html") +.. class:: incremental + +Finally, we build an HttpResponse and return it. + +.. class:: incremental + +This is, fundamentally, no different from the ``stub_view`` just above. + + +Fix URLs +-------- + +We need to fix the url for our blog index page + +.. container:: incremental + + Update ``urls.py`` in ``myblog``: + + .. code-block:: python + :class: small + + url(r'^$', + 'list_view', + name="blog_index"), + +.. class:: incremental small + +:: + + (djangoenv)$ python manage.py test myblog + ... + Ran 3 tests in 0.033s + + OK + + +Common Patterns +--------------- + +This is a common pattern in Django views: + +.. class:: incremental + +* get a template from the loader +* build a context, usually using a RequestContext +* render the template +* return an HttpResponse + +.. class:: incremental + +So common in fact that Django provides two shortcuts for us to use: + +.. class:: incremental + +* ``render(request, template[, ctx][, ctx_instance])`` +* ``render_to_response(template[, ctx][, ctx_instance])`` + + +Shorten Our View +---------------- + +Let's replace most of our view with the ``render`` shortcut + +.. code-block:: python + :class: small + + from django.shortcuts import render # <- already there + + # rewrite our view + def list_view(request): + published = Post.objects.exclude(published_date__exact=None) + posts = published.order_by('-published_date') + context = {'posts': posts} + return render(request, 'list.html', context) + +.. class:: incremental + +Remember though, all we did manually before is still happening + + +Our Detail View +--------------- + +Next, let's add a view function for the detail view of a post + +.. class:: incremental + +It will need to get the ``id`` of the post to show as an argument + +.. class:: incremental + +Like the list view, it should only show published posts + +.. class:: incremental + +But unlike the list view, it will need to return *something* if an unpublished +post is requested. + +.. class:: incremental + +Let's start with the tests in ``views.py`` + + +Testing the Details +------------------- + +Add the following test to our ``FrontEndTestCase`` in ``myblog/tests.py``: + +.. code-block:: python + :class: small incremental + + def test_details_only_published(self): + for count in range(1,11): + title = "Post %d Title" % count + post = Post.objects.get(title=title) + resp = self.client.get('/posts/%d/' % post.pk) + if count < 6: + self.assertEqual(resp.status_code, 200) + self.assertContains(resp, title) + else: + self.assertEqual(resp.status_code, 404) + + +Run Your Tests +-------------- + +.. code-block:: bash + + (djangoenv)$ python manage.py test myblog + Creating test database for alias 'default'... + .F.. + ====================================================================== + FAIL: test_details_only_published (myblog.tests.FrontEndTestCase) + ... + Ran 4 tests in 0.043s + + FAILED (failures=1) + Destroying test database for alias 'default'... + + +Let's Fix That Test +------------------- + +Now, add a new view to ``myblog/views.py``: + +.. code-block:: python + :class: incremental small + + def detail_view(request, post_id): + published = Post.objects.exclude(published_date__exact=None) + try: + post = published.get(pk=post_id) + except Post.DoesNotExist: + raise Http404 + context = {'post': post} + return render(request, 'detail.html', context) + + +Missing Content +--------------- + +One of the features of the Django ORM is that all models raise a DoesNotExist +exception if ``get`` returns nothing. + +.. class:: incremental + +This exception is actually an attribute of the Model you look for. There's also +an ``ObjectDoesNotExist`` for when you don't know which model you have. + +.. class:: incremental + +We can use that fact to raise a Not Found exception. + +.. class:: incremental + +Django will handle the rest for us. +Add the Template +---------------- + +We also need to add ``detail.html`` to ``myblog/templates``: +.. code-block:: jinja + :class: tiny + {% extends "base.html" %} + {% block content %} + Home +

    {{ post }}

    + +
    + {{ post.text }} +
    +
      + {% for category in post.categories.all %} +
    • {{ category }}
    • + {% endfor %} +
    + {% endblock %} -Break Time + +Hook it Up ---------- -.. class:: big-centered +In order to view a single post, we'll need a link from the list view + +.. container:: incremental + + We can use the ``url`` template tag (like flask ``url_for``): + + .. code-block:: jinja + :class: small + + {% url '' arg1 arg2 %} + +.. class:: incremental + +In our ``list.html`` template, let's link the post titles: + +.. code-block:: jinja + :class: small incremental + + {% for post in posts %} +
    +

    + {{ post }} +

    + ... + + +Fix URLs +-------- + +Again, we need to insert our new view into the existing ``myblog/urls.py`` in +``myblog``: + +.. code-block:: python + :class: small + + url(http://github.com/r'%5Eposts/(?P%3Cpost_id%3E\d+)/$', + 'detail_view', + name="blog_detail"), + +.. class:: incremental small + +:: + + (djangoenv)$ python manage.py test myblog + ... + Ran 4 tests in 0.077s + + OK + + +A Moment To Play +---------------- + +We've got some good stuff to look at now. Fire up the server + +.. class:: incremental + +Reload your blog index page and click around a bit. + +.. class:: incremental + +You can now move back and forth between list and detail view. + +.. class:: incremental + +Try loading the detail view for a post that doesn't exist + + +Congratulations +--------------- + +You've got a functional Blog + +.. class:: incremental + +It's not very pretty, though. + +.. class:: incremental + +We can fix that by adding some css + +.. class:: incremental + +This gives us a chance to learn about Django's handling of *static files* + + +Static Files +------------ + +Like templates, Django expects to find static files in particular locations + +.. class:: incremental + +It will look for them in a directory named ``static`` in any installed apps. + +.. class:: incremental + +They will be served from the url path in the STATIC_URL setting. + +.. class:: incremental + +By default, this is ``/static/`` + + +Add CSS +------- + +I've prepared a css file for us to use. You can find it in the class resources + +.. class:: incremental + +Create a new directory ``static`` in the ``myblog`` app. + +.. class:: incremental + +Copy the ``django_css`` file into that new directory. + +.. container:: incremental + + Then add this link to the of ``base.html``: + + .. code-block:: html + :class: small + + My Django Blog + + + +View Your Results +----------------- + +Reload http://localhost:8000/ and view the results of your work + +.. class:: incremental + +We now have a reasonable view of the posts of our blog on the front end + +.. class:: incremental + +And we have a way to create and categorize posts using the admin + +.. class:: incremental + +However, we lack a way to move between the two. + +.. class:: incremental + +Let's add that ability next. + + +Adding A Control Bar +-------------------- + +We'll start by adding a control bar to our ``base.html`` template: + +.. code-block:: jinja + :class: small + + + ... + +
    + ... + + +Request Context Revisited +------------------------- + +When we set up our views, we used the ``render`` shortcut, which provides a +``RequestContext`` + +.. class:: incremental + +This gives us access to ``user`` in our templates + +.. class:: incremental + +It provides access to methods about the state and rights of that user + +.. class:: incremental + +We can use these to conditionally display links or UI elements. Like only +showing the admin link to staff members. + + +Login/Logout +------------ + +Django also provides a reasonable set of views for login/logout. + +.. class:: incremental + +The first step to using them is to hook them into a urlconf. + +.. container:: incremental + + Add the following to ``mysite/urls.py``: + + .. code-block:: python + :class: small + + url(http://github.com/r'%5E',%20include('myblog.urls')), #<- already there + url(r'^login/$', + 'django.contrib.auth.views.login', + {'template_name': 'login.html'}, + name="login"), + url(r'^logout/$', + 'django.contrib.auth.views.logout', + {'next_page': '/'}, + name="logout"), + + +Login Template +-------------- + +We need to create a new ``login.html`` template in ``mysite/templates``: -Let's take a break here and return in 10 minutes. +.. code-block:: jinja + :class: small + {% extends "base.html" %} + {% block content %} +

    My Blog Login

    +
    {% csrf_token %} + {{ form.as_p }} +

    +
    + {% endblock %} +Submitting Forms +---------------- + +In a web application, submitting forms is potentially hazardous + +.. class:: incremental + +Data is being sent to our application from some remote place + +.. class:: incremental + +If that data is going to alter the state of our application, we **must** use +POST + +.. class:: incremental + +Even so, we are vulnerable to Cross-Site Request Forgery, a common attack +vector. + + +Danger: CSRF +------------ + +Django provides a convenient system to fight this. + +.. class:: incremental + +In fact, for POST requests, it *requires* that you use it. + +.. class:: incremental + +The Django middleware that does this is enabled by default. + +.. class:: incremental + +All you need to do is include the ``{% csrf_token %}`` tag in your form. + + +Hooking It Up +------------- + +In ``base.html`` make the following updates: + +.. code-block:: jinja + :class: small + + + admin + + logout + + login + +.. container:: incremental + + Finally, in ``settings.py`` add the following: + + .. code-block:: python + :class: small + + LOGIN_URL = '/login/' + LOGIN_REDIRECT_URL = '/' + +Forms In Django +--------------- +In adding a login view, we've gotten a sneak peak at how forms work in Django. +.. class:: incremental + +However, learning more about them is beyond what we can achieve in this +session. + +.. class:: incremental + +The form system in Django is quite nice, however. I urge you to `read more about it`_ + +.. _read more about it: https://docs.djangoproject.com/en/1.6/topics/forms/ + +.. class:: incremental + +In particular, you might want to pay attention to the documentation on `Model Forms` + +.. _Model Forms: https://docs.djangoproject.com/en/1.6/topics/forms/modelforms/ + + +Ta-Daaaaaa! +----------- + +So, that's it. We've created a workable, simple blog app in Django. + +.. class:: incremental + +There's much more we could do with this app. And for homework, you'll do some +of it. + +.. class:: incremental + +Then next session, we'll work as we did in session 6. + +.. class:: incremental + +We'll divide up into pairs, and implement a simple feature to extend our blog. + + +Homework +-------- + +For your homework this week, we'll fix one glaring problem with our blog admin. + +.. class:: incremental + +As you created new categories and posts, and related them to each-other, how +did you feel about that work? + +.. class:: incremental + +Although from a data perspective, the category model is the right place for the +ManytoMany relationship to posts, this leads to awkward usage in the admin. + +.. class:: incremental +It would be much easier if we could designate a category for a post *from the +Post admin*. +Your Assignment +--------------- +You'll be reversing that editing relationship so that you can add categories to +posts, and cannot choose posts from categories. +Take the following steps: +1. Read the documentation about the `Django admin.`_ +2. You'll need to create a customized `ModelAdmin`_ class for the ``Post`` and + ``Category`` models. +3. And you'll need to create an `InlineModelAdmin`_ to represent Categories on + the Post admin view. +4. Finally, you'll need to `suppress the display`_ of the 'posts' field on + your ``Category`` admin view. +.. _Django admin.: https://docs.djangoproject.com/en/1.6/ref/contrib/admin/ +.. _ModelAdmin: https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#modeladmin-objects +.. _InlineModelAdmin: https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#inlinemodeladmin-objects +.. _suppress the display: https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#modeladmin-options +Pushing Further +--------------- +All told, those changes should not require more than about 15 total lines of +code. +The trick of course is reading and finding out which fifteen lines to write. +If you complete that task in less than 3-4 hours of work, consider looking into +other ways of customizing the admin. +Tasks you might consider: +* Change the admin index to say 'Categories' instead of 'Categorys'. +* Add columns for the date fields to the list display of Posts. +* Display the created and modified dates for your posts when viewing them in + the admin. +* Add a column to the list display of Posts that shows the author. For more + fun, make this a link that takes you to the admin page for that user. +* For the biggest challenge, look into `admin actions`_ and add an action to + the Post admin that allows you to bulk publish posts from the Post list + display +.. _admin actions: https://docs.djangoproject.com/en/1.6/ref/contrib/admin/actions/ diff --git a/source/presentations/session08.rst b/source/presentations/session08.rst index ffa6f7ef..da9e0ad3 100644 --- a/source/presentations/session08.rst +++ b/source/presentations/session08.rst @@ -5,1756 +5,14 @@ Internet Programming with Python :align: left :width: 50% -Session 8: A Django Application +Session 8: Extending Django .. class:: intro-blurb right -Wherein we complete our Django blog app. +Wherein we extend our Django blog app. .. class:: image-credit image: http://djangopony.com/ -Where We Stand --------------- - -We've created a couple of models, Post and Category, that make up our blog -app. - -.. class:: incremental - -We've taken some time to get familiar with the basic workings of the Django -ORM. - -.. class:: incremental - -We've made a minor modification to our model classes and written tests for it. - -.. class:: incremental - -And we've installed the Django Admin site and added our app to it. - - -Customizing the Admin ---------------------- - -We have noted, however, that the admin isn't exactly right for our needs. - -.. class:: incremental - -* Listing of posts should show created, modified and published dates -* Listing of posts should show the author of a post, with a link to the author -* It should be possible to add a post to a category while creating or editing - it - -.. class:: incremental small center - -https://docs.djangoproject.com/en/1.5/ref/contrib/admin/ - - -The ModelAdmin Class --------------------- - -Open ``admin.py`` from your ``myblog`` package. - -.. class:: incremental - -* The ``admin.site`` is a globally available instance of the ``Admin`` class. -* It is initialized at runtime automatically. -* It stores a registry of the models that are registered with it. -* Each call to ``admin.site.register`` adds a new model to the global *site*. -* ``register`` takes two args: a *Model* subclass and an optional *ModelAdmin* subclass -* If you call it without the optional subclass, you get the default. - -.. class:: incremental - -Most usable admin functions are provided by the ModelAdmin. - - -Custom ModelAdmin ------------------ - -Our first task is to list date and author information. - -.. container:: incremental - - In ``admin.py`` add the following code (): - - .. code-block:: python - :class: small - - # this is new - class PostAdmin(admin.ModelAdmin): - list_display = ('__unicode__', 'created_date', 'modified_date', - 'published_date', 'author') - - admin.site.register(Post, PostAdmin) #<- update this registration - -.. class:: incremental - -Let's see what that did. - - -View The Results ----------------- - -If you haven't already, activate your virtualenv then fire up the development -server: - -:: - - (djangoenv)$ python manage.py runserver - -.. class:: incremental - -Load http://localhost:8000/admin and click through to the Post admin. - -.. class:: incremental - -Pretty simple, eh? - - -List Display ------------- - -A Couple of things about the ``list_display`` option are important to know: - -.. class:: incremental - -* The value you provide must be an iterable even if it has only one item -* Each item in the iterable becomes a column in the list -* The first item is the one that links to the change page for that object - - * That can be customized by the ``list_display_links`` option - -* Listed items can be field names or callables. - -* Callables can be module-level functions, or methods on the ModelAdmin or - Model - - -A Better Author Listing ------------------------ - -Let's use this last bit to fix the author listing. - -.. class:: incremental - -We'll need functionality that provides: - -.. class:: incremental - -* The full name of the author, if present, otherwise the username. -* A link to the admin change form for that author. - -.. class:: incremental - -Where should this go? Module? ModelAdmin? Model? - -.. class:: incremental - -* The first could be useful in public listings -* The second is really only useful on the backend - - -Add Tests ---------- - -In ``tests.py`` add the following test: - -.. code-block:: python - :class: small - - class PostTestCase(TestCase): - #... - def test_author_name(self): - for author in User.objects.all(): - fn, ln, un = (author.first_name, - author.last_name, - author.username) - author_name = Post(author=author).author_name() - if not (fn and ln): - self.assertEqual(author_name, un) - else: - if fn: - self.assertTrue(fn in author_name) - if ln: - self.assertTrue(ln in author_name) - - -Add Tests ---------- - -To test the admin, we'll first need a new TestClass: - -.. code-block:: python - :class: small - - # new imports - from django.contrib.admin.sites import AdminSite - from myblog.admin import PostAdmin - - # new TestCase - class PostAdminTestCase(TestCase): - fixtures = ['myblog_test_fixture.json', ] - - def setUp(self): - admin = AdminSite() - self.ma = PostAdmin(Post, admin) - for author in User.objects.all(): - title = "%s's title" % author.username - post = Post(title=title, author=author) - post.save() - - -Add Tests ---------- - -And then we need a test added to it: - -.. code-block:: python - :class: small - - def test_author_link(self): - expected_link_path = '/admin/auth/user/%s' - for post in Post.objects.all(): - expected = expected_link_path % post.author.pk - actual = self.ma.author_link(post) - self.assertTrue(expected in actual) - -.. container:: incremental - - Quit the django server and run your tests: - - .. class:: small - - :: - - (djangoenv)$ python manage.py test myblog - ... - Ran 4 tests in 0.026s - FAILED (errors=2) - - -Make Them Pass --------------- - -First, add the ``author_name`` method to our Post model in ``models.py``: - -.. code-block:: python - :class: small - - def author_name(self): - raw_name = "%s %s" % (self.author.first_name, - self.author.last_name) - name = raw_name.strip() - if not name: - name = self.author.username - return name - -.. class:: small incremental - -:: - - (djangoenv)$ python manage.py test myblog - ... - Ran 4 tests in 0.027s - FAILED (errors=1) - - -Make Them Pass --------------- - -Finally, add the ``author_link`` method to the PostAdmin in ``admin.py``: - -.. code-block:: python - :class: small - - # add an import - from django.core.urlresolvers import reverse - - # and a method - class PostAdmin(admin.ModelAdmin): - #... - def author_link(self, post): - url = reverse('admin:auth_user_change', args=(post.id,)) - name = post.author_name() - return '%s' % (url, name) - -.. class:: small incremental - -:: - - (djangoenv)$ python manage.py test myblog - ...Ran 4 tests in 0.035s - OK - - -Hook It Up ----------- - -First, replace the ``'author'`` name in ``list_display`` with -``'author_link'``: - -.. code-block:: python - :class: small - - list_display = (..., 'author_link') - -.. container:: incremental - - We also need to let the admin know our HTML is safe: - - .. code-block:: python - :class: small - - def author_link(self, post): - #... method body - author_link.allow_tags = True - - -Wait, What?? ------------- - -In Python, *everything* is an object. Even methods of classes. - -.. class:: incremental - -The Django admin uses special *method attributes* to control the methods you -create for ``list_display``. - -.. container:: incremental - - Another special attribute controls the column title used in the list page: - - .. code-block:: python - :class: small - - def author_link(self, post): - #... method body - author_link.allow_tags = True - author_link.short_description = "Author" #<- add this - - -See The Results ---------------- - -Start up the Django server again and see what you've done: - -.. class:: small - -:: - - (djangoenv)$ python manage.py runserver - -.. class:: incremental - -Reload your admin site, click on the Post admin and see the new 'Author' -column. - -.. class:: incremental - -* Click on an author name. -* Set the first and last names (if you haven't already). -* Go back to Posts and see the outcome of this change. - -.. class:: incremental - -Not bad, eh? - - -Categorize Posts ----------------- - -We'd like to be able to add categories to posts while adding or editing them. - -.. class:: incremental - -But there is no field on the ``Post`` model that would show them. - -.. class:: incremental - -Django provides the concept of an ``inline`` form to allow adding objects that -are related when there is no field available. - -.. class:: incremental - -In the Django Admin, these are created using subclasses of the -``InlineAdmin``. - - -Create an Inline Admin ----------------------- - -In ``admin.py`` add the following code *above* the definition of PostAdmin: - -.. code-block:: python - :class: small - - class CategoryInlineAdmin(admin.TabularInline): - model = Category.posts.through - extra = 1 - -.. container:: incremental - - And then add one line to the PostAdmin class definition: - - .. code-block:: python - :class: small - - class PostAdmin(admin.ModelAdmin): - #... other options - inlines = [CategoryInlineAdmin, ] - - #... methods - - -Try It Out ----------- - -Restart the Django server and see what you've done: - -.. class:: small - -:: - - (djangoenv)$ python manage.py runserver - -.. class:: incremental - -Note that you can even add *new* categories via the inline form. - -.. class:: incremental - -But, in the form for a category, you see the field for Post. That shouldn't be -there. - - -A Final Tweak -------------- - -See if you can figure out how to remove the ``posts`` field from the -CategoryAdmin. - -.. code-block:: python - :class: small incremental - - # create a custom model admin class - class CategoryAdmin(admin.ModelAdmin): - exclude = ('posts', ) - - # and register Category to use it in the Admin - admin.site.register(Category, CategoryAdmin) - - -A Public Face -------------- - -Point your browser at http://localhost:8000/ - -.. class:: incremental - -What do you see? - -.. class:: incremental - -Why? - -.. class:: incremental - -We need to add some public pages for our blog. - -.. class:: incremental - -In Django, the code that builds a page that you can see is called a *view*. - -Django Views ------------- - -A *view* can be defined as a *callable* that takes a request and returns a -response. - -.. class:: incremental - -This should sound pretty familiar to you. - -.. class:: incremental - -Classically, Django views were functions. - -.. class:: incremental - -Version 1.3 added support for Class-based Views (a class with a ``__call__`` -method is a callable) - - -A Basic View ------------- - -Let's add a really simple view to our app. - -.. class:: incremental - -It will be a stub for our public UI. Add this to ``views.py`` in ``myblog`` - -.. code-block:: python - :class: small incremental - - from django.http import HttpResponse, HttpResponseRedirect, Http404 - - def stub_view(request, *args, **kwargs): - body = "Stub View\n\n" - if args: - body += "Args:\n" - body += "\n".join(["\t%s" % a for a in args]) - if kwargs: - body += "Kwargs:\n" - body += "\n".join(["\t%s: %s" % i for i in kwargs.items()]) - return HttpResponse(body, content_type="text/plain") - - -Hooking It Up -------------- - -We talked in the previous session about the Django urlconf - -.. class:: incremental - -We used our project urlconf to hook the Django admin into our project. - -.. class:: incremental - -We want to do the same thing for our new app. - -.. class:: incremental - -In general, an *app* that serves any sort of views should contain its own -urlconf. - -.. class:: incremental - -The project urlconf should mainly *include* these where possible. - - -Adding A Urlconf ----------------- - -Create a new file ``urls.py`` inside the ``myblog`` app package. - -.. container:: incremental - - Open it in your editor and add the following code: - - .. code-block:: python - :class: small - - from django.conf.urls import patterns, url - - urlpatterns = patterns('myblog.views', - url(r'^$', - 'stub_view', - name="blog_index"), - ) - - -Include Blog Urls ------------------ - -In order for our new urls to load, we'll need to include them in our project -urlconf - -.. container:: incremental - - Open ``urls.py`` from the ``mysite`` project package and add this: - - .. code-block:: python - :class: small - - urlpatterns = patterns('', - url(http://github.com/r'%5E',%20include('myblog.urls')), #<- add this - #... other included urls - ) - -.. class:: incremental - -Try reloading http://localhost:8000/ - -.. class:: incremental - -You should see some output now. - - -A Word On Prefixes ------------------- - -The ``patterns`` function takes a first argument called the *prefix* - -.. class:: incremental - -When it is not empty, it is added to any view names in ``url()`` calls in the -same ``patterns``. - -.. class:: incremental - -In a root urlconf like the one in ``mysite``, this isn't too useful - -.. class:: incremental - -But in ``myblog.urls`` it lets us refer to views by simple function name - -.. class:: incremental - -No need to import every view. - - -Project URL Space ------------------ - -A project is defined by the urls a user can visit. - -.. class:: incremental - -What should our users be able to see when they visit our blog? - -.. class:: incremental - -* A list view that shows blog posts, most recent first. -* An individual post view, showing a single post (a permalink). - -.. class:: incremental - -Let's add urls for each of these, use the stub view for now. - - -Our URLs --------- - -We've already got a good url for the list page: ``blog_index`` at '/' - -.. container:: incremental - - For the view of a single post, we'll need to capture the id of the post. - Add this to ``urlpatterns``: - - .. code-block:: python - :class: small incremental - - url(http://github.com/r'%5Eposts/(/d+)/$', - 'stub_view', - name="blog_detail"), - -.. class:: incremental - -``(\d+)`` captures one or more digits as the post_id. - -.. class:: incremental - -Load http://localhost:8000/posts/1234/ and see what you get. - - -A Word on Capture in URLs -------------------------- - -When you load the above url, you should see ``1234`` listed as an *arg* - -.. container:: incremental - - Try changing the regexp like so: - - .. code-block:: python - :class: small - - r'^posts/(?P\d+)/$' - -.. class:: incremental - -Reload the same url. Notice the change. - -.. class:: incremental - -How you declare a capture group in your url pattern regexp influenced how it -will be passed to the view callable. - - -Full Urlconf ------------- - -.. code-block:: python - :class: small - - from django.conf.urls import patterns, url - - urlpatterns = patterns('myblog.views', - url(r'^$', - 'stub_view', - name="blog_index"), - url(http://github.com/r'%5Eposts/(?P%3Cpost_id%3E\d+)/$', - 'stub_view', - name="blog_detail"), - ) - - -Testing Views -------------- - -Before we begin, we need to add some tests for the views we are about to -create. - -.. class:: incremental - -We'll need tests for a list view and a detail view - -.. class:: incremental - -To save us time, I've written these tests already - -.. class:: incremental - -You can find them in the class resources directory: ``blog_view_tests.py`` - -.. class:: incremental - -Copy the contents of that file into our blog ``tests.py`` file. - - -Run The Tests -------------- - -:: - - (djangoenv)$ python manage.py test myblog - ... - ---------------------------------------------------------------------- - Ran 7 tests in 0.478s - - FAILED (failures=2) - Destroying test database for alias 'default'... - - -Our First View --------------- - -Add the view for listing blog posts to ``views.py``. - -.. code-block:: python - :class: small - - # add these imports - from django.template import RequestContext, loader - from myblog.models import Post - - # and this view - def list_view(request): - published = Post.objects.exclude(published_date__exact=None) - posts = published.order_by('-published_date') - template = loader.get_template('list.html') - context = RequestContext(request, { - 'posts': posts, - }) - body = template.render(context) - return HttpResponse(body, content_type="text/html") - - -Getting Posts -------------- - -.. code-block:: python - :class: small - - published = Post.objects.exclude(published_date__exact=None) - posts = published.order_by('-published_date') - -.. class:: incremental - -We begin by using the QuerySet API to fetch all the posts that have -``published_date`` set - -.. class:: incremental - -Using the chaining nature of the API we order these posts by -``published_date`` - -.. class:: incremental - -Remember, at this point, no query has actually been issued to the database. - - -Getting a Template ------------------- - -.. code-block:: python - :class: small - - template = loader.get_template('list.html') - -.. class:: incremental - -Django uses configuration to determine how to find templates. - -.. class:: incremental - -By default, Django looks in installed *apps* for a ``templates`` directory - -.. class:: incremental - -It also provides a place to list specific directories. - -.. class:: incremental - -Let's set that up in ``settings.py`` - - -Project Templates ------------------ - -In ``settings.py`` find ``TEMPLATE_DIRS`` and add the absolute path to your -``mysite`` project package: - -.. code-block:: python - :class: small - - TEMPLATE_DIRS = ('/absolute/path/to/mysite/mysite/templates', ) - -.. class:: incremental - -Then add a ``templates`` directory to your ``mysite`` project package - -.. class:: incremental - -Finally, in that directory add a new file ``base.html`` and populate it with -the following: - - -base.html ---------- - -.. code-block:: jinja - :class: small - - - - - My Django Blog - - -
    -
    - {% block content %} - [content will go here] - {% endblock %} -
    -
    - - - - -Templates in Django -------------------- - -Before we move on, a quick word about Django templates. - -.. class:: incremental - -We've seen Jinja2 which was "inspired by Django's templating system". - -.. class:: incremental - -Basically, you already know how to write Django templates. - -.. class:: incremental - -Django templates **do not** allow any python expressions. - -.. class:: incremental center small - -https://docs.djangoproject.com/en/1.5/ref/templates/builtins/ - - -Blog Templates --------------- - -Our view tries to load ``list.html``. - -.. class:: incremental - -This template is probably specific to the blog functionality of our site - -.. class:: incremental - -It is common to keep shared templates in your project directory and -specialized ones in app directories. - -.. class:: incremental - -Add a ``templates`` directory to your ``myblog`` app, too. - -.. class:: incremental - -In it, create a new file ``list.html`` and add this: - - -list.html ---------- - -.. code-block:: jinja - :class: tiny - - {% extends "base.html" %} - - {% block content %} -

    Recent Posts

    - - {% comment %} here is where the query happens {% endcomment %} - {% for post in posts %} -
    -

    {{ post }}

    - -
    - {{ post.text }} -
    -
      - {% for category in post.categories.all %} -
    • {{ category }}
    • - {% endfor %} -
    -
    - {% endfor %} - {% endblock %} - - -Template Context ----------------- - -.. code-block:: python - :class: small - - context = RequestContext(request, { - 'posts': posts, - }) - body = template.render(context) - -.. class:: incremental - -Like Jinja2, django templates are rendered by passing in a *context* - -.. class:: incremental - -Django's RequestContext provides common bits, similar to the global context in -Flask - -.. class:: incremental - -We add our posts to that context so they can be used by the template. - - -Return a Response ------------------ - -.. code-block:: python - :class: small - - return HttpResponse(body, content_type="text/html") - -.. class:: incremental - -Finally, we build an HttpResponse and return it. - -.. class:: incremental - -This is, fundamentally, no different from the ``stub_view`` just above. - - -Fix URLs --------- - -We need to fix the url for our blog index page - -.. container:: incremental - - Update ``urls.py`` in ``myblog``: - - .. code-block:: python - :class: small - - url(r'^$', - 'list_view', - name="blog_index"), - -.. class:: incremental small - -:: - - (djangoenv)$ python manage.py test myblog - ... - Ran 7 tests in 0.494s - FAILED (failures=1) - - -Common Patterns ---------------- - -This is a common pattern in Django views: - -.. class:: incremental - -* get a template from the loader -* build a context, usually using a RequestContext -* render the template -* return an HttpResponse - -.. class:: incremental - -So common in fact that Django provides two shortcuts for us to use: - -.. class:: incremental - -* ``render(request, template[, ctx][, ctx_instance])`` -* ``render_to_response(template[, ctx][, ctx_instance])`` - - -Shorten Our View ----------------- - -Let's replace most of our view with the ``render`` shortcut - -.. code-block:: python - :class: small - - # replace RequestContext and loader import - from django.shortcuts import render - - # rewrite our view - def list_view(request): - published = Post.objects.exclude(published_date__exact=None) - posts = published.order_by('-published_date') - context = {'posts': posts} - return render(request, 'list.html', context) - -.. class:: incremental - -Remember though, all we did manually before is still happening - - -Detail View ------------ - -Next, let's write a view function for the detail view of a post - -.. container:: incremental - - It should have the following signature: - - .. code-block:: python - :class: small - - detail_view(request, post_id) - -.. class:: incremental - -We will call the template ``detail.html`` - -.. class:: incremental - -Let's start with the code in ``views.py`` - - -detail_view ------------ - -.. code-block:: python - :class: incremental small - - def detail_view(request, post_id): - published = Post.objects.exclude(published_date__exact=None) - try: - post = published.get(pk=post_id) - except Post.DoesNotExist: - raise Http404 - context = {'post': post} - return render(request, 'detail.html', context) - -.. class:: incremental - -All models raise a DoesNotExist exception if ``get`` returns nothing. - -.. class:: incremental - -We can use that fact to raise a Not Found exception. - -.. class:: incremental - -Django will handle the rest for us. - - -detail.html ------------ - -.. code-block:: jinja - :class: small - - {% extends "base.html" %} - - {% block content %} - Home -

    {{ post }}

    - -
    - {{ post.text }} -
    -
      - {% for category in post.categories.all %} -
    • {{ category }}
    • - {% endfor %} -
    - {% endblock %} - - -Hook it Up ----------- - -In order to view a single post, we'll need a link from the list view - -.. container:: incremental - - We can use the ``url`` template tag (like flask url_for): - - .. code-block:: jinja - :class: small - - {% url '' arg1 arg2 %} - -.. class:: incremental - -In our ``list.html`` template, let's link the post titles: - -.. code-block:: jinja - :class: small incremental - - {% for post in posts %} -
    -

    - {{ post }} -

    - ... - - -Fix URLs --------- - -Again, we need to insert our new view into the existing ``urls.py`` in -``myblog``: - -.. code-block:: python - :class: small - - url(http://github.com/r'%5Eposts/(?P%3Cpost_id%3E\d+)/$', - 'detail_view', - name="blog_detail"), - -.. class:: incremental small - -:: - - (djangoenv)$ python manage.py test myblog - ... - Ran 7 tests in 0.513s - OK - - -A Moment To Play ----------------- - -We've got some good stuff to look at now. Fire up the server - -.. class:: incremental - -Reload your blog index page and click around a bit. - -.. class:: incremental - -You can now move back and forth between list and detail view. - -.. class:: incremental - -Try loading the detail view for a post that doesn't exist - - -Congratulations ---------------- - -You've got a functional Blog - -.. class:: incremental - -It's not very pretty, though. - -.. class:: incremental - -We can fix that by adding some css - -.. class:: incremental - -This gives us a chance to learn about Django's handling of *static files* - - -Static Files ------------- - -Like templates, Django expects to find static files in particular locations - -.. class:: incremental - -It will look for them in a directory named ``static`` in any installed apps. - -.. class:: incremental - -They will be served from the url path in the STATIC_URL setting. - -.. class:: incremental - -By default, this is ``/static/`` - - -Add CSS -------- - -I've prepared a css file for us to use. You can find it in the class resources - -.. class:: incremental - -Create a new directory ``static`` in the ``myblog`` app. - -.. class:: incremental - -Copy the ``django_css`` file into that new directory. - -.. container:: incremental - - Then add this link to the of ``base.html``: - - .. code-block:: html - :class: small - - My Django Blog - - - -View Your Results ------------------ - -Reload http://localhost:8000/ and view the results of your work - -.. class:: incremental - -We now have a reasonable view of the posts of our blog on the front end - -.. class:: incremental - -And we have a way to create and categorize posts using the admin - -.. class:: incremental - -However, we lack a way to move between the two. - -.. class:: incremental - -Let's add that ability next. - - -Adding A Control Bar --------------------- - -We'll start by adding a control bar to our ``base.html`` template: - -.. code-block:: jinja - :class: small - - - ... - -
    - ... - - -Request Context Revisited -------------------------- - -When we set up our views, we used the ``render`` shortcut, which provides a -``RequestContext`` - -.. class:: incremental - -This gives us access to ``user`` in our templates - -.. class:: incremental - -It provides access to methods about the state and rights of that user - -.. class:: incremental - -We can use these to conditionally display links or UI elements. - - -Login/Logout ------------- - -Django provides a reasonable set of views for login/logout. - -.. class:: incremental - -The first step to using them is to hook them into a urlconf. - -.. container:: incremental - - Add the following to ``mysite/urls.py``: - - .. code-block:: python - :class: small - - url(http://github.com/r'%5E',%20include('myblog.urls')), #<- already there - url(r'^login/$', - 'django.contrib.auth.views.login', - {'template_name': 'login.html'}, - name="login"), - url(r'^logout/$', - 'django.contrib.auth.views.logout', - {'next_page': '/'}, - name="logout"), - - -Login Template --------------- - -We need to create a new ``login.html`` template in ``mysite/templates``: - -.. code-block:: jinja - :class: small - - {% extends "base.html" %} - - {% block content %} -

    My Blog Login

    -
    {% csrf_token %} - {{ form.as_p }} -

    -
    - {% endblock %} - - -Submitting Forms ----------------- - -In a web application, submitting forms is potentially hazardous - -.. class:: incremental - -Data is being sent to our application from some remote place - -.. class:: incremental - -If that data is going to alter the state of our application, we **must** use -POST - -.. class:: incremental - -Even so, we are vulnerable to Cross-Site Request Forgery, a common attack -vector. - - -Danger: CSRF ------------- - -Django provides a convenient system to fight this. - -.. class:: incremental - -In fact, for POST requests, it *requires* that you use it. - -.. class:: incremental - -The Django middleware that does this is enabled by default. - -.. class:: incremental - -All you need to do is include the ``{% csrf_token %}`` tag in your form. - - -Hooking It Up -------------- - -In ``base.html`` make the following updates: - -.. code-block:: jinja - :class: small - - - admin - - logout - - login - -.. container:: incremental - - Finally, in ``settings.py`` add the following: - - .. code-block:: python - :class: small - - LOGIN_URL = '/login/' - LOGIN_REDIRECT_URL = '/' - - -Handling Forms --------------- - -Adding login and logout has given us a sneak peek at forms. - -.. class:: incremental - -But there is a *lot* of magic happening that we should see directly. - -.. class:: incremental - -As a last task, let's add a non-admin way to create new posts. - -.. class:: incremental - -We'll use a form, submit it to a view, and have it create a new Post object - - -Django Forms ------------- - -Forms are, like Models, a Django *class* - -.. class:: incremental - -Like Models, you add fields to a form as class *attributes* - -.. class:: incremental - -Like Model fields, the fields on a form are also Python class instances. - -.. class:: incremental - -Unlike Model fields, Form fields are built to interact with data in a -*request* - -.. class:: incremental - -By tradition, they are created in a module called ``forms.py`` - - -Post Form ---------- - -Create ``forms.py`` in ``myblog`` and open it in your editor. - -.. code-block:: python - :class: small - - from django import forms - from myblog.models import Post - - class PostForm(forms.ModelForm): - - class Meta: - model = Post - fields = ('title', 'text', 'author') - -.. class:: incremental - -The ``ModelForm`` class generates fields based on the model. - -.. class:: incremental - -Use ``fields`` to force only a subset of those. - - -A View for Our Form -------------------- - -The basic approach to handling forms in Django always follows this pattern: - -.. code-block:: python - :class: small - - if request.method == 'POST': - # bind a form instance to POST data - if form.is_valid(): - # process the form data here - # tell the user about the success - else: - # tell the user about the problem - else: - # create an unbound form - # render the form template - -.. class:: incremental - -Let's create a ``add_post`` view that does this with our ``PostForm`` - -add_post view -------------- - -.. code-block:: python - :class: small - - # add imports to views.py - from django.core.exceptions import PermissionDenied - from django.contrib import messages - from django.core.urlresolvers import reverse - from myblog.forms import PostForm - - # and a new view function: - def add_view(request): - user = request.user - if not user.is_authenticated: - raise PermissionDenied - if request.method == 'POST': - form = PostForm(request.POST) - # handle form submission - else: - form = PostForm() - context = {'form': form} - return render(request, 'add.html', context) - - -Add A URL ---------- - -In ``myblog/urls.py`` add a new entry to our urlconf: - -.. code-block:: python - :class: small - - url(r'^add/$', - 'add_view', - name="add_post"), - -.. container:: incremental - - And hook it up to the control bar link in ``base.html`` - - .. code-block:: jinja - - - new post - - -Create add.html ---------------- - -Finally, we need to create a template, ``add.html`` in ``myblog/templates``: - -.. code-block:: jinja - :class: small - - {% extends "base.html" %} - - {% block content %} -

    New Blog Post

    -
    {% csrf_token %} - {{ form.as_p }} -

    -
    - {% endblock %} - - -Try it Out ----------- - -You should be able to click on the 'new post' button in the control bar. - -.. class:: incremental - -How does the form look? - -.. class:: incremental - -It would be nice if the 'author' field were auto-populated, and even hidden. - -.. class:: incremental - -Let's do that next. - - -Form 'initial' --------------- - -When instantiating a form, you can pass it *initial* values. - -.. container:: incremental - - In ``views.py`` make the following changes to the ``add_view``: - - .. code-block:: python - :class: small - - def add_view(request): - user = request.user - if not user.is_authenticated: - raise PermissionDenied - if request.method == 'POST': - #... not quite ready for this yet. - else: - initial = {'author': user} #<- add this - form = PostForm(initial=initial) #<- updated - - -Hidden Fields -------------- - -If you reload, you should now see ``author`` pre-popluated. - -.. container:: incremental - - To hide it, we must update the 'widget' it will use in ``forms.py``: - - .. code-block:: python - :class: small - - class PostForm(forms.ModelForm): - - class Meta: - #... - widgets = { - 'author': forms.HiddenInput(), - } - -.. class:: incremental - -Reload again to see the input disappear. Check page source to see the 'hidden' -input. - - -Form Submission ---------------- - -That's all we need to have for processing. We want to: - -.. class:: incremental - -* Validate the form input -* Report validation errors to the user and return the bound form -* If no errors occur, save the form, creating an instance -* Report success to the user and redirect to the list homepage. - -.. class:: incremental - -Django's ``messages`` framework will allow notifications. - - -Handle a Submitted Form ------------------------ - -In ``views.py``, update the ``add_view``: - -.. code-block:: python - :class: small - - def add_view(request): - user = request.user - if not user.is_authenticated(): - raise PermissionDenied - if request.method == 'POST': - form = PostForm(request.POST) - if form.is_valid(): - post = form.save() - msg = "post '%s' saved" % post - messages.add_message(request, messages.INFO, msg) - return HttpResponseRedirect(reverse('blog_index')) - else: - messages.add_message(request, messages.INFO, - "please fix the errors below") - else: - #... - - -Showing Messages ----------------- - -The ``messages`` framework pushes messages onto a stack. - -.. class:: incremental - -You can then pop them back off by printing them in a template. - -.. container:: incremental - - In ``base.html`` let's give them a place to go: - - .. code-block:: jinja - :class: small - -
    - {% if messages %} -
    - {% for message in messages %} -

    {{ message }}

    - {% endfor %} -
    - {% endif %} - - - -Final Run ---------- - -That should be enough to get us going. - -.. class:: incremental - -Fill out your form, supplying title and text. - -.. class:: incremental - -Submit the form, and notice the messaging from the system. - -.. class:: incremental - -Why is your new post not appearing in the blog list? - - -Next Steps ----------- - -There are a number of improvements one could make to this blog system: - -.. class:: incremental - -* Send email notifications to "blog administrators" that would notify them of - new posts awaiting publication. -* Provide a second list view giving users access to edit their unpublished - posts. -* Provide restricted access to certain users to view all unpublished posts and - choose to publish them. -* Add a form field for the post category and put the post in a category when - processing the form -* Provide a list view of a category, showing all posts in it. -* Provide HTML editing for post text. - - -That's All For Now ------------------- - -But this is all we have time for in this session. - -.. class:: big-centered incremental - -We'll see you next session! From cf41f3e66697d9308f0811dc63ede6ef2a703650 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 8 Feb 2014 19:22:44 -0800 Subject: [PATCH 272/487] add assignment for session 7 --- assignments/session07/tasks.txt | 49 +++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 assignments/session07/tasks.txt diff --git a/assignments/session07/tasks.txt b/assignments/session07/tasks.txt new file mode 100644 index 00000000..b3df2917 --- /dev/null +++ b/assignments/session07/tasks.txt @@ -0,0 +1,49 @@ +Session 7 Homework +================== + +We noted in class that it is awkward to have to add a post to a category, +instead of being able to designate a category for a post when authoring the +post. You will update your blog admin so that this is fixed. + +Required Tasks +-------------- + +Take the following steps: + +1. Read the documentation about the Django admin. +2. You'll need to create a customized ModelAdmin class for the Post and + Category models. +3. And you'll need to create an InlineModelAdmin to represent Categories on the + Post admin view. +4. Finally, you'll need to suppress the display of the 'posts' field on your + Category admin view. + +resources: + +https://docs.djangoproject.com/en/1.6/ref/contrib/admin/ +https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#modeladmin-objects +https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#inlinemodeladmin-objects +https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#modeladmin-options + + +Optional Tasks +-------------- + +If you complete the above in less than 3-4 hours of work, consider looking into +other ways of customizing the admin. + +Tasks you might consider: + +* Change the admin index to say 'Categories' instead of 'Categorys'. +* Add columns for the date fields to the list display of Posts. +* Display the created and modified dates for your posts when viewing them in + the admin. +* Add a column to the list display of Posts that shows the author. For more + fun, make this a link that takes you to the admin page for that user. +* For the biggest challenge, look into `admin actions`_ and add an action to + the Post admin that allows you to bulk publish posts from the Post list + display + +resources: + +https://docs.djangoproject.com/en/1.6/ref/contrib/admin/actions/ From cc84152c7495450005a1ef80ea5e24f4ed13e4b5 Mon Sep 17 00:00:00 2001 From: cewing Date: Sat, 8 Feb 2014 19:23:50 -0800 Subject: [PATCH 273/487] update the session 8 resources to contain what is finished after session 7 --- resources/session08/mysite/myblog/admin.py | 38 +--- .../mysite/myblog/migrations/0001_initial.py | 78 ++++++++ .../migrations/0002_auto__add_category.py | 93 +++++++++ .../mysite/myblog/migrations/__init__.py | 0 resources/session08/mysite/myblog/models.py | 14 +- .../mysite/myblog/static/django_blog.css | 2 +- .../mysite/myblog/templates/detail.html | 2 +- .../mysite/myblog/templates/list.html | 9 +- resources/session08/mysite/myblog/tests.py | 43 +--- resources/session08/mysite/myblog/urls.py | 5 +- resources/session08/mysite/myblog/views.py | 38 +--- resources/session08/mysite/mysite/settings.py | 189 ++++++------------ .../mysite/mysite/templates/base.html | 13 +- .../mysite/mysite/templates/login.html | 2 +- resources/session08/mysite/mysite/urls.py | 14 +- resources/session08/mysite/mysite/wsgi.py | 26 +-- source/presentations/session07.rst | 7 +- 17 files changed, 269 insertions(+), 304 deletions(-) create mode 100644 resources/session08/mysite/myblog/migrations/0001_initial.py create mode 100644 resources/session08/mysite/myblog/migrations/0002_auto__add_category.py create mode 100644 resources/session08/mysite/myblog/migrations/__init__.py diff --git a/resources/session08/mysite/myblog/admin.py b/resources/session08/mysite/myblog/admin.py index a2c21638..f4539ccc 100644 --- a/resources/session08/mysite/myblog/admin.py +++ b/resources/session08/mysite/myblog/admin.py @@ -1,37 +1,7 @@ from django.contrib import admin -from django.core.urlresolvers import reverse -from myblog.models import Post, Category +from myblog.models import Post +from myblog.models import Category -class CategoryInlineAdmin(admin.TabularInline): - model = Category.posts.through - extra = 1 - verbose_name = "Category" - verbose_name_plural = "Categories" - - -class PostAdmin(admin.ModelAdmin): - list_display = ('__unicode__', 'created_date', 'modified_date', - 'published_date', 'author_link') - readonly_fields = ('created_date', 'modified_date') - inlines = [CategoryInlineAdmin, ] - - def author_link(self, post): - url = reverse('admin:auth_user_change', args=(post.id,)) - name = post.author_name() - return '%s' % (url, name) - author_link.allow_tags = True - - def get_readonly_fields(self, request, obj=None): - fields = () - if obj is not None: - fields = self.readonly_fields - return fields - - -class CategoryAdmin(admin.ModelAdmin): - exclude = ('posts', ) - - -admin.site.register(Post, PostAdmin) -admin.site.register(Category, CategoryAdmin) +admin.site.register(Post) +admin.site.register(Category) diff --git a/resources/session08/mysite/myblog/migrations/0001_initial.py b/resources/session08/mysite/myblog/migrations/0001_initial.py new file mode 100644 index 00000000..75c584ca --- /dev/null +++ b/resources/session08/mysite/myblog/migrations/0001_initial.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Post' + db.create_table(u'myblog_post', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('title', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('text', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), + ('author', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('created_date', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), + ('modified_date', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), + ('published_date', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)), + )) + db.send_create_signal(u'myblog', ['Post']) + + + def backwards(self, orm): + # Deleting model 'Post' + db.delete_table(u'myblog_post') + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'myblog.post': { + 'Meta': {'object_name': 'Post'}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'created_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'published_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + } + } + + complete_apps = ['myblog'] \ No newline at end of file diff --git a/resources/session08/mysite/myblog/migrations/0002_auto__add_category.py b/resources/session08/mysite/myblog/migrations/0002_auto__add_category.py new file mode 100644 index 00000000..5afa4370 --- /dev/null +++ b/resources/session08/mysite/myblog/migrations/0002_auto__add_category.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Category' + db.create_table(u'myblog_category', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal(u'myblog', ['Category']) + + # Adding M2M table for field posts on 'Category' + m2m_table_name = db.shorten_name(u'myblog_category_posts') + db.create_table(m2m_table_name, ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('category', models.ForeignKey(orm[u'myblog.category'], null=False)), + ('post', models.ForeignKey(orm[u'myblog.post'], null=False)) + )) + db.create_unique(m2m_table_name, ['category_id', 'post_id']) + + + def backwards(self, orm): + # Deleting model 'Category' + db.delete_table(u'myblog_category') + + # Removing M2M table for field posts on 'Category' + db.delete_table(db.shorten_name(u'myblog_category_posts')) + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'myblog.category': { + 'Meta': {'object_name': 'Category'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'categories'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['myblog.Post']"}) + }, + u'myblog.post': { + 'Meta': {'object_name': 'Post'}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'created_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'published_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + } + } + + complete_apps = ['myblog'] \ No newline at end of file diff --git a/resources/session08/mysite/myblog/migrations/__init__.py b/resources/session08/mysite/myblog/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/resources/session08/mysite/myblog/models.py b/resources/session08/mysite/myblog/models.py index 44ed1e0f..67674268 100644 --- a/resources/session08/mysite/myblog/models.py +++ b/resources/session08/mysite/myblog/models.py @@ -4,7 +4,7 @@ class Post(models.Model): title = models.CharField(max_length=128) - text = models.TextField(blank=True) + text = models.TextField(blank=True, null=True) author = models.ForeignKey(User) created_date = models.DateTimeField(auto_now_add=True) modified_date = models.DateTimeField(auto_now=True) @@ -13,19 +13,12 @@ class Post(models.Model): def __unicode__(self): return self.title - def author_name(self): - raw_name = "%s %s" % (self.author.first_name, - self.author.last_name) - name = raw_name.strip() - if not name: - name = self.author.username - return name - class Category(models.Model): name = models.CharField(max_length=128) description = models.TextField(blank=True) - posts = models.ManyToManyField(Post, + posts = models.ManyToManyField( + Post, blank=True, null=True, related_name='categories' @@ -33,4 +26,3 @@ class Category(models.Model): def __unicode__(self): return self.name - diff --git a/resources/session08/mysite/myblog/static/django_blog.css b/resources/session08/mysite/myblog/static/django_blog.css index 64560dc0..45a882de 100644 --- a/resources/session08/mysite/myblog/static/django_blog.css +++ b/resources/session08/mysite/myblog/static/django_blog.css @@ -71,4 +71,4 @@ ul.categories { } ul.categories li { display: inline; -} \ No newline at end of file +} diff --git a/resources/session08/mysite/myblog/templates/detail.html b/resources/session08/mysite/myblog/templates/detail.html index 34e1b356..cd0322ff 100644 --- a/resources/session08/mysite/myblog/templates/detail.html +++ b/resources/session08/mysite/myblog/templates/detail.html @@ -14,4 +14,4 @@

    {{ post }}

  • {{ category }}
  • {% endfor %}
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/resources/session08/mysite/myblog/templates/list.html b/resources/session08/mysite/myblog/templates/list.html index b2299169..c51702ff 100644 --- a/resources/session08/mysite/myblog/templates/list.html +++ b/resources/session08/mysite/myblog/templates/list.html @@ -2,12 +2,11 @@ {% block content %}

Recent Posts

- + + {% comment %} here is where the query happens {% endcomment %} {% for post in posts %}
-

- {{ post }} -

+

{{ post }}

@@ -21,4 +20,4 @@

{% endfor %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/resources/session08/mysite/myblog/tests.py b/resources/session08/mysite/myblog/tests.py index a51abbe7..5671bfda 100644 --- a/resources/session08/mysite/myblog/tests.py +++ b/resources/session08/mysite/myblog/tests.py @@ -1,12 +1,9 @@ import datetime from django.test import TestCase from django.contrib.auth.models import User -from django.contrib.admin.sites import AdminSite from django.utils.timezone import utc - from myblog.models import Post from myblog.models import Category -from myblog.admin import PostAdmin class PostTestCase(TestCase): @@ -21,19 +18,6 @@ def test_unicode(self): actual = unicode(p1) self.assertEqual(expected, actual) - def test_author_name(self): - for author in User.objects.all(): - fn, ln, un = (author.first_name, author.last_name, - author.username) - author_name = Post(author=author).author_name() - if not (fn and ln): - self.assertEqual(author_name, un) - else: - if fn: - self.assertTrue(fn in author_name) - if ln: - self.assertTrue(ln in author_name) - class CategoryTestCase(TestCase): @@ -44,36 +28,14 @@ def test_unicode(self): self.assertEqual(expected, actual) -class PostAdminTestCase(TestCase): - fixtures = ['myblog_test_fixture.json', ] - - def setUp(self): - admin = AdminSite() - self.ma = PostAdmin(Post, admin) - for author in User.objects.all(): - title = "%s's title" % author.username - post = Post(title=title, author=author) - post.save() - self.client.login(username='admin', password='secret') - - def test_author_link(self): - expected_link_path = '/admin/auth/user/%s' - for post in Post.objects.all(): - expected = expected_link_path % post.author.pk - actual = self.ma.author_link(post) - self.assertTrue(expected in actual) - - class FrontEndTestCase(TestCase): """test views provided in the front-end""" fixtures = ['myblog_test_fixture.json', ] - + def setUp(self): self.now = datetime.datetime.utcnow().replace(tzinfo=utc) self.timedelta = datetime.timedelta(15) author = User.objects.get(pk=1) - self.category = Category(name='A Category') - self.category.save() for count in range(1,11): post = Post(title="Post %d Title" % count, text="foo", @@ -83,9 +45,6 @@ def setUp(self): pubdate = self.now - self.timedelta * count post.published_date = pubdate post.save() - if bool(count & 1): - # put odd items in category: - self.category.posts.add(post) def test_list_only_published(self): resp = self.client.get('/') diff --git a/resources/session08/mysite/myblog/urls.py b/resources/session08/mysite/myblog/urls.py index 3c72e6bc..8b97b5dc 100644 --- a/resources/session08/mysite/myblog/urls.py +++ b/resources/session08/mysite/myblog/urls.py @@ -5,10 +5,7 @@ url(r'^$', 'list_view', name="blog_index"), - url(http://github.com/r'%5Eposts/(?P%3Cpost_id%3E\d+)/$', + url(http://github.com/r'%5Eposts/(/d+)/$', 'detail_view', name="blog_detail"), - url(r'^add/$', - 'add_view', - name="add_post"), ) diff --git a/resources/session08/mysite/myblog/views.py b/resources/session08/mysite/myblog/views.py index 3768595e..c3f48eb0 100644 --- a/resources/session08/mysite/myblog/views.py +++ b/resources/session08/mysite/myblog/views.py @@ -1,12 +1,7 @@ -from django.http import HttpResponse, Http404 -from django.http import HttpResponseRedirect from django.shortcuts import render -from django.core.exceptions import PermissionDenied -from django.core.urlresolvers import reverse -from django.contrib import messages - +from django.http import HttpResponse, HttpResponseRedirect, Http404 +from django.template import RequestContext, loader from myblog.models import Post -from myblog.forms import PostForm def stub_view(request, *args, **kwargs): @@ -23,8 +18,12 @@ def stub_view(request, *args, **kwargs): def list_view(request): published = Post.objects.exclude(published_date__exact=None) posts = published.order_by('-published_date') - context = {'posts': posts} - return render(request, 'list.html', context) + template = loader.get_template('list.html') + context = RequestContext(request, { + 'posts': posts, + }) + body = template.render(context) + return HttpResponse(body, content_type="text/html") def detail_view(request, post_id): @@ -35,24 +34,3 @@ def detail_view(request, post_id): raise Http404 context = {'post': post} return render(request, 'detail.html', context) - - -def add_view(request): - user = request.user - if not user.is_authenticated: - raise PermissionDenied - if request.method == 'POST': - form = PostForm(request.POST) - if form.is_valid: - post = form.save() - msg = "post '%s' saved" % post - messages.add_message(request, messages.INFO, msg) - return HttpResponseRedirect(reverse('blog_index')) - else: - messages.add_message("please fix the errors below") - else: - initial = {'author': user} - form = PostForm(initial=initial) - - context = {'form': form} - return render(request, 'add.html', context) diff --git a/resources/session08/mysite/mysite/settings.py b/resources/session08/mysite/mysite/settings.py index 8c2a28a9..e9a98f3c 100644 --- a/resources/session08/mysite/mysite/settings.py +++ b/resources/session08/mysite/mysite/settings.py @@ -1,162 +1,91 @@ -# Django settings for mysite project. +""" +Django settings for mysite project. -DEBUG = True -TEMPLATE_DEBUG = DEBUG +For more information on this file, see +https://docs.djangoproject.com/en/1.6/topics/settings/ -ADMINS = ( - # ('Your Name', 'your_email@example.com'), -) +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.6/ref/settings/ +""" -MANAGERS = ADMINS +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +import os +BASE_DIR = os.path.dirname(os.path.dirname(__file__)) -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': 'mysite.db', - # The following settings are not used with sqlite3: - 'USER': '', - 'PASSWORD': '', - 'HOST': '', - 'PORT': '', - } -} -# Hosts/domain names that are valid for this site; required if DEBUG is False -# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts -ALLOWED_HOSTS = [] +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/ -# Local time zone for this installation. Choices can be found here: -# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name -# although not all choices may be available on all operating systems. -# In a Windows environment this must be set to your system time zone. -TIME_ZONE = 'America/Chicago' +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'izjnm)3w#gc)za-gnc0vwayf45ucd1p59w=_ia74h^q7z2j@p8' -# Language code for this installation. All choices can be found here: -# http://www.i18nguy.com/unicode/language-identifiers.html -LANGUAGE_CODE = 'en-us' - -SITE_ID = 1 - -# If you set this to False, Django will make some optimizations so as not -# to load the internationalization machinery. -USE_I18N = True - -# If you set this to False, Django will not format dates, numbers and -# calendars according to the current locale. -USE_L10N = True - -# If you set this to False, Django will not use timezone-aware datetimes. -USE_TZ = True - -# Absolute filesystem path to the directory that will hold user-uploaded files. -# Example: "/var/www/example.com/media/" -MEDIA_ROOT = '' - -# URL that handles the media served from MEDIA_ROOT. Make sure to use a -# trailing slash. -# Examples: "http://example.com/media/", "http://media.example.com/" -MEDIA_URL = '' - -# Absolute path to the directory static files should be collected to. -# Don't put anything in this directory yourself; store your static files -# in apps' "static/" subdirectories and in STATICFILES_DIRS. -# Example: "/var/www/example.com/static/" -STATIC_ROOT = '' +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True -# URL prefix for static files. -# Example: "http://example.com/static/", "http://static.example.com/" -STATIC_URL = '/static/' +TEMPLATE_DEBUG = True -# Additional locations of static files -STATICFILES_DIRS = ( - # Put strings here, like "/home/html/static" or "C:/www/django/static". - # Always use forward slashes, even on Windows. - # Don't forget to use absolute paths, not relative paths. -) +ALLOWED_HOSTS = [] -# List of finder classes that know how to find static files in -# various locations. -STATICFILES_FINDERS = ( - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', -# 'django.contrib.staticfiles.finders.DefaultStorageFinder', -) -# Make this unique, and don't share it with anybody. -SECRET_KEY = '(g!gi6orza2nez)tf-xj_g%5g3!+pmdhs15xjgat)0g!10qku*' +# Application definition -# List of callables that know how to import templates from various sources. -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', -# 'django.template.loaders.eggs.Loader', +INSTALLED_APPS = ( + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'south', + 'myblog', ) MIDDLEWARE_CLASSES = ( - 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', - # Uncomment the next line for simple clickjacking protection: - # 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', ) ROOT_URLCONF = 'mysite.urls' -# Python dotted path to the WSGI application used by Django's runserver. WSGI_APPLICATION = 'mysite.wsgi.application' -TEMPLATE_DIRS = ( - # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". - # Always use forward slashes, even on Windows. - # Don't forget to use absolute paths, not relative paths. - '/Users/cewing/projects/training/uw_pce/testme/training.python_web/resources/session08/mysite/mysite/templates' -) -INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.messages', - 'django.contrib.staticfiles', - # Uncomment the next line to enable the admin: - 'django.contrib.admin', - # Uncomment the next line to enable admin documentation: - # 'django.contrib.admindocs', - 'myblog', -) +# Database +# https://docs.djangoproject.com/en/1.6/ref/settings/#databases -# A sample logging configuration. The only tangible logging -# performed by this configuration is to send an email to -# the site admins on every HTTP 500 error when DEBUG=False. -# See http://docs.djangoproject.com/en/dev/topics/logging for -# more details on how to customize your logging configuration. -LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'filters': { - 'require_debug_false': { - '()': 'django.utils.log.RequireDebugFalse' - } - }, - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'filters': ['require_debug_false'], - 'class': 'django.utils.log.AdminEmailHandler' - } - }, - 'loggers': { - 'django.request': { - 'handlers': ['mail_admins'], - 'level': 'ERROR', - 'propagate': True, - }, +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': 'mysite.db', } } +# Internationalization +# https://docs.djangoproject.com/en/1.6/topics/i18n/ +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.6/howto/static-files/ + +STATIC_URL = '/static/' + +TEMPLATE_DIRS = ( + '/Users/cewing/projects/training/uw_pce/testme/mysite/mysite/templates', +) LOGIN_URL = '/login/' -LOGIN_REDIRECT_URL = '/' \ No newline at end of file +LOGIN_REDIRECT_URL = '/' + diff --git a/resources/session08/mysite/mysite/templates/base.html b/resources/session08/mysite/mysite/templates/base.html index 5168b320..61300646 100644 --- a/resources/session08/mysite/mysite/templates/base.html +++ b/resources/session08/mysite/mysite/templates/base.html @@ -8,22 +8,15 @@ +

this is my user: {{user}}

- {% if messages %} -
- {% for message in messages %} -

{{ message }}

- {% endfor %} -
- {% endif %}
{% block content %} [content will go here] @@ -31,4 +24,4 @@
- \ No newline at end of file + diff --git a/resources/session08/mysite/mysite/templates/login.html b/resources/session08/mysite/mysite/templates/login.html index e1a56ee8..1566d0f7 100644 --- a/resources/session08/mysite/mysite/templates/login.html +++ b/resources/session08/mysite/mysite/templates/login.html @@ -6,4 +6,4 @@

My Blog Login

{{ form.as_p }}

-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/resources/session08/mysite/mysite/urls.py b/resources/session08/mysite/mysite/urls.py index f3f985db..9c67dfdb 100644 --- a/resources/session08/mysite/mysite/urls.py +++ b/resources/session08/mysite/mysite/urls.py @@ -1,11 +1,14 @@ from django.conf.urls import patterns, include, url -# Uncomment the next two lines to enable the admin: from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', + # Examples: + # url(http://github.com/r'%5E'),%20'mysite.views.home',%20name='home'), + # url(http://github.com/r'%5Eblog/',%20include('blog.urls')), url(http://github.com/r'%5E',%20include('myblog.urls')), + url(http://github.com/r'%5Eadmin/',%20include(admin.site.urls)), url(r'^login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}, @@ -14,13 +17,4 @@ 'django.contrib.auth.views.logout', {'next_page': '/'}, name="logout"), - # Examples: - # url(http://github.com/r'%5E'),%20'mysite.views.home',%20name='home'), - # url(http://github.com/r'%5Emysite/',%20include('mysite.foo.urls')), - - # Uncomment the admin/doc line below to enable admin documentation: - # url(http://github.com/r'%5Eadmin/doc/',%20include('django.contrib.admindocs.urls')), - - # Uncomment the next line to enable the admin: - url(http://github.com/r'%5Eadmin/',%20include(admin.site.urls)), ) diff --git a/resources/session08/mysite/mysite/wsgi.py b/resources/session08/mysite/mysite/wsgi.py index 34e900eb..10ef32d9 100644 --- a/resources/session08/mysite/mysite/wsgi.py +++ b/resources/session08/mysite/mysite/wsgi.py @@ -1,32 +1,14 @@ """ WSGI config for mysite project. -This module contains the WSGI application used by Django's development server -and any production WSGI deployments. It should expose a module-level variable -named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover -this application via the ``WSGI_APPLICATION`` setting. - -Usually you will have the standard Django WSGI application here, but it also -might make sense to replace the whole Django WSGI application with a custom one -that later delegates to the Django one. For example, you could introduce WSGI -middleware here, or combine a Django application with an application of another -framework. +It exposes the WSGI callable as a module-level variable named ``application``. +For more information on this file, see +https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ """ -import os -# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks -# if running multiple sites in the same mod_wsgi process. To fix this, use -# mod_wsgi daemon mode with each site in its own daemon process, or use -# os.environ["DJANGO_SETTINGS_MODULE"] = "mysite.settings" +import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") -# This application object is used by any WSGI server configured to use this -# file. This includes Django's development server, if the WSGI_APPLICATION -# setting points here. from django.core.wsgi import get_wsgi_application application = get_wsgi_application() - -# Apply WSGI middleware here. -# from helloworld.wsgi import HelloWorldApplication -# application = HelloWorldApplication(application) diff --git a/source/presentations/session07.rst b/source/presentations/session07.rst index 66bdf5b0..3f270de1 100644 --- a/source/presentations/session07.rst +++ b/source/presentations/session07.rst @@ -1690,8 +1690,7 @@ Post admin*. Your Assignment --------------- -You'll be reversing that editing relationship so that you can add categories to -posts, and cannot choose posts from categories. +You'll be reverse that relationship so that you can only add categories to posts Take the following steps: @@ -1721,7 +1720,9 @@ The trick of course is reading and finding out which fifteen lines to write. If you complete that task in less than 3-4 hours of work, consider looking into other ways of customizing the admin. -Tasks you might consider: + +Tasks you might consider +------------------------ * Change the admin index to say 'Categories' instead of 'Categorys'. * Add columns for the date fields to the list display of Posts. From f52e7da71e80de5242f1db5329322bc32bf848ea Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Tue, 11 Feb 2014 12:00:17 -0800 Subject: [PATCH 274/487] fixed plural --- source/presentations/django_intro.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/presentations/django_intro.rst b/source/presentations/django_intro.rst index 0951003c..8824066a 100644 --- a/source/presentations/django_intro.rst +++ b/source/presentations/django_intro.rst @@ -246,7 +246,7 @@ Django's ORM provides a layer of *abstraction* between you and SQL .. class:: incremental -You write Python classes called *models* describing the object that make up +You write Python classes called *models* describing the objects that make up your system. .. class:: incremental From 3e1768efa4fe6ad07917cbaf069a80a0a1c96686 Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Tue, 11 Feb 2014 12:28:20 -0800 Subject: [PATCH 275/487] Fixed INSTALLED_APPS --- source/presentations/django_intro.rst | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/source/presentations/django_intro.rst b/source/presentations/django_intro.rst index 8824066a..fdcc01f5 100644 --- a/source/presentations/django_intro.rst +++ b/source/presentations/django_intro.rst @@ -303,16 +303,12 @@ Django already includes some *apps* for you. :class: small INSTALLED_APPS = ( + 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', - 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', - # Uncomment the next line to enable the admin: - # 'django.contrib.admin', - # Uncomment the next line to enable admin documentation: - # 'django.contrib.admindocs', ) @@ -610,10 +606,10 @@ You extend Django functionality by *installing apps*. This is pretty simple: :class: small INSTALLED_APPS = ( + 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', - 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', 'myblog', # <- YOU ADD THIS PART From 92b5f718c13bfdb77461ea9572a5754f1ad550f8 Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Tue, 11 Feb 2014 12:31:28 -0800 Subject: [PATCH 276/487] The first user is "admin", as per prior recommendation. --- source/presentations/django_intro.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/presentations/django_intro.rst b/source/presentations/django_intro.rst index fdcc01f5..d2379a57 100644 --- a/source/presentations/django_intro.rst +++ b/source/presentations/django_intro.rst @@ -724,7 +724,7 @@ Let's use the *manager* to get an instance of the ``User`` class: >>> from django.contrib.auth.models import User >>> all_users = User.objects.all() >>> all_users - [] + [] >>> u1 = all_users[0] >>> p1.author = u1 From 51232b8dd3c911e9356289aa75c4b57da1b9a5a6 Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Tue, 11 Feb 2014 12:57:02 -0800 Subject: [PATCH 277/487] There are no tests in tests.py yet. --- source/presentations/django_intro.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/presentations/django_intro.rst b/source/presentations/django_intro.rst index d2379a57..f98b7921 100644 --- a/source/presentations/django_intro.rst +++ b/source/presentations/django_intro.rst @@ -1000,7 +1000,7 @@ Now that we have a fixture, we need to instruct our tests to use it. .. container:: incremental - Edit ``tests.py`` (which comes with one test already) to look like this: + Edit ``tests.py`` to look like this: .. code-block:: python :class: small From 12d57c2960de2d9268ed1a8176fdf91d7a2c7c65 Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Tue, 11 Feb 2014 13:02:42 -0800 Subject: [PATCH 278/487] Fix Typo --- source/presentations/django_intro.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/presentations/django_intro.rst b/source/presentations/django_intro.rst index f98b7921..ea57c5c8 100644 --- a/source/presentations/django_intro.rst +++ b/source/presentations/django_intro.rst @@ -1249,7 +1249,7 @@ Django too has a system for dispatching requests to code: the *urlconf*. .. class:: incremental -* A urlconf is a an iterable of calls to the ``django.conf.urls.url`` function +* A urlconf is an iterable of calls to the ``django.conf.urls.url`` function * This function takes: * a regexp *rule*, representing the URL From 0121bc4a6e943b21c7a58607d5f296228b9dd3f8 Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Sun, 16 Feb 2014 16:38:29 -0800 Subject: [PATCH 279/487] Wrong file name for css --- source/presentations/session07.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/presentations/session07.rst b/source/presentations/session07.rst index 3f270de1..4d708d63 100644 --- a/source/presentations/session07.rst +++ b/source/presentations/session07.rst @@ -1435,7 +1435,7 @@ Create a new directory ``static`` in the ``myblog`` app. .. class:: incremental -Copy the ``django_css`` file into that new directory. +Copy the ``django_blog.css`` file into that new directory. .. container:: incremental From 5e235dad6efe5b2b03b5fb00f953fd1aa769bc15 Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Sun, 16 Feb 2014 16:53:22 -0800 Subject: [PATCH 280/487] Update session07.rst --- source/presentations/session07.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/presentations/session07.rst b/source/presentations/session07.rst index 4d708d63..02d50ee8 100644 --- a/source/presentations/session07.rst +++ b/source/presentations/session07.rst @@ -1690,7 +1690,7 @@ Post admin*. Your Assignment --------------- -You'll be reverse that relationship so that you can only add categories to posts +You'll be reversing that relationship so that you can only add categories to posts Take the following steps: From 8e048665cb5c2681c1893c75b743f55fd060a069 Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Thu, 20 Feb 2014 11:31:17 -0800 Subject: [PATCH 281/487] baseline of myblog app as it was at the end of class on Feb 18 --- assignments/session07/mysite/manage.py | 10 ++ .../session07/mysite/myblog/__init__.py | 0 assignments/session07/mysite/myblog/admin.py | 6 ++ .../myblog/fixtures/myblog_test_fixture.json | 38 +++++++ .../mysite/myblog/migrations/0001_initial.py | 78 +++++++++++++++ .../migrations/0002_auto__add_category.py | 93 ++++++++++++++++++ .../mysite/myblog/migrations/__init__.py | 0 assignments/session07/mysite/myblog/models.py | 22 +++++ .../mysite/myblog/static/django_blog.css | 74 ++++++++++++++ .../mysite/myblog/templates/detail.html | 17 ++++ .../mysite/myblog/templates/list.html | 25 +++++ assignments/session07/mysite/myblog/tests.py | 65 ++++++++++++ assignments/session07/mysite/myblog/urls.py | 10 ++ assignments/session07/mysite/myblog/views.py | 29 ++++++ assignments/session07/mysite/mysite.db | Bin 0 -> 155648 bytes .../session07/mysite/mysite/__init__.py | 0 .../session07/mysite/mysite/settings.py | 89 +++++++++++++++++ .../mysite/mysite/templates/base.html | 26 +++++ .../mysite/mysite/templates/login.html | 9 ++ assignments/session07/mysite/mysite/urls.py | 20 ++++ assignments/session07/mysite/mysite/wsgi.py | 14 +++ 21 files changed, 625 insertions(+) create mode 100755 assignments/session07/mysite/manage.py create mode 100644 assignments/session07/mysite/myblog/__init__.py create mode 100644 assignments/session07/mysite/myblog/admin.py create mode 100644 assignments/session07/mysite/myblog/fixtures/myblog_test_fixture.json create mode 100644 assignments/session07/mysite/myblog/migrations/0001_initial.py create mode 100644 assignments/session07/mysite/myblog/migrations/0002_auto__add_category.py create mode 100644 assignments/session07/mysite/myblog/migrations/__init__.py create mode 100644 assignments/session07/mysite/myblog/models.py create mode 100644 assignments/session07/mysite/myblog/static/django_blog.css create mode 100644 assignments/session07/mysite/myblog/templates/detail.html create mode 100644 assignments/session07/mysite/myblog/templates/list.html create mode 100644 assignments/session07/mysite/myblog/tests.py create mode 100644 assignments/session07/mysite/myblog/urls.py create mode 100644 assignments/session07/mysite/myblog/views.py create mode 100644 assignments/session07/mysite/mysite.db create mode 100644 assignments/session07/mysite/mysite/__init__.py create mode 100644 assignments/session07/mysite/mysite/settings.py create mode 100644 assignments/session07/mysite/mysite/templates/base.html create mode 100644 assignments/session07/mysite/mysite/templates/login.html create mode 100644 assignments/session07/mysite/mysite/urls.py create mode 100644 assignments/session07/mysite/mysite/wsgi.py diff --git a/assignments/session07/mysite/manage.py b/assignments/session07/mysite/manage.py new file mode 100755 index 00000000..8a50ec04 --- /dev/null +++ b/assignments/session07/mysite/manage.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) diff --git a/assignments/session07/mysite/myblog/__init__.py b/assignments/session07/mysite/myblog/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/assignments/session07/mysite/myblog/admin.py b/assignments/session07/mysite/myblog/admin.py new file mode 100644 index 00000000..67aec2d6 --- /dev/null +++ b/assignments/session07/mysite/myblog/admin.py @@ -0,0 +1,6 @@ +from django.contrib import admin +from myblog.models import Post +from myblog.models import Category + +admin.site.register(Post) +admin.site.register(Category) diff --git a/assignments/session07/mysite/myblog/fixtures/myblog_test_fixture.json b/assignments/session07/mysite/myblog/fixtures/myblog_test_fixture.json new file mode 100644 index 00000000..592dea17 --- /dev/null +++ b/assignments/session07/mysite/myblog/fixtures/myblog_test_fixture.json @@ -0,0 +1,38 @@ +[ +{ + "pk": 1, + "model": "auth.user", + "fields": { + "username": "admin", + "first_name": "Mr.", + "last_name": "Administrator", + "is_active": true, + "is_superuser": true, + "is_staff": true, + "last_login": "2013-05-24T05:35:58.628Z", + "groups": [], + "user_permissions": [], + "password": "pbkdf2_sha256$10000$1rQazFNdOfFt$6aw/uIrv2uASkZ7moXMTajSN+ySYuowBnbP6ILNQntE=", + "email": "admin@example.com", + "date_joined": "2013-05-24T05:35:58.628Z" + } +}, +{ + "pk": 2, + "model": "auth.user", + "fields": { + "username": "noname", + "first_name": "", + "last_name": "", + "is_active": true, + "is_superuser": true, + "is_staff": true, + "last_login": "2013-05-24T05:35:58.628Z", + "groups": [], + "user_permissions": [], + "password": "pbkdf2_sha256$10000$1rQazFNdOfFt$6aw/uIrv2uASkZ7moXMTajSN+ySYuowBnbP6ILNQntE=", + "email": "noname@example.com", + "date_joined": "2013-05-24T05:35:58.628Z" + } +} +] diff --git a/assignments/session07/mysite/myblog/migrations/0001_initial.py b/assignments/session07/mysite/myblog/migrations/0001_initial.py new file mode 100644 index 00000000..4e7a9de9 --- /dev/null +++ b/assignments/session07/mysite/myblog/migrations/0001_initial.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Post' + db.create_table(u'myblog_post', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('title', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('text', self.gf('django.db.models.fields.TextField')(blank=True)), + ('author', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('created_date', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), + ('modified_date', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), + ('published_date', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)), + )) + db.send_create_signal(u'myblog', ['Post']) + + + def backwards(self, orm): + # Deleting model 'Post' + db.delete_table(u'myblog_post') + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'myblog.post': { + 'Meta': {'object_name': 'Post'}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'created_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'published_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'text': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + } + } + + complete_apps = ['myblog'] \ No newline at end of file diff --git a/assignments/session07/mysite/myblog/migrations/0002_auto__add_category.py b/assignments/session07/mysite/myblog/migrations/0002_auto__add_category.py new file mode 100644 index 00000000..1ecf7fcc --- /dev/null +++ b/assignments/session07/mysite/myblog/migrations/0002_auto__add_category.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Category' + db.create_table(u'myblog_category', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal(u'myblog', ['Category']) + + # Adding M2M table for field posts on 'Category' + m2m_table_name = db.shorten_name(u'myblog_category_posts') + db.create_table(m2m_table_name, ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('category', models.ForeignKey(orm[u'myblog.category'], null=False)), + ('post', models.ForeignKey(orm[u'myblog.post'], null=False)) + )) + db.create_unique(m2m_table_name, ['category_id', 'post_id']) + + + def backwards(self, orm): + # Deleting model 'Category' + db.delete_table(u'myblog_category') + + # Removing M2M table for field posts on 'Category' + db.delete_table(db.shorten_name(u'myblog_category_posts')) + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'myblog.category': { + 'Meta': {'object_name': 'Category'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'categories'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['myblog.Post']"}) + }, + u'myblog.post': { + 'Meta': {'object_name': 'Post'}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}), + 'created_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'published_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'text': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + } + } + + complete_apps = ['myblog'] \ No newline at end of file diff --git a/assignments/session07/mysite/myblog/migrations/__init__.py b/assignments/session07/mysite/myblog/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/assignments/session07/mysite/myblog/models.py b/assignments/session07/mysite/myblog/models.py new file mode 100644 index 00000000..29b851c7 --- /dev/null +++ b/assignments/session07/mysite/myblog/models.py @@ -0,0 +1,22 @@ +from django.db import models +from django.contrib.auth.models import User + +class Post(models.Model): + title = models.CharField(max_length=128) + text = models.TextField(blank=True) + author = models.ForeignKey(User) + created_date = models.DateTimeField(auto_now_add=True) + modified_date = models.DateTimeField(auto_now=True) + published_date = models.DateTimeField(blank=True, null=True) + + def __unicode__(self): + return self.title + +class Category(models.Model): + name = models.CharField(max_length=128) + description = models.TextField(blank=True) + posts = models.ManyToManyField(Post, blank=True, null=True, + related_name='categories') + + def __unicode__(self): + return self.name \ No newline at end of file diff --git a/assignments/session07/mysite/myblog/static/django_blog.css b/assignments/session07/mysite/myblog/static/django_blog.css new file mode 100644 index 00000000..64560dc0 --- /dev/null +++ b/assignments/session07/mysite/myblog/static/django_blog.css @@ -0,0 +1,74 @@ +body { + background-color: #eee; + color: #111; + font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + margin:0; + padding:0; +} +#container { + margin:0; + padding:0; + margin-top: 0px; +} +#header { + background-color: #333; + border-botton: 1px solid #111; + margin:0; + padding:0; +} +#control-bar { + margin: 0em 0em 1em; + list-style: none; + list-style-type: none; + text-align: right; + color: #eee; + font-size: 80%; + padding-bottom: 0.4em; +} +#control-bar li { + display: inline-block; +} +#control-bar li a { + color: #eee; + padding: 0.5em; + text-decoration: none; +} +#control-bar li a:hover { + color: #cce; +} +#content { + margin: 0em 1em 1em; +} + +ul#entries { + list-style: none; + list-style-type: none; +} +div.entry { + margin-right: 2em; + margin-top: 1em; + border-top: 1px solid #cecece; +} +ul#entries li:first-child div.entry { + border-top: none; + margin-top: 0em; +} +div.entry-body { + margin-left: 2em; +} +.notification { + float: right; + text-align: center; + width: 25%; + padding: 1em; +} +.info { + background-color: #aae; +} +ul.categories { + list-style: none; + list-style-type: none; +} +ul.categories li { + display: inline; +} \ No newline at end of file diff --git a/assignments/session07/mysite/myblog/templates/detail.html b/assignments/session07/mysite/myblog/templates/detail.html new file mode 100644 index 00000000..cd0322ff --- /dev/null +++ b/assignments/session07/mysite/myblog/templates/detail.html @@ -0,0 +1,17 @@ +{% extends "base.html" %} + +{% block content %} +Home +

{{ post }}

+ +
+ {{ post.text }} +
+
    + {% for category in post.categories.all %} +
  • {{ category }}
  • + {% endfor %} +
+{% endblock %} diff --git a/assignments/session07/mysite/myblog/templates/list.html b/assignments/session07/mysite/myblog/templates/list.html new file mode 100644 index 00000000..88920817 --- /dev/null +++ b/assignments/session07/mysite/myblog/templates/list.html @@ -0,0 +1,25 @@ +{% extends "base.html" %} + +{% block content %} +

Recent Posts

+ + {% comment %} here is where the query happens {% endcomment %} + {% for post in posts %} +
+

+ {{ post }} +

+ +
+ {{ post.text }} +
+
    + {% for category in post.categories.all %} +
  • {{ category }}
  • + {% endfor %} +
+
+ {% endfor %} +{% endblock %} diff --git a/assignments/session07/mysite/myblog/tests.py b/assignments/session07/mysite/myblog/tests.py new file mode 100644 index 00000000..a2a27010 --- /dev/null +++ b/assignments/session07/mysite/myblog/tests.py @@ -0,0 +1,65 @@ +from django.test import TestCase +from django.contrib.auth.models import User +from myblog.models import Post +from myblog.models import Category +import datetime +from django.utils.timezone import utc + +class PostTestCase(TestCase): + fixtures = ['myblog_test_fixture.json', ] + + def setUp(self): + self.user = User.objects.get(pk=1) + + def test_unicode(self): + expected = "This is a title" + p1 = Post(title=expected) + actual = unicode(p1) + self.assertEqual(expected, actual) + +class CategoryTestCase(TestCase): + + def test_unicode(self): + expected = "A Category" + c1 = Category(name=expected) + actual = unicode(c1) + self.assertEqual(expected, actual) + +class FrontEndTestCase(TestCase): + """test views provided in the front-end""" + fixtures = ['myblog_test_fixture.json', ] + + def setUp(self): + self.now = datetime.datetime.utcnow().replace(tzinfo=utc) + self.timedelta = datetime.timedelta(15) + author = User.objects.get(pk=1) + for count in range(1,11): + post = Post(title="Post %d Title" % count, + text="foo", + author=author) + if count < 6: + # publish the first five posts + pubdate = self.now - self.timedelta * count + post.published_date = pubdate + post.save() + + def test_list_only_published(self): + resp = self.client.get('/') + self.assertTrue("Recent Posts" in resp.content) + for count in range(1,11): + title = "Post %d Title" % count + if count < 6: + self.assertContains(resp, title, count=1) + else: + self.assertNotContains(resp, title) + + def test_details_only_published(self): + for count in range(1,11): + title = "Post %d Title" % count + post = Post.objects.get(title=title) + resp = self.client.get('/posts/%d/' % post.pk) + if count < 6: + self.assertEqual(resp.status_code, 200) + self.assertContains(resp, title) + else: + self.assertEqual(resp.status_code, 404) diff --git a/assignments/session07/mysite/myblog/urls.py b/assignments/session07/mysite/myblog/urls.py new file mode 100644 index 00000000..ddce82fb --- /dev/null +++ b/assignments/session07/mysite/myblog/urls.py @@ -0,0 +1,10 @@ +from django.conf.urls import patterns, url + +urlpatterns = patterns('myblog.views', + url(r'^$', + 'list_view', + name="blog_index"), + url(http://github.com/r'%5Eposts/(?P%3Cpost_id%3E\d+)/$', + 'detail_view', + name="blog_detail"), +) \ No newline at end of file diff --git a/assignments/session07/mysite/myblog/views.py b/assignments/session07/mysite/myblog/views.py new file mode 100644 index 00000000..54c4bb75 --- /dev/null +++ b/assignments/session07/mysite/myblog/views.py @@ -0,0 +1,29 @@ +from django.shortcuts import render +from django.http import HttpResponse, HttpResponseRedirect, Http404 +from django.template import RequestContext, loader +from myblog.models import Post + +def stub_view(request, *args, **kwargs): + body = "Stub View\n\n" + if args: + body += "Args:\n" + body += "\n".join(["\t%s" % a for a in args]) + if kwargs: + body += "Kwargs:\n" + body += "\n".join(["\t%s: %s" % i for i in kwargs.items()]) + return HttpResponse(body, content_type="text/plain") + +def list_view(request): + published = Post.objects.exclude(published_date__exact=None) + posts = published.order_by('-published_date') + context = {'posts': posts} + return render(request, 'list.html', context) + +def detail_view(request, post_id): + published = Post.objects.exclude(published_date__exact=None) + try: + post = published.get(pk=post_id) + except Post.DoesNotExist: + raise Http404 + context = {'post': post} + return render(request, 'detail.html', context) \ No newline at end of file diff --git a/assignments/session07/mysite/mysite.db b/assignments/session07/mysite/mysite.db new file mode 100644 index 0000000000000000000000000000000000000000..63c9e9a57dbf40bdfacafb2a0d046cc8f04f22df GIT binary patch literal 155648 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 bAOHf7Isv}q=gWVIFaJH(@}GzE_y7MN3OLNV literal 0 HcmV?d00001 diff --git a/assignments/session07/mysite/mysite/__init__.py b/assignments/session07/mysite/mysite/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/assignments/session07/mysite/mysite/settings.py b/assignments/session07/mysite/mysite/settings.py new file mode 100644 index 00000000..78a3248e --- /dev/null +++ b/assignments/session07/mysite/mysite/settings.py @@ -0,0 +1,89 @@ +""" +Django settings for mysite project. + +For more information on this file, see +https://docs.djangoproject.com/en/1.6/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.6/ref/settings/ +""" + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +import os +BASE_DIR = os.path.dirname(os.path.dirname(__file__)) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'o$)p$v##&^xobe)62v2mvh(+m297vqd-sqnma@c0@g#g&o_!bw' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +TEMPLATE_DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = ( + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'south', + 'myblog', +) + +MIDDLEWARE_CLASSES = ( + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +) + +ROOT_URLCONF = 'mysite.urls' + +WSGI_APPLICATION = 'mysite.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.6/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': 'mysite.db', + } +} + +# Internationalization +# https://docs.djangoproject.com/en/1.6/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.6/howto/static-files/ + +STATIC_URL = '/static/' + +TEMPLATE_DIRS = (os.path.join(BASE_DIR, 'mysite/templates'),) + +LOGIN_URL = '/login/' +LOGIN_REDIRECT_URL = '/' diff --git a/assignments/session07/mysite/mysite/templates/base.html b/assignments/session07/mysite/mysite/templates/base.html new file mode 100644 index 00000000..2a01d991 --- /dev/null +++ b/assignments/session07/mysite/mysite/templates/base.html @@ -0,0 +1,26 @@ + + + + My Django Blog + + + + +
+
+ {% block content %} + [content will go here] + {% endblock %} +
+
+ + diff --git a/assignments/session07/mysite/mysite/templates/login.html b/assignments/session07/mysite/mysite/templates/login.html new file mode 100644 index 00000000..1566d0f7 --- /dev/null +++ b/assignments/session07/mysite/mysite/templates/login.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} + +{% block content %} +

My Blog Login

+
{% csrf_token %} + {{ form.as_p }} +

+
+{% endblock %} diff --git a/assignments/session07/mysite/mysite/urls.py b/assignments/session07/mysite/mysite/urls.py new file mode 100644 index 00000000..9c67dfdb --- /dev/null +++ b/assignments/session07/mysite/mysite/urls.py @@ -0,0 +1,20 @@ +from django.conf.urls import patterns, include, url + +from django.contrib import admin +admin.autodiscover() + +urlpatterns = patterns('', + # Examples: + # url(http://github.com/r'%5E'),%20'mysite.views.home',%20name='home'), + # url(http://github.com/r'%5Eblog/',%20include('blog.urls')), + url(http://github.com/r'%5E',%20include('myblog.urls')), + url(http://github.com/r'%5Eadmin/',%20include(admin.site.urls)), + url(r'^login/$', + 'django.contrib.auth.views.login', + {'template_name': 'login.html'}, + name="login"), + url(r'^logout/$', + 'django.contrib.auth.views.logout', + {'next_page': '/'}, + name="logout"), +) diff --git a/assignments/session07/mysite/mysite/wsgi.py b/assignments/session07/mysite/mysite/wsgi.py new file mode 100644 index 00000000..10ef32d9 --- /dev/null +++ b/assignments/session07/mysite/mysite/wsgi.py @@ -0,0 +1,14 @@ +""" +WSGI config for mysite project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ +""" + +import os +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() From 1c59bb903eada3ac4a4cb87ca759e41525b5ca17 Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Thu, 20 Feb 2014 11:34:34 -0800 Subject: [PATCH 282/487] fix test with bad indentation --- assignments/session07/mysite/myblog/tests.py | 76 ++++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/assignments/session07/mysite/myblog/tests.py b/assignments/session07/mysite/myblog/tests.py index a2a27010..413b2131 100644 --- a/assignments/session07/mysite/myblog/tests.py +++ b/assignments/session07/mysite/myblog/tests.py @@ -19,47 +19,47 @@ def test_unicode(self): class CategoryTestCase(TestCase): - def test_unicode(self): - expected = "A Category" - c1 = Category(name=expected) - actual = unicode(c1) - self.assertEqual(expected, actual) + def test_unicode(self): + expected = "A Category" + c1 = Category(name=expected) + actual = unicode(c1) + self.assertEqual(expected, actual) class FrontEndTestCase(TestCase): - """test views provided in the front-end""" - fixtures = ['myblog_test_fixture.json', ] + """test views provided in the front-end""" + fixtures = ['myblog_test_fixture.json', ] - def setUp(self): - self.now = datetime.datetime.utcnow().replace(tzinfo=utc) - self.timedelta = datetime.timedelta(15) - author = User.objects.get(pk=1) - for count in range(1,11): - post = Post(title="Post %d Title" % count, - text="foo", - author=author) - if count < 6: - # publish the first five posts - pubdate = self.now - self.timedelta * count - post.published_date = pubdate - post.save() + def setUp(self): + self.now = datetime.datetime.utcnow().replace(tzinfo=utc) + self.timedelta = datetime.timedelta(15) + author = User.objects.get(pk=1) + for count in range(1,11): + post = Post(title="Post %d Title" % count, + text="foo", + author=author) + if count < 6: + # publish the first five posts + pubdate = self.now - self.timedelta * count + post.published_date = pubdate + post.save() def test_list_only_published(self): - resp = self.client.get('/') - self.assertTrue("Recent Posts" in resp.content) - for count in range(1,11): - title = "Post %d Title" % count - if count < 6: - self.assertContains(resp, title, count=1) - else: - self.assertNotContains(resp, title) + resp = self.client.get('/') + self.assertTrue("Recent Posts" in resp.content) + for count in range(1,11): + title = "Post %d Title" % count + if count < 6: + self.assertContains(resp, title, count=1) + else: + self.assertNotContains(resp, title) - def test_details_only_published(self): - for count in range(1,11): - title = "Post %d Title" % count - post = Post.objects.get(title=title) - resp = self.client.get('/posts/%d/' % post.pk) - if count < 6: - self.assertEqual(resp.status_code, 200) - self.assertContains(resp, title) - else: - self.assertEqual(resp.status_code, 404) + def test_details_only_published(self): + for count in range(1,11): + title = "Post %d Title" % count + post = Post.objects.get(title=title) + resp = self.client.get('/posts/%d/' % post.pk) + if count < 6: + self.assertEqual(resp.status_code, 200) + self.assertContains(resp, title) + else: + self.assertEqual(resp.status_code, 404) From 172303e0a05dc65b52f33b33645c04d93d78e0ef Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 24 Feb 2014 21:18:32 -0800 Subject: [PATCH 283/487] update session 08 --- source/presentations/session08.rst | 120 +++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/source/presentations/session08.rst b/source/presentations/session08.rst index da9e0ad3..ca6cea03 100644 --- a/source/presentations/session08.rst +++ b/source/presentations/session08.rst @@ -16,3 +16,123 @@ Wherein we extend our Django blog app. image: http://djangopony.com/ +Last Week +--------- + +Last week, we created a nice, simple Django microblog application. + +.. class:: incremental + +Over the week, as your homework, you made some modifications to improve how it +works. + +.. class:: incremental + +There's still quite a bit more we can do to improve this application. + +.. class:: incremental + +And today, that's what we are going to do. + + +Preparation +----------- + +In order for this to work properly, we'll need to have a few things in place. + +.. container:: incremental small + + First, we'll start from a canonical copy of the microblog. Make a fork of + the following repository to your github account: + + .. code-block:: + :class: small + + https://github.com/cewing/django-microblog + +.. container:: incremental small + + Then, clone that repository to your local machine: + + .. code-block:: bash + :class: small + + $ git clone https://github.com//django-microblog.git + or + $ git clone git@github.com:/django-microblog.git + +Connect to Your Partner +----------------------- + +Finally, you'll want to connect to your partner's repository, so that you can +each work on your own laptop and still share the changes you make. + +.. container:: incremental small + + First, add your partner's repository as ``upstream`` to yours: + + .. code-block:: bash + :class: small + + $ git remote add upstream https://github.com//django-microblog.git + or + $ git remote add upstream git@github.com:/django-microblog.git + +.. container:: incremental small + + Then, fetch their copy so that you can easily merge their changes later: + + .. code-block:: bash + :class: small + + $ git fetch upstream + + +While You Work +-------------- + +.. class:: small + +Now, when you switch roles during your work, here's the workflow you can use: + +.. class:: small + +1. The current driver commits all changes and pushes to their repository: + +.. code-block:: bash + :class: small + + $ git commit -a -m "Time to switch roles" + $ git push origin master + +.. class:: small + +2. The new driver fetches and merges changes made upstream: + +.. code-block:: bash + :class: small + + $ git fetch --all + $ git branch -a + * master + remotes/origin/master + remotes/upstream/master + $ git merge upstream/master + +.. class:: small + +3. The new driver continues working from where their partner left off. + + +Homework +-------- + +For this week's homework, you will need to install the Zope Object Database +(ZODB) + +Instructions for this `may be found here`_. + +.. _may be found here: https://github.com/UWPCE-PythonCert/training.python_web/blob/master/resources/common/zodb-install-instructions.rst + +This is not trivial work. Please be sure to start early in the week so if +there is trouble, you'll be able to recover. From 08863ac057e90c858ef1a4378a9e8497c312a6f6 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 24 Feb 2014 21:20:18 -0800 Subject: [PATCH 284/487] updated and merged --- source/presentations/session08.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/presentations/session08.rst b/source/presentations/session08.rst index ca6cea03..2fdfc768 100644 --- a/source/presentations/session08.rst +++ b/source/presentations/session08.rst @@ -61,6 +61,7 @@ In order for this to work properly, we'll need to have a few things in place. or $ git clone git@github.com:/django-microblog.git + Connect to Your Partner ----------------------- @@ -136,3 +137,4 @@ Instructions for this `may be found here`_. This is not trivial work. Please be sure to start early in the week so if there is trouble, you'll be able to recover. + From 3950f3f8ec3d3529a50ca936e8372006676af3f5 Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Sun, 2 Mar 2014 14:39:46 -0800 Subject: [PATCH 285/487] Small typo --- source/presentations/session09.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/presentations/session09.rst b/source/presentations/session09.rst index 0a1f7ae0..6bc081ac 100644 --- a/source/presentations/session09.rst +++ b/source/presentations/session09.rst @@ -924,7 +924,7 @@ Instances of these classes are able to know when they've been changed. .. class:: incremental -When a ZODB transaction is committed, all changes objects are saved. +When a ZODB transaction is committed, all changed objects are saved. Persistent Base Classes From ee760cab433de0e69f459b9264c99f6eec832376 Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Sun, 2 Mar 2014 14:40:41 -0800 Subject: [PATCH 286/487] Minor typo --- source/presentations/session09.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/presentations/session09.rst b/source/presentations/session09.rst index 6bc081ac..fe1bbf9e 100644 --- a/source/presentations/session09.rst +++ b/source/presentations/session09.rst @@ -1235,7 +1235,7 @@ We are ready to add views now. We'll need: * A view of the Wiki itself, which redirects to the front page. * A view of an existing Page * A view that allows us to *add* a new Page -* A view that allows us to *edit* and existing Page +* A view that allows us to *edit* an existing Page .. class:: incremental From c1e509e0069f27c8e79d9b2c011f7ee1fdf01e5f Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Sun, 2 Mar 2014 14:52:55 -0800 Subject: [PATCH 287/487] Update session09.rst --- source/presentations/session09.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/presentations/session09.rst b/source/presentations/session09.rst index fe1bbf9e..754b8dda 100644 --- a/source/presentations/session09.rst +++ b/source/presentations/session09.rst @@ -1545,7 +1545,7 @@ Update ``view_page``: def view_page(context, request): #... - content = wikiwords.sub(check, content) #<- already there + content = WIKIWORDS.sub(check, content) #<- already there edit_url = request.resource_url(http://github.com/context,%20'edit_page') #<- add return dict(page=context, content=content, From d501637266380b7b5c4585266b8c5d58f0ebba85 Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Sun, 2 Mar 2014 16:39:25 -0800 Subject: [PATCH 288/487] logged_in is not defined by slide 12 Using this base.pt without commenting out the (or otherwise removing the "logged_in") will break the template. --- resources/session10/base.pt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/resources/session10/base.pt b/resources/session10/base.pt index 6d7e665c..db9e81d6 100644 --- a/resources/session10/base.pt +++ b/resources/session10/base.pt @@ -42,9 +42,11 @@ @@ -59,4 +61,4 @@ - \ No newline at end of file + From ddb211dabbabcd86d3e01848f7058b98ecdad01e Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 2 Mar 2014 17:02:02 -0800 Subject: [PATCH 289/487] update cgi_1.py to have a more "correct" shebang --- resources/session04/cgi/cgi-bin/cgi_1.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/session04/cgi/cgi-bin/cgi_1.py b/resources/session04/cgi/cgi-bin/cgi_1.py index b969de64..7dfafcd2 100755 --- a/resources/session04/cgi/cgi-bin/cgi_1.py +++ b/resources/session04/cgi/cgi-bin/cgi_1.py @@ -1,5 +1,5 @@ -#!/usr/bin/python -import cgi +#!/usr/bin/env python +import cgi cgi.test() From ba7cb047b224fd8b4ec3d727c7f03261be8ea5d6 Mon Sep 17 00:00:00 2001 From: Fulvio Casali Date: Mon, 3 Mar 2014 23:35:14 -0800 Subject: [PATCH 290/487] move adding template to session09. revert change to base.pt --- resources/session09/base.pt | 62 +++++++++++++++ resources/session10/base.pt | 2 - source/presentations/session09.rst | 124 +++++++++++++++++++++++++++++ source/presentations/session10.rst | 84 +------------------ 4 files changed, 190 insertions(+), 82 deletions(-) create mode 100644 resources/session09/base.pt diff --git a/resources/session09/base.pt b/resources/session09/base.pt new file mode 100644 index 00000000..c89d5283 --- /dev/null +++ b/resources/session09/base.pt @@ -0,0 +1,62 @@ + + + + Pyramid Wiki + + + + + + + + +
+
+
+
+ pyramid +
+
+
+
+
+
+ + Viewing Page Name Goes + Here + +
+ You can return to the + FrontPage. +
+ +
+
+
+
+ +
+
+
+ + + diff --git a/resources/session10/base.pt b/resources/session10/base.pt index db9e81d6..c89d5283 100644 --- a/resources/session10/base.pt +++ b/resources/session10/base.pt @@ -42,11 +42,9 @@ diff --git a/source/presentations/session09.rst b/source/presentations/session09.rst index 754b8dda..b79b0e88 100644 --- a/source/presentations/session09.rst +++ b/source/presentations/session09.rst @@ -1560,6 +1560,130 @@ Update ``view_page``: OK +What's in the ZODB? +------------------- + +We can inspect the database directly. + +.. class:: incremental + +Start an interactive session with: + +:: + + (pyramidenv)$ pshell development.ini + ... + >>> root + {'FrontPage': } + +.. class:: incremental small + +:: + + >>> root['FrontPage'].data + 'This is the front page' + +.. class:: incremental small + +:: + + >>> root['FrontPage'].__dict__ + {'__name__': 'FrontPage', 'data': 'This is the front page', '__parent__': {'FrontPage': }} + + + + +Adding Templates +---------------- + +What is the page template name for ``view_page``? + +.. class:: incremental + +Create ``view.pt`` in your ``templates`` directory. + +.. class:: incremental + +Also copy the file ``base.pt`` from the class resources. + +.. class:: incremental + +Pyramid can use a number of different templating engines. + +.. class:: incremental + +We'll be using Chameleon, which also supports extending other templates. + + +The view.pt Template +-------------------- + +Type this code into your ``view.pt`` file: + +.. code-block:: xml + + + + +
+ Page text goes here. +
+

+ + Edit this page + +

+
+
+ + +View Your Work +-------------- + +We've created the following: + +.. class:: incremental small + +* A wiki view that redirects to the automatically-created FrontPage page +* A page view that will render the ``data`` from a page, along with a url for + editing that page +* A page template to show a wiki page. + +.. class:: incremental + +That's all we need to be able to see our work. Start Pyramid: + +.. class:: incremental small + +:: + + (pyramidenv)$ pserve development.ini + Starting server in PID 43925. + serving on http://0.0.0.0:6543 + +.. class:: incremental + +Load http://localhost:6543/ + + +What You Should See +------------------- + +.. image:: img/wiki_frontpage.png + :align: center + :width: 95% + + +Page Editing +------------ + +You'll notice that the page has a link to ``Edit This Page`` + +.. class:: incremental + +If you click it, you get a 404. We haven't created that view yet. + + Next Steps ---------- diff --git a/source/presentations/session10.rst b/source/presentations/session10.rst index f7af5495..8c3731fc 100644 --- a/source/presentations/session10.rst +++ b/source/presentations/session10.rst @@ -13,28 +13,6 @@ Session 10: A Pyramid Application | Totally not built by aliens. -Adding Templates ----------------- - -What is the page template name for ``view_page``? - -.. class:: incremental - -Create ``view.pt`` in your ``templates`` directory. - -.. class:: incremental - -Also copy the file ``base.pt`` from the class resources. - -.. class:: incremental - -Pyramid can use a number of different templating engines. - -.. class:: incremental - -We'll be using Chameleon, which also supports extending other templates. - - Chameleon Templates ------------------- @@ -152,30 +130,13 @@ METAL provides operators related to creating and using template macros: Much of this will become clearer as we actually create our templates. -The view.pt Template --------------------- - -Type this code into your ``view.pt`` file: - -.. code-block:: xml - - - -
- Page text goes here. -
-

- - Edit this page - -

-
-
- - A Few Notes ----------- +Take a look at our ``view.pt`` template again. + +.. class:: incremental + ```` and ```` tags are processed and removed by the engine. .. class:: incremental @@ -212,43 +173,6 @@ The ``structure`` expression ensures that the HTML is not escaped. our anchor to the value passed into our template as ``edit_url``. -View Your Work --------------- - -We've created the following: - -.. class:: incremental small - -* A wiki view that redirects to the automatically-created FrontPage page -* A page view that will render the ``data`` from a page, along with a url for - editing that page -* A page template to show a wiki page. - -.. class:: incremental - -That's all we need to be able to see our work. Start Pyramid: - -.. class:: incremental small - -:: - - (pyramidenv)$ pserve development.ini - Starting server in PID 43925. - serving on http://0.0.0.0:6543 - -.. class:: incremental - -Load http://localhost:6543/ - - -What You Should See -------------------- - -.. image:: img/wiki_frontpage.png - :align: center - :width: 95% - - Page Editing ------------ From 3ba0e0220defec77a4d7223155c8259456ea7989 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 27 May 2014 09:34:35 -0700 Subject: [PATCH 291/487] typo --- source/presentations/session07.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/presentations/session07.rst b/source/presentations/session07.rst index 02d50ee8..c5a6c966 100644 --- a/source/presentations/session07.rst +++ b/source/presentations/session07.rst @@ -783,7 +783,7 @@ Full Urlconf Testing Views ------------- -Before we begin writin real views, we need to add some tests for the views we +Before we begin writing real views, we need to add some tests for the views we are about to create. .. class:: incremental From 6128dfaa9bc59cd0521f8bbe3b912327d85a5b9c Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 27 May 2014 09:35:47 -0700 Subject: [PATCH 292/487] add newline --- resources/session10/wikitutorial/wikitutorial/templates/edit.pt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/session10/wikitutorial/wikitutorial/templates/edit.pt b/resources/session10/wikitutorial/wikitutorial/templates/edit.pt index 9d6ef02a..12af8152 100644 --- a/resources/session10/wikitutorial/wikitutorial/templates/edit.pt +++ b/resources/session10/wikitutorial/wikitutorial/templates/edit.pt @@ -12,4 +12,4 @@ - \ No newline at end of file + From 84dc67f7c5a966572f60889b698911dd21e764e5 Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 28 Dec 2014 18:22:47 -0800 Subject: [PATCH 293/487] update .gitignore to omit junk --- .gitignore | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d04dac0b..86ecdd9d 100644 --- a/.gitignore +++ b/.gitignore @@ -31,4 +31,10 @@ svn-commit.tmp bin build include -lib \ No newline at end of file +lib +cast-offs +develop-eggs +development +*.db +*.sublime-project +*.sublime-workspace From 5459388e9583a5a59c8c5ef8fa59183cb720ecdd Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 30 Dec 2014 19:33:21 -0800 Subject: [PATCH 294/487] pep8 fix --- assignments/session02/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignments/session02/tests.py b/assignments/session02/tests.py index a74fe150..1438857c 100644 --- a/assignments/session02/tests.py +++ b/assignments/session02/tests.py @@ -77,7 +77,7 @@ def test_passed_mimetype_in_response(self): def test_passed_body_in_response(self): bodies = [ - "a body", + "a body", "a longer body\nwith two lines", open("webroot/sample.txt", 'r').read(), ] From 73b49de5f81fd249643d32587105cf52652025d7 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 30 Dec 2014 19:37:16 -0800 Subject: [PATCH 295/487] begin shuffling things around --- source/presentations/session01.rst | 1201 ------------------ source/presentations/session04-old.rst | 1435 +++++++++++++++++++++ source/presentations/session04.rst | 1616 ++++++++++-------------- 3 files changed, 2126 insertions(+), 2126 deletions(-) delete mode 100644 source/presentations/session01.rst create mode 100644 source/presentations/session04-old.rst diff --git a/source/presentations/session01.rst b/source/presentations/session01.rst deleted file mode 100644 index 69f9106b..00000000 --- a/source/presentations/session01.rst +++ /dev/null @@ -1,1201 +0,0 @@ -Python Web Programming -====================== - -.. image:: img/python.png - :align: left - :width: 33% - -Session 1: Networking and Sockets - -.. class:: intro-blurb - -Wherein we learn about the basic structure of the internet and explore the -building blocks that make it possible. - - -But First ---------- - -Class presentations are available online for your use - -.. class:: small - -https://github.com/UWPCE-PythonCert/training.python_web - -.. class:: incremental - -Licensed with Creative Commons BY-NC-SA - -.. class:: small incremental - -* You must attribute the work -* You may not use the work for commercial purposes -* You have to share your versions just like this one - -.. class:: incremental - -Find mistakes? See improvements? Make a pull request. - - -But First ---------- - -Classroom Protocol - -.. class:: incremental - -Questions to ask: - -.. class:: incremental - -* What did you just say? -* Please explain what we just did again? -* Why didn't that work for me? -* Is that a typo? - - -But First ---------- - -Classroom Protocol - -.. class:: incremental - -Questions **not** to ask: - -.. class:: incremental - -* **Hypotheticals**: What happens if I do X? -* **Research**: Can Python do Y? -* **Syllabus**: Are we going to cover Z in class? -* **Marketing questions**: please just don't. -* **Performance questions**: Is Python fast enough? -* **Unpythonic**: Why doesn't Python do it some other way? -* **Show off**: Look what I just did! - - -But First ---------- - -.. class:: big-centered - -Introductions - - -Computer Communications ------------------------ - -.. image:: img/network_topology.png - :align: left - :width: 40% - -.. class:: incremental - -* processes can communicate - -* inside one machine - -* between two machines - -* among many machines - -.. class:: image-credit - -image: http://en.wikipedia.org/wiki/Internet_Protocol_Suite - - -Computer Communications ------------------------ - -.. image:: img/data_in_tcpip_stack.png - :align: left - :width: 55% - -.. class:: incremental - -* Process divided into 'layers' - -* 'Layers' are mostly arbitrary - -* Different descriptions have different layers - -* Most common is the 'TCP/IP Stack' - -.. class:: image-credit - -image: http://en.wikipedia.org/wiki/Internet_Protocol_Suite - - -The TCP/IP Stack - Link ------------------------ - -The bottom layer is the 'Link Layer' - -.. class:: incremental - -* Deals with the physical connections between machines, 'the wire' - -* Packages data for physical transport - -* Executes transmission over a physical medium - - * what that medium is is arbitrary - -* Implemented in the Network Interface Card(s) (NIC) in your computer - - -The TCP/IP Stack - Internet ---------------------------- - -Moving up, we have the 'Internet Layer' - -.. class:: incremental - -* Deals with addressing and routing - - * Where are we going and how do we get there? - -* Agnostic as to physical medium (IP over Avian Carrier - IPoAC) - -* Makes no promises of reliability - -* Two addressing systems - - .. class:: incremental - - * IPv4 (current, limited '192.168.1.100') - - * IPv6 (future, 3.4 x 10^38 addresses, '2001:0db8:85a3:0042:0000:8a2e:0370:7334') - - -The TCP/IP Stack - Internet ---------------------------- - -.. class:: big-centered - -That's 4.3 x 10^28 addresses *per person alive today* - - -The TCP/IP Stack - Transport ----------------------------- - -Next up is the 'Transport Layer' - -.. class:: incremental - -* Deals with transmission and reception of data - - * error correction, flow control, congestion management - -* Common protocols include TCP & UDP - - * TCP: Tranmission Control Protocol - - * UDP: User Datagram Protocol - -* Not all Transport Protocols are 'reliable' - - .. class:: incremental - - * TCP ensures that dropped packets are resent - - * UDP makes no such assurance - - * Reliability is slow and expensive - - -The TCP/IP Stack - Transport ----------------------------- - -The 'Transport Layer' also establishes the concept of a **port** - -.. class:: incremental - -* IP Addresses designate a specific *machine* on the network - -* A **port** provides addressing for individual *applications* in a single host - -* 192.168.1.100:80 (the *:80* part is the **port**) - -* [2001:db8:85a3:8d3:1319:8a2e:370:7348]:443 (*:443* is the **port**) - -.. class:: incremental - -This means that you don't have to worry about information intended for your -web browser being accidentally read by your email client. - - -The TCP/IP Stack - Transport ----------------------------- - -There are certain **ports** which are commonly understood to belong to given -applications or protocols: - -.. class:: incremental - -* 80/443 - HTTP/HTTPS -* 20 - FTP -* 22 - SSH -* 23 - Telnet -* 25 - SMTP -* ... - -.. class:: incremental - -These ports are often referred to as **well-known ports** - -.. class:: small - -(see http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers) - - -The TCP/IP Stack - Transport ----------------------------- - -Ports are grouped into a few different classes - -.. class:: incremental - -* Ports numbered 0 - 1023 are *reserved* - -* Ports numbered 1024 - 65535 are *open* - -* Ports numbered 1024 - 49151 may be *registered* - -* Ports numbered 49152 - 65535 are called *ephemeral* - - -The TCP/IP Stack - Application ------------------------------- - -The topmost layer is the 'Application Layer' - -.. class:: incremental - -* Deals directly with data produced or consumed by an application - -* Reads or writes data using a set of understood, well-defined **protocols** - - * HTTP, SMTP, FTP etc. - -* Does not know (or need to know) about lower layer functionality - - * The exception to this rule is **endpoint** data (or IP:Port) - - -The TCP/IP Stack - Application ------------------------------- - -.. class:: big-centered - -this is where we live and work - - -Sockets -------- - -Think back for a second to what we just finished discussing, the TCP/IP stack. - -.. class:: incremental - -* The *Internet* layer gives us an **IP Address** - -* The *Transport* layer establishes the idea of a **port**. - -* The *Application* layer doesn't care about what happens below... - -* *Except for* **endpoint data** (IP:Port) - -.. class:: incremental - -A **Socket** is the software representation of that endpoint. - -.. class:: incremental - -Opening a **socket** creates a kind of transceiver that can send and/or -receive *bytes* at a given IP address and Port. - - -Sockets in Python ------------------ - -Python provides a standard library module which provides socket functionality. -It is called **socket**. - -.. class:: incremental - -The library is really just a very thin wrapper around the system -implementation of *BSD Sockets* - -.. class:: incremental - -Let's spend a few minutes getting to know this module. - -.. class:: incremental - -We're going to do this next part together, so open up a terminal and start a -python interpreter - - -Sockets in Python ------------------ - -The Python sockets library allows us to find out what port a *service* uses: - -.. class:: small - - >>> import socket - >>> socket.getservbyname('ssh') - 22 - -.. class:: incremental - -You can also do a *reverse lookup*, finding what service uses a given *port*: - -.. class:: incremental small - - >>> socket.getservbyport(80) - 'http' - - -Sockets in Python ------------------ - -The sockets library also provides tools for finding out information about -*hosts*. For example, you can find out about the hostname and IP address of -the machine you are currently using:: - - >>> socket.gethostname() - 'heffalump.local' - >>> socket.gethostbyname(socket.gethostname()) - '10.211.55.2' - - -Sockets in Python ------------------ - -You can also find out about machines that are located elsewhere, assuming you -know their hostname. For example:: - - >>> socket.gethostbyname('google.com') - '173.194.33.4' - >>> socket.gethostbyname('uw.edu') - '128.95.155.135' - >>> socket.gethostbyname('crisewing.com') - '108.59.11.99' - - -Sockets in Python ------------------ - -The ``gethostbyname_ex`` method of the ``socket`` library provides more -information about the machines we are exploring:: - - >>> socket.gethostbyname_ex('google.com') - ('google.com', [], ['173.194.33.9', '173.194.33.14', - ... - '173.194.33.6', '173.194.33.7', - '173.194.33.8']) - >>> socket.gethostbyname_ex('crisewing.com') - ('crisewing.com', [], ['108.59.11.99']) - >>> socket.gethostbyname_ex('www.rad.washington.edu') - ('elladan.rad.washington.edu', # <- canonical hostname - ['www.rad.washington.edu'], # <- any machine aliases - ['128.95.247.84']) # <- all active IP addresses - - -Sockets in Python ------------------ - -To create a socket, you use the **socket** method of the ``socket`` library. -It takes up to three optional positional arguments (here we use none to get -the default behavior):: - - >>> foo = socket.socket() - >>> foo - - - -Sockets in Python ------------------ - -A socket has some properties that are immediately important to us. These -include the *family*, *type* and *protocol* of the socket:: - - >>> foo.family - 2 - >>> foo.type - 1 - >>> foo.proto - 0 - -.. class:: incremental - -You might notice that the values for these properties are integers. In fact, -these integers are **constants** defined in the socket library. - - -A quick utility method ----------------------- - -Let's define a method in place to help us see these constants. It will take a -single argument, the shared prefix for a defined set of constants: - -.. class:: small - -:: - - >>> def get_constants(prefix): - ... """mapping of socket module constants to their names.""" - ... return dict( - ... (getattr(socket, n), n) - ... for n in dir(socket) - ... if n.startswith(prefix) - ... ) - ... - >>> - -.. class:: small - -(you can also find this in ``resources/session01/session1.py``) - - -Socket Families ---------------- - -Think back a moment to our discussion of the *Internet* layer of the TCP/IP -stack. There were a couple of different types of IP addresses: - -.. class:: incremental - -* IPv4 ('192.168.1.100') - -* IPv6 ('2001:0db8:85a3:0042:0000:8a2e:0370:7334') - -.. class:: incremental - -The **family** of a socket corresponds to the *addressing system* it uses for -connecting. - - -Socket Families ---------------- - -Families defined in the ``socket`` library are prefixed by ``AF_``:: - - >>> families = get_constants('AF_') - >>> families - {0: 'AF_UNSPEC', 1: 'AF_UNIX', 2: 'AF_INET', - 11: 'AF_SNA', 12: 'AF_DECnet', 16: 'AF_APPLETALK', - 17: 'AF_ROUTE', 23: 'AF_IPX', 30: 'AF_INET6'} - -.. class:: small incremental - -*Your results may vary* - -.. class:: incremental - -Of all of these, the ones we care most about are ``2`` (IPv4) and ``30`` (IPv6). - - -Unix Domain Sockets -------------------- - -When you are on a machine with an operating system that is Unix-like, you will -find another generally useful socket family: ``AF_UNIX``, or Unix Domain -Sockets. Sockets in this family: - -.. class:: incremental - -* connect processes **on the same machine** - -* are generally a bit slower than IPC connnections - -* have the benefit of allowing the same API for programs that might run on one - machine __or__ across the network - -* use an 'address' that looks like a pathname ('/tmp/foo.sock') - - -Test your skills ----------------- - -What is the *default* family for the socket we created just a moment ago? - -.. class:: incremental - -(remember we bound the socket to the symbol ``foo``) - -.. class:: incremental center - -How did you figure this out? - - -Socket Types ------------- - -The socket *type* determines the semantics of socket communications. - -Look up socket type constants with the ``SOCK_`` prefix:: - - >>> types = get_constants('SOCK_') - >>> types - {1: 'SOCK_STREAM', 2: 'SOCK_DGRAM', - ...} - -.. class:: incremental - -The most common are ``1`` (Stream communication (TCP)) and ``2`` (Datagram -communication (UDP)). - - -Test your skills ----------------- - -What is the *default* type for our generic socket, ``foo``? - - -Socket Protocols ----------------- - -A socket also has a designated *protocol*. The constants for these are -prefixed by ``IPPROTO_``:: - - >>> protocols = get_constants('IPPROTO_') - >>> protocols - {0: 'IPPROTO_IP', 1: 'IPPROTO_ICMP', - ..., - 255: 'IPPROTO_RAW'} - -.. class:: incremental - -The choice of which protocol to use for a socket is determined by the -*internet layer* protocol you intend to use. ``TCP``? ``UDP``? ``ICMP``? -``IGMP``? - - -Test your skills ----------------- - -What is the *default* protocol used by our generic socket, ``foo``? - - -Custom Sockets --------------- - -These three properties of a socket correspond to the three positional -arguments you may pass to the socket constructor. - -.. container:: incremental - - Using them allows you to create sockets with specific communications - profiles:: - - >>> bar = socket.socket(socket.AF_INET, - ... socket.SOCK_DGRAM, - ... socket.IPPROTO_UDP) - ... - >>> bar - - - -Break Time ----------- - -So far we have: - -.. class:: incremental - -* learned about the "layers" of the TCP/IP Stack -* discussed *families*, *types* and *protocols* in sockets -* learned how to create sockets with a specific communications profile. - -.. class:: incremental - -When we return we'll learn how to find the communcations profiles of remote -sockets, how to connect to them, and how to send and receive messages. - -.. class:: incremental - -Take a few minutes now to clear your head (do not quit your python -interpreter). - - -Address Information -------------------- - -When you are creating a socket to communicate with a remote service, the -remote socket will have a specific communications profile. - -.. class:: incremental - -The local socket you create must match that communications profile. - -.. class:: incremental - -How can you determine the *correct* values to use? - -.. class:: incremental center - -You ask. - - -Address Information -------------------- - -The function ``socket.getaddrinfo`` provides information about available -connections on a given host. - -.. code-block:: python - :class: small - - socket.getaddrinfo('127.0.0.1', 80) - -.. class:: incremental - -This provides all you need to make a proper connection to a socket on a remote -host. The value returned is a tuple of: - -.. class:: incremental - -* socket family -* socket type -* socket protocol -* canonical name (usually empty, unless requested by flag) -* socket address (tuple of IP and Port) - - -A quick utility method ----------------------- - -Again, let's create a utility method in-place so we can see this in action: - -.. class:: small - -:: - - >>> def get_address_info(host, port): - ... for response in socket.getaddrinfo(host, port): - ... fam, typ, pro, nam, add = response - ... print 'family: ', families[fam] - ... print 'type: ', types[typ] - ... print 'protocol: ', protocols[pro] - ... print 'canonical name: ', nam - ... print 'socket address: ', add - ... print - ... - >>> - -.. class:: small - -(you can also find this in ``resources/session01/session1.py``) - - -On Your Own Machine -------------------- - -Now, ask your own machine what possible connections are available for 'http':: - - >>> get_address_info(socket.gethostname(), 'http') - family: AF_INET - type: SOCK_DGRAM - protocol: IPPROTO_UDP - canonical name: - socket address: ('10.211.55.2', 80) - - family: AF_INET - ... - >>> - -.. class:: incremental - -What answers do you get? - - -On the Internet ---------------- - -:: - - >>> get_address_info('crisewing.com', 'http') - family: AF_INET - type: SOCK_DGRAM - ... - - family: AF_INET - type: SOCK_STREAM - ... - >>> - -.. class:: incremental - -Try a few other servers you know about. - - -First Steps ------------ - -.. class:: big-centered - -Let's put this to use - - -Construct a Socket ------------------- - -We've already made a socket ``foo`` using the generic constructor without any -arguments. We can make a better one now by using real address information from -a real server online [**do not type this yet**]: - -.. class:: small - -:: - - >>> streams = [info - ... for info in socket.getaddrinfo('crisewing.com', 'http') - ... if info[1] == socket.SOCK_STREAM] - >>> streams - [(2, 1, 6, '', ('108.59.11.99', 80))] - >>> info = streams[0] - >>> cewing_socket = socket.socket(*info[:3]) - - -Connecting a Socket -------------------- - -Once the socket is constructed with the appropriate *family*, *type* and -*protocol*, we can connect it to the address of our remote server:: - - >>> cewing_socket.connect(info[-1]) - >>> - -.. class:: incremental - -* a successful connection returns ``None`` - -* a failed connection raises an error - -* you can use the *type* of error returned to tell why the connection failed. - - -Sending a Message ------------------ - -Send a message to the server on the other end of our connection (we'll -learn in session 2 about the message we are sending):: - - >>> msg = "GET / HTTP/1.1\r\n" - >>> msg += "Host: crisewing.com\r\n\r\n" - >>> cewing_socket.sendall(msg) - >>> - -.. class:: incremental small - -* the transmission continues until all data is sent or an error occurs - -* success returns ``None`` - -* failure to send raises an error - -* you can use the type of error to figure out why the transmission failed - -* if an error occurs you **cannot** know how much, if any, of your data was - sent - - -Receiving a Reply ------------------ - -Whatever reply we get is received by the socket we created. We can read it -back out (again, **do not type this yet**):: - - >>> response = cewing_socket.recv(4096) - >>> response - 'HTTP/1.1 200 OK\r\nDate: Thu, 03 Jan 2013 05:56:53 - ... - -.. class:: incremental small - -* The sole required argument is ``buffer_size`` (an integer). It should be a - power of 2 and smallish (~4096) -* It returns a byte string of ``buffer_size`` (or smaller if less data was - received) -* If the response is longer than ``buffer size``, you can call the method - repeatedly. The last bunch will be less than ``buffer size``. - - -Cleaning Up ------------ - -When you are finished with a connection, you should always close it:: - - >>> cewing_socket.close() - - -Putting it all together ------------------------ - -First, connect and send a message: - -.. class:: small - -:: - - >>> streams = [info - ... for info in socket.getaddrinfo('crisewing.com', 'http') - ... if info[1] == socket.SOCK_STREAM] - >>> info = streams[0] - >>> cewing_socket = socket.socket(*info[:3]) - >>> cewing_socket.connect(info[-1]) - >>> msg = "GET / HTTP/1.1\r\n" - >>> msg += "Host: crisewing.com\r\n\r\n" - >>> cewing_socket.sendall(msg) - - -Putting it all together ------------------------ - -Then, receive a reply, iterating until it is complete: - -:: - - >>> buffsize = 4096 - >>> response = '' - >>> done = False - >>> while not done: - ... msg_part = cewing_socket.recv(buffsize) - ... if len(msg_part) < buffsize: - ... done = True - ... cewing_socket.close() - ... response += msg_part - ... - >>> len(response) - 19427 - - -Server Side ------------ - -.. class:: big-centered - -What about the other half of the equation? - -Construct a Socket ------------------- - -**For the moment, stop typing this into your interpreter.** - -.. container:: incremental - - Again, we begin by constructing a socket. Since we are actually the server - this time, we get to choose family, type and protocol:: - - >>> server_socket = socket.socket( - ... socket.AF_INET, - ... socket.SOCK_STREAM, - ... socket.IPPROTO_TCP) - ... - >>> server_socket - - - -Bind the Socket ---------------- - -Our server socket needs to be bound to an address. This is the IP Address and -Port to which clients must connect:: - - >>> address = ('127.0.0.1', 50000) - >>> server_socket.bind(address) - -.. class:: incremental - -**Terminology Note**: In a server/client relationship, the server *binds* to -an address and port. The client *connects* - - -Listen for Connections ----------------------- - -Once our socket is bound to an address, we can listen for attempted -connections:: - - >>> server_socket.listen(1) - -.. class:: incremental - -* The argument to ``listen`` is the *backlog* - -* The *backlog* is the **maximum** number of connection requests that the - socket will queue - -* Once the limit is reached, the socket refuses new connections. - - -Accept Incoming Messages ------------------------- - -When a socket is listening, it can receive incoming connection requests:: - - >>> connection, client_address = server_socket.accept() - ... # this blocks until a client connects - >>> connection.recv(16) - -.. class:: incremental - -* The ``connection`` returned by a call to ``accept`` is a **new socket**. - This new socket is used to communicate with the client - -* The ``client_address`` is a two-tuple of IP Address and Port for the client - socket - -* When a connection request is 'accepted', it is removed from the backlog - queue. - - -Send a Reply ------------- - -The same socket that received a message from the client may be used to return -a reply:: - - >>> connection.sendall("message received") - - -Clean Up --------- - -Once a transaction between the client and server is complete, the -``connection`` socket should be closed:: - - >>> connection.close() - -.. class:: incremental - -Note that the ``server_socket`` is *never* closed as long as the server -continues to run. - - -Getting the Flow ----------------- - -The flow of this interaction can be a bit confusing. Let's see it in action -step-by-step. - -.. class:: incremental - -Open a second python interpreter and place it next to your first so you can -see both of them at the same time. - - -Create a Server ---------------- - -In your first python interpreter, create a server socket and prepare it for -connections:: - - >>> server_socket = socket.socket( - ... socket.AF_INET, - ... socket.SOCK_STREAM, - ... socket.IPPROTO_IP) - >>> server_socket.bind(('127.0.0.1', 50000)) - >>> server_socket.listen(1) - >>> conn, addr = server_socket.accept() - -.. class:: incremental - -At this point, you should **not** get back a prompt. The server socket is -waiting for a connection to be made. - - -Create a Client ---------------- - -In your second interpreter, create a client socket and prepare to send a -message:: - - >>> import socket - >>> client_socket = socket.socket( - ... socket.AF_INET, - ... socket.SOCK_STREAM, - ... socket.IPPROTO_IP) - -.. container:: incremental - - Before connecting, keep your eye on the server interpreter:: - - >>> client_socket.connect(('127.0.0.1', 50000)) - - -Send a Message Client->Server ------------------------------ - -As soon as you made the connection above, you should have seen the prompt -return in your server interpreter. The ``accept`` method finally returned a -new connection socket. - -.. class:: incremental - -When you're ready, type the following in the *client* interpreter. - -.. class:: incremental - -:: - - >>> client_socket.sendall("Hey, can you hear me?") - - -Receive and Respond -------------------- - -Back in your server interpreter, go ahead and receive the message from your -client:: - - >>> conn.recv(32) - 'Hey, can you hear me?' - -Send a message back, and then close up your connection:: - - >>> conn.sendall("Yes, I hear you.") - >>> conn.close() - - -Finish Up ---------- - -Back in your client interpreter, take a look at the response to your message, -then be sure to close your client socket too:: - - >>> client_socket.recv(32) - 'Yes, I hear you.' - >>> client_socket.close() - -And now that we're done, we can close up the server too (back in the server -interpreter):: - - >>> server_socket.close() - - -Congratulations! ----------------- - -.. class:: big-centered - -You've run your first client-server interaction - - -Homework --------- - -Your homework assignment for this week is to take what you've learned here -and build a simple "echo" server. - -.. class:: incremental - -The server should automatically return to any client that connects *exactly* -what it receives (it should **echo** all messages). - -.. class:: incremental - -You will also write a python script that, when run, will send a message to the -server and receive the reply, printing it to ``stdout``. - -.. class:: incremental - -Finally, you'll do all of this so that it can be tested. - - -What You Have -------------- - -In our class repository, there is a folder ``assignments/session01``. - -.. class:: incremental - -Inside that folder, you should find: - -.. class:: incremental - -* A file ``tasks.txt`` that contains these instructions - -* A skeleton for your server in ``echo_server.py`` - -* A skeleton for your client script in ``echo_client.py`` - -* Some simple tests in ``tests.py`` - -.. class:: incremental - -Your task is to make the tests pass. - - -Running the tests ------------------ - -To run the tests, you'll have to set the server running in one terminal: - -.. class:: small - -:: - - $ python echo_server.py - -.. container:: incremental - - Then, in a second terminal, you will execute the tests: - - .. class:: small - - :: - - $ python tests.py - -.. container:: incremental - - You should see output like this: - - .. class:: small - - :: - - [...] - FAILED (failures=2) - - -Submitting Your Homework ------------------------- - -To submit your homework: - -.. class:: incremental - -* In github, make a fork of my repository into *your* account. - -* Clone your fork of my repository to your computer. - -* Do your work in the ``assignments/session01/`` folder on your computer and - commit your changes to your fork. - -* When you are finished and your tests are passing, you will open a pull - request in github.com from your fork to mine. - -.. class:: incremental - -I will review your work when I receive your pull requests, make comments on it -there, and then close the pull request. - - -Going Further -------------- - -In ``assignments/session01/tasks.txt`` you'll find a few extra problems to try. - -.. class:: incremental - -If you finish the first part of the homework in less than 3-4 hours give one -or more of these a whirl. - -.. class:: incremental - -They are not required, but if you include solutions in your pull request, I'll -review your work. diff --git a/source/presentations/session04-old.rst b/source/presentations/session04-old.rst new file mode 100644 index 00000000..f8214583 --- /dev/null +++ b/source/presentations/session04-old.rst @@ -0,0 +1,1435 @@ +Python Web Programming +====================== + +.. image:: img/gateway.jpg + :align: left + :width: 50% + +Session 4: CGI, WSGI and Living Online + +.. class:: intro-blurb + +Wherein we discover the gateways to dynamic processes on a server. + +.. class:: image-credit + +image: The Wandering Angel http://www.flickr.com/photos/wandering_angel/1467802750/ - CC-BY + +But First +--------- + +.. class:: big-centered + +A look at some of the cool mashups you built over the week. + + +But First +--------- + +Clean up the git situation. + + +But First +--------- + +Before you leave the classroom today, please complete the following tasks: + +1. Create a virtualenv called ``flaskenv`` +2. Activate that virtualenv +3. ``pip install flask`` to your virtualenv + +You will need this for some of your homework this week. + +But First +--------- + +A special note to pay attention to the readings. You will be expected to have +read the basics on Jinja2, SQLite3 and Flask **before** class starts. + +Previously +---------- + +.. class:: incremental + +* You've learned about passing messages back and forth with sockets +* You've created a simple HTTP server using sockets +* You may even have made your server *dynamic* by returning the output of a + python script. + +.. class:: incremental + +What if you want to pass information to that script? + +.. class:: incremental + +How can you give the script access to information about the HTTP request +itself? + + +Stepping Away +------------- + +A computer has an *environment*: + +.. container:: incremental + + in \*nix, you can see this in a shell: + + .. class:: small + + :: + + $ printenv + TERM_PROGRAM=iTerm.app + ... + +.. container:: incremental + + or in Windows at the command prompt: + + .. class:: small + + :: + + C:\> set + ALLUSERSPROFILE=C:\ProgramData + ... + + +Setting The Environment +----------------------- + +This can be manipulated: + +.. container:: incremental + + In a ``bash`` shell we can do this: + + .. class:: small + + :: + + $ export VARIABLE='some value' + $ echo $VARIABLE + some value + +.. container:: incremental + + or at a Windows command prompt: + + .. class:: small + + :: + + C:\Users\Administrator\> set VARIABLE='some value' + C:\Users\Administrator\> echo %VARIABLE% + 'some value' + + +Viewing the Results +------------------- + +These new values are now part of the *environment* + +.. container:: incremental + + \*nix: + + .. class:: small + + :: + + $ printenv + TERM_PROGRAM=iTerm.app + ... + VARIABLE=some value + +.. container:: incremental + + Windows: + + .. class:: small + + :: + + C:\> set + ALLUSERSPROFILE=C:\ProgramData + ... + VARIABLE='some value' + +Environment in Python +--------------------- + +We can see this *environment* in Python, too:: + + $ python + +.. code-block:: python + + >>> import os + >>> print os.environ['VARIABLE'] + some_value + >>> print os.environ.keys() + ['VERSIONER_PYTHON_PREFER_32_BIT', 'VARIABLE', + 'LOGNAME', 'USER', 'PATH', ...] + +Altering the Environment +------------------------ + +You can alter os environment values while in Python: + +.. code-block:: python + :class: small + + >>> os.environ['VARIABLE'] = 'new_value' + >>> print os.environ['VARIABLE'] + new_value + +.. container:: incremental + + But that doesn't change the original value, *outside* Python: + + .. class:: small + + :: + + >>> ^D + + $ echo this is the value: $VARIABLE + this is the value: some_value + + C:\> \Users\Administrator\> echo %VARIABLE% + 'some value' + +Lessons Learned +--------------- + +.. class:: incremental + +* Subprocesses inherit their environment from their Parent +* Parents do not see changes to environment in subprocesses +* In Python, you can actually set the environment for a subprocess explicitly + +.. class:: incremental small + +:: + + subprocess.Popen(args, bufsize=0, executable=None, + stdin=None, stdout=None, stderr=None, + preexec_fn=None, close_fds=False, + shell=False, cwd=None, env=None, # <------- + universal_newlines=False, startupinfo=None, + creationflags=0) + + +Web Environment +--------------- + +.. class:: big-centered + +CGI is little more than a set of standard environmental variables + + +RFC 3875 +-------- + +First discussed in 1993, formalized in 1997, the current version (1.1) has +been in place since 2004. + +From the preamble: + +.. class:: center + +*This memo provides information for the Internet community. It does not specify +an Internet standard of any kind.* + +.. class:: image-credit + +RFC 3875 - CGI Version 1.1: http://tools.ietf.org/html/rfc3875 + + +Meta-Variables +-------------- + +.. class:: small + +:: + + 4. The CGI Request . . . . . . . . . . . . . . . . . . . . . . . 10 + 4.1. Request Meta-Variables . . . . . . . . . . . . . . . . . 10 + 4.1.1. AUTH_TYPE. . . . . . . . . . . . . . . . . . . . 11 + 4.1.2. CONTENT_LENGTH . . . . . . . . . . . . . . . . . 12 + 4.1.3. CONTENT_TYPE . . . . . . . . . . . . . . . . . . 12 + 4.1.4. GATEWAY_INTERFACE. . . . . . . . . . . . . . . . 13 + 4.1.5. PATH_INFO. . . . . . . . . . . . . . . . . . . . 13 + 4.1.6. PATH_TRANSLATED. . . . . . . . . . . . . . . . . 14 + 4.1.7. QUERY_STRING . . . . . . . . . . . . . . . . . . 15 + 4.1.8. REMOTE_ADDR. . . . . . . . . . . . . . . . . . . 15 + 4.1.9. REMOTE_HOST. . . . . . . . . . . . . . . . . . . 16 + 4.1.10. REMOTE_IDENT . . . . . . . . . . . . . . . . . . 16 + 4.1.11. REMOTE_USER. . . . . . . . . . . . . . . . . . . 16 + 4.1.12. REQUEST_METHOD . . . . . . . . . . . . . . . . . 17 + 4.1.13. SCRIPT_NAME. . . . . . . . . . . . . . . . . . . 17 + 4.1.14. SERVER_NAME. . . . . . . . . . . . . . . . . . . 17 + 4.1.15. SERVER_PORT. . . . . . . . . . . . . . . . . . . 18 + 4.1.16. SERVER_PROTOCOL. . . . . . . . . . . . . . . . . 18 + 4.1.17. SERVER_SOFTWARE. . . . . . . . . . . . . . . . . 19 + + +Running CGI +----------- + +You have a couple of options: + +.. class:: incremental + +* Python Standard Library CGIHTTPServer +* Apache +* IIS (on Windows) +* Some other HTTP server that implements CGI (lighttpd, ...?) + +.. class:: incremental + +Let's keep it simple by using the Python module + + +Preparations +------------ + +In the class resources, you'll find a directory named ``cgi``. Make a copy of +that folder in your class working directory. + +.. class:: incremental small red + +Windows Users, you will have to edit the first line of +``cgi/cgi-bin/cgi_1.py`` to point to your python executable. + +.. class:: incremental + +* Open *two* terminal windows in this ``cgi`` directory +* In the first terminal, run ``python -m CGIHTTPServer`` +* Open a web browser and load ``http://localhost:8000/`` +* Click on *CGI Test 1* + + +Did that work? +-------------- + +* If nothing at all happens, check your terminal window +* Look for this: ``OSError: [Errno 13] Permission denied`` +* If you see something like that, check permissions for ``cgi-bin`` *and* + ``cgi_1.py`` +* The file must be executable, the directory needs to be readable *and* + executable. + + +.. class:: incremental + +Remember that you can use the bash ``chmod`` command to change permissions in +\*nix + +.. class:: incremental + +Windows users, use the 'properties' context menu to get to permissions, just +grant 'full' + +Break It +-------- + +Problems with permissions can lead to failure. So can scripting errors + +.. class:: incremental + +* Open ``cgi/cgi-bin/cgi_1.py`` in an editor +* Before where it says ``cgi.test()``, add a single line: + +.. code-block:: python + :class: incremental + + 1 / 0 + +.. class:: incremental + +Reload your browser, what happens now? + + +Errors in CGI +------------- + +CGI is famously difficult to debug. There are reasons for this: + +.. class:: incremental + +* CGI is designed to provide access to runnable processes to *the internet* +* The internet is a wretched hive of scum and villainy +* Revealing error conditions can expose data that could be exploited + +Viewing Errors in Python CGI +---------------------------- + +Back in your editor, add the following lines, just below ``import cgi``: + +.. code-block:: python + :class: incremental + + import cgitb + cgitb.enable() + +.. class:: incremental + +Now, reload again. + +cgitb Output +------------ + +.. image:: img/cgitb_output.png + :align: center + :width: 100% + + +Repair the Error +---------------- + +Let's fix the error from our traceback. Edit your ``cgi_1.py`` file to match: + +.. code-block:: python + :class: small + + #!/usr/bin/python + import cgi + import cgitb + + cgitb.enable() + + cgi.test() + +.. class:: incremental + +Notice the first line of that script: ``#!/usr/bin/python``. This is called a +*shebang* (short for hash-bang) and it tells the system what executable +program to use when running the script. + + +CGI Process Execution +--------------------- + +When a web server like ``CGIHTTPServer`` or ``Apache`` runs a CGI script, it +simply attempts to run the script as if it were a normal system user. This is +just like you calling:: + + $ ./cgi_bin/cgi_1.py + +.. class:: incremental + +In fact try that now in your second terminal (use the real path), what do you +get? + +.. class:: incremental small center + +Windows folks, you may need ``C:\>python cgi_1.py`` + +.. class:: incremental + +What is missing? + + +CGI Process Execution +--------------------- + +There are a couple of important facts that are related to the way CGI +processes are run: + +.. class:: incremental + +* The script **must** include a *shebang* so that the system knows how to run + it. +* The script **must** be executable. +* The *executable* named in the *shebang* will be called as the *nobody* user. +* This is a security feature to prevent CGI scripts from running as a user + with any privileges. +* This means that the *executable* from the script *shebang* must be one that + *anyone* can run. + + +The CGI Environment +------------------- + +CGI is largely a set of agreed-upon environmental variables. + +.. class:: incremental + +We've seen how environmental variables are found in python in ``os.environ`` + +.. class:: incremental + +We've also seen that at least some of the variables in CGI are **not** in the +standard set of environment variables. + +.. class:: incremental + +Where do they come from? + + +CGI Servers +----------- + +Let's find 'em. In a terminal (on your local machine, please) fire up python: + +.. code-block:: + + >>> import CGIHTTPServer + >>> CGIHTTPServer.__file__ + '/big/giant/path/to/lib/python2.6/CGIHTTPServer.py' + +.. class:: incremental + +Copy this path and open the file it points to in your text editor + + +Environmental Set Up +-------------------- + +From CGIHTTPServer.py, in the CGIHTTPServer.run_cgi method: + +.. code-block:: python + :class: tiny + + # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html + # XXX Much of the following could be prepared ahead of time! + env = {} + env['SERVER_SOFTWARE'] = self.version_string() + env['SERVER_NAME'] = self.server.server_name + env['GATEWAY_INTERFACE'] = 'CGI/1.1' + env['SERVER_PROTOCOL'] = self.protocol_version + env['SERVER_PORT'] = str(self.server.server_port) + env['REQUEST_METHOD'] = self.command + ... + ua = self.headers.getheader('user-agent') + if ua: + env['HTTP_USER_AGENT'] = ua + ... + os.environ.update(env) + ... + + +CGI Scripts +----------- + +And that's it, the big secret. The server takes care of setting up the +environment so it has what is needed. + +.. class:: incremental + +Now, in reverse. How does the information that a script creates end up in your +browser? + +.. class:: incremental + +A CGI Script must print its results to stdout. + +.. class:: incremental + +Use the same method as above to import and open the source file for the +``cgi`` module. Note what ``test`` does for an example of this. + + +Recap: +------ + +What the Server Does: + +.. class:: incremental small + +* parses the request +* sets up the environment, including HTTP and SERVER variables +* figures out if the URI points to a CGI script and runs it +* builds an appropriate HTTP Response first line ('HTTP/1.1 200 OK\\r\\n') +* appends what comes from the script on stdout and sends that back + +What the Script Does: + +.. class:: incremental small + +* names appropriate *executable* in it's *shebang* line +* uses os.environ to read information from the HTTP request +* builds *any and all* appropriate **HTTP Headers** (Content-type:, + Content-length:, ...) +* prints headers, empty line and script output (body) to stdout + + +In-Class Exercise +----------------- + +You've seen the output from the ``cgi.test()`` method from the ``cgi`` module. +Let's make our own version of this. + +.. class:: incremental small + +* In the directory ``cgi-bin`` you will find the file ``cgi_2.py``. +* Open that file in your editor. +* The script contains some html with text naming elements of the CGI + environment. +* You should use the values in os.environ to fill in the blanks. +* You should be able to view the results of your work by loading + ``http://localhost:8000/`` and clicking on *Exercise One* + +.. class:: incremental center + +**GO** + + +User Provided Data +------------------ + +All this is well and good, but where's the *dynamic* stuff? + +.. class:: incremental + +It'd be nice if a user could pass form data to our script for it to use. + +.. container:: incremental + + In HTTP, these types of inputs show up in the URL *query* (the part after + the ``?``):: + + http://myhost.com/script.py?a=23&b=37 + + +Form Data in CGI +---------------- + +In the ``cgi`` module, we get access to this with the ``FieldStorage`` class: + +.. code-block:: python + :class: incremental small + + import cgi + + form = cgi.FieldStorage() + stringval = form.getvalue('a', None) + listval = form.getlist('b') + +.. class:: incremental + +* The values in the ``FieldStorage`` are *always* strings +* ``getvalue`` allows you to return a default, in case the field isn't present +* ``getlist`` always returns a list: empty, one-valued, or as many values as + are present + + +In-Class Exercise +----------------- + +Let's create a dynamic adding machine. + +.. class:: incremental + +* In the ``cgi-bin`` directory you'll find ``cgi_sums.py``. +* In the ``index.html`` file in the ``cgi`` directory, the third link leads to + this file. +* You will use the structure of that link, and what you learned just now about + ``cgi.FieldStorage``. +* Complete the cgi script in ``cgi_sums.py`` so that the result of adding all + operands sent via the url query is returned. + +.. class:: incremental + +For extra fun, return the results in ``json`` format (mimetype: +'application/json'). + + +My Solution +----------- + +.. code-block:: python + :class: small incremental + + form = cgi.FieldStorage() + operands = form.getlist('operand') + total = 0 + for operand in operands: + try: + value = int(operand) + except ValueError: + value = 0 + total += value + + output = {'result': total} + json_output = json.dumps(output) + + print "Content-Type: application/json" + print "Content-Length: %s" % len(json_output) + print + print json_output + + +Stopping Point +-------------- + +.. class:: big-centered + +Let's take a break here, before continuing + + +CGI Problems +------------ + +CGI is great, but there are problems: + +.. class:: incremental + +* Code is executed *in a new process* +* **Every** call to a CGI script starts a new process on the server +* Starting a new process is expensive in terms of server resources +* *Especially for interpreted languages like Python* + +.. class:: incremental + +How do we overcome this problem? + + +Alternatives to CGI +------------------- + +The most popular approach is to have a long-running process *inside* the +server that handles CGI scripts. + +.. class:: incremental + +FastCGI and SCGI are existing implementations of CGI in this fashion. The +Apache module **mod_python** offers a similar capability for Python code. + +.. class:: incremental + +* Each of these options has a specific API +* None are compatible with each-other +* Code written for one is **not portable** to another + +.. class:: incremental + +This makes it much more difficult to *share resources* + + +WSGI +---- + +Enter WSGI, the Web Server Gateway Interface. + +.. class:: incremental + +Where other alternatives are specific implementations of the CGI standard, +WSGI is itself a new standard, not an implementation. + +.. class:: incremental + +WSGI is generalized to describe a set of interactions, so that developers can +write WSGI-capable apps and deploy them on any WSGI server. + +.. class:: incremental + +Read the WSGI spec: http://www.python.org/dev/peps/pep-0333 + + +WSGI: Apps and Servers +---------------------- + +.. class:: small + +WSGI consists of two parts, a *server* and an *application*. + +.. class:: small + +A WSGI Server must: + +.. class:: incremental small + +* set up an environment, much like the one in CGI +* provide a method ``start_response(status, headers, exc_info=None)`` +* build a response body by calling an *application*, passing + ``environment`` and ``start_response`` as args +* return a response with the status, headers and body + +.. class:: small + +A WSGI Appliction must: + +.. class:: incremental small + +* Be a callable (function, method, class) +* Take an environment and a ``start_response`` callable as arguments +* Call the ``start_response`` method. +* Return an iterable of 0 or more strings, which are treated as the body of + the response. + + +Simplified WSGI Server +---------------------- + +.. code-block:: python + :class: small + + from some_application import simple_app + + def build_env(request): + # put together some environment info from the reqeuest + return env + + def handle_request(request, app): + environ = build_env(request) + iterable = app(environ, start_response) + for data in iterable: + # send data to client here + + def start_response(status, headers): + # start an HTTP response, sending status and headers + + # listen for HTTP requests and pass on to handle_request() + serve(simple_app) + + +Simple WSGI Application +----------------------- + +Where the simplified server above is **not** functional, this *is* a complete +app: + +.. code-block:: python + + def application(environ, start_response) + status = "200 OK" + body = "Hello World\n" + response_headers = [('Content-type', 'text/plain'), + ('Content-length', len(body))] + start_response(status, response_headers) + return [body] + + +WSGI Middleware +--------------- + +A third part of the puzzle is something called WSGI *middleware* + +.. class:: incremental + +* Middleware implements both the *server* and *application* interfaces +* Middleware acts as a server when viewed from an application +* Middleware acts as an application when viewed from a server + +.. image:: img/wsgi_middleware_onion.png + :align: center + :width: 38% + :class: incremental + + +Flowcharts +---------- + +WSGI Servers: + +.. class:: center incremental + +**HTTP <---> WSGI** + +.. class:: incremental + +WSGI Applications: + +.. class:: center incremental + +**WSGI <---> app code** + + +The Whole Enchilada +------------------- + +The WSGI *Stack* can thus be expressed like so: + +.. class:: incremental big-centered + +**HTTP <---> WSGI <---> app code** + + +Using wsgiref +------------- + +The Python standard lib provides a reference implementation of WSGI: + +.. image:: img/wsgiref_flow.png + :align: center + :width: 80% + :class: incremental + + +Apache mod_wsgi +--------------- + +You can also deploy with Apache as your HTTP server, using **mod_wsgi**: + +.. image:: img/mod_wsgi_flow.png + :align: center + :width: 80% + :class: incremental + + +Proxied WSGI Servers +-------------------- + +Finally, it is also common to see WSGI apps deployed via a proxied WSGI +server: + +.. image:: img/proxy_wsgi.png + :align: center + :width: 80% + :class: incremental + + +The WSGI Environment +-------------------- + +.. class:: small + +REQUEST_METHOD + The HTTP request method, such as "GET" or "POST". This cannot ever be an + empty string, and so is always required. +SCRIPT_NAME + The initial portion of the request URL's "path" that corresponds to the + application object, so that the application knows its virtual "location". + This may be an empty string, if the application corresponds to the "root" of + the server. +PATH_INFO + The remainder of the request URL's "path", designating the virtual + "location" of the request's target within the application. This may be an + empty string, if the request URL targets the application root and does not + have a trailing slash. +QUERY_STRING + The portion of the request URL that follows the "?", if any. May be empty or + absent. +CONTENT_TYPE + The contents of any Content-Type fields in the HTTP request. May be empty or + absent. + + +The WSGI Environment +-------------------- + +.. class:: small + +CONTENT_LENGTH + The contents of any Content-Length fields in the HTTP request. May be empty + or absent. +SERVER_NAME, SERVER_PORT + When combined with SCRIPT_NAME and PATH_INFO, these variables can be used to + complete the URL. Note, however, that HTTP_HOST, if present, should be used + in preference to SERVER_NAME for reconstructing the request URL. See the URL + Reconstruction section below for more detail. SERVER_NAME and SERVER_PORT + can never be empty strings, and so are always required. +SERVER_PROTOCOL + The version of the protocol the client used to send the request. Typically + this will be something like "HTTP/1.0" or "HTTP/1.1" and may be used by the + application to determine how to treat any HTTP request headers. (This + variable should probably be called REQUEST_PROTOCOL, since it denotes the + protocol used in the request, and is not necessarily the protocol that will + be used in the server's response. However, for compatibility with CGI we + have to keep the existing name.) + + +The WSGI Environment +-------------------- + +.. class:: small + +HTTP\_ Variables + Variables corresponding to the client-supplied HTTP request headers (i.e., + variables whose names begin with "HTTP\_"). The presence or absence of these + variables should correspond with the presence or absence of the appropriate + HTTP header in the request. + +.. class:: center incremental + +**Seem Familiar?** + + +A Bit of Repetition +------------------- + +Let's start simply. We'll begin by repeating our first CGI exercise in WSGI + +.. class:: incremental + +* Find the ``wsgi`` directory in the class resources. Copy it to your working + directory. +* Open the file ``wsgi_1.py`` in your text editor. +* We will fill in the missing values using the wsgi ``environ``, just as we + use ``os.environ`` in cgi + +.. class:: incremental center + +**But First** + + +Orientation +----------- + +.. code-block:: python + :class: small + + if __name__ == '__main__': + from wsgiref.simple_server import make_server + srv = make_server('localhost', 8080, application) + srv.serve_forever() + +.. class:: incremental + +Note that we pass our ``application`` function to the server factory + +.. class:: incremental + +We don't have to write a server, ``wsgiref`` does that for us. + +.. class:: incremental + +In fact, you should *never* have to write a WSGI server. + + +Orientation +----------- + +.. code-block:: python + :class: small + + def application(environ, start_response): + response_body = body % ( + environ.get('SERVER_NAME', 'Unset'), # server name + ... + ) + status = '200 OK' + response_headers = [('Content-Type', 'text/html'), + ('Content-Length', str(len(response_body)))] + start_response(status, response_headers) + return [response_body] + +.. class:: incremental + +We do not define ``start_response``, the application does that. + +.. class:: incremental + +We *are* responsible for determining the HTTP status. + + +Running a WSGI Script +--------------------- + +You can run this script with python:: + + $ python wsgi_1.py + +.. class:: incremental + +This will start a wsgi server. What host and port will it use? + +.. class:: incremental + +Point your browser at ``http://localhost:8080/``. Did it work? + +.. class:: incremental + +Go ahead and fill in the missing bits. Use the ``environ`` passed into +``application`` + + +Some Tips +--------- + +Because WSGI is a long-running process, the file you are editing is *not* +reloaded after you edit it. + +.. class:: incremental + +You'll need to quit and re-run the script between edits. + +.. class:: incremental + +You may also want to consider using ``print environ`` in your application so +you can see the dictionary. + +.. class:: incremental + +If you do that, where will the printed environment appear? + + +A More Complex Example +---------------------- + +Let's create a multi-page wsgi application. It will serve a small database of +python books. + +.. class:: incremental + +The database (with a very simple api) can be found in ``wsgi/bookdb.py`` + +.. class:: incremental + +* We'll need a listing page that shows the titles of all the books +* Each title will link to a details page for that book +* The details page for each book will display all the information and have a + link back to the list + + +Some Questions to Ponder +------------------------ + +.. class:: incremental + +When viewing our first wsgi app, do we see the name of the wsgi application +script anywhere in the URL? + +.. class:: incremental + +In our wsgi application script, how many applications did we actually have? + +.. class:: incremental + +How are we going to serve different types of information out of a single +application? + + +Dispatch +-------- + +We have to write an app that will map our incoming request path to some code +that can handle that request. + +.. class:: incremental + +This process is called ``dispatch``. There are many possible approaches + +.. class:: incremental + +Let's begin by designing this piece of it. + +.. class:: incremental + +Open ``bookapp.py`` from the ``wsgi`` folder. We'll do our work here. + + +PATH +---- + +The wsgi environment gives us access to *PATH_INFO*, which maps to the URI the +user requested when they loaded the page. + +.. class:: incremental + +We can design the URLs that our app will use to assist us in routing. + +.. class:: incremental + +Let's declare that any request for ``/`` will map to the list page + +.. container:: incremental + + We can also say that the URL for a book will look like this:: + + http://localhost:8080/book/ + +Writing resolve_path +-------------------- + +Let's write a function, called ``resolve_path`` in our application file. + +.. class:: incremental + +* It should take the *PATH_INFO* value from environ as an argument. +* It should return the function that will be called. +* It should also return any arguments needed to call that function. +* This implies of course that the arguments should be part of the PATH + + +My Solution +----------- + +.. code-block:: python + :class: small incremental + + def resolve_path(path): + urls = [(r'^$', books), + (r'^book/(id[\d]+)$', book)] + matchpath = path.lstrip('/') + for regexp, func in urls: + match = re.match(regexp, matchpath) + if match is None: + continue + args = match.groups([]) + return func, args + # we get here if no url matches + raise NameError + + +Application Updates +------------------- + +We need to hook our new router into the application. + +.. class:: incremental + +* The path should be extracted from ``environ``. +* The router should be used to get a function and arguments +* The body to return should come from calling that function with those + arguments +* If an error is raised by calling the function, an appropriate response + should be returned +* If the router raises a NameError, the application should return a 404 + response + + +My Solution +----------- + +.. code-block:: python + :class: small incremental + + def application(environ, start_response): + headers = [("Content-type", "text/html")] + try: + path = environ.get('PATH_INFO', None) + if path is None: + raise NameError + func, args = resolve_path(path) + body = func(*args) + status = "200 OK" + except NameError: + status = "404 Not Found" + body = "

Not Found

" + except Exception: + status = "500 Internal Server Error" + body = "

Internal Server Error

" + finally: + headers.append(('Content-length', str(len(body)))) + start_response(status, headers) + return [body] + + +Test Your Work +-------------- + +Once you've got your script settled, run it:: + + $ python bookapp.py + +.. class:: incremental + +Then point your browser at ``http://localhost:8080/`` + +.. class:: incremental + +* ``http://localhost/book/id3`` +* ``http://localhost/book/id73/`` +* ``http://localhost/sponge/damp`` + +.. class:: incremental + +Did that all work as you would have expected? + + +Building the List +----------------- + +The function ``books`` should return an html list of book titles where each +title is a link to the detail page for that book + +.. class:: incremental + +* You'll need all the ids and titles from the book database. +* You'll need to build a list in HTML using this information +* Each list item should have the book title as a link +* The href for the link should be of the form ``/book/`` + + +My Solution +----------- + +.. code-block:: python + :class: incremental small + + def books(): + all_books = DB.titles() + body = ['

My Bookshelf

', '
    '] + item_template = '
  • {title}
  • ' + for book in all_books: + body.append(item_template.format(**book)) + body.append('
') + return '\n'.join(body) + + +Test Your Work +-------------- + +Quit and then restart your application script:: + + $ python bookapp.py + +.. container:: incremental + + Then reload the root of your application:: + + http://localhost:8080/ + +.. class:: incremental + +You should see a nice list of the books in the database. Do you? + +.. class:: incremental + +Click on a link to view the detail page. Does it load without error? + + +Showing Details +--------------- + +The next step of course is to polish up those detail pages. + +.. class:: incremental + +* You'll need to retrieve a single book from the database +* You'll need to format the details about that book and return them as HTML +* You'll need to guard against ids that do not map to books + +.. class:: incremental + +In this last case, what's the right HTTP response code to send? + + +My Solution +----------- + +.. code-block:: python + :class: incremental small + + def book(book_id): + page = """ +

{title}

+ + + + +
Author{author}
Publisher{publisher}
ISBN{isbn}
+ Back to the list + """ + book = DB.title_info(book_id) + if book is None: + raise NameError + return page.format(**book) + + +Revel in Your Success +--------------------- + +Quit and restart your script one more time + +.. class:: incremental + +Then poke around at your application and see the good you've made + +.. class:: incremental + +And your application is portable and sharable + +.. class:: incremental + +It should run equally well under any `wsgi server +`_ + + +A Few Steps Further +------------------- + +Next steps for an app like this might be: + +* Create a shared full page template and incorporate it into your app +* Improve the error handling by emitting error codes other than 404 and 500 +* Swap out the basic backend here with a different one, maybe a Web Service? +* Think about ways to make the application less tightly coupled to the pages + it serves + + +Homework +-------- + +For your homework this week, you'll be creating a wsgi application of your +own. + +.. class:: incremental + +As the source of your data, use the mashup you created last week. + +.. class:: incremental + +Your application should have at least two separate "pages" in it. + +.. class:: incremental + +The HTML you produce does not need to be pretty, but it should be something +that shows up in a browser. + + +Submitting Your Homework +------------------------ + +To submit your homework: + +.. class:: small + +* Create a new python script in ``assignments/session04``. It should be + something I can run with: + +.. class:: small + +:: + + $ python your_script.py + +.. class:: small + +* Once your script is running, I should be able to view your application in my + browser. + +* Include all instructions I need to successfully run and view your script. + +* Add tests for your code. I should be able to run the tests like so: + +.. class:: small + +:: + + $ python tests.py + +.. class:: small + +* Commit your changes to your fork of the repo in github, then open a pull + request. + + +But Wait, There's More +---------------------- + +In addition, read and step through the quick tutorials on templates and +database persistence in the assignments directory. + +Use your flaskenv Python, it has everything you need installed. + + +Wrap-Up +------- + +For educational purposes, you might wish to take a look at the source code for +the ``wsgiref`` module. It's the canonical example of a simple wsgi server + + >>> import wsgiref + >>> wsgiref.__file__ + '/full/path/to/your/copy/of/wsgiref.py' + ... + +.. class:: incremental center + +**See you Next Time** diff --git a/source/presentations/session04.rst b/source/presentations/session04.rst index f8214583..69f9106b 100644 --- a/source/presentations/session04.rst +++ b/source/presentations/session04.rst @@ -1,1435 +1,1201 @@ Python Web Programming ====================== -.. image:: img/gateway.jpg +.. image:: img/python.png :align: left - :width: 50% + :width: 33% -Session 4: CGI, WSGI and Living Online +Session 1: Networking and Sockets .. class:: intro-blurb -Wherein we discover the gateways to dynamic processes on a server. +Wherein we learn about the basic structure of the internet and explore the +building blocks that make it possible. -.. class:: image-credit - -image: The Wandering Angel http://www.flickr.com/photos/wandering_angel/1467802750/ - CC-BY But First --------- -.. class:: big-centered +Class presentations are available online for your use -A look at some of the cool mashups you built over the week. +.. class:: small +https://github.com/UWPCE-PythonCert/training.python_web -But First ---------- +.. class:: incremental -Clean up the git situation. +Licensed with Creative Commons BY-NC-SA +.. class:: small incremental -But First ---------- +* You must attribute the work +* You may not use the work for commercial purposes +* You have to share your versions just like this one -Before you leave the classroom today, please complete the following tasks: +.. class:: incremental -1. Create a virtualenv called ``flaskenv`` -2. Activate that virtualenv -3. ``pip install flask`` to your virtualenv +Find mistakes? See improvements? Make a pull request. -You will need this for some of your homework this week. But First --------- -A special note to pay attention to the readings. You will be expected to have -read the basics on Jinja2, SQLite3 and Flask **before** class starts. - -Previously ----------- +Classroom Protocol .. class:: incremental -* You've learned about passing messages back and forth with sockets -* You've created a simple HTTP server using sockets -* You may even have made your server *dynamic* by returning the output of a - python script. +Questions to ask: .. class:: incremental -What if you want to pass information to that script? +* What did you just say? +* Please explain what we just did again? +* Why didn't that work for me? +* Is that a typo? -.. class:: incremental -How can you give the script access to information about the HTTP request -itself? - - -Stepping Away -------------- - -A computer has an *environment*: +But First +--------- -.. container:: incremental +Classroom Protocol - in \*nix, you can see this in a shell: - - .. class:: small - - :: - - $ printenv - TERM_PROGRAM=iTerm.app - ... +.. class:: incremental -.. container:: incremental +Questions **not** to ask: - or in Windows at the command prompt: - - .. class:: small - - :: - - C:\> set - ALLUSERSPROFILE=C:\ProgramData - ... +.. class:: incremental +* **Hypotheticals**: What happens if I do X? +* **Research**: Can Python do Y? +* **Syllabus**: Are we going to cover Z in class? +* **Marketing questions**: please just don't. +* **Performance questions**: Is Python fast enough? +* **Unpythonic**: Why doesn't Python do it some other way? +* **Show off**: Look what I just did! -Setting The Environment ------------------------ -This can be manipulated: +But First +--------- -.. container:: incremental +.. class:: big-centered - In a ``bash`` shell we can do this: - - .. class:: small - - :: - - $ export VARIABLE='some value' - $ echo $VARIABLE - some value +Introductions -.. container:: incremental - or at a Windows command prompt: - - .. class:: small - - :: - - C:\Users\Administrator\> set VARIABLE='some value' - C:\Users\Administrator\> echo %VARIABLE% - 'some value' +Computer Communications +----------------------- +.. image:: img/network_topology.png + :align: left + :width: 40% -Viewing the Results -------------------- +.. class:: incremental -These new values are now part of the *environment* +* processes can communicate -.. container:: incremental +* inside one machine - \*nix: - - .. class:: small - - :: - - $ printenv - TERM_PROGRAM=iTerm.app - ... - VARIABLE=some value +* between two machines -.. container:: incremental +* among many machines - Windows: - - .. class:: small - - :: - - C:\> set - ALLUSERSPROFILE=C:\ProgramData - ... - VARIABLE='some value' +.. class:: image-credit -Environment in Python ---------------------- +image: http://en.wikipedia.org/wiki/Internet_Protocol_Suite -We can see this *environment* in Python, too:: - $ python +Computer Communications +----------------------- -.. code-block:: python +.. image:: img/data_in_tcpip_stack.png + :align: left + :width: 55% - >>> import os - >>> print os.environ['VARIABLE'] - some_value - >>> print os.environ.keys() - ['VERSIONER_PYTHON_PREFER_32_BIT', 'VARIABLE', - 'LOGNAME', 'USER', 'PATH', ...] +.. class:: incremental -Altering the Environment ------------------------- +* Process divided into 'layers' -You can alter os environment values while in Python: +* 'Layers' are mostly arbitrary -.. code-block:: python - :class: small +* Different descriptions have different layers - >>> os.environ['VARIABLE'] = 'new_value' - >>> print os.environ['VARIABLE'] - new_value +* Most common is the 'TCP/IP Stack' -.. container:: incremental +.. class:: image-credit - But that doesn't change the original value, *outside* Python: - - .. class:: small - - :: +image: http://en.wikipedia.org/wiki/Internet_Protocol_Suite - >>> ^D - $ echo this is the value: $VARIABLE - this is the value: some_value - - C:\> \Users\Administrator\> echo %VARIABLE% - 'some value' +The TCP/IP Stack - Link +----------------------- -Lessons Learned ---------------- +The bottom layer is the 'Link Layer' .. class:: incremental -* Subprocesses inherit their environment from their Parent -* Parents do not see changes to environment in subprocesses -* In Python, you can actually set the environment for a subprocess explicitly +* Deals with the physical connections between machines, 'the wire' -.. class:: incremental small +* Packages data for physical transport -:: +* Executes transmission over a physical medium - subprocess.Popen(args, bufsize=0, executable=None, - stdin=None, stdout=None, stderr=None, - preexec_fn=None, close_fds=False, - shell=False, cwd=None, env=None, # <------- - universal_newlines=False, startupinfo=None, - creationflags=0) + * what that medium is is arbitrary +* Implemented in the Network Interface Card(s) (NIC) in your computer -Web Environment ---------------- -.. class:: big-centered +The TCP/IP Stack - Internet +--------------------------- -CGI is little more than a set of standard environmental variables +Moving up, we have the 'Internet Layer' +.. class:: incremental -RFC 3875 --------- +* Deals with addressing and routing -First discussed in 1993, formalized in 1997, the current version (1.1) has -been in place since 2004. + * Where are we going and how do we get there? -From the preamble: +* Agnostic as to physical medium (IP over Avian Carrier - IPoAC) -.. class:: center +* Makes no promises of reliability -*This memo provides information for the Internet community. It does not specify -an Internet standard of any kind.* +* Two addressing systems -.. class:: image-credit + .. class:: incremental -RFC 3875 - CGI Version 1.1: http://tools.ietf.org/html/rfc3875 + * IPv4 (current, limited '192.168.1.100') + * IPv6 (future, 3.4 x 10^38 addresses, '2001:0db8:85a3:0042:0000:8a2e:0370:7334') -Meta-Variables --------------- -.. class:: small +The TCP/IP Stack - Internet +--------------------------- -:: +.. class:: big-centered - 4. The CGI Request . . . . . . . . . . . . . . . . . . . . . . . 10 - 4.1. Request Meta-Variables . . . . . . . . . . . . . . . . . 10 - 4.1.1. AUTH_TYPE. . . . . . . . . . . . . . . . . . . . 11 - 4.1.2. CONTENT_LENGTH . . . . . . . . . . . . . . . . . 12 - 4.1.3. CONTENT_TYPE . . . . . . . . . . . . . . . . . . 12 - 4.1.4. GATEWAY_INTERFACE. . . . . . . . . . . . . . . . 13 - 4.1.5. PATH_INFO. . . . . . . . . . . . . . . . . . . . 13 - 4.1.6. PATH_TRANSLATED. . . . . . . . . . . . . . . . . 14 - 4.1.7. QUERY_STRING . . . . . . . . . . . . . . . . . . 15 - 4.1.8. REMOTE_ADDR. . . . . . . . . . . . . . . . . . . 15 - 4.1.9. REMOTE_HOST. . . . . . . . . . . . . . . . . . . 16 - 4.1.10. REMOTE_IDENT . . . . . . . . . . . . . . . . . . 16 - 4.1.11. REMOTE_USER. . . . . . . . . . . . . . . . . . . 16 - 4.1.12. REQUEST_METHOD . . . . . . . . . . . . . . . . . 17 - 4.1.13. SCRIPT_NAME. . . . . . . . . . . . . . . . . . . 17 - 4.1.14. SERVER_NAME. . . . . . . . . . . . . . . . . . . 17 - 4.1.15. SERVER_PORT. . . . . . . . . . . . . . . . . . . 18 - 4.1.16. SERVER_PROTOCOL. . . . . . . . . . . . . . . . . 18 - 4.1.17. SERVER_SOFTWARE. . . . . . . . . . . . . . . . . 19 - - -Running CGI ------------ +That's 4.3 x 10^28 addresses *per person alive today* -You have a couple of options: -.. class:: incremental +The TCP/IP Stack - Transport +---------------------------- -* Python Standard Library CGIHTTPServer -* Apache -* IIS (on Windows) -* Some other HTTP server that implements CGI (lighttpd, ...?) +Next up is the 'Transport Layer' .. class:: incremental -Let's keep it simple by using the Python module +* Deals with transmission and reception of data + * error correction, flow control, congestion management -Preparations ------------- +* Common protocols include TCP & UDP -In the class resources, you'll find a directory named ``cgi``. Make a copy of -that folder in your class working directory. + * TCP: Tranmission Control Protocol -.. class:: incremental small red + * UDP: User Datagram Protocol -Windows Users, you will have to edit the first line of -``cgi/cgi-bin/cgi_1.py`` to point to your python executable. +* Not all Transport Protocols are 'reliable' -.. class:: incremental + .. class:: incremental -* Open *two* terminal windows in this ``cgi`` directory -* In the first terminal, run ``python -m CGIHTTPServer`` -* Open a web browser and load ``http://localhost:8000/`` -* Click on *CGI Test 1* + * TCP ensures that dropped packets are resent + * UDP makes no such assurance + + * Reliability is slow and expensive -Did that work? --------------- -* If nothing at all happens, check your terminal window -* Look for this: ``OSError: [Errno 13] Permission denied`` -* If you see something like that, check permissions for ``cgi-bin`` *and* - ``cgi_1.py`` -* The file must be executable, the directory needs to be readable *and* - executable. +The TCP/IP Stack - Transport +---------------------------- +The 'Transport Layer' also establishes the concept of a **port** .. class:: incremental -Remember that you can use the bash ``chmod`` command to change permissions in -\*nix +* IP Addresses designate a specific *machine* on the network -.. class:: incremental +* A **port** provides addressing for individual *applications* in a single host -Windows users, use the 'properties' context menu to get to permissions, just -grant 'full' +* 192.168.1.100:80 (the *:80* part is the **port**) -Break It --------- - -Problems with permissions can lead to failure. So can scripting errors +* [2001:db8:85a3:8d3:1319:8a2e:370:7348]:443 (*:443* is the **port**) .. class:: incremental -* Open ``cgi/cgi-bin/cgi_1.py`` in an editor -* Before where it says ``cgi.test()``, add a single line: +This means that you don't have to worry about information intended for your +web browser being accidentally read by your email client. -.. code-block:: python - :class: incremental - 1 / 0 +The TCP/IP Stack - Transport +---------------------------- + +There are certain **ports** which are commonly understood to belong to given +applications or protocols: .. class:: incremental -Reload your browser, what happens now? +* 80/443 - HTTP/HTTPS +* 20 - FTP +* 22 - SSH +* 23 - Telnet +* 25 - SMTP +* ... +.. class:: incremental -Errors in CGI -------------- +These ports are often referred to as **well-known ports** -CGI is famously difficult to debug. There are reasons for this: +.. class:: small -.. class:: incremental +(see http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers) -* CGI is designed to provide access to runnable processes to *the internet* -* The internet is a wretched hive of scum and villainy -* Revealing error conditions can expose data that could be exploited -Viewing Errors in Python CGI +The TCP/IP Stack - Transport ---------------------------- -Back in your editor, add the following lines, just below ``import cgi``: - -.. code-block:: python - :class: incremental - - import cgitb - cgitb.enable() +Ports are grouped into a few different classes .. class:: incremental -Now, reload again. +* Ports numbered 0 - 1023 are *reserved* -cgitb Output ------------- +* Ports numbered 1024 - 65535 are *open* -.. image:: img/cgitb_output.png - :align: center - :width: 100% +* Ports numbered 1024 - 49151 may be *registered* +* Ports numbered 49152 - 65535 are called *ephemeral* -Repair the Error ----------------- -Let's fix the error from our traceback. Edit your ``cgi_1.py`` file to match: +The TCP/IP Stack - Application +------------------------------ -.. code-block:: python - :class: small +The topmost layer is the 'Application Layer' - #!/usr/bin/python - import cgi - import cgitb +.. class:: incremental - cgitb.enable() +* Deals directly with data produced or consumed by an application - cgi.test() +* Reads or writes data using a set of understood, well-defined **protocols** -.. class:: incremental + * HTTP, SMTP, FTP etc. -Notice the first line of that script: ``#!/usr/bin/python``. This is called a -*shebang* (short for hash-bang) and it tells the system what executable -program to use when running the script. +* Does not know (or need to know) about lower layer functionality + * The exception to this rule is **endpoint** data (or IP:Port) -CGI Process Execution ---------------------- -When a web server like ``CGIHTTPServer`` or ``Apache`` runs a CGI script, it -simply attempts to run the script as if it were a normal system user. This is -just like you calling:: +The TCP/IP Stack - Application +------------------------------ - $ ./cgi_bin/cgi_1.py +.. class:: big-centered -.. class:: incremental +this is where we live and work -In fact try that now in your second terminal (use the real path), what do you -get? -.. class:: incremental small center +Sockets +------- -Windows folks, you may need ``C:\>python cgi_1.py`` +Think back for a second to what we just finished discussing, the TCP/IP stack. .. class:: incremental -What is missing? +* The *Internet* layer gives us an **IP Address** +* The *Transport* layer establishes the idea of a **port**. -CGI Process Execution ---------------------- +* The *Application* layer doesn't care about what happens below... -There are a couple of important facts that are related to the way CGI -processes are run: +* *Except for* **endpoint data** (IP:Port) .. class:: incremental -* The script **must** include a *shebang* so that the system knows how to run - it. -* The script **must** be executable. -* The *executable* named in the *shebang* will be called as the *nobody* user. -* This is a security feature to prevent CGI scripts from running as a user - with any privileges. -* This means that the *executable* from the script *shebang* must be one that - *anyone* can run. +A **Socket** is the software representation of that endpoint. +.. class:: incremental -The CGI Environment -------------------- +Opening a **socket** creates a kind of transceiver that can send and/or +receive *bytes* at a given IP address and Port. -CGI is largely a set of agreed-upon environmental variables. -.. class:: incremental +Sockets in Python +----------------- -We've seen how environmental variables are found in python in ``os.environ`` +Python provides a standard library module which provides socket functionality. +It is called **socket**. .. class:: incremental -We've also seen that at least some of the variables in CGI are **not** in the -standard set of environment variables. +The library is really just a very thin wrapper around the system +implementation of *BSD Sockets* .. class:: incremental -Where do they come from? +Let's spend a few minutes getting to know this module. +.. class:: incremental -CGI Servers ------------ - -Let's find 'em. In a terminal (on your local machine, please) fire up python: +We're going to do this next part together, so open up a terminal and start a +python interpreter -.. code-block:: - >>> import CGIHTTPServer - >>> CGIHTTPServer.__file__ - '/big/giant/path/to/lib/python2.6/CGIHTTPServer.py' +Sockets in Python +----------------- -.. class:: incremental +The Python sockets library allows us to find out what port a *service* uses: -Copy this path and open the file it points to in your text editor +.. class:: small + >>> import socket + >>> socket.getservbyname('ssh') + 22 -Environmental Set Up --------------------- +.. class:: incremental -From CGIHTTPServer.py, in the CGIHTTPServer.run_cgi method: +You can also do a *reverse lookup*, finding what service uses a given *port*: -.. code-block:: python - :class: tiny - - # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html - # XXX Much of the following could be prepared ahead of time! - env = {} - env['SERVER_SOFTWARE'] = self.version_string() - env['SERVER_NAME'] = self.server.server_name - env['GATEWAY_INTERFACE'] = 'CGI/1.1' - env['SERVER_PROTOCOL'] = self.protocol_version - env['SERVER_PORT'] = str(self.server.server_port) - env['REQUEST_METHOD'] = self.command - ... - ua = self.headers.getheader('user-agent') - if ua: - env['HTTP_USER_AGENT'] = ua - ... - os.environ.update(env) - ... +.. class:: incremental small + >>> socket.getservbyport(80) + 'http' -CGI Scripts ------------ -And that's it, the big secret. The server takes care of setting up the -environment so it has what is needed. +Sockets in Python +----------------- -.. class:: incremental +The sockets library also provides tools for finding out information about +*hosts*. For example, you can find out about the hostname and IP address of +the machine you are currently using:: -Now, in reverse. How does the information that a script creates end up in your -browser? + >>> socket.gethostname() + 'heffalump.local' + >>> socket.gethostbyname(socket.gethostname()) + '10.211.55.2' -.. class:: incremental -A CGI Script must print its results to stdout. +Sockets in Python +----------------- -.. class:: incremental +You can also find out about machines that are located elsewhere, assuming you +know their hostname. For example:: -Use the same method as above to import and open the source file for the -``cgi`` module. Note what ``test`` does for an example of this. + >>> socket.gethostbyname('google.com') + '173.194.33.4' + >>> socket.gethostbyname('uw.edu') + '128.95.155.135' + >>> socket.gethostbyname('crisewing.com') + '108.59.11.99' -Recap: ------- +Sockets in Python +----------------- -What the Server Does: +The ``gethostbyname_ex`` method of the ``socket`` library provides more +information about the machines we are exploring:: -.. class:: incremental small + >>> socket.gethostbyname_ex('google.com') + ('google.com', [], ['173.194.33.9', '173.194.33.14', + ... + '173.194.33.6', '173.194.33.7', + '173.194.33.8']) + >>> socket.gethostbyname_ex('crisewing.com') + ('crisewing.com', [], ['108.59.11.99']) + >>> socket.gethostbyname_ex('www.rad.washington.edu') + ('elladan.rad.washington.edu', # <- canonical hostname + ['www.rad.washington.edu'], # <- any machine aliases + ['128.95.247.84']) # <- all active IP addresses -* parses the request -* sets up the environment, including HTTP and SERVER variables -* figures out if the URI points to a CGI script and runs it -* builds an appropriate HTTP Response first line ('HTTP/1.1 200 OK\\r\\n') -* appends what comes from the script on stdout and sends that back -What the Script Does: +Sockets in Python +----------------- -.. class:: incremental small +To create a socket, you use the **socket** method of the ``socket`` library. +It takes up to three optional positional arguments (here we use none to get +the default behavior):: -* names appropriate *executable* in it's *shebang* line -* uses os.environ to read information from the HTTP request -* builds *any and all* appropriate **HTTP Headers** (Content-type:, - Content-length:, ...) -* prints headers, empty line and script output (body) to stdout + >>> foo = socket.socket() + >>> foo + -In-Class Exercise +Sockets in Python ----------------- -You've seen the output from the ``cgi.test()`` method from the ``cgi`` module. -Let's make our own version of this. +A socket has some properties that are immediately important to us. These +include the *family*, *type* and *protocol* of the socket:: -.. class:: incremental small + >>> foo.family + 2 + >>> foo.type + 1 + >>> foo.proto + 0 -* In the directory ``cgi-bin`` you will find the file ``cgi_2.py``. -* Open that file in your editor. -* The script contains some html with text naming elements of the CGI - environment. -* You should use the values in os.environ to fill in the blanks. -* You should be able to view the results of your work by loading - ``http://localhost:8000/`` and clicking on *Exercise One* +.. class:: incremental -.. class:: incremental center +You might notice that the values for these properties are integers. In fact, +these integers are **constants** defined in the socket library. -**GO** +A quick utility method +---------------------- -User Provided Data ------------------- +Let's define a method in place to help us see these constants. It will take a +single argument, the shared prefix for a defined set of constants: -All this is well and good, but where's the *dynamic* stuff? +.. class:: small -.. class:: incremental +:: -It'd be nice if a user could pass form data to our script for it to use. + >>> def get_constants(prefix): + ... """mapping of socket module constants to their names.""" + ... return dict( + ... (getattr(socket, n), n) + ... for n in dir(socket) + ... if n.startswith(prefix) + ... ) + ... + >>> -.. container:: incremental +.. class:: small - In HTTP, these types of inputs show up in the URL *query* (the part after - the ``?``):: +(you can also find this in ``resources/session01/session1.py``) - http://myhost.com/script.py?a=23&b=37 +Socket Families +--------------- -Form Data in CGI ----------------- +Think back a moment to our discussion of the *Internet* layer of the TCP/IP +stack. There were a couple of different types of IP addresses: -In the ``cgi`` module, we get access to this with the ``FieldStorage`` class: +.. class:: incremental -.. code-block:: python - :class: incremental small +* IPv4 ('192.168.1.100') - import cgi - - form = cgi.FieldStorage() - stringval = form.getvalue('a', None) - listval = form.getlist('b') +* IPv6 ('2001:0db8:85a3:0042:0000:8a2e:0370:7334') .. class:: incremental -* The values in the ``FieldStorage`` are *always* strings -* ``getvalue`` allows you to return a default, in case the field isn't present -* ``getlist`` always returns a list: empty, one-valued, or as many values as - are present +The **family** of a socket corresponds to the *addressing system* it uses for +connecting. -In-Class Exercise ------------------ +Socket Families +--------------- -Let's create a dynamic adding machine. +Families defined in the ``socket`` library are prefixed by ``AF_``:: -.. class:: incremental + >>> families = get_constants('AF_') + >>> families + {0: 'AF_UNSPEC', 1: 'AF_UNIX', 2: 'AF_INET', + 11: 'AF_SNA', 12: 'AF_DECnet', 16: 'AF_APPLETALK', + 17: 'AF_ROUTE', 23: 'AF_IPX', 30: 'AF_INET6'} + +.. class:: small incremental -* In the ``cgi-bin`` directory you'll find ``cgi_sums.py``. -* In the ``index.html`` file in the ``cgi`` directory, the third link leads to - this file. -* You will use the structure of that link, and what you learned just now about - ``cgi.FieldStorage``. -* Complete the cgi script in ``cgi_sums.py`` so that the result of adding all - operands sent via the url query is returned. +*Your results may vary* .. class:: incremental -For extra fun, return the results in ``json`` format (mimetype: -'application/json'). +Of all of these, the ones we care most about are ``2`` (IPv4) and ``30`` (IPv6). -My Solution ------------ +Unix Domain Sockets +------------------- -.. code-block:: python - :class: small incremental +When you are on a machine with an operating system that is Unix-like, you will +find another generally useful socket family: ``AF_UNIX``, or Unix Domain +Sockets. Sockets in this family: - form = cgi.FieldStorage() - operands = form.getlist('operand') - total = 0 - for operand in operands: - try: - value = int(operand) - except ValueError: - value = 0 - total += value +.. class:: incremental - output = {'result': total} - json_output = json.dumps(output) +* connect processes **on the same machine** - print "Content-Type: application/json" - print "Content-Length: %s" % len(json_output) - print - print json_output +* are generally a bit slower than IPC connnections +* have the benefit of allowing the same API for programs that might run on one + machine __or__ across the network -Stopping Point --------------- +* use an 'address' that looks like a pathname ('/tmp/foo.sock') -.. class:: big-centered -Let's take a break here, before continuing +Test your skills +---------------- +What is the *default* family for the socket we created just a moment ago? -CGI Problems ------------- +.. class:: incremental -CGI is great, but there are problems: +(remember we bound the socket to the symbol ``foo``) -.. class:: incremental +.. class:: incremental center -* Code is executed *in a new process* -* **Every** call to a CGI script starts a new process on the server -* Starting a new process is expensive in terms of server resources -* *Especially for interpreted languages like Python* +How did you figure this out? -.. class:: incremental -How do we overcome this problem? +Socket Types +------------ +The socket *type* determines the semantics of socket communications. -Alternatives to CGI -------------------- +Look up socket type constants with the ``SOCK_`` prefix:: -The most popular approach is to have a long-running process *inside* the -server that handles CGI scripts. + >>> types = get_constants('SOCK_') + >>> types + {1: 'SOCK_STREAM', 2: 'SOCK_DGRAM', + ...} .. class:: incremental -FastCGI and SCGI are existing implementations of CGI in this fashion. The -Apache module **mod_python** offers a similar capability for Python code. +The most common are ``1`` (Stream communication (TCP)) and ``2`` (Datagram +communication (UDP)). -.. class:: incremental -* Each of these options has a specific API -* None are compatible with each-other -* Code written for one is **not portable** to another +Test your skills +---------------- -.. class:: incremental +What is the *default* type for our generic socket, ``foo``? -This makes it much more difficult to *share resources* +Socket Protocols +---------------- -WSGI ----- +A socket also has a designated *protocol*. The constants for these are +prefixed by ``IPPROTO_``:: -Enter WSGI, the Web Server Gateway Interface. + >>> protocols = get_constants('IPPROTO_') + >>> protocols + {0: 'IPPROTO_IP', 1: 'IPPROTO_ICMP', + ..., + 255: 'IPPROTO_RAW'} .. class:: incremental -Where other alternatives are specific implementations of the CGI standard, -WSGI is itself a new standard, not an implementation. +The choice of which protocol to use for a socket is determined by the +*internet layer* protocol you intend to use. ``TCP``? ``UDP``? ``ICMP``? +``IGMP``? -.. class:: incremental -WSGI is generalized to describe a set of interactions, so that developers can -write WSGI-capable apps and deploy them on any WSGI server. +Test your skills +---------------- -.. class:: incremental +What is the *default* protocol used by our generic socket, ``foo``? -Read the WSGI spec: http://www.python.org/dev/peps/pep-0333 +Custom Sockets +-------------- -WSGI: Apps and Servers ----------------------- +These three properties of a socket correspond to the three positional +arguments you may pass to the socket constructor. -.. class:: small +.. container:: incremental -WSGI consists of two parts, a *server* and an *application*. + Using them allows you to create sockets with specific communications + profiles:: + + >>> bar = socket.socket(socket.AF_INET, + ... socket.SOCK_DGRAM, + ... socket.IPPROTO_UDP) + ... + >>> bar + -.. class:: small -A WSGI Server must: +Break Time +---------- -.. class:: incremental small +So far we have: -* set up an environment, much like the one in CGI -* provide a method ``start_response(status, headers, exc_info=None)`` -* build a response body by calling an *application*, passing - ``environment`` and ``start_response`` as args -* return a response with the status, headers and body +.. class:: incremental -.. class:: small +* learned about the "layers" of the TCP/IP Stack +* discussed *families*, *types* and *protocols* in sockets +* learned how to create sockets with a specific communications profile. -A WSGI Appliction must: +.. class:: incremental -.. class:: incremental small +When we return we'll learn how to find the communcations profiles of remote +sockets, how to connect to them, and how to send and receive messages. -* Be a callable (function, method, class) -* Take an environment and a ``start_response`` callable as arguments -* Call the ``start_response`` method. -* Return an iterable of 0 or more strings, which are treated as the body of - the response. +.. class:: incremental +Take a few minutes now to clear your head (do not quit your python +interpreter). -Simplified WSGI Server ----------------------- -.. code-block:: python - :class: small +Address Information +------------------- - from some_application import simple_app - - def build_env(request): - # put together some environment info from the reqeuest - return env - - def handle_request(request, app): - environ = build_env(request) - iterable = app(environ, start_response) - for data in iterable: - # send data to client here - - def start_response(status, headers): - # start an HTTP response, sending status and headers - - # listen for HTTP requests and pass on to handle_request() - serve(simple_app) +When you are creating a socket to communicate with a remote service, the +remote socket will have a specific communications profile. +.. class:: incremental -Simple WSGI Application ------------------------ +The local socket you create must match that communications profile. -Where the simplified server above is **not** functional, this *is* a complete -app: +.. class:: incremental -.. code-block:: python +How can you determine the *correct* values to use? - def application(environ, start_response) - status = "200 OK" - body = "Hello World\n" - response_headers = [('Content-type', 'text/plain'), - ('Content-length', len(body))] - start_response(status, response_headers) - return [body] +.. class:: incremental center +You ask. -WSGI Middleware ---------------- -A third part of the puzzle is something called WSGI *middleware* +Address Information +------------------- -.. class:: incremental +The function ``socket.getaddrinfo`` provides information about available +connections on a given host. -* Middleware implements both the *server* and *application* interfaces -* Middleware acts as a server when viewed from an application -* Middleware acts as an application when viewed from a server +.. code-block:: python + :class: small -.. image:: img/wsgi_middleware_onion.png - :align: center - :width: 38% - :class: incremental + socket.getaddrinfo('127.0.0.1', 80) +.. class:: incremental -Flowcharts ----------- +This provides all you need to make a proper connection to a socket on a remote +host. The value returned is a tuple of: -WSGI Servers: +.. class:: incremental -.. class:: center incremental +* socket family +* socket type +* socket protocol +* canonical name (usually empty, unless requested by flag) +* socket address (tuple of IP and Port) -**HTTP <---> WSGI** -.. class:: incremental +A quick utility method +---------------------- -WSGI Applications: +Again, let's create a utility method in-place so we can see this in action: -.. class:: center incremental +.. class:: small -**WSGI <---> app code** +:: + >>> def get_address_info(host, port): + ... for response in socket.getaddrinfo(host, port): + ... fam, typ, pro, nam, add = response + ... print 'family: ', families[fam] + ... print 'type: ', types[typ] + ... print 'protocol: ', protocols[pro] + ... print 'canonical name: ', nam + ... print 'socket address: ', add + ... print + ... + >>> -The Whole Enchilada -------------------- +.. class:: small -The WSGI *Stack* can thus be expressed like so: +(you can also find this in ``resources/session01/session1.py``) -.. class:: incremental big-centered -**HTTP <---> WSGI <---> app code** +On Your Own Machine +------------------- +Now, ask your own machine what possible connections are available for 'http':: -Using wsgiref -------------- + >>> get_address_info(socket.gethostname(), 'http') + family: AF_INET + type: SOCK_DGRAM + protocol: IPPROTO_UDP + canonical name: + socket address: ('10.211.55.2', 80) + + family: AF_INET + ... + >>> -The Python standard lib provides a reference implementation of WSGI: +.. class:: incremental -.. image:: img/wsgiref_flow.png - :align: center - :width: 80% - :class: incremental +What answers do you get? -Apache mod_wsgi +On the Internet --------------- -You can also deploy with Apache as your HTTP server, using **mod_wsgi**: +:: -.. image:: img/mod_wsgi_flow.png - :align: center - :width: 80% - :class: incremental + >>> get_address_info('crisewing.com', 'http') + family: AF_INET + type: SOCK_DGRAM + ... + family: AF_INET + type: SOCK_STREAM + ... + >>> -Proxied WSGI Servers --------------------- +.. class:: incremental -Finally, it is also common to see WSGI apps deployed via a proxied WSGI -server: +Try a few other servers you know about. -.. image:: img/proxy_wsgi.png - :align: center - :width: 80% - :class: incremental +First Steps +----------- -The WSGI Environment --------------------- +.. class:: big-centered -.. class:: small +Let's put this to use -REQUEST_METHOD - The HTTP request method, such as "GET" or "POST". This cannot ever be an - empty string, and so is always required. -SCRIPT_NAME - The initial portion of the request URL's "path" that corresponds to the - application object, so that the application knows its virtual "location". - This may be an empty string, if the application corresponds to the "root" of - the server. -PATH_INFO - The remainder of the request URL's "path", designating the virtual - "location" of the request's target within the application. This may be an - empty string, if the request URL targets the application root and does not - have a trailing slash. -QUERY_STRING - The portion of the request URL that follows the "?", if any. May be empty or - absent. -CONTENT_TYPE - The contents of any Content-Type fields in the HTTP request. May be empty or - absent. - - -The WSGI Environment --------------------- -.. class:: small +Construct a Socket +------------------ -CONTENT_LENGTH - The contents of any Content-Length fields in the HTTP request. May be empty - or absent. -SERVER_NAME, SERVER_PORT - When combined with SCRIPT_NAME and PATH_INFO, these variables can be used to - complete the URL. Note, however, that HTTP_HOST, if present, should be used - in preference to SERVER_NAME for reconstructing the request URL. See the URL - Reconstruction section below for more detail. SERVER_NAME and SERVER_PORT - can never be empty strings, and so are always required. -SERVER_PROTOCOL - The version of the protocol the client used to send the request. Typically - this will be something like "HTTP/1.0" or "HTTP/1.1" and may be used by the - application to determine how to treat any HTTP request headers. (This - variable should probably be called REQUEST_PROTOCOL, since it denotes the - protocol used in the request, and is not necessarily the protocol that will - be used in the server's response. However, for compatibility with CGI we - have to keep the existing name.) - - -The WSGI Environment --------------------- +We've already made a socket ``foo`` using the generic constructor without any +arguments. We can make a better one now by using real address information from +a real server online [**do not type this yet**]: .. class:: small -HTTP\_ Variables - Variables corresponding to the client-supplied HTTP request headers (i.e., - variables whose names begin with "HTTP\_"). The presence or absence of these - variables should correspond with the presence or absence of the appropriate - HTTP header in the request. - -.. class:: center incremental +:: -**Seem Familiar?** + >>> streams = [info + ... for info in socket.getaddrinfo('crisewing.com', 'http') + ... if info[1] == socket.SOCK_STREAM] + >>> streams + [(2, 1, 6, '', ('108.59.11.99', 80))] + >>> info = streams[0] + >>> cewing_socket = socket.socket(*info[:3]) -A Bit of Repetition +Connecting a Socket ------------------- -Let's start simply. We'll begin by repeating our first CGI exercise in WSGI +Once the socket is constructed with the appropriate *family*, *type* and +*protocol*, we can connect it to the address of our remote server:: + + >>> cewing_socket.connect(info[-1]) + >>> .. class:: incremental -* Find the ``wsgi`` directory in the class resources. Copy it to your working - directory. -* Open the file ``wsgi_1.py`` in your text editor. -* We will fill in the missing values using the wsgi ``environ``, just as we - use ``os.environ`` in cgi +* a successful connection returns ``None`` -.. class:: incremental center +* a failed connection raises an error -**But First** +* you can use the *type* of error returned to tell why the connection failed. -Orientation ------------ +Sending a Message +----------------- -.. code-block:: python - :class: small +Send a message to the server on the other end of our connection (we'll +learn in session 2 about the message we are sending):: - if __name__ == '__main__': - from wsgiref.simple_server import make_server - srv = make_server('localhost', 8080, application) - srv.serve_forever() + >>> msg = "GET / HTTP/1.1\r\n" + >>> msg += "Host: crisewing.com\r\n\r\n" + >>> cewing_socket.sendall(msg) + >>> -.. class:: incremental +.. class:: incremental small -Note that we pass our ``application`` function to the server factory +* the transmission continues until all data is sent or an error occurs -.. class:: incremental +* success returns ``None`` -We don't have to write a server, ``wsgiref`` does that for us. +* failure to send raises an error -.. class:: incremental +* you can use the type of error to figure out why the transmission failed -In fact, you should *never* have to write a WSGI server. +* if an error occurs you **cannot** know how much, if any, of your data was + sent -Orientation ------------ +Receiving a Reply +----------------- -.. code-block:: python - :class: small +Whatever reply we get is received by the socket we created. We can read it +back out (again, **do not type this yet**):: - def application(environ, start_response): - response_body = body % ( - environ.get('SERVER_NAME', 'Unset'), # server name - ... - ) - status = '200 OK' - response_headers = [('Content-Type', 'text/html'), - ('Content-Length', str(len(response_body)))] - start_response(status, response_headers) - return [response_body] + >>> response = cewing_socket.recv(4096) + >>> response + 'HTTP/1.1 200 OK\r\nDate: Thu, 03 Jan 2013 05:56:53 + ... -.. class:: incremental +.. class:: incremental small -We do not define ``start_response``, the application does that. +* The sole required argument is ``buffer_size`` (an integer). It should be a + power of 2 and smallish (~4096) +* It returns a byte string of ``buffer_size`` (or smaller if less data was + received) +* If the response is longer than ``buffer size``, you can call the method + repeatedly. The last bunch will be less than ``buffer size``. -.. class:: incremental -We *are* responsible for determining the HTTP status. +Cleaning Up +----------- +When you are finished with a connection, you should always close it:: -Running a WSGI Script ---------------------- + >>> cewing_socket.close() -You can run this script with python:: - $ python wsgi_1.py +Putting it all together +----------------------- -.. class:: incremental +First, connect and send a message: -This will start a wsgi server. What host and port will it use? +.. class:: small -.. class:: incremental +:: -Point your browser at ``http://localhost:8080/``. Did it work? + >>> streams = [info + ... for info in socket.getaddrinfo('crisewing.com', 'http') + ... if info[1] == socket.SOCK_STREAM] + >>> info = streams[0] + >>> cewing_socket = socket.socket(*info[:3]) + >>> cewing_socket.connect(info[-1]) + >>> msg = "GET / HTTP/1.1\r\n" + >>> msg += "Host: crisewing.com\r\n\r\n" + >>> cewing_socket.sendall(msg) -.. class:: incremental -Go ahead and fill in the missing bits. Use the ``environ`` passed into -``application`` +Putting it all together +----------------------- +Then, receive a reply, iterating until it is complete: -Some Tips ---------- +:: -Because WSGI is a long-running process, the file you are editing is *not* -reloaded after you edit it. + >>> buffsize = 4096 + >>> response = '' + >>> done = False + >>> while not done: + ... msg_part = cewing_socket.recv(buffsize) + ... if len(msg_part) < buffsize: + ... done = True + ... cewing_socket.close() + ... response += msg_part + ... + >>> len(response) + 19427 + + +Server Side +----------- -.. class:: incremental +.. class:: big-centered -You'll need to quit and re-run the script between edits. +What about the other half of the equation? -.. class:: incremental +Construct a Socket +------------------ -You may also want to consider using ``print environ`` in your application so -you can see the dictionary. +**For the moment, stop typing this into your interpreter.** -.. class:: incremental +.. container:: incremental -If you do that, where will the printed environment appear? + Again, we begin by constructing a socket. Since we are actually the server + this time, we get to choose family, type and protocol:: + >>> server_socket = socket.socket( + ... socket.AF_INET, + ... socket.SOCK_STREAM, + ... socket.IPPROTO_TCP) + ... + >>> server_socket + -A More Complex Example ----------------------- -Let's create a multi-page wsgi application. It will serve a small database of -python books. +Bind the Socket +--------------- -.. class:: incremental +Our server socket needs to be bound to an address. This is the IP Address and +Port to which clients must connect:: -The database (with a very simple api) can be found in ``wsgi/bookdb.py`` + >>> address = ('127.0.0.1', 50000) + >>> server_socket.bind(address) .. class:: incremental -* We'll need a listing page that shows the titles of all the books -* Each title will link to a details page for that book -* The details page for each book will display all the information and have a - link back to the list +**Terminology Note**: In a server/client relationship, the server *binds* to +an address and port. The client *connects* -Some Questions to Ponder ------------------------- +Listen for Connections +---------------------- -.. class:: incremental +Once our socket is bound to an address, we can listen for attempted +connections:: -When viewing our first wsgi app, do we see the name of the wsgi application -script anywhere in the URL? + >>> server_socket.listen(1) .. class:: incremental -In our wsgi application script, how many applications did we actually have? +* The argument to ``listen`` is the *backlog* -.. class:: incremental +* The *backlog* is the **maximum** number of connection requests that the + socket will queue -How are we going to serve different types of information out of a single -application? +* Once the limit is reached, the socket refuses new connections. -Dispatch --------- - -We have to write an app that will map our incoming request path to some code -that can handle that request. - -.. class:: incremental - -This process is called ``dispatch``. There are many possible approaches +Accept Incoming Messages +------------------------ -.. class:: incremental +When a socket is listening, it can receive incoming connection requests:: -Let's begin by designing this piece of it. + >>> connection, client_address = server_socket.accept() + ... # this blocks until a client connects + >>> connection.recv(16) .. class:: incremental -Open ``bookapp.py`` from the ``wsgi`` folder. We'll do our work here. +* The ``connection`` returned by a call to ``accept`` is a **new socket**. + This new socket is used to communicate with the client +* The ``client_address`` is a two-tuple of IP Address and Port for the client + socket -PATH ----- +* When a connection request is 'accepted', it is removed from the backlog + queue. -The wsgi environment gives us access to *PATH_INFO*, which maps to the URI the -user requested when they loaded the page. -.. class:: incremental - -We can design the URLs that our app will use to assist us in routing. +Send a Reply +------------ -.. class:: incremental +The same socket that received a message from the client may be used to return +a reply:: -Let's declare that any request for ``/`` will map to the list page + >>> connection.sendall("message received") -.. container:: incremental - We can also say that the URL for a book will look like this:: - - http://localhost:8080/book/ +Clean Up +-------- -Writing resolve_path --------------------- +Once a transaction between the client and server is complete, the +``connection`` socket should be closed:: -Let's write a function, called ``resolve_path`` in our application file. + >>> connection.close() .. class:: incremental -* It should take the *PATH_INFO* value from environ as an argument. -* It should return the function that will be called. -* It should also return any arguments needed to call that function. -* This implies of course that the arguments should be part of the PATH +Note that the ``server_socket`` is *never* closed as long as the server +continues to run. -My Solution ------------ - -.. code-block:: python - :class: small incremental - - def resolve_path(path): - urls = [(r'^$', books), - (r'^book/(id[\d]+)$', book)] - matchpath = path.lstrip('/') - for regexp, func in urls: - match = re.match(regexp, matchpath) - if match is None: - continue - args = match.groups([]) - return func, args - # we get here if no url matches - raise NameError - - -Application Updates -------------------- +Getting the Flow +---------------- -We need to hook our new router into the application. +The flow of this interaction can be a bit confusing. Let's see it in action +step-by-step. .. class:: incremental -* The path should be extracted from ``environ``. -* The router should be used to get a function and arguments -* The body to return should come from calling that function with those - arguments -* If an error is raised by calling the function, an appropriate response - should be returned -* If the router raises a NameError, the application should return a 404 - response - - -My Solution ------------ - -.. code-block:: python - :class: small incremental - - def application(environ, start_response): - headers = [("Content-type", "text/html")] - try: - path = environ.get('PATH_INFO', None) - if path is None: - raise NameError - func, args = resolve_path(path) - body = func(*args) - status = "200 OK" - except NameError: - status = "404 Not Found" - body = "

Not Found

" - except Exception: - status = "500 Internal Server Error" - body = "

Internal Server Error

" - finally: - headers.append(('Content-length', str(len(body)))) - start_response(status, headers) - return [body] - - -Test Your Work --------------- - -Once you've got your script settled, run it:: +Open a second python interpreter and place it next to your first so you can +see both of them at the same time. - $ python bookapp.py -.. class:: incremental +Create a Server +--------------- -Then point your browser at ``http://localhost:8080/`` +In your first python interpreter, create a server socket and prepare it for +connections:: -.. class:: incremental + >>> server_socket = socket.socket( + ... socket.AF_INET, + ... socket.SOCK_STREAM, + ... socket.IPPROTO_IP) + >>> server_socket.bind(('127.0.0.1', 50000)) + >>> server_socket.listen(1) + >>> conn, addr = server_socket.accept() -* ``http://localhost/book/id3`` -* ``http://localhost/book/id73/`` -* ``http://localhost/sponge/damp`` - .. class:: incremental -Did that all work as you would have expected? +At this point, you should **not** get back a prompt. The server socket is +waiting for a connection to be made. -Building the List ------------------ +Create a Client +--------------- -The function ``books`` should return an html list of book titles where each -title is a link to the detail page for that book +In your second interpreter, create a client socket and prepare to send a +message:: -.. class:: incremental + >>> import socket + >>> client_socket = socket.socket( + ... socket.AF_INET, + ... socket.SOCK_STREAM, + ... socket.IPPROTO_IP) -* You'll need all the ids and titles from the book database. -* You'll need to build a list in HTML using this information -* Each list item should have the book title as a link -* The href for the link should be of the form ``/book/`` +.. container:: incremental + Before connecting, keep your eye on the server interpreter:: -My Solution ------------ + >>> client_socket.connect(('127.0.0.1', 50000)) -.. code-block:: python - :class: incremental small - def books(): - all_books = DB.titles() - body = ['

My Bookshelf

', '
    '] - item_template = '
  • {title}
  • ' - for book in all_books: - body.append(item_template.format(**book)) - body.append('
') - return '\n'.join(body) +Send a Message Client->Server +----------------------------- +As soon as you made the connection above, you should have seen the prompt +return in your server interpreter. The ``accept`` method finally returned a +new connection socket. -Test Your Work --------------- +.. class:: incremental -Quit and then restart your application script:: +When you're ready, type the following in the *client* interpreter. - $ python bookapp.py +.. class:: incremental -.. container:: incremental +:: - Then reload the root of your application:: + >>> client_socket.sendall("Hey, can you hear me?") - http://localhost:8080/ -.. class:: incremental +Receive and Respond +------------------- -You should see a nice list of the books in the database. Do you? +Back in your server interpreter, go ahead and receive the message from your +client:: -.. class:: incremental + >>> conn.recv(32) + 'Hey, can you hear me?' -Click on a link to view the detail page. Does it load without error? +Send a message back, and then close up your connection:: + >>> conn.sendall("Yes, I hear you.") + >>> conn.close() -Showing Details ---------------- -The next step of course is to polish up those detail pages. +Finish Up +--------- -.. class:: incremental +Back in your client interpreter, take a look at the response to your message, +then be sure to close your client socket too:: -* You'll need to retrieve a single book from the database -* You'll need to format the details about that book and return them as HTML -* You'll need to guard against ids that do not map to books + >>> client_socket.recv(32) + 'Yes, I hear you.' + >>> client_socket.close() -.. class:: incremental +And now that we're done, we can close up the server too (back in the server +interpreter):: -In this last case, what's the right HTTP response code to send? + >>> server_socket.close() -My Solution ------------ +Congratulations! +---------------- -.. code-block:: python - :class: incremental small +.. class:: big-centered - def book(book_id): - page = """ -

{title}

- - - - -
Author{author}
Publisher{publisher}
ISBN{isbn}
- Back to the list - """ - book = DB.title_info(book_id) - if book is None: - raise NameError - return page.format(**book) +You've run your first client-server interaction -Revel in Your Success ---------------------- +Homework +-------- -Quit and restart your script one more time +Your homework assignment for this week is to take what you've learned here +and build a simple "echo" server. .. class:: incremental -Then poke around at your application and see the good you've made +The server should automatically return to any client that connects *exactly* +what it receives (it should **echo** all messages). .. class:: incremental -And your application is portable and sharable +You will also write a python script that, when run, will send a message to the +server and receive the reply, printing it to ``stdout``. .. class:: incremental -It should run equally well under any `wsgi server -`_ - - -A Few Steps Further -------------------- +Finally, you'll do all of this so that it can be tested. -Next steps for an app like this might be: -* Create a shared full page template and incorporate it into your app -* Improve the error handling by emitting error codes other than 404 and 500 -* Swap out the basic backend here with a different one, maybe a Web Service? -* Think about ways to make the application less tightly coupled to the pages - it serves +What You Have +------------- +In our class repository, there is a folder ``assignments/session01``. -Homework --------- +.. class:: incremental -For your homework this week, you'll be creating a wsgi application of your -own. +Inside that folder, you should find: .. class:: incremental -As the source of your data, use the mashup you created last week. +* A file ``tasks.txt`` that contains these instructions -.. class:: incremental +* A skeleton for your server in ``echo_server.py`` -Your application should have at least two separate "pages" in it. +* A skeleton for your client script in ``echo_client.py`` + +* Some simple tests in ``tests.py`` .. class:: incremental -The HTML you produce does not need to be pretty, but it should be something -that shows up in a browser. +Your task is to make the tests pass. -Submitting Your Homework ------------------------- +Running the tests +----------------- -To submit your homework: +To run the tests, you'll have to set the server running in one terminal: .. class:: small -* Create a new python script in ``assignments/session04``. It should be - something I can run with: +:: -.. class:: small + $ python echo_server.py -:: +.. container:: incremental - $ python your_script.py + Then, in a second terminal, you will execute the tests: + + .. class:: small + + :: + + $ python tests.py -.. class:: small +.. container:: incremental -* Once your script is running, I should be able to view your application in my - browser. + You should see output like this: + + .. class:: small + + :: + + [...] + FAILED (failures=2) -* Include all instructions I need to successfully run and view your script. -* Add tests for your code. I should be able to run the tests like so: +Submitting Your Homework +------------------------ -.. class:: small +To submit your homework: -:: +.. class:: incremental - $ python tests.py +* In github, make a fork of my repository into *your* account. -.. class:: small +* Clone your fork of my repository to your computer. -* Commit your changes to your fork of the repo in github, then open a pull - request. +* Do your work in the ``assignments/session01/`` folder on your computer and + commit your changes to your fork. +* When you are finished and your tests are passing, you will open a pull + request in github.com from your fork to mine. -But Wait, There's More ----------------------- +.. class:: incremental -In addition, read and step through the quick tutorials on templates and -database persistence in the assignments directory. +I will review your work when I receive your pull requests, make comments on it +there, and then close the pull request. -Use your flaskenv Python, it has everything you need installed. +Going Further +------------- -Wrap-Up -------- +In ``assignments/session01/tasks.txt`` you'll find a few extra problems to try. -For educational purposes, you might wish to take a look at the source code for -the ``wsgiref`` module. It's the canonical example of a simple wsgi server +.. class:: incremental - >>> import wsgiref - >>> wsgiref.__file__ - '/full/path/to/your/copy/of/wsgiref.py' - ... +If you finish the first part of the homework in less than 3-4 hours give one +or more of these a whirl. -.. class:: incremental center +.. class:: incremental -**See you Next Time** +They are not required, but if you include solutions in your pull request, I'll +review your work. From 01ab9336d039ce754a1434a4a570a19ab178914c Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 30 Dec 2014 19:37:36 -0800 Subject: [PATCH 296/487] start a new session 1 file --- source/presentations/session01.rst | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 source/presentations/session01.rst diff --git a/source/presentations/session01.rst b/source/presentations/session01.rst new file mode 100644 index 00000000..7380e0ae --- /dev/null +++ b/source/presentations/session01.rst @@ -0,0 +1,6 @@ +Python Web Programming +====================== + +.. image:: img/python.png + :align: left + :width: 33% From b3f463c88710768c311015a9a20766b93ffa99da Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 30 Dec 2014 19:50:32 -0800 Subject: [PATCH 297/487] update for 2015 run --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 0b22e372..d79a8a4e 100644 --- a/README.rst +++ b/README.rst @@ -10,9 +10,9 @@ This package provides the source for all lecture materials used for the `Internet Programming in Python`_ section of the `Certificate in Python Programming`_ offered by the `University of Washington Professional & Continuing Education`_ program. This version of the documentation is used for -the Winter 2014 instance of the course, Taught by `Cris Ewing`_ +the Winter 2015 instance of the course, Taught by `Cris Ewing`_ -.. _Internet Programming in Python: http://www.pce.uw.edu/courses/internet-programming-python/downtown-seattle-winter-2014/ +.. _Internet Programming in Python: http://www.pce.uw.edu/courses/internet-programming-python/downtown-seattle-winter-2015/ .. _Certificate in Python Programming: http://www.pce.uw.edu/certificates/python-programming.html .. _University of Washington Professional & Continuing Education: http://www.pce.uw.edu/ .. _Cris Ewing: http://www.linkedin.com/profile/view?id=19741495 From 1cc4198e72b18c4274691cf393d533838a21a288 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 2 Jan 2015 16:50:21 -0800 Subject: [PATCH 298/487] begin converting buildout to use hieroglyph for prettier slides and better slide/text integration --- .gitignore | 3 +++ Makefile | 42 +++++++++++++++++++++++++++++----- buildout.cfg | 58 ++++++++++++----------------------------------- commands/build.in | 14 ------------ 4 files changed, 54 insertions(+), 63 deletions(-) delete mode 100644 commands/build.in diff --git a/.gitignore b/.gitignore index 86ecdd9d..663f268d 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ development *.db *.sublime-project *.sublime-workspace +.mr.developer.cfg +outline_improvements.txt +src diff --git a/Makefile b/Makefile index 11bcf2d7..20506467 100644 --- a/Makefile +++ b/Makefile @@ -3,10 +3,15 @@ # You can set these variables from the command line. SPHINXOPTS = -SPHINXBUILD = sphinx-build +SPHINXBUILD = ./bin/sphinx-build PAPER = BUILDDIR = build +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter @@ -29,17 +34,20 @@ help: @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 " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" @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)/* + rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @@ -77,17 +85,17 @@ qthelp: @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/InternetProgrammingwithPython.qhcp" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PythonWebProgramming.qhcp" @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/InternetProgrammingwithPython.qhc" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PythonWebProgramming.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/InternetProgrammingwithPython" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/InternetProgrammingwithPython" + @echo "# mkdir -p $$HOME/.local/share/devhelp/PythonWebProgramming" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PythonWebProgramming" @echo "# devhelp" epub: @@ -108,6 +116,12 @@ latexpdf: $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @@ -151,3 +165,19 @@ doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + + +slides: + $(SPHINXBUILD) -b slides $(ALLSPHINXOPTS) $(BUILDDIR)/slides + @echo "Build finished. The HTML slides are in $(BUILDDIR)/slides." + diff --git a/buildout.cfg b/buildout.cfg index f8537e31..a69c7287 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -2,13 +2,13 @@ # Buildout to set-up Sphinx # [buildout] -parts = -# venv -# venv-pygments - build_s5 - executable +parts = sphinx +extensions = mr.developer +auto-checkout = * +always-checkout = force + allow-picked-versions = true show-picked-versions = true @@ -18,55 +18,23 @@ script-in = ${buildout:directory}/commands/build.in [sphinx] recipe = collective.recipe.sphinxbuilder -#doc-directory = . -outputs = +outputs = html source = ${buildout:directory}/source/main build = ${buildout:directory}/build eggs = Sphinx docutils - roman Pygments - -[venv] -recipe = rjm.recipe.venv -venv_options = --no-site-packages -distutils_urls = - http://pypi.python.org/packages/source/d/docutils/docutils-0.9.1.tar.gz - -[build_s5] -recipe = collective.recipe.template[genshi]:genshi -input = ${buildout:script-in} -output = ${buildout:directory}/bin/build_s5 -build-suffix = html -build-directory = ${buildout:directory}/build/html/presentations -build-cmd = ${buildout:directory}/bin/rst2s5.py - -[executable] -recipe = collective.recipe.cmd -on_install = true -on_update = true -cmds = - chmod 744 ${build_s5:output} - -# manually install Pygments into the docutils venv so it will be there for -# colorizing slide code examples. -[venv-pygments] -recipe = collective.recipe.cmd -on_install = true -on_update = false -cmds = - ${buildout:directory}/bin/easy_install Pygments - + hieroglyph + ipython [versions] # pin versions for continued sanity -Jinja2 = 2.6 +Jinja2 = 2.7.2 Pygments = 1.6 -Sphinx = 1.1.3 -collective.recipe.sphinxbuilder = 0.7.1 -roman = 1.4.0 +Sphinx = 1.2.2 +collective.recipe.sphinxbuilder = 0.8.2 #Required by: #collective.recipe.sphinxbuilder 0.7.1 @@ -89,3 +57,7 @@ rjm.recipe.venv = 0.8 #Required by: #rjm.recipe.venv 0.8 virtualenv = 1.10 + + +[sources] +hieroglyph = git https://github.com/nyergler/hieroglyph.git diff --git a/commands/build.in b/commands/build.in deleted file mode 100644 index cc365279..00000000 --- a/commands/build.in +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -shopt -s nullglob -SRC=rst -DEST=${options['build-suffix']} - -cp -R ${parts.buildout.directory}/source/ui ${options['build-directory']}/ -cp -R ${parts.buildout.directory}/source/img ${options['build-directory']}/ - -for RST in ${parts.buildout.directory}/source/presentations/*.rst -do - BASE=`basename $$RST` - OUT=${options['build-directory']}/$${BASE%.$$SRC}.$$DEST - ${options['build-cmd']} $$RST $$OUT -done From a674a7d6474333e085dd25e159a5a0a69d7204b5 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 2 Jan 2015 17:09:02 -0800 Subject: [PATCH 299/487] remove unused packages from buildout --- buildout.cfg | 6 ------ 1 file changed, 6 deletions(-) diff --git a/buildout.cfg b/buildout.cfg index a69c7287..ed81b6b9 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -48,12 +48,6 @@ zc.buildout = 1.5.2 #collective.recipe.sphinxbuilder 0.7.1 zc.recipe.egg = 1.3.2 -Genshi = 0.6 -collective.recipe.cmd = 0.5 -collective.recipe.template = 1.9 -rjm.recipe.venv = 0.8 - - #Required by: #rjm.recipe.venv 0.8 virtualenv = 1.10 From 05f3997314b3bde3044770a8e6bf97b6408004e5 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 2 Jan 2015 17:43:21 -0800 Subject: [PATCH 300/487] cleanup --- source/{main => }/index.rst | 0 source/main/conf.py | 284 -------------- source/{main => }/outline.rst | 0 source/{main => }/readings.rst | 0 source/ui/default/blank.gif | Bin 49 -> 0 bytes source/ui/default/framing.css | 25 -- source/ui/default/iepngfix.htc | 42 --- source/ui/default/opera.css | 8 - source/ui/default/outline.css | 16 - source/ui/default/pretty.css | 120 ------ source/ui/default/print.css | 24 -- source/ui/default/s5-core.css | 11 - source/ui/default/slides.css | 10 - source/ui/default/slides.js | 558 ---------------------------- source/ui/uw_pce_theme/blank.gif | Bin 49 -> 0 bytes source/ui/uw_pce_theme/framing.css | 25 -- source/ui/uw_pce_theme/iepngfix.htc | 42 --- source/ui/uw_pce_theme/opera.css | 8 - source/ui/uw_pce_theme/outline.css | 16 - source/ui/uw_pce_theme/pretty.css | 252 ------------- source/ui/uw_pce_theme/print.css | 24 -- source/ui/uw_pce_theme/s5-core.css | 11 - source/ui/uw_pce_theme/slides.css | 10 - source/ui/uw_pce_theme/slides.js | 558 ---------------------------- 24 files changed, 2044 deletions(-) rename source/{main => }/index.rst (100%) delete mode 100644 source/main/conf.py rename source/{main => }/outline.rst (100%) rename source/{main => }/readings.rst (100%) delete mode 100644 source/ui/default/blank.gif delete mode 100644 source/ui/default/framing.css delete mode 100644 source/ui/default/iepngfix.htc delete mode 100644 source/ui/default/opera.css delete mode 100644 source/ui/default/outline.css delete mode 100644 source/ui/default/pretty.css delete mode 100644 source/ui/default/print.css delete mode 100644 source/ui/default/s5-core.css delete mode 100644 source/ui/default/slides.css delete mode 100644 source/ui/default/slides.js delete mode 100644 source/ui/uw_pce_theme/blank.gif delete mode 100644 source/ui/uw_pce_theme/framing.css delete mode 100644 source/ui/uw_pce_theme/iepngfix.htc delete mode 100644 source/ui/uw_pce_theme/opera.css delete mode 100644 source/ui/uw_pce_theme/outline.css delete mode 100644 source/ui/uw_pce_theme/pretty.css delete mode 100644 source/ui/uw_pce_theme/print.css delete mode 100644 source/ui/uw_pce_theme/s5-core.css delete mode 100644 source/ui/uw_pce_theme/slides.css delete mode 100644 source/ui/uw_pce_theme/slides.js diff --git a/source/main/index.rst b/source/index.rst similarity index 100% rename from source/main/index.rst rename to source/index.rst diff --git a/source/main/conf.py b/source/main/conf.py deleted file mode 100644 index 4c55833d..00000000 --- a/source/main/conf.py +++ /dev/null @@ -1,284 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Internet Programming with Python documentation build configuration file, created by -# sphinx-quickstart on Sat Nov 3 13:22:19 2012. -# -# 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'Python Web Programming Workshop' -copyright = u'2012-2013, Cris Ewing' - -# 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 = '1.0' -# The full version, including alpha/beta/rc tags. -release = '1.0' - -# 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 = [] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = 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 = 'InternetProgrammingwithPythondoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'InternetProgrammingwithPython.tex', u'Internet Programming with Python Documentation', - u'Cris Ewing', '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 - -# 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', 'internetprogrammingwithpython', u'Internet Programming with Python Documentation', - [u'Cris Ewing'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------------ - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'InternetProgrammingwithPython', u'Internet Programming with Python Documentation', - u'Cris Ewing', 'InternetProgrammingwithPython', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - - -# -- Options for Epub output --------------------------------------------------- - -# Bibliographic Dublin Core info. -epub_title = u'Internet Programming with Python' -epub_author = u'Cris Ewing' -epub_publisher = u'Cris Ewing' -epub_copyright = u'2012, Cris Ewing' - -# The language of the text. It defaults to the language option -# or en if the language is not set. -#epub_language = '' - -# The scheme of the identifier. Typical schemes are ISBN or URL. -#epub_scheme = '' - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -#epub_identifier = '' - -# A unique identification for the text. -#epub_uid = '' - -# A tuple containing the cover image and cover page html template filenames. -#epub_cover = () - -# HTML files that should be inserted before the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_pre_files = [] - -# HTML files shat should be inserted after the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_post_files = [] - -# A list of files that should not be packed into the epub file. -#epub_exclude_files = [] - -# The depth of the table of contents in toc.ncx. -#epub_tocdepth = 3 - -# Allow duplicate toc entries. -#epub_tocdup = True diff --git a/source/main/outline.rst b/source/outline.rst similarity index 100% rename from source/main/outline.rst rename to source/outline.rst diff --git a/source/main/readings.rst b/source/readings.rst similarity index 100% rename from source/main/readings.rst rename to source/readings.rst diff --git a/source/ui/default/blank.gif b/source/ui/default/blank.gif deleted file mode 100644 index 75b945d2553848b8b6f41fe5e24599c0687b8472..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49 zcmZ?wbhEHbWMp7unE0RJ|Ns9C3=9Vj8~~DvKUo+V7?>DzfNY>Fh|Ltj$Y2csQN9XW diff --git a/source/ui/default/framing.css b/source/ui/default/framing.css deleted file mode 100644 index c4727f30..00000000 --- a/source/ui/default/framing.css +++ /dev/null @@ -1,25 +0,0 @@ -/* This file has been placed in the public domain. */ -/* The following styles size, place, and layer the slide components. - Edit these if you want to change the overall slide layout. - The commented lines can be uncommented (and modified, if necessary) - to help you with the rearrangement process. */ - -/* target = 1024x768 */ - -div#header, div#footer, .slide {width: 100%; top: 0; left: 0;} -div#header {position: fixed; top: 0; height: 3em; z-index: 1;} -div#footer {top: auto; bottom: 0; height: 2.5em; z-index: 5;} -.slide {top: 0; width: 92%; padding: 2.5em 4% 4%; z-index: 2;} -div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;} -div#controls form {position: absolute; bottom: 0; right: 0; width: 100%; - margin: 0;} -#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em; - z-index: 10;} -html>body #currentSlide {position: fixed;} - -/* -div#header {background: #FCC;} -div#footer {background: #CCF;} -div#controls {background: #BBD;} -div#currentSlide {background: #FFC;} -*/ diff --git a/source/ui/default/iepngfix.htc b/source/ui/default/iepngfix.htc deleted file mode 100644 index 9f3d628b..00000000 --- a/source/ui/default/iepngfix.htc +++ /dev/null @@ -1,42 +0,0 @@ - - - - - \ No newline at end of file diff --git a/source/ui/default/opera.css b/source/ui/default/opera.css deleted file mode 100644 index c9d1148b..00000000 --- a/source/ui/default/opera.css +++ /dev/null @@ -1,8 +0,0 @@ -/* This file has been placed in the public domain. */ -/* DO NOT CHANGE THESE unless you really want to break Opera Show */ -.slide { - visibility: visible !important; - position: static !important; - page-break-before: always; -} -#slide0 {page-break-before: avoid;} diff --git a/source/ui/default/outline.css b/source/ui/default/outline.css deleted file mode 100644 index fa767e22..00000000 --- a/source/ui/default/outline.css +++ /dev/null @@ -1,16 +0,0 @@ -/* This file has been placed in the public domain. */ -/* Don't change this unless you want the layout stuff to show up in the - outline view! */ - -.layout div, #footer *, #controlForm * {display: none;} -#footer, #controls, #controlForm, #navLinks, #toggle { - display: block; visibility: visible; margin: 0; padding: 0;} -#toggle {float: right; padding: 0.5em;} -html>body #toggle {position: fixed; top: 0; right: 0;} - -/* making the outline look pretty-ish */ - -#slide0 h1, #slide0 h2, #slide0 h3, #slide0 h4 {border: none; margin: 0;} -#toggle {border: 1px solid; border-width: 0 0 1px 1px; background: #FFF;} - -.outline {display: inline ! important;} diff --git a/source/ui/default/pretty.css b/source/ui/default/pretty.css deleted file mode 100644 index 1cede72d..00000000 --- a/source/ui/default/pretty.css +++ /dev/null @@ -1,120 +0,0 @@ -/* This file has been placed in the public domain. */ -/* Following are the presentation styles -- edit away! */ - -html, body {margin: 0; padding: 0;} -body {background: white; color: black;} -/* Replace the background style above with the style below (and again for - div#header) for a graphic: */ -/* background: white url(http://github.com/bodybg.gif) -16px 0 no-repeat; */ -:link, :visited {text-decoration: none; color: #00C;} -#controls :active {color: #88A !important;} -#controls :focus {outline: 1px dotted #227;} -h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;} - -blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em;} -blockquote p {margin: 0;} - -kbd {font-weight: bold; font-size: 1em;} -sup {font-size: smaller; line-height: 1px;} - -.slide pre {padding: 0; margin-left: 0; margin-right: 0; font-size: 90%;} -.slide ul ul li {list-style: square;} -.slide img.leader {display: block; margin: 0 auto;} -.slide tt {font-size: 90%;} - -div#header, div#footer {background: #005; color: #AAB; font-family: sans-serif;} -/* background: #005 url(http://github.com/bodybg.gif) -16px 0 no-repeat; */ -div#footer {font-size: 0.5em; font-weight: bold; padding: 1em 0;} -#footer h1 {display: block; padding: 0 1em;} -#footer h2 {display: block; padding: 0.8em 1em 0;} - -.slide {font-size: 1.2em;} -.slide h1 {position: absolute; top: 0.45em; z-index: 1; - margin: 0; padding-left: 0.7em; white-space: nowrap; - font: bold 150% sans-serif; color: #DDE; background: #005;} -.slide h2 {font: bold 120%/1em sans-serif; padding-top: 0.5em;} -.slide h3 {font: bold 100% sans-serif; padding-top: 0.5em;} -h1 abbr {font-variant: small-caps;} - -div#controls {position: absolute; left: 50%; bottom: 0; - width: 50%; text-align: right; font: bold 0.9em sans-serif;} -html>body div#controls {position: fixed; padding: 0 0 1em 0; top: auto;} -div#controls form {position: absolute; bottom: 0; right: 0; width: 100%; - margin: 0; padding: 0;} -#controls #navLinks a {padding: 0; margin: 0 0.5em; - background: #005; border: none; color: #779; cursor: pointer;} -#controls #navList {height: 1em;} -#controls #navList #jumplist {position: absolute; bottom: 0; right: 0; - background: #DDD; color: #227;} - -#currentSlide {text-align: center; font-size: 0.5em; color: #449; - font-family: sans-serif; font-weight: bold;} - -#slide0 {padding-top: 1.5em} -#slide0 h1 {position: static; margin: 1em 0 0; padding: 0; color: #000; - font: bold 2em sans-serif; white-space: normal; background: transparent;} -#slide0 h2 {font: bold italic 1em sans-serif; margin: 0.25em;} -#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;} -#slide0 h4 {margin-top: 0; font-size: 1em;} - -ul.urls {list-style: none; display: inline; margin: 0;} -.urls li {display: inline; margin: 0;} -.external {border-bottom: 1px dotted gray;} -html>body .external {border-bottom: none;} -.external:after {content: " \274F"; font-size: smaller; color: #77B;} - -.incremental, .incremental *, .incremental *:after {visibility: visible; - color: white; border: 0;} -img.incremental {visibility: hidden;} -.slide .current {color: green;} - -.slide-display {display: inline ! important;} - -.huge {font-family: sans-serif; font-weight: bold; font-size: 150%;} -.big {font-family: sans-serif; font-weight: bold; font-size: 120%;} -.small {font-size: 75%;} -.tiny {font-size: 50%;} -.huge tt, .big tt, .small tt, .tiny tt {font-size: 115%;} -.huge pre, .big pre, .small pre, .tiny pre {font-size: 115%;} - -.maroon {color: maroon;} -.red {color: red;} -.magenta {color: magenta;} -.fuchsia {color: fuchsia;} -.pink {color: #FAA;} -.orange {color: orange;} -.yellow {color: yellow;} -.lime {color: lime;} -.green {color: green;} -.olive {color: olive;} -.teal {color: teal;} -.cyan {color: cyan;} -.aqua {color: aqua;} -.blue {color: blue;} -.navy {color: navy;} -.purple {color: purple;} -.black {color: black;} -.gray {color: gray;} -.silver {color: silver;} -.white {color: white;} - -.left {text-align: left ! important;} -.center {text-align: center ! important;} -.right {text-align: right ! important;} - -.animation {position: relative; margin: 1em 0; padding: 0;} -.animation img {position: absolute;} - -/* Docutils-specific overrides */ - -.slide table.docinfo {margin: 1em 0 0.5em 2em;} - -pre.literal-block, pre.doctest-block {background-color: white;} - -tt.docutils {background-color: white;} - -/* diagnostics */ -/* -li:after {content: " [" attr(class) "]"; color: #F88;} -div:before {content: "[" attr(class) "]"; color: #F88;} -*/ diff --git a/source/ui/default/print.css b/source/ui/default/print.css deleted file mode 100644 index 9d057cc8..00000000 --- a/source/ui/default/print.css +++ /dev/null @@ -1,24 +0,0 @@ -/* This file has been placed in the public domain. */ -/* The following rule is necessary to have all slides appear in print! - DO NOT REMOVE IT! */ -.slide, ul {page-break-inside: avoid; visibility: visible !important;} -h1 {page-break-after: avoid;} - -body {font-size: 12pt; background: white;} -* {color: black;} - -#slide0 h1 {font-size: 200%; border: none; margin: 0.5em 0 0.25em;} -#slide0 h3 {margin: 0; padding: 0;} -#slide0 h4 {margin: 0 0 0.5em; padding: 0;} -#slide0 {margin-bottom: 3em;} - -#header {display: none;} -#footer h1 {margin: 0; border-bottom: 1px solid; color: gray; - font-style: italic;} -#footer h2, #controls {display: none;} - -.print {display: inline ! important;} - -/* The following rule keeps the layout stuff out of print. - Remove at your own risk! */ -.layout, .layout * {display: none !important;} diff --git a/source/ui/default/s5-core.css b/source/ui/default/s5-core.css deleted file mode 100644 index 6965f5e8..00000000 --- a/source/ui/default/s5-core.css +++ /dev/null @@ -1,11 +0,0 @@ -/* This file has been placed in the public domain. */ -/* Do not edit or override these styles! - The system will likely break if you do. */ - -div#header, div#footer, div#controls, .slide {position: absolute;} -html>body div#header, html>body div#footer, - html>body div#controls, html>body .slide {position: fixed;} -.handout {display: none;} -.layout {display: block;} -.slide, .hideme, .incremental {visibility: hidden;} -#slide0 {visibility: visible;} diff --git a/source/ui/default/slides.css b/source/ui/default/slides.css deleted file mode 100644 index 82bdc0ee..00000000 --- a/source/ui/default/slides.css +++ /dev/null @@ -1,10 +0,0 @@ -/* This file has been placed in the public domain. */ - -/* required to make the slide show run at all */ -@import url(http://github.com/s5-core.css); - -/* sets basic placement and size of slide components */ -@import url(http://github.com/framing.css); - -/* styles that make the slides look good */ -@import url(http://github.com/pretty.css); diff --git a/source/ui/default/slides.js b/source/ui/default/slides.js deleted file mode 100644 index 81e04e5d..00000000 --- a/source/ui/default/slides.js +++ /dev/null @@ -1,558 +0,0 @@ -// S5 v1.1 slides.js -- released into the Public Domain -// Modified for Docutils (http://docutils.sf.net) by David Goodger -// -// Please see http://www.meyerweb.com/eric/tools/s5/credits.html for -// information about all the wonderful and talented contributors to this code! - -var undef; -var slideCSS = ''; -var snum = 0; -var smax = 1; -var slideIDs = new Array(); -var incpos = 0; -var number = undef; -var s5mode = true; -var defaultView = 'slideshow'; -var controlVis = 'visible'; - -var isIE = navigator.appName == 'Microsoft Internet Explorer' ? 1 : 0; -var isOp = navigator.userAgent.indexOf('Opera') > -1 ? 1 : 0; -var isGe = navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('Safari') < 1 ? 1 : 0; - -function hasClass(object, className) { - if (!object.className) return false; - return (object.className.search('(^|\\s)' + className + '(\\s|$)') != -1); -} - -function hasValue(object, value) { - if (!object) return false; - return (object.search('(^|\\s)' + value + '(\\s|$)') != -1); -} - -function removeClass(object,className) { - if (!object) return; - object.className = object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'), RegExp.$1+RegExp.$2); -} - -function addClass(object,className) { - if (!object || hasClass(object, className)) return; - if (object.className) { - object.className += ' '+className; - } else { - object.className = className; - } -} - -function GetElementsWithClassName(elementName,className) { - var allElements = document.getElementsByTagName(elementName); - var elemColl = new Array(); - for (var i = 0; i< allElements.length; i++) { - if (hasClass(allElements[i], className)) { - elemColl[elemColl.length] = allElements[i]; - } - } - return elemColl; -} - -function isParentOrSelf(element, id) { - if (element == null || element.nodeName=='BODY') return false; - else if (element.id == id) return true; - else return isParentOrSelf(element.parentNode, id); -} - -function nodeValue(node) { - var result = ""; - if (node.nodeType == 1) { - var children = node.childNodes; - for (var i = 0; i < children.length; ++i) { - result += nodeValue(children[i]); - } - } - else if (node.nodeType == 3) { - result = node.nodeValue; - } - return(result); -} - -function slideLabel() { - var slideColl = GetElementsWithClassName('*','slide'); - var list = document.getElementById('jumplist'); - smax = slideColl.length; - for (var n = 0; n < smax; n++) { - var obj = slideColl[n]; - - var did = 'slide' + n.toString(); - if (obj.getAttribute('id')) { - slideIDs[n] = obj.getAttribute('id'); - } - else { - obj.setAttribute('id',did); - slideIDs[n] = did; - } - if (isOp) continue; - - var otext = ''; - var menu = obj.firstChild; - if (!menu) continue; // to cope with empty slides - while (menu && menu.nodeType == 3) { - menu = menu.nextSibling; - } - if (!menu) continue; // to cope with slides with only text nodes - - var menunodes = menu.childNodes; - for (var o = 0; o < menunodes.length; o++) { - otext += nodeValue(menunodes[o]); - } - list.options[list.length] = new Option(n + ' : ' + otext, n); - } -} - -function currentSlide() { - var cs; - var footer_nodes; - var vis = 'visible'; - if (document.getElementById) { - cs = document.getElementById('currentSlide'); - footer_nodes = document.getElementById('footer').childNodes; - } else { - cs = document.currentSlide; - footer = document.footer.childNodes; - } - cs.innerHTML = '' + snum + '<\/span> ' + - '\/<\/span> ' + - '' + (smax-1) + '<\/span>'; - if (snum == 0) { - vis = 'hidden'; - } - cs.style.visibility = vis; - for (var i = 0; i < footer_nodes.length; i++) { - if (footer_nodes[i].nodeType == 1) { - footer_nodes[i].style.visibility = vis; - } - } -} - -function go(step) { - if (document.getElementById('slideProj').disabled || step == 0) return; - var jl = document.getElementById('jumplist'); - var cid = slideIDs[snum]; - var ce = document.getElementById(cid); - if (incrementals[snum].length > 0) { - for (var i = 0; i < incrementals[snum].length; i++) { - removeClass(incrementals[snum][i], 'current'); - removeClass(incrementals[snum][i], 'incremental'); - } - } - if (step != 'j') { - snum += step; - lmax = smax - 1; - if (snum > lmax) snum = lmax; - if (snum < 0) snum = 0; - } else - snum = parseInt(jl.value); - var nid = slideIDs[snum]; - var ne = document.getElementById(nid); - if (!ne) { - ne = document.getElementById(slideIDs[0]); - snum = 0; - } - if (step < 0) {incpos = incrementals[snum].length} else {incpos = 0;} - if (incrementals[snum].length > 0 && incpos == 0) { - for (var i = 0; i < incrementals[snum].length; i++) { - if (hasClass(incrementals[snum][i], 'current')) - incpos = i + 1; - else - addClass(incrementals[snum][i], 'incremental'); - } - } - if (incrementals[snum].length > 0 && incpos > 0) - addClass(incrementals[snum][incpos - 1], 'current'); - ce.style.visibility = 'hidden'; - ne.style.visibility = 'visible'; - jl.selectedIndex = snum; - currentSlide(); - number = 0; -} - -function goTo(target) { - if (target >= smax || target == snum) return; - go(target - snum); -} - -function subgo(step) { - if (step > 0) { - removeClass(incrementals[snum][incpos - 1],'current'); - removeClass(incrementals[snum][incpos], 'incremental'); - addClass(incrementals[snum][incpos],'current'); - incpos++; - } else { - incpos--; - removeClass(incrementals[snum][incpos],'current'); - addClass(incrementals[snum][incpos], 'incremental'); - addClass(incrementals[snum][incpos - 1],'current'); - } -} - -function toggle() { - var slideColl = GetElementsWithClassName('*','slide'); - var slides = document.getElementById('slideProj'); - var outline = document.getElementById('outlineStyle'); - if (!slides.disabled) { - slides.disabled = true; - outline.disabled = false; - s5mode = false; - fontSize('1em'); - for (var n = 0; n < smax; n++) { - var slide = slideColl[n]; - slide.style.visibility = 'visible'; - } - } else { - slides.disabled = false; - outline.disabled = true; - s5mode = true; - fontScale(); - for (var n = 0; n < smax; n++) { - var slide = slideColl[n]; - slide.style.visibility = 'hidden'; - } - slideColl[snum].style.visibility = 'visible'; - } -} - -function showHide(action) { - var obj = GetElementsWithClassName('*','hideme')[0]; - switch (action) { - case 's': obj.style.visibility = 'visible'; break; - case 'h': obj.style.visibility = 'hidden'; break; - case 'k': - if (obj.style.visibility != 'visible') { - obj.style.visibility = 'visible'; - } else { - obj.style.visibility = 'hidden'; - } - break; - } -} - -// 'keys' code adapted from MozPoint (http://mozpoint.mozdev.org/) -function keys(key) { - if (!key) { - key = event; - key.which = key.keyCode; - } - if (key.which == 84) { - toggle(); - return; - } - if (s5mode) { - switch (key.which) { - case 10: // return - case 13: // enter - if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return; - if (key.target && isParentOrSelf(key.target, 'controls')) return; - if(number != undef) { - goTo(number); - break; - } - case 32: // spacebar - case 34: // page down - case 39: // rightkey - case 40: // downkey - if(number != undef) { - go(number); - } else if (!incrementals[snum] || incpos >= incrementals[snum].length) { - go(1); - } else { - subgo(1); - } - break; - case 33: // page up - case 37: // leftkey - case 38: // upkey - if(number != undef) { - go(-1 * number); - } else if (!incrementals[snum] || incpos <= 0) { - go(-1); - } else { - subgo(-1); - } - break; - case 36: // home - goTo(0); - break; - case 35: // end - goTo(smax-1); - break; - case 67: // c - showHide('k'); - break; - } - if (key.which < 48 || key.which > 57) { - number = undef; - } else { - if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return; - if (key.target && isParentOrSelf(key.target, 'controls')) return; - number = (((number != undef) ? number : 0) * 10) + (key.which - 48); - } - } - return false; -} - -function clicker(e) { - number = undef; - var target; - if (window.event) { - target = window.event.srcElement; - e = window.event; - } else target = e.target; - if (target.href != null || hasValue(target.rel, 'external') || isParentOrSelf(target, 'controls') || isParentOrSelf(target,'embed') || isParentOrSelf(target, 'object')) return true; - if (!e.which || e.which == 1) { - if (!incrementals[snum] || incpos >= incrementals[snum].length) { - go(1); - } else { - subgo(1); - } - } -} - -function findSlide(hash) { - var target = document.getElementById(hash); - if (target) { - for (var i = 0; i < slideIDs.length; i++) { - if (target.id == slideIDs[i]) return i; - } - } - return null; -} - -function slideJump() { - if (window.location.hash == null || window.location.hash == '') { - currentSlide(); - return; - } - if (window.location.hash == null) return; - var dest = null; - dest = findSlide(window.location.hash.slice(1)); - if (dest == null) { - dest = 0; - } - go(dest - snum); -} - -function fixLinks() { - var thisUri = window.location.href; - thisUri = thisUri.slice(0, thisUri.length - window.location.hash.length); - var aelements = document.getElementsByTagName('A'); - for (var i = 0; i < aelements.length; i++) { - var a = aelements[i].href; - var slideID = a.match('\#.+'); - if ((slideID) && (slideID[0].slice(0,1) == '#')) { - var dest = findSlide(slideID[0].slice(1)); - if (dest != null) { - if (aelements[i].addEventListener) { - aelements[i].addEventListener("click", new Function("e", - "if (document.getElementById('slideProj').disabled) return;" + - "go("+dest+" - snum); " + - "if (e.preventDefault) e.preventDefault();"), true); - } else if (aelements[i].attachEvent) { - aelements[i].attachEvent("onclick", new Function("", - "if (document.getElementById('slideProj').disabled) return;" + - "go("+dest+" - snum); " + - "event.returnValue = false;")); - } - } - } - } -} - -function externalLinks() { - if (!document.getElementsByTagName) return; - var anchors = document.getElementsByTagName('a'); - for (var i=0; i' + - '

cr8bZ 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