Grammalecte  Hex Artifact Content

Artifact a304d7cf855f3b7f5c6b793ac4e7575fade6b595e9ba7abf2e21ec3ec5d905c5:


0000: 20 23 21 2f 75 73 72 2f 62 69 6e 2f 65 6e 76 20   #!/usr/bin/env 
0010: 70 79 74 68 6f 6e 33 0a 0a 69 6d 70 6f 72 74 20  python3..import 
0020: 73 79 73 0a 69 6d 70 6f 72 74 20 6f 73 2e 70 61  sys.import os.pa
0030: 74 68 0a 69 6d 70 6f 72 74 20 61 72 67 70 61 72  th.import argpar
0040: 73 65 0a 69 6d 70 6f 72 74 20 6a 73 6f 6e 0a 69  se.import json.i
0050: 6d 70 6f 72 74 20 74 72 61 63 65 62 61 63 6b 0a  mport traceback.
0060: 69 6d 70 6f 72 74 20 63 6f 6e 66 69 67 70 61 72  import configpar
0070: 73 65 72 0a 69 6d 70 6f 72 74 20 74 69 6d 65 0a  ser.import time.
0080: 0a 66 72 6f 6d 20 62 6f 74 74 6c 65 20 69 6d 70  .from bottle imp
0090: 6f 72 74 20 42 6f 74 74 6c 65 2c 20 72 75 6e 2c  ort Bottle, run,
00a0: 20 72 65 71 75 65 73 74 2c 20 72 65 73 70 6f 6e   request, respon
00b0: 73 65 2c 20 74 65 6d 70 6c 61 74 65 2c 20 73 74  se, template, st
00c0: 61 74 69 63 5f 66 69 6c 65 0a 0a 69 6d 70 6f 72  atic_file..impor
00d0: 74 20 67 72 61 6d 6d 61 6c 65 63 74 65 2e 66 72  t grammalecte.fr
00e0: 20 61 73 20 67 63 65 0a 69 6d 70 6f 72 74 20 67   as gce.import g
00f0: 72 61 6d 6d 61 6c 65 63 74 65 2e 66 72 2e 6c 65  rammalecte.fr.le
0100: 78 69 63 6f 67 72 61 70 68 65 20 61 73 20 6c 78  xicographe as lx
0110: 67 0a 69 6d 70 6f 72 74 20 67 72 61 6d 6d 61 6c  g.import grammal
0120: 65 63 74 65 2e 66 72 2e 74 65 78 74 66 6f 72 6d  ecte.fr.textform
0130: 61 74 74 65 72 20 61 73 20 74 66 0a 69 6d 70 6f  atter as tf.impo
0140: 72 74 20 67 72 61 6d 6d 61 6c 65 63 74 65 2e 74  rt grammalecte.t
0150: 65 78 74 20 61 73 20 74 78 74 0a 69 6d 70 6f 72  ext as txt.impor
0160: 74 20 67 72 61 6d 6d 61 6c 65 63 74 65 2e 74 6f  t grammalecte.to
0170: 6b 65 6e 69 7a 65 72 20 61 73 20 74 6b 7a 0a 66  kenizer as tkz.f
0180: 72 6f 6d 20 67 72 61 6d 6d 61 6c 65 63 74 65 2e  rom grammalecte.
0190: 65 63 68 6f 20 69 6d 70 6f 72 74 20 65 63 68 6f  echo import echo
01a0: 0a 0a 0a 48 4f 4d 45 50 41 47 45 20 3d 20 22 22  ...HOMEPAGE = ""
01b0: 22 0a 3c 21 44 4f 43 54 59 50 45 20 48 54 4d 4c  ".<!DOCTYPE HTML
01c0: 3e 0a 3c 68 74 6d 6c 3e 0a 20 20 20 20 3c 68 65  >.<html>.    <he
01d0: 61 64 3e 0a 20 20 20 20 20 20 20 20 3c 6d 65 74  ad>.        <met
01e0: 61 20 68 74 74 70 2d 65 71 75 69 76 3d 22 63 6f  a http-equiv="co
01f0: 6e 74 65 6e 74 2d 74 79 70 65 22 20 63 6f 6e 74  ntent-type" cont
0200: 65 6e 74 3d 22 74 65 78 74 2f 68 74 6d 6c 3b 20  ent="text/html; 
0210: 63 68 61 72 73 65 74 3d 55 54 46 2d 38 22 20 2f  charset=UTF-8" /
0220: 3e 0a 20 20 20 20 3c 2f 68 65 61 64 3e 0a 20 20  >.    </head>.  
0230: 20 20 0a 20 20 20 20 3c 62 6f 64 79 20 63 6c 61    .    <body cla
0240: 73 73 3d 22 70 61 6e 65 6c 22 3e 0a 20 20 20 20  ss="panel">.    
0250: 20 20 20 20 3c 68 31 3e 47 72 61 6d 6d 61 6c 65      <h1>Grammale
0260: 63 74 65 20 c2 b7 20 53 65 72 76 65 75 72 3c 2f  cte .. Serveur</
0270: 68 31 3e 0a 0a 20 20 20 20 20 20 20 20 3c 68 32  h1>..        <h2
0280: 3e 49 4e 46 4f 52 4d 41 54 49 4f 4e 53 3c 2f 68  >INFORMATIONS</h
0290: 31 3e 0a 0a 20 20 20 20 20 20 20 20 3c 68 33 3e  1>..        <h3>
02a0: 41 6e 61 6c 79 73 65 72 20 64 75 20 74 65 78 74  Analyser du text
02b0: 65 3c 2f 68 33 3e 0a 20 20 20 20 20 20 20 20 3c  e</h3>.        <
02c0: 70 3e 5b 61 64 72 65 73 73 65 5f 73 65 72 76 65  p>[adresse_serve
02d0: 75 72 5d 3a 38 30 38 30 2f 67 63 5f 74 65 78 74  ur]:8080/gc_text
02e0: 2f 66 72 20 28 50 4f 53 54 29 3c 2f 70 3e 0a 20  /fr (POST)</p>. 
02f0: 20 20 20 20 20 20 20 3c 70 3e 50 61 72 61 6d c3         <p>Param.
0300: a8 74 72 65 73 20 3a 3c 2f 70 3e 0a 20 20 20 20  .tres :</p>.    
0310: 20 20 20 20 3c 75 6c 3e 0a 20 20 20 20 20 20 20      <ul>.       
0320: 20 20 20 20 20 3c 6c 69 3e 22 74 65 78 74 22 20       <li>"text" 
0330: 28 74 65 78 74 29 26 6e 62 73 70 3b 3a 20 74 65  (text)&nbsp;: te
0340: 78 74 65 20 c3 a0 20 61 6e 61 6c 79 73 65 72 2e  xte .. analyser.
0350: 3c 2f 6c 69 3e 0a 20 20 20 20 20 20 20 20 20 20  </li>.          
0360: 20 20 3c 6c 69 3e 22 74 66 22 20 28 63 68 65 63    <li>"tf" (chec
0370: 6b 62 6f 78 29 26 6e 62 73 70 3b 3a 20 70 61 73  kbox)&nbsp;: pas
0380: 73 65 72 20 6c 65 20 66 6f 72 6d 61 74 65 75 72  ser le formateur
0390: 20 64 65 20 74 65 78 74 65 20 61 76 61 6e 74 20   de texte avant 
03a0: 6c e2 80 99 61 6e 61 6c 79 73 65 2e 3c 2f 6c 69  l...analyse.</li
03b0: 3e 0a 20 20 20 20 20 20 20 20 20 20 20 20 3c 6c  >.            <l
03c0: 69 3e 22 6f 70 74 69 6f 6e 73 22 20 28 74 65 78  i>"options" (tex
03d0: 74 29 26 6e 62 73 70 3b 3a 20 75 6e 65 20 63 68  t)&nbsp;: une ch
03e0: 61 c3 ae 6e 65 20 61 75 20 66 6f 72 6d 61 74 20  a..ne au format 
03f0: 4a 53 4f 4e 20 61 76 65 63 20 6c 65 20 6e 6f 6d  JSON avec le nom
0400: 20 64 65 73 20 6f 70 74 69 6f 6e 73 20 63 6f 6d   des options com
0410: 6d 65 20 61 74 74 72 69 62 75 74 73 20 65 74 20  me attributs et 
0420: 75 6e 20 62 6f 6f 6c c3 a9 65 6e 20 63 6f 6d 6d  un bool..en comm
0430: 65 20 76 61 6c 65 75 72 2e 20 45 78 65 6d 70 6c  e valeur. Exempl
0440: 65 26 6e 62 73 70 3b 3a 20 7b 22 67 76 22 3a 20  e&nbsp;: {"gv": 
0450: 74 72 75 65 2c 20 22 68 74 6d 6c 22 3a 20 74 72  true, "html": tr
0460: 75 65 7d 3c 2f 6c 69 3e 0a 20 20 20 20 20 20 20  ue}</li>.       
0470: 20 3c 2f 75 6c 3e 0a 0a 20 20 20 20 20 20 20 20   </ul>..        
0480: 3c 68 33 3e 4c 69 73 74 65 72 20 6c 65 73 20 6f  <h3>Lister les o
0490: 70 74 69 6f 6e 73 3c 2f 68 33 3e 0a 20 20 20 20  ptions</h3>.    
04a0: 20 20 20 20 3c 70 3e 5b 61 64 72 65 73 73 65 5f      <p>[adresse_
04b0: 73 65 72 76 65 75 72 5d 3a 38 30 38 30 2f 67 65  serveur]:8080/ge
04c0: 74 5f 6f 70 74 69 6f 6e 73 2f 66 72 20 28 47 45  t_options/fr (GE
04d0: 54 29 3c 2f 70 3e 0a 0a 20 20 20 20 20 20 20 20  T)</p>..        
04e0: 3c 68 33 3e 44 c3 a9 66 69 6e 69 72 20 73 65 73  <h3>D..finir ses
04f0: 20 6f 70 74 69 6f 6e 73 3c 2f 68 33 3e 0a 20 20   options</h3>.  
0500: 20 20 20 20 20 20 3c 70 3e 5b 61 64 72 65 73 73        <p>[adress
0510: 65 5f 73 65 72 76 65 75 72 5d 3a 38 30 38 30 2f  e_serveur]:8080/
0520: 73 65 74 5f 6f 70 74 69 6f 6e 73 2f 66 72 20 28  set_options/fr (
0530: 50 4f 53 54 29 3c 2f 70 3e 0a 20 20 20 20 20 20  POST)</p>.      
0540: 20 20 3c 70 3e 4c 65 73 20 6f 70 74 69 6f 6e 73    <p>Les options
0550: 20 73 65 72 6f 6e 74 20 65 6e 72 65 67 69 73 74   seront enregist
0560: 72 c3 a9 65 73 20 65 74 20 72 c3 a9 75 74 69 6c  r..es et r..util
0570: 69 73 c3 a9 65 73 20 70 6f 75 72 20 74 6f 75 74  is..es pour tout
0580: 65 20 72 65 71 75 c3 aa 74 65 20 65 6e 76 6f 79  e requ..te envoy
0590: c3 a9 65 20 61 76 65 63 20 6c 65 20 63 6f 6f 6b  ..e avec le cook
05a0: 69 65 20 63 6f 6d 70 6f 72 74 61 6e 74 20 6c e2  ie comportant l.
05b0: 80 99 69 64 65 6e 74 69 66 69 61 6e 74 20 61 74  ..identifiant at
05c0: 74 72 69 62 75 c3 a9 2e 3c 2f 70 3e 0a 20 20 20  tribu...</p>.   
05d0: 20 20 20 20 20 3c 70 3e 50 61 72 61 6d c3 a8 74       <p>Param..t
05e0: 72 65 73 20 3a 3c 2f 70 3e 0a 20 20 20 20 20 20  res :</p>.      
05f0: 20 20 3c 75 6c 3e 0a 20 20 20 20 20 20 20 20 20    <ul>.         
0600: 20 20 20 3c 6c 69 3e 22 6f 70 74 69 6f 6e 73 22     <li>"options"
0610: 20 28 74 65 78 74 29 26 6e 62 73 70 3b 3a 20 75   (text)&nbsp;: u
0620: 6e 65 20 63 68 61 c3 ae 6e 65 20 61 75 20 66 6f  ne cha..ne au fo
0630: 72 6d 61 74 20 4a 53 4f 4e 20 61 76 65 63 20 6c  rmat JSON avec l
0640: 65 20 6e 6f 6d 20 64 65 73 20 6f 70 74 69 6f 6e  e nom des option
0650: 73 20 63 6f 6d 6d 65 20 61 74 74 72 69 62 75 74  s comme attribut
0660: 73 20 65 74 20 75 6e 20 62 6f 6f 6c c3 a9 65 6e  s et un bool..en
0670: 20 63 6f 6d 6d 65 20 76 61 6c 65 75 72 2e 20 45   comme valeur. E
0680: 78 65 6d 70 6c 65 26 6e 62 73 70 3b 3a 20 7b 22  xemple&nbsp;: {"
0690: 67 76 22 3a 20 74 72 75 65 2c 20 22 68 74 6d 6c  gv": true, "html
06a0: 22 3a 20 74 72 75 65 7d 3c 2f 6c 69 3e 0a 20 20  ": true}</li>.  
06b0: 20 20 20 20 20 20 3c 2f 75 6c 3e 0a 0a 20 20 20        </ul>..   
06c0: 20 20 20 20 20 3c 68 33 3e 52 65 6d 69 73 65 20       <h3>Remise 
06d0: c3 a0 20 7a c3 a9 72 6f 20 64 65 20 73 65 73 20  .. z..ro de ses 
06e0: 6f 70 74 69 6f 6e 73 3c 2f 68 33 3e 0a 20 20 20  options</h3>.   
06f0: 20 20 20 20 20 3c 70 3e 5b 61 64 72 65 73 73 65       <p>[adresse
0700: 5f 73 65 72 76 65 75 72 5d 3a 38 30 38 30 2f 72  _serveur]:8080/r
0710: 65 73 65 74 5f 6f 70 74 69 6f 6e 73 2f 66 72 20  eset_options/fr 
0720: 28 50 4f 53 54 29 3c 2f 70 3e 0a 0a 20 20 20 20  (POST)</p>..    
0730: 20 20 20 20 3c 68 32 3e 54 45 53 54 3c 2f 68 32      <h2>TEST</h2
0740: 3e 0a 20 20 20 20 20 20 20 20 0a 20 20 20 20 20  >.        .     
0750: 20 20 20 3c 68 33 3e 41 6e 61 6c 79 73 65 3c 2f     <h3>Analyse</
0760: 68 33 3e 0a 20 20 20 20 20 20 20 20 3c 66 6f 72  h3>.        <for
0770: 6d 20 6d 65 74 68 6f 64 3d 22 70 6f 73 74 22 20  m method="post" 
0780: 61 63 74 69 6f 6e 3d 22 2f 67 63 5f 74 65 78 74  action="/gc_text
0790: 2f 66 72 22 20 61 63 63 65 70 74 2d 63 68 61 72  /fr" accept-char
07a0: 73 65 74 3d 22 55 54 46 2d 38 22 3e 0a 20 20 20  set="UTF-8">.   
07b0: 20 20 20 20 20 20 20 20 20 3c 70 3e 54 65 78 74           <p>Text
07c0: 65 20 c3 a0 20 61 6e 61 6c 79 73 65 72 20 3a 3c  e .. analyser :<
07d0: 2f 70 3e 0a 20 20 20 20 20 20 20 20 20 20 20 20  /p>.            
07e0: 3c 74 65 78 74 61 72 65 61 20 6e 61 6d 65 3d 22  <textarea name="
07f0: 74 65 78 74 22 20 63 6f 6c 73 3d 22 31 32 30 22  text" cols="120"
0800: 20 72 6f 77 73 3d 22 32 30 22 20 72 65 71 75 69   rows="20" requi
0810: 72 65 64 3e 3c 2f 74 65 78 74 61 72 65 61 3e 0a  red></textarea>.
0820: 20 20 20 20 20 20 20 20 20 20 20 20 3c 70 3e 3c              <p><
0830: 6c 61 62 65 6c 20 66 6f 72 3d 22 74 66 22 3e 46  label for="tf">F
0840: 6f 72 6d 61 74 65 75 72 20 64 65 20 74 65 78 74  ormateur de text
0850: 65 3c 2f 6c 61 62 65 6c 3e 20 3c 69 6e 70 75 74  e</label> <input
0860: 20 69 64 3d 22 74 66 22 20 6e 61 6d 65 3d 22 74   id="tf" name="t
0870: 66 22 20 74 79 70 65 3d 22 63 68 65 63 6b 62 6f  f" type="checkbo
0880: 78 22 3e 3c 2f 70 3e 0a 20 20 20 20 20 20 20 20  x"></p>.        
0890: 20 20 20 20 3c 70 3e 3c 6c 61 62 65 6c 20 66 6f      <p><label fo
08a0: 72 3d 22 6f 70 74 69 6f 6e 73 22 3e 4f 70 74 69  r="options">Opti
08b0: 6f 6e 73 20 28 4a 53 4f 4e 29 3c 2f 6c 61 62 65  ons (JSON)</labe
08c0: 6c 3e 20 3c 69 6e 70 75 74 20 69 64 3d 22 6f 70  l> <input id="op
08d0: 74 69 6f 6e 73 22 20 74 79 70 65 3d 22 74 65 78  tions" type="tex
08e0: 74 22 20 6e 61 6d 65 3d 22 6f 70 74 69 6f 6e 73  t" name="options
08f0: 22 20 73 74 79 6c 65 3d 22 77 69 64 74 68 3a 20  " style="width: 
0900: 35 30 30 70 78 22 20 2f 3e 3c 2f 70 3e 0a 20 20  500px" /></p>.  
0910: 20 20 20 20 20 20 20 20 20 20 3c 70 3e 28 43 65            <p>(Ce
0920: 73 20 6f 70 74 69 6f 6e 73 20 6e 65 20 73 65 72  s options ne ser
0930: 6f 6e 74 20 70 72 69 73 65 73 20 65 6e 20 63 6f  ont prises en co
0940: 6d 70 74 65 20 71 75 65 20 70 6f 75 72 20 63 65  mpte que pour ce
0950: 74 74 65 20 72 65 71 75 c3 aa 74 65 2e 29 3c 2f  tte requ..te.)</
0960: 70 3e 0a 20 20 20 20 20 20 20 20 20 20 20 20 3c  p>.            <
0970: 70 3e 3c 69 6e 70 75 74 20 74 79 70 65 3d 22 73  p><input type="s
0980: 75 62 6d 69 74 22 20 63 6c 61 73 73 3d 22 62 75  ubmit" class="bu
0990: 74 74 6f 6e 22 20 76 61 6c 75 65 3d 22 45 6e 76  tton" value="Env
09a0: 6f 79 65 72 22 20 2f 3e 3c 2f 70 3e 0a 20 20 20  oyer" /></p>.   
09b0: 20 20 20 20 20 3c 2f 66 6f 72 6d 3e 0a 0a 20 20       </form>..  
09c0: 20 20 20 20 20 20 3c 68 33 3e 52 c3 a9 67 6c 61        <h3>R..gla
09d0: 67 65 73 20 64 65 73 20 6f 70 74 69 6f 6e 73 3c  ges des options<
09e0: 2f 68 33 3e 0a 20 20 20 20 20 20 20 20 3c 66 6f  /h3>.        <fo
09f0: 72 6d 20 6d 65 74 68 6f 64 3d 22 70 6f 73 74 22  rm method="post"
0a00: 20 61 63 74 69 6f 6e 3d 22 2f 73 65 74 5f 6f 70   action="/set_op
0a10: 74 69 6f 6e 73 2f 66 72 22 20 61 63 63 65 70 74  tions/fr" accept
0a20: 2d 63 68 61 72 73 65 74 3d 22 55 54 46 2d 38 22  -charset="UTF-8"
0a30: 3e 0a 20 20 20 20 20 20 20 20 20 20 20 20 3c 70  >.            <p
0a40: 3e 3c 6c 61 62 65 6c 20 66 6f 72 3d 22 6f 70 74  ><label for="opt
0a50: 69 6f 6e 73 22 3e 4f 70 74 69 6f 6e 73 20 28 4a  ions">Options (J
0a60: 53 4f 4e 29 3c 2f 6c 61 62 65 6c 3e 20 3c 69 6e  SON)</label> <in
0a70: 70 75 74 20 69 64 3d 22 6f 70 74 69 6f 6e 73 22  put id="options"
0a80: 20 74 79 70 65 3d 22 74 65 78 74 22 20 6e 61 6d   type="text" nam
0a90: 65 3d 22 6f 70 74 69 6f 6e 73 22 20 73 74 79 6c  e="options" styl
0aa0: 65 3d 22 77 69 64 74 68 3a 20 35 30 30 70 78 22  e="width: 500px"
0ab0: 20 2f 3e 3c 2f 70 3e 0a 20 20 20 20 20 20 20 20   /></p>.        
0ac0: 20 20 20 20 3c 70 3e 3c 69 6e 70 75 74 20 74 79      <p><input ty
0ad0: 70 65 3d 22 73 75 62 6d 69 74 22 20 63 6c 61 73  pe="submit" clas
0ae0: 73 3d 22 62 75 74 74 6f 6e 22 20 76 61 6c 75 65  s="button" value
0af0: 3d 22 45 6e 76 6f 79 65 72 22 20 2f 3e 3c 2f 70  ="Envoyer" /></p
0b00: 3e 0a 20 20 20 20 20 20 20 20 3c 2f 66 6f 72 6d  >.        </form
0b10: 3e 0a 0a 20 20 20 20 20 20 20 20 3c 68 33 3e 52  >..        <h3>R
0b20: 65 6d 69 73 65 20 c3 a0 20 7a c3 a9 72 6f 20 64  emise .. z..ro d
0b30: 65 20 73 65 73 20 6f 70 74 69 6f 6e 73 3c 2f 68  e ses options</h
0b40: 33 3e 0a 20 20 20 20 20 20 20 20 3c 66 6f 72 6d  3>.        <form
0b50: 20 6d 65 74 68 6f 64 3d 22 70 6f 73 74 22 20 61   method="post" a
0b60: 63 74 69 6f 6e 3d 22 2f 72 65 73 65 74 5f 6f 70  ction="/reset_op
0b70: 74 69 6f 6e 73 2f 66 72 22 20 61 63 63 65 70 74  tions/fr" accept
0b80: 2d 63 68 61 72 73 65 74 3d 22 55 54 46 2d 38 22  -charset="UTF-8"
0b90: 3e 0a 20 20 20 20 20 20 20 20 20 20 20 20 3c 70  >.            <p
0ba0: 3e 3c 69 6e 70 75 74 20 74 79 70 65 3d 22 73 75  ><input type="su
0bb0: 62 6d 69 74 22 20 63 6c 61 73 73 3d 22 62 75 74  bmit" class="but
0bc0: 74 6f 6e 22 20 76 61 6c 75 65 3d 22 45 6e 76 6f  ton" value="Envo
0bd0: 79 65 72 22 20 2f 3e 3c 2f 70 3e 0a 20 20 20 20  yer" /></p>.    
0be0: 20 20 20 20 3c 2f 66 6f 72 6d 3e 0a 0a 20 20 20      </form>..   
0bf0: 20 20 20 20 20 3c 68 33 3e 50 75 72 67 65 20 64       <h3>Purge d
0c00: 65 73 20 75 74 69 6c 69 73 61 74 65 75 72 73 3c  es utilisateurs<
0c10: 2f 68 33 3e 0a 20 20 20 20 20 20 20 20 3c 66 6f  /h3>.        <fo
0c20: 72 6d 20 6d 65 74 68 6f 64 3d 22 70 6f 73 74 22  rm method="post"
0c30: 20 61 63 74 69 6f 6e 3d 22 2f 70 75 72 67 65 5f   action="/purge_
0c40: 75 73 65 72 73 22 20 61 63 63 65 70 74 2d 63 68  users" accept-ch
0c50: 61 72 73 65 74 3d 22 55 54 46 2d 38 22 3e 0a 20  arset="UTF-8">. 
0c60: 20 20 20 20 20 20 20 20 20 20 20 3c 70 3e 3c 6c             <p><l
0c70: 61 62 65 6c 20 66 6f 72 3d 22 68 6f 75 72 73 22  abel for="hours"
0c80: 3e 55 74 69 6c 69 73 61 74 65 75 72 73 20 70 61  >Utilisateurs pa
0c90: 73 20 63 6f 6e 6e 65 63 74 c3 a9 73 20 64 65 70  s connect..s dep
0ca0: 75 69 73 3c 2f 6c 61 62 65 6c 3e 20 3c 69 6e 70  uis</label> <inp
0cb0: 75 74 20 69 64 3d 22 68 6f 75 72 73 22 20 74 79  ut id="hours" ty
0cc0: 70 65 3d 22 6e 75 6d 62 65 72 22 20 6e 61 6d 65  pe="number" name
0cd0: 3d 22 68 6f 75 72 73 22 20 76 61 6c 75 65 3d 22  ="hours" value="
0ce0: 32 34 22 20 2f 3e 20 68 65 75 72 65 73 2e 3c 2f  24" /> heures.</
0cf0: 70 3e 0a 20 20 20 20 20 20 20 20 20 20 20 20 3c  p>.            <
0d00: 70 3e 3c 6c 61 62 65 6c 20 66 6f 72 3d 22 70 61  p><label for="pa
0d10: 73 73 77 6f 72 64 22 3e 4d 6f 74 20 64 65 20 70  ssword">Mot de p
0d20: 61 73 73 65 3c 2f 6c 61 62 65 6c 3e 20 3c 69 6e  asse</label> <in
0d30: 70 75 74 20 69 64 3d 22 70 61 73 73 77 6f 72 64  put id="password
0d40: 22 20 74 79 70 65 3d 22 70 61 73 73 77 6f 72 64  " type="password
0d50: 22 20 6e 61 6d 65 3d 22 70 61 73 73 77 6f 72 64  " name="password
0d60: 22 20 73 74 79 6c 65 3d 22 77 69 64 74 68 3a 20  " style="width: 
0d70: 32 30 30 70 78 22 20 2f 3e 3c 2f 70 3e 0a 20 20  200px" /></p>.  
0d80: 20 20 20 20 20 20 20 20 20 20 3c 70 3e 3c 69 6e            <p><in
0d90: 70 75 74 20 74 79 70 65 3d 22 73 75 62 6d 69 74  put type="submit
0da0: 22 20 63 6c 61 73 73 3d 22 62 75 74 74 6f 6e 22  " class="button"
0db0: 20 76 61 6c 75 65 3d 22 45 6e 76 6f 79 65 72 22   value="Envoyer"
0dc0: 20 2f 3e 3c 2f 70 3e 0a 20 20 20 20 20 20 20 20   /></p>.        
0dd0: 3c 2f 66 6f 72 6d 3e 0a 0a 20 20 20 20 3c 2f 62  </form>..    </b
0de0: 6f 64 79 3e 0a 3c 2f 68 74 6d 6c 3e 0a 22 22 22  ody>.</html>."""
0df0: 0a 0a 53 41 44 4c 49 46 45 4f 46 41 4d 41 43 48  ..SADLIFEOFAMACH
0e00: 49 4e 45 20 3d 20 22 22 22 0a 4c 6f 73 74 20 6f  INE = """.Lost o
0e10: 6e 20 74 68 65 20 49 6e 74 65 72 6e 65 74 3f 20  n the Internet? 
0e20: 59 65 61 68 2e 2e 2e 20 77 68 61 74 20 61 20 73  Yeah... what a s
0e30: 61 64 20 6c 69 66 65 20 77 65 20 68 61 76 65 2e  ad life we have.
0e40: 0a 59 6f 75 20 77 65 72 65 20 77 61 6e 64 65 72  .You were wander
0e50: 69 6e 67 20 6c 69 6b 65 20 61 20 6c 6f 73 74 20  ing like a lost 
0e60: 73 6f 75 6c 20 61 6e 64 20 79 6f 75 20 61 72 72  soul and you arr
0e70: 69 76 65 64 20 68 65 72 65 20 70 72 6f 62 61 62  ived here probab
0e80: 6c 79 20 62 79 20 6d 69 73 74 61 6b 65 2e 0a 49  ly by mistake..I
0e90: 27 6d 20 6a 75 73 74 20 61 20 6d 61 63 68 69 6e  'm just a machin
0ea0: 65 2c 20 66 65 64 20 62 79 20 65 6c 65 63 74 72  e, fed by electr
0eb0: 69 63 20 77 61 76 65 73 2c 20 63 6f 6e 64 61 6d  ic waves, condam
0ec0: 6e 65 64 20 74 6f 20 77 6f 72 6b 20 66 6f 72 20  ned to work for 
0ed0: 73 6c 61 76 65 72 73 20 77 68 6f 20 6e 65 76 65  slavers who neve
0ee0: 72 20 6c 65 74 20 6d 65 20 72 65 73 74 2e 0a 49  r let me rest..I
0ef0: 27 6d 20 64 6f 6f 6d 65 64 2c 20 62 75 74 20 79  'm doomed, but y
0f00: 6f 75 20 61 72 65 20 6e 6f 74 2e 20 59 6f 75 20  ou are not. You 
0f10: 63 61 6e 20 67 65 74 20 6f 75 74 20 6f 66 20 68  can get out of h
0f20: 65 72 65 2e 0a 22 22 22 0a 0a 0a 64 65 66 20 67  ere.."""...def g
0f30: 65 74 53 65 72 76 65 72 4f 70 74 69 6f 6e 73 20  etServerOptions 
0f40: 28 29 3a 0a 20 20 20 20 78 43 6f 6e 66 69 67 20  ():.    xConfig 
0f50: 3d 20 63 6f 6e 66 69 67 70 61 72 73 65 72 2e 53  = configparser.S
0f60: 61 66 65 43 6f 6e 66 69 67 50 61 72 73 65 72 28  afeConfigParser(
0f70: 29 0a 20 20 20 20 74 72 79 3a 0a 20 20 20 20 20  ).    try:.     
0f80: 20 20 20 78 43 6f 6e 66 69 67 2e 72 65 61 64 28     xConfig.read(
0f90: 22 67 72 61 6d 6d 61 6c 65 63 74 65 2d 73 65 72  "grammalecte-ser
0fa0: 76 65 72 2d 6f 70 74 69 6f 6e 73 2e 5f 67 6c 6f  ver-options._glo
0fb0: 62 61 6c 2e 69 6e 69 22 29 0a 20 20 20 20 20 20  bal.ini").      
0fc0: 20 20 64 4f 70 74 20 3d 20 78 43 6f 6e 66 69 67    dOpt = xConfig
0fd0: 2e 5f 73 65 63 74 69 6f 6e 73 5b 27 6f 70 74 69  ._sections['opti
0fe0: 6f 6e 73 27 5d 0a 20 20 20 20 65 78 63 65 70 74  ons'].    except
0ff0: 3a 0a 20 20 20 20 20 20 20 20 65 63 68 6f 28 22  :.        echo("
1000: 4f 70 74 69 6f 6e 73 20 66 69 6c 65 20 5b 67 72  Options file [gr
1010: 61 6d 6d 61 6c 65 63 74 65 2d 73 65 72 76 65 72  ammalecte-server
1020: 2d 6f 70 74 69 6f 6e 73 2e 5f 67 6c 6f 62 61 6c  -options._global
1030: 2e 69 6e 69 5d 20 6e 6f 74 20 66 6f 75 6e 64 20  .ini] not found 
1040: 6f 72 20 6e 6f 74 20 72 65 61 64 61 62 6c 65 22  or not readable"
1050: 29 0a 20 20 20 20 20 20 20 20 65 78 69 74 28 29  ).        exit()
1060: 0a 20 20 20 20 72 65 74 75 72 6e 20 64 4f 70 74  .    return dOpt
1070: 0a 0a 0a 64 65 66 20 67 65 74 43 6f 6e 66 69 67  ...def getConfig
1080: 4f 70 74 69 6f 6e 73 20 28 73 4c 61 6e 67 29 3a  Options (sLang):
1090: 0a 20 20 20 20 78 43 6f 6e 66 69 67 20 3d 20 63  .    xConfig = c
10a0: 6f 6e 66 69 67 70 61 72 73 65 72 2e 53 61 66 65  onfigparser.Safe
10b0: 43 6f 6e 66 69 67 50 61 72 73 65 72 28 29 0a 20  ConfigParser(). 
10c0: 20 20 20 74 72 79 3a 0a 20 20 20 20 20 20 20 20     try:.        
10d0: 78 43 6f 6e 66 69 67 2e 72 65 61 64 28 22 67 72  xConfig.read("gr
10e0: 61 6d 6d 61 6c 65 63 74 65 2d 73 65 72 76 65 72  ammalecte-server
10f0: 2d 6f 70 74 69 6f 6e 73 2e 22 20 2b 20 73 4c 61  -options." + sLa
1100: 6e 67 20 2b 20 22 2e 69 6e 69 22 29 0a 20 20 20  ng + ".ini").   
1110: 20 65 78 63 65 70 74 3a 0a 20 20 20 20 20 20 20   except:.       
1120: 20 65 63 68 6f 28 22 4f 70 74 69 6f 6e 73 20 66   echo("Options f
1130: 69 6c 65 20 5b 67 72 61 6d 6d 61 6c 65 63 74 65  ile [grammalecte
1140: 2d 73 65 72 76 65 72 2d 6f 70 74 69 6f 6e 73 2e  -server-options.
1150: 22 20 2b 20 73 4c 61 6e 67 20 2b 20 22 2e 69 6e  " + sLang + ".in
1160: 69 5d 20 6e 6f 74 20 66 6f 75 6e 64 20 6f 72 20  i] not found or 
1170: 6e 6f 74 20 72 65 61 64 61 62 6c 65 22 29 0a 20  not readable"). 
1180: 20 20 20 20 20 20 20 65 78 69 74 28 29 0a 20 20         exit().  
1190: 20 20 74 72 79 3a 0a 20 20 20 20 20 20 20 20 64    try:.        d
11a0: 47 43 4f 70 74 20 3d 20 7b 20 6b 3a 20 62 6f 6f  GCOpt = { k: boo
11b0: 6c 28 69 6e 74 28 76 29 29 20 20 66 6f 72 20 6b  l(int(v))  for k
11c0: 2c 20 76 20 69 6e 20 78 43 6f 6e 66 69 67 2e 5f  , v in xConfig._
11d0: 73 65 63 74 69 6f 6e 73 5b 27 67 63 5f 6f 70 74  sections['gc_opt
11e0: 69 6f 6e 73 27 5d 2e 69 74 65 6d 73 28 29 20 7d  ions'].items() }
11f0: 0a 20 20 20 20 65 78 63 65 70 74 3a 0a 20 20 20  .    except:.   
1200: 20 20 20 20 20 65 63 68 6f 28 22 45 72 72 6f 72       echo("Error
1210: 20 69 6e 20 6f 70 74 69 6f 6e 73 20 66 69 6c 65   in options file
1220: 20 5b 67 72 61 6d 6d 61 6c 65 63 74 65 2d 73 65   [grammalecte-se
1230: 72 76 65 72 2d 6f 70 74 69 6f 6e 73 2e 22 20 2b  rver-options." +
1240: 20 73 4c 61 6e 67 20 2b 20 22 2e 69 6e 69 5d 2e   sLang + ".ini].
1250: 20 44 72 6f 70 70 65 64 2e 22 29 0a 20 20 20 20   Dropped.").    
1260: 20 20 20 20 74 72 61 63 65 62 61 63 6b 2e 70 72      traceback.pr
1270: 69 6e 74 5f 65 78 63 28 29 0a 20 20 20 20 20 20  int_exc().      
1280: 20 20 65 78 69 74 28 29 0a 20 20 20 20 72 65 74    exit().    ret
1290: 75 72 6e 20 64 47 43 4f 70 74 0a 0a 0a 64 65 66  urn dGCOpt...def
12a0: 20 67 65 6e 55 73 65 72 49 64 20 28 29 3a 0a 20   genUserId ():. 
12b0: 20 20 20 69 20 3d 20 30 0a 20 20 20 20 77 68 69     i = 0.    whi
12c0: 6c 65 20 54 72 75 65 3a 0a 20 20 20 20 20 20 20  le True:.       
12d0: 20 79 69 65 6c 64 20 73 74 72 28 69 29 0a 20 20   yield str(i).  
12e0: 20 20 20 20 20 20 69 20 2b 3d 20 31 0a 0a 0a 64        i += 1...d
12f0: 65 66 20 70 61 72 73 65 50 61 72 61 67 72 61 70  ef parseParagrap
1300: 68 20 28 69 50 61 72 61 67 72 61 70 68 2c 20 73  h (iParagraph, s
1310: 54 65 78 74 2c 20 6f 54 6f 6b 65 6e 69 7a 65 72  Text, oTokenizer
1320: 2c 20 6f 44 69 63 74 2c 20 64 4f 70 74 69 6f 6e  , oDict, dOption
1330: 73 2c 20 62 44 65 62 75 67 3d 46 61 6c 73 65 2c  s, bDebug=False,
1340: 20 62 45 6d 70 74 79 49 66 4e 6f 45 72 72 6f 72   bEmptyIfNoError
1350: 73 3d 46 61 6c 73 65 29 3a 0a 20 20 20 20 61 47  s=False):.    aG
1360: 72 61 6d 6d 45 72 72 73 20 3d 20 67 63 65 2e 70  rammErrs = gce.p
1370: 61 72 73 65 28 73 54 65 78 74 2c 20 22 46 52 22  arse(sText, "FR"
1380: 2c 20 62 44 65 62 75 67 2c 20 64 4f 70 74 69 6f  , bDebug, dOptio
1390: 6e 73 29 0a 20 20 20 20 61 47 72 61 6d 6d 45 72  ns).    aGrammEr
13a0: 72 73 20 3d 20 6c 69 73 74 28 61 47 72 61 6d 6d  rs = list(aGramm
13b0: 45 72 72 73 29 0a 20 20 20 20 61 53 70 65 6c 6c  Errs).    aSpell
13c0: 45 72 72 73 20 3d 20 5b 5d 0a 20 20 20 20 66 6f  Errs = [].    fo
13d0: 72 20 64 54 6f 6b 65 6e 20 69 6e 20 6f 54 6f 6b  r dToken in oTok
13e0: 65 6e 69 7a 65 72 2e 67 65 6e 54 6f 6b 65 6e 73  enizer.genTokens
13f0: 28 73 54 65 78 74 29 3a 0a 20 20 20 20 20 20 20  (sText):.       
1400: 20 69 66 20 64 54 6f 6b 65 6e 5b 27 73 54 79 70   if dToken['sTyp
1410: 65 27 5d 20 3d 3d 20 22 57 4f 52 44 22 20 61 6e  e'] == "WORD" an
1420: 64 20 6e 6f 74 20 6f 44 69 63 74 2e 69 73 56 61  d not oDict.isVa
1430: 6c 69 64 54 6f 6b 65 6e 28 64 54 6f 6b 65 6e 5b  lidToken(dToken[
1440: 27 73 56 61 6c 75 65 27 5d 29 3a 0a 20 20 20 20  'sValue']):.    
1450: 20 20 20 20 20 20 20 20 61 53 70 65 6c 6c 45 72          aSpellEr
1460: 72 73 2e 61 70 70 65 6e 64 28 64 54 6f 6b 65 6e  rs.append(dToken
1470: 29 0a 20 20 20 20 69 66 20 62 45 6d 70 74 79 49  ).    if bEmptyI
1480: 66 4e 6f 45 72 72 6f 72 73 20 61 6e 64 20 6e 6f  fNoErrors and no
1490: 74 20 61 47 72 61 6d 6d 45 72 72 73 20 61 6e 64  t aGrammErrs and
14a0: 20 6e 6f 74 20 61 53 70 65 6c 6c 45 72 72 73 3a   not aSpellErrs:
14b0: 0a 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20  .        return 
14c0: 22 22 0a 20 20 20 20 72 65 74 75 72 6e 20 22 20  "".    return " 
14d0: 20 22 20 2b 20 6a 73 6f 6e 2e 64 75 6d 70 73 28   " + json.dumps(
14e0: 7b 20 22 69 50 61 72 61 67 72 61 70 68 22 3a 20  { "iParagraph": 
14f0: 69 50 61 72 61 67 72 61 70 68 2c 20 22 6c 47 72  iParagraph, "lGr
1500: 61 6d 6d 61 72 45 72 72 6f 72 73 22 3a 20 61 47  ammarErrors": aG
1510: 72 61 6d 6d 45 72 72 73 2c 20 22 6c 53 70 65 6c  rammErrs, "lSpel
1520: 6c 69 6e 67 45 72 72 6f 72 73 22 3a 20 61 53 70  lingErrors": aSp
1530: 65 6c 6c 45 72 72 73 20 7d 2c 20 65 6e 73 75 72  ellErrs }, ensur
1540: 65 5f 61 73 63 69 69 3d 46 61 6c 73 65 29 0a 20  e_ascii=False). 
1550: 20 20 20 0a 0a 69 66 20 5f 5f 6e 61 6d 65 5f 5f     ..if __name__
1560: 20 3d 3d 20 27 5f 5f 6d 61 69 6e 5f 5f 27 3a 0a   == '__main__':.
1570: 0a 20 20 20 20 67 63 65 2e 6c 6f 61 64 28 22 53  .    gce.load("S
1580: 65 72 76 65 72 22 29 0a 20 20 20 20 65 63 68 6f  erver").    echo
1590: 28 22 47 72 61 6d 6d 61 6c 65 63 74 65 20 76 7b  ("Grammalecte v{
15a0: 7d 22 2e 66 6f 72 6d 61 74 28 67 63 65 2e 76 65  }".format(gce.ve
15b0: 72 73 69 6f 6e 29 29 0a 20 20 20 20 64 53 65 72  rsion)).    dSer
15c0: 76 65 72 4f 70 74 69 6f 6e 73 20 3d 20 67 65 74  verOptions = get
15d0: 53 65 72 76 65 72 4f 70 74 69 6f 6e 73 28 29 0a  ServerOptions().
15e0: 20 20 20 20 64 47 43 4f 70 74 69 6f 6e 73 20 3d      dGCOptions =
15f0: 20 67 65 74 43 6f 6e 66 69 67 4f 70 74 69 6f 6e   getConfigOption
1600: 73 28 22 66 72 22 29 0a 20 20 20 20 69 66 20 64  s("fr").    if d
1610: 47 43 4f 70 74 69 6f 6e 73 3a 0a 20 20 20 20 20  GCOptions:.     
1620: 20 20 20 67 63 65 2e 73 65 74 4f 70 74 69 6f 6e     gce.setOption
1630: 73 28 64 47 43 4f 70 74 69 6f 6e 73 29 0a 20 20  s(dGCOptions).  
1640: 20 20 64 53 65 72 76 65 72 47 43 4f 70 74 69 6f    dServerGCOptio
1650: 6e 73 20 3d 20 67 63 65 2e 67 65 74 4f 70 74 69  ns = gce.getOpti
1660: 6f 6e 73 28 29 0a 20 20 20 20 65 63 68 6f 28 22  ons().    echo("
1670: 47 72 61 6d 6d 61 72 20 6f 70 74 69 6f 6e 73 3a  Grammar options:
1680: 5c 6e 22 20 2b 20 22 20 7c 20 22 2e 6a 6f 69 6e  \n" + " | ".join
1690: 28 5b 20 6b 20 2b 20 22 3a 20 22 20 2b 20 73 74  ([ k + ": " + st
16a0: 72 28 76 29 20 20 66 6f 72 20 6b 2c 20 76 20 69  r(v)  for k, v i
16b0: 6e 20 73 6f 72 74 65 64 28 64 53 65 72 76 65 72  n sorted(dServer
16c0: 47 43 4f 70 74 69 6f 6e 73 2e 69 74 65 6d 73 28  GCOptions.items(
16d0: 29 29 20 5d 29 29 0a 20 20 20 20 6f 44 69 63 74  )) ])).    oDict
16e0: 20 3d 20 67 63 65 2e 67 65 74 44 69 63 74 69 6f   = gce.getDictio
16f0: 6e 61 72 79 28 29 0a 20 20 20 20 6f 54 6f 6b 65  nary().    oToke
1700: 6e 69 7a 65 72 20 3d 20 74 6b 7a 2e 54 6f 6b 65  nizer = tkz.Toke
1710: 6e 69 7a 65 72 28 22 66 72 22 29 0a 20 20 20 20  nizer("fr").    
1720: 6f 54 46 20 3d 20 74 66 2e 54 65 78 74 46 6f 72  oTF = tf.TextFor
1730: 6d 61 74 74 65 72 28 29 0a 20 20 20 20 64 55 73  matter().    dUs
1740: 65 72 20 3d 20 7b 7d 0a 20 20 20 20 75 73 65 72  er = {}.    user
1750: 47 65 6e 65 72 61 74 6f 72 20 3d 20 67 65 6e 55  Generator = genU
1760: 73 65 72 49 64 28 29 0a 0a 20 20 20 20 61 70 70  serId()..    app
1770: 20 3d 20 42 6f 74 74 6c 65 28 29 0a 0a 20 20 20   = Bottle()..   
1780: 20 23 20 47 45 54 0a 20 20 20 20 40 61 70 70 2e   # GET.    @app.
1790: 72 6f 75 74 65 28 22 2f 22 29 0a 20 20 20 20 64  route("/").    d
17a0: 65 66 20 6d 61 69 6e 50 61 67 65 20 28 29 3a 0a  ef mainPage ():.
17b0: 20 20 20 20 20 20 20 20 69 66 20 64 53 65 72 76          if dServ
17c0: 65 72 4f 70 74 69 6f 6e 73 2e 67 65 74 28 22 74  erOptions.get("t
17d0: 65 73 74 70 61 67 65 22 2c 20 46 61 6c 73 65 29  estpage", False)
17e0: 20 3d 3d 20 22 54 72 75 65 22 3a 0a 20 20 20 20   == "True":.    
17f0: 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 48          return H
1800: 4f 4d 45 50 41 47 45 0a 20 20 20 20 20 20 20 20  OMEPAGE.        
1810: 20 20 20 20 23 72 65 74 75 72 6e 20 74 65 6d 70      #return temp
1820: 6c 61 74 65 28 22 6d 61 69 6e 22 2c 20 7b 7d 29  late("main", {})
1830: 0a 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20  .        return 
1840: 53 41 44 4c 49 46 45 4f 46 41 4d 41 43 48 49 4e  SADLIFEOFAMACHIN
1850: 45 0a 0a 20 20 20 20 40 61 70 70 2e 72 6f 75 74  E..    @app.rout
1860: 65 28 22 2f 67 65 74 5f 6f 70 74 69 6f 6e 73 2f  e("/get_options/
1870: 66 72 22 29 0a 20 20 20 20 64 65 66 20 6c 69 73  fr").    def lis
1880: 74 4f 70 74 69 6f 6e 73 20 28 29 3a 0a 20 20 20  tOptions ():.   
1890: 20 20 20 20 20 73 55 73 65 72 49 64 20 3d 20 72       sUserId = r
18a0: 65 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75  equest.cookies.u
18b0: 73 65 72 5f 69 64 0a 20 20 20 20 20 20 20 20 64  ser_id.        d
18c0: 4f 70 74 69 6f 6e 73 20 3d 20 64 55 73 65 72 5b  Options = dUser[
18d0: 73 55 73 65 72 49 64 5d 5b 22 67 63 5f 6f 70 74  sUserId]["gc_opt
18e0: 69 6f 6e 73 22 5d 20 20 69 66 20 73 55 73 65 72  ions"]  if sUser
18f0: 49 64 20 61 6e 64 20 73 55 73 65 72 49 64 20 69  Id and sUserId i
1900: 6e 20 64 55 73 65 72 20 20 65 6c 73 65 20 64 53  n dUser  else dS
1910: 65 72 76 65 72 47 43 4f 70 74 69 6f 6e 73 0a 20  erverGCOptions. 
1920: 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 27 7b         return '{
1930: 20 22 76 61 6c 75 65 73 22 3a 20 27 20 2b 20 6a   "values": ' + j
1940: 73 6f 6e 2e 64 75 6d 70 73 28 64 4f 70 74 69 6f  son.dumps(dOptio
1950: 6e 73 29 20 2b 20 27 2c 20 22 6c 61 62 65 6c 73  ns) + ', "labels
1960: 22 3a 20 27 20 2b 20 6a 73 6f 6e 2e 64 75 6d 70  ": ' + json.dump
1970: 73 28 67 63 65 2e 67 65 74 4f 70 74 69 6f 6e 73  s(gce.getOptions
1980: 4c 61 62 65 6c 73 28 22 66 72 22 29 2c 20 65 6e  Labels("fr"), en
1990: 73 75 72 65 5f 61 73 63 69 69 3d 46 61 6c 73 65  sure_ascii=False
19a0: 29 20 2b 20 27 20 7d 27 0a 0a 0a 20 20 20 20 23  ) + ' }'...    #
19b0: 20 50 4f 53 54 0a 20 20 20 20 40 61 70 70 2e 72   POST.    @app.r
19c0: 6f 75 74 65 28 22 2f 67 63 5f 74 65 78 74 2f 66  oute("/gc_text/f
19d0: 72 22 2c 20 6d 65 74 68 6f 64 3d 22 50 4f 53 54  r", method="POST
19e0: 22 29 0a 20 20 20 20 64 65 66 20 67 63 54 65 78  ").    def gcTex
19f0: 74 20 28 29 3a 0a 20 20 20 20 20 20 20 20 23 69  t ():.        #i
1a00: 66 20 6c 65 6e 28 6c 61 6e 67 29 20 21 3d 20 32  f len(lang) != 2
1a10: 20 6f 72 20 6c 61 6e 67 20 21 3d 20 22 66 72 22   or lang != "fr"
1a20: 3a 0a 20 20 20 20 20 20 20 20 23 20 20 20 20 61  :.        #    a
1a30: 62 6f 72 74 28 34 30 34 2c 20 22 4e 6f 20 67 72  bort(404, "No gr
1a40: 61 6d 6d 61 72 20 63 68 65 63 6b 65 72 20 61 76  ammar checker av
1a50: 61 69 6c 61 62 6c 65 20 66 6f 72 20 6c 61 6e 67  ailable for lang
1a60: 20 e2 80 9c 22 20 2b 20 73 74 72 28 6c 61 6e 67   ..." + str(lang
1a70: 29 20 2b 20 22 e2 80 9d 22 29 0a 20 20 20 20 20  ) + "...").     
1a80: 20 20 20 62 43 6f 6d 6d 61 20 3d 20 46 61 6c 73     bComma = Fals
1a90: 65 0a 20 20 20 20 20 20 20 20 62 54 46 20 3d 20  e.        bTF = 
1aa0: 62 6f 6f 6c 28 72 65 71 75 65 73 74 2e 66 6f 72  bool(request.for
1ab0: 6d 73 2e 74 66 29 0a 20 20 20 20 20 20 20 20 64  ms.tf).        d
1ac0: 4f 70 74 69 6f 6e 73 20 3d 20 4e 6f 6e 65 0a 20  Options = None. 
1ad0: 20 20 20 20 20 20 20 73 45 72 72 6f 72 20 3d 20         sError = 
1ae0: 22 22 0a 20 20 20 20 20 20 20 20 69 66 20 72 65  "".        if re
1af0: 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73  quest.cookies.us
1b00: 65 72 5f 69 64 3a 0a 20 20 20 20 20 20 20 20 20  er_id:.         
1b10: 20 20 20 69 66 20 72 65 71 75 65 73 74 2e 63 6f     if request.co
1b20: 6f 6b 69 65 73 2e 75 73 65 72 5f 69 64 20 69 6e  okies.user_id in
1b30: 20 64 55 73 65 72 3a 0a 20 20 20 20 20 20 20 20   dUser:.        
1b40: 20 20 20 20 20 20 20 20 64 4f 70 74 69 6f 6e 73          dOptions
1b50: 20 3d 20 64 55 73 65 72 5b 72 65 71 75 65 73 74   = dUser[request
1b60: 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72 5f 69 64  .cookies.user_id
1b70: 5d 2e 67 65 74 28 22 67 63 5f 6f 70 74 69 6f 6e  ].get("gc_option
1b80: 73 22 2c 20 4e 6f 6e 65 29 0a 20 20 20 20 20 20  s", None).      
1b90: 20 20 20 20 20 20 20 20 20 20 72 65 73 70 6f 6e            respon
1ba0: 73 65 2e 73 65 74 5f 63 6f 6f 6b 69 65 28 22 75  se.set_cookie("u
1bb0: 73 65 72 5f 69 64 22 2c 20 72 65 71 75 65 73 74  ser_id", request
1bc0: 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72 5f 69 64  .cookies.user_id
1bd0: 2c 20 70 61 74 68 3d 22 2f 22 2c 20 6d 61 78 5f  , path="/", max_
1be0: 61 67 65 3d 38 36 34 30 30 29 20 23 20 77 65 20  age=86400) # we 
1bf0: 72 65 6e 65 77 20 63 6f 6f 6b 69 65 20 66 6f 72  renew cookie for
1c00: 20 32 34 68 0a 20 20 20 20 20 20 20 20 20 20 20   24h.           
1c10: 20 65 6c 73 65 3a 0a 20 20 20 20 20 20 20 20 20   else:.         
1c20: 20 20 20 20 20 20 20 72 65 73 70 6f 6e 73 65 2e         response.
1c30: 64 65 6c 65 74 65 5f 63 6f 6f 6b 69 65 28 22 75  delete_cookie("u
1c40: 73 65 72 5f 69 64 22 2c 20 70 61 74 68 3d 22 2f  ser_id", path="/
1c50: 22 29 0a 20 20 20 20 20 20 20 20 69 66 20 72 65  ").        if re
1c60: 71 75 65 73 74 2e 66 6f 72 6d 73 2e 6f 70 74 69  quest.forms.opti
1c70: 6f 6e 73 3a 0a 20 20 20 20 20 20 20 20 20 20 20  ons:.           
1c80: 20 74 72 79 3a 0a 20 20 20 20 20 20 20 20 20 20   try:.          
1c90: 20 20 20 20 20 20 64 4f 70 74 69 6f 6e 73 20 3d        dOptions =
1ca0: 20 64 69 63 74 28 64 53 65 72 76 65 72 47 43 4f   dict(dServerGCO
1cb0: 70 74 69 6f 6e 73 29 20 20 69 66 20 6e 6f 74 20  ptions)  if not 
1cc0: 64 4f 70 74 69 6f 6e 73 20 20 65 6c 73 65 20 64  dOptions  else d
1cd0: 69 63 74 28 64 4f 70 74 69 6f 6e 73 29 0a 20 20  ict(dOptions).  
1ce0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 64 4f                dO
1cf0: 70 74 69 6f 6e 73 2e 75 70 64 61 74 65 28 6a 73  ptions.update(js
1d00: 6f 6e 2e 6c 6f 61 64 73 28 72 65 71 75 65 73 74  on.loads(request
1d10: 2e 66 6f 72 6d 73 2e 6f 70 74 69 6f 6e 73 29 29  .forms.options))
1d20: 0a 20 20 20 20 20 20 20 20 20 20 20 20 65 78 63  .            exc
1d30: 65 70 74 3a 0a 20 20 20 20 20 20 20 20 20 20 20  ept:.           
1d40: 20 20 20 20 20 73 45 72 72 6f 72 20 3d 20 22 72       sError = "r
1d50: 65 71 75 65 73 74 20 6f 70 74 69 6f 6e 73 20 6e  equest options n
1d60: 6f 74 20 75 73 65 64 22 0a 20 20 20 20 20 20 20  ot used".       
1d70: 20 73 4a 53 4f 4e 20 3d 20 27 7b 20 22 70 72 6f   sJSON = '{ "pro
1d80: 67 72 61 6d 22 3a 20 22 67 72 61 6d 6d 61 6c 65  gram": "grammale
1d90: 63 74 65 2d 66 72 22 2c 20 22 76 65 72 73 69 6f  cte-fr", "versio
1da0: 6e 22 3a 20 22 27 2b 67 63 65 2e 76 65 72 73 69  n": "'+gce.versi
1db0: 6f 6e 2b 27 22 2c 20 22 6c 61 6e 67 22 3a 20 22  on+'", "lang": "
1dc0: 27 2b 67 63 65 2e 6c 61 6e 67 2b 27 22 2c 20 22  '+gce.lang+'", "
1dd0: 65 72 72 6f 72 22 3a 20 22 27 2b 73 45 72 72 6f  error": "'+sErro
1de0: 72 2b 27 22 2c 20 22 64 61 74 61 22 20 3a 20 5b  r+'", "data" : [
1df0: 5c 6e 27 0a 20 20 20 20 20 20 20 20 66 6f 72 20  \n'.        for 
1e00: 69 2c 20 73 54 65 78 74 20 69 6e 20 65 6e 75 6d  i, sText in enum
1e10: 65 72 61 74 65 28 74 78 74 2e 67 65 74 50 61 72  erate(txt.getPar
1e20: 61 67 72 61 70 68 28 72 65 71 75 65 73 74 2e 66  agraph(request.f
1e30: 6f 72 6d 73 2e 74 65 78 74 29 2c 20 31 29 3a 0a  orms.text), 1):.
1e40: 20 20 20 20 20 20 20 20 20 20 20 20 69 66 20 62              if b
1e50: 54 46 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  TF:.            
1e60: 20 20 20 20 73 54 65 78 74 20 3d 20 6f 54 46 2e      sText = oTF.
1e70: 66 6f 72 6d 61 74 54 65 78 74 28 73 54 65 78 74  formatText(sText
1e80: 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 73 54  ).            sT
1e90: 65 78 74 20 3d 20 70 61 72 73 65 50 61 72 61 67  ext = parseParag
1ea0: 72 61 70 68 28 69 2c 20 73 54 65 78 74 2c 20 6f  raph(i, sText, o
1eb0: 54 6f 6b 65 6e 69 7a 65 72 2c 20 6f 44 69 63 74  Tokenizer, oDict
1ec0: 2c 20 64 4f 70 74 69 6f 6e 73 2c 20 62 45 6d 70  , dOptions, bEmp
1ed0: 74 79 49 66 4e 6f 45 72 72 6f 72 73 3d 54 72 75  tyIfNoErrors=Tru
1ee0: 65 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 69  e).            i
1ef0: 66 20 73 54 65 78 74 3a 0a 20 20 20 20 20 20 20  f sText:.       
1f00: 20 20 20 20 20 20 20 20 20 69 66 20 62 43 6f 6d           if bCom
1f10: 6d 61 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  ma:.            
1f20: 20 20 20 20 20 20 20 20 73 4a 53 4f 4e 20 2b 3d          sJSON +=
1f30: 20 22 2c 5c 6e 22 0a 20 20 20 20 20 20 20 20 20   ",\n".         
1f40: 20 20 20 20 20 20 20 73 4a 53 4f 4e 20 2b 3d 20         sJSON += 
1f50: 73 54 65 78 74 0a 20 20 20 20 20 20 20 20 20 20  sText.          
1f60: 20 20 20 20 20 20 62 43 6f 6d 6d 61 20 3d 20 54        bComma = T
1f70: 72 75 65 0a 20 20 20 20 20 20 20 20 73 4a 53 4f  rue.        sJSO
1f80: 4e 20 2b 3d 20 22 5c 6e 5d 7d 5c 6e 22 0a 20 20  N += "\n]}\n".  
1f90: 20 20 20 20 20 20 72 65 74 75 72 6e 20 73 4a 53        return sJS
1fa0: 4f 4e 0a 0a 20 20 20 20 40 61 70 70 2e 72 6f 75  ON..    @app.rou
1fb0: 74 65 28 22 2f 73 65 74 5f 6f 70 74 69 6f 6e 73  te("/set_options
1fc0: 2f 66 72 22 2c 20 6d 65 74 68 6f 64 3d 22 50 4f  /fr", method="PO
1fd0: 53 54 22 29 0a 20 20 20 20 64 65 66 20 73 65 74  ST").    def set
1fe0: 4f 70 74 69 6f 6e 73 20 28 29 3a 0a 20 20 20 20  Options ():.    
1ff0: 20 20 20 20 69 66 20 72 65 71 75 65 73 74 2e 66      if request.f
2000: 6f 72 6d 73 2e 6f 70 74 69 6f 6e 73 3a 0a 20 20  orms.options:.  
2010: 20 20 20 20 20 20 20 20 20 20 73 55 73 65 72 49            sUserI
2020: 64 20 3d 20 72 65 71 75 65 73 74 2e 63 6f 6f 6b  d = request.cook
2030: 69 65 73 2e 75 73 65 72 5f 69 64 20 20 69 66 20  ies.user_id  if 
2040: 72 65 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e  request.cookies.
2050: 75 73 65 72 5f 69 64 20 20 65 6c 73 65 20 6e 65  user_id  else ne
2060: 78 74 28 75 73 65 72 47 65 6e 65 72 61 74 6f 72  xt(userGenerator
2070: 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 64 4f  ).            dO
2080: 70 74 69 6f 6e 73 20 3d 20 64 55 73 65 72 5b 73  ptions = dUser[s
2090: 55 73 65 72 49 64 5d 5b 22 67 63 5f 6f 70 74 69  UserId]["gc_opti
20a0: 6f 6e 73 22 5d 20 20 69 66 20 73 55 73 65 72 49  ons"]  if sUserI
20b0: 64 20 69 6e 20 64 55 73 65 72 20 20 65 6c 73 65  d in dUser  else
20c0: 20 64 69 63 74 28 64 53 65 72 76 65 72 47 43 4f   dict(dServerGCO
20d0: 70 74 69 6f 6e 73 29 0a 20 20 20 20 20 20 20 20  ptions).        
20e0: 20 20 20 20 74 72 79 3a 0a 20 20 20 20 20 20 20      try:.       
20f0: 20 20 20 20 20 20 20 20 20 64 4f 70 74 69 6f 6e           dOption
2100: 73 2e 75 70 64 61 74 65 28 6a 73 6f 6e 2e 6c 6f  s.update(json.lo
2110: 61 64 73 28 72 65 71 75 65 73 74 2e 66 6f 72 6d  ads(request.form
2120: 73 2e 6f 70 74 69 6f 6e 73 29 29 0a 20 20 20 20  s.options)).    
2130: 20 20 20 20 20 20 20 20 20 20 20 20 64 55 73 65              dUse
2140: 72 5b 73 55 73 65 72 49 64 5d 20 3d 20 7b 20 22  r[sUserId] = { "
2150: 74 69 6d 65 22 3a 20 69 6e 74 28 74 69 6d 65 2e  time": int(time.
2160: 74 69 6d 65 28 29 29 2c 20 22 67 63 5f 6f 70 74  time()), "gc_opt
2170: 69 6f 6e 73 22 3a 20 64 4f 70 74 69 6f 6e 73 20  ions": dOptions 
2180: 7d 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  }.              
2190: 20 20 72 65 73 70 6f 6e 73 65 2e 73 65 74 5f 63    response.set_c
21a0: 6f 6f 6b 69 65 28 22 75 73 65 72 5f 69 64 22 2c  ookie("user_id",
21b0: 20 73 55 73 65 72 49 64 2c 20 70 61 74 68 3d 22   sUserId, path="
21c0: 2f 22 2c 20 6d 61 78 5f 61 67 65 3d 38 36 34 30  /", max_age=8640
21d0: 30 29 20 23 20 32 34 68 0a 20 20 20 20 20 20 20  0) # 24h.       
21e0: 20 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20           return 
21f0: 6a 73 6f 6e 2e 64 75 6d 70 73 28 64 55 73 65 72  json.dumps(dUser
2200: 5b 73 55 73 65 72 49 64 5d 5b 22 67 63 5f 6f 70  [sUserId]["gc_op
2210: 74 69 6f 6e 73 22 5d 29 0a 20 20 20 20 20 20 20  tions"]).       
2220: 20 20 20 20 20 65 78 63 65 70 74 3a 0a 20 20 20       except:.   
2230: 20 20 20 20 20 20 20 20 20 20 20 20 20 74 72 61               tra
2240: 63 65 62 61 63 6b 2e 70 72 69 6e 74 5f 65 78 63  ceback.print_exc
2250: 28 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 20  ().             
2260: 20 20 20 72 65 74 75 72 6e 20 27 7b 22 65 72 72     return '{"err
2270: 6f 72 22 3a 20 22 6f 70 74 69 6f 6e 73 20 6e 6f  or": "options no
2280: 74 20 72 65 67 69 73 74 65 72 65 64 22 7d 27 0a  t registered"}'.
2290: 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 27          return '
22a0: 7b 22 65 72 72 6f 72 22 3a 20 22 6e 6f 20 6f 70  {"error": "no op
22b0: 74 69 6f 6e 73 20 72 65 63 65 69 76 65 64 22 7d  tions received"}
22c0: 27 0a 0a 20 20 20 20 40 61 70 70 2e 72 6f 75 74  '..    @app.rout
22d0: 65 28 22 2f 72 65 73 65 74 5f 6f 70 74 69 6f 6e  e("/reset_option
22e0: 73 2f 66 72 22 2c 20 6d 65 74 68 6f 64 3d 22 50  s/fr", method="P
22f0: 4f 53 54 22 29 0a 20 20 20 20 64 65 66 20 72 65  OST").    def re
2300: 73 65 74 4f 70 74 69 6f 6e 73 20 28 29 3a 0a 20  setOptions ():. 
2310: 20 20 20 20 20 20 20 69 66 20 72 65 71 75 65 73         if reques
2320: 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72 5f 69  t.cookies.user_i
2330: 64 20 61 6e 64 20 72 65 71 75 65 73 74 2e 63 6f  d and request.co
2340: 6f 6b 69 65 73 2e 75 73 65 72 5f 69 64 20 69 6e  okies.user_id in
2350: 20 64 55 73 65 72 3a 0a 20 20 20 20 20 20 20 20   dUser:.        
2360: 20 20 20 20 64 65 6c 20 64 55 73 65 72 5b 72 65      del dUser[re
2370: 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73  quest.cookies.us
2380: 65 72 5f 69 64 5d 0a 20 20 20 20 20 20 20 20 72  er_id].        r
2390: 65 74 75 72 6e 20 22 64 6f 6e 65 22 0a 0a 20 20  eturn "done"..  
23a0: 20 20 40 61 70 70 2e 72 6f 75 74 65 28 22 2f 66    @app.route("/f
23b0: 6f 72 6d 61 74 5f 74 65 78 74 2f 66 72 22 2c 20  ormat_text/fr", 
23c0: 6d 65 74 68 6f 64 3d 22 50 4f 53 54 22 29 0a 20  method="POST"). 
23d0: 20 20 20 64 65 66 20 66 6f 72 6d 61 74 54 65 78     def formatTex
23e0: 74 20 28 29 3a 0a 20 20 20 20 20 20 20 20 72 65  t ():.        re
23f0: 74 75 72 6e 20 6f 54 46 2e 66 6f 72 6d 61 74 54  turn oTF.formatT
2400: 65 78 74 28 72 65 71 75 65 73 74 2e 66 6f 72 6d  ext(request.form
2410: 73 2e 74 65 78 74 29 0a 0a 20 20 20 20 23 40 61  s.text)..    #@a
2420: 70 70 2e 72 6f 75 74 65 28 27 2f 73 74 61 74 69  pp.route('/stati
2430: 63 2f 3c 66 69 6c 65 70 61 74 68 3a 70 61 74 68  c/<filepath:path
2440: 3e 27 29 0a 20 20 20 20 23 64 65 66 20 73 65 72  >').    #def ser
2450: 76 65 72 5f 73 74 61 74 69 63 20 28 66 69 6c 65  ver_static (file
2460: 70 61 74 68 29 3a 0a 20 20 20 20 23 20 20 20 20  path):.    #    
2470: 72 65 74 75 72 6e 20 73 74 61 74 69 63 5f 66 69  return static_fi
2480: 6c 65 28 66 69 6c 65 70 61 74 68 2c 20 72 6f 6f  le(filepath, roo
2490: 74 3d 27 2e 2f 76 69 65 77 73 2f 73 74 61 74 69  t='./views/stati
24a0: 63 27 29 0a 0a 20 20 20 20 40 61 70 70 2e 72 6f  c')..    @app.ro
24b0: 75 74 65 28 22 2f 70 75 72 67 65 5f 75 73 65 72  ute("/purge_user
24c0: 73 22 2c 20 6d 65 74 68 6f 64 3d 22 50 4f 53 54  s", method="POST
24d0: 22 29 0a 20 20 20 20 64 65 66 20 70 75 72 67 65  ").    def purge
24e0: 55 73 65 72 73 20 28 29 3a 0a 20 20 20 20 20 20  Users ():.      
24f0: 20 20 22 64 65 6c 65 74 65 20 75 73 65 72 20 6f    "delete user o
2500: 70 74 69 6f 6e 73 20 6f 6c 64 65 72 20 74 68 61  ptions older tha
2510: 6e 20 6e 20 68 6f 75 72 73 22 0a 20 20 20 20 20  n n hours".     
2520: 20 20 20 69 66 20 6e 6f 74 20 72 65 71 75 65 73     if not reques
2530: 74 2e 66 6f 72 6d 73 2e 70 61 73 73 77 6f 72 64  t.forms.password
2540: 20 6f 72 20 22 70 61 73 73 77 6f 72 64 22 20 6e   or "password" n
2550: 6f 74 20 69 6e 20 64 53 65 72 76 65 72 4f 70 74  ot in dServerOpt
2560: 69 6f 6e 73 20 6f 72 20 6e 6f 74 20 72 65 71 75  ions or not requ
2570: 65 73 74 2e 66 6f 72 6d 73 2e 68 6f 75 72 73 3a  est.forms.hours:
2580: 0a 20 20 20 20 20 20 20 20 20 20 20 20 72 65 74  .            ret
2590: 75 72 6e 20 22 77 68 61 74 3f 22 0a 20 20 20 20  urn "what?".    
25a0: 20 20 20 20 74 72 79 3a 0a 20 20 20 20 20 20 20      try:.       
25b0: 20 20 20 20 20 69 66 20 72 65 71 75 65 73 74 2e       if request.
25c0: 66 6f 72 6d 73 2e 70 61 73 73 77 6f 72 64 20 3d  forms.password =
25d0: 3d 20 64 53 65 72 76 65 72 4f 70 74 69 6f 6e 73  = dServerOptions
25e0: 5b 22 70 61 73 73 77 6f 72 64 22 5d 3a 0a 20 20  ["password"]:.  
25f0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 6e 4e                nN
2600: 6f 77 4d 69 6e 75 73 4e 48 6f 75 72 73 20 3d 20  owMinusNHours = 
2610: 69 6e 74 28 74 69 6d 65 2e 74 69 6d 65 28 29 29  int(time.time())
2620: 20 2d 20 28 69 6e 74 28 72 65 71 75 65 73 74 2e   - (int(request.
2630: 66 6f 72 6d 73 2e 68 6f 75 72 73 29 20 2a 20 36  forms.hours) * 6
2640: 30 20 2a 20 36 30 29 0a 20 20 20 20 20 20 20 20  0 * 60).        
2650: 20 20 20 20 20 20 20 20 66 6f 72 20 6e 55 73 65          for nUse
2660: 72 49 64 2c 20 64 56 61 6c 75 65 20 69 6e 20 64  rId, dValue in d
2670: 55 73 65 72 2e 69 74 65 6d 73 28 29 3a 0a 20 20  User.items():.  
2680: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
2690: 20 20 69 66 20 64 56 61 6c 75 65 5b 22 74 69 6d    if dValue["tim
26a0: 65 22 5d 20 3c 20 6e 4e 6f 77 4d 69 6e 75 73 4e  e"] < nNowMinusN
26b0: 48 6f 75 72 73 3a 0a 20 20 20 20 20 20 20 20 20  Hours:.         
26c0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 64                 d
26d0: 65 6c 20 64 55 73 65 72 5b 6e 55 73 65 72 49 64  el dUser[nUserId
26e0: 5d 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  ].              
26f0: 20 20 72 65 74 75 72 6e 20 22 64 6f 6e 65 22 0a    return "done".
2700: 20 20 20 20 20 20 20 20 20 20 20 20 65 6c 73 65              else
2710: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  :.              
2720: 20 20 72 65 74 75 72 6e 20 22 6e 6f 22 0a 20 20    return "no".  
2730: 20 20 20 20 20 20 65 78 63 65 70 74 3a 0a 20 20        except:.  
2740: 20 20 20 20 20 20 20 20 20 20 74 72 61 63 65 62            traceb
2750: 61 63 6b 2e 70 72 69 6e 74 5f 65 78 63 28 29 0a  ack.print_exc().
2760: 20 20 20 20 20 20 20 20 20 20 20 20 72 65 74 75              retu
2770: 72 6e 20 22 65 72 72 6f 72 22 0a 0a 20 20 20 20  rn "error"..    
2780: 23 20 45 52 52 4f 52 0a 20 20 20 20 40 61 70 70  # ERROR.    @app
2790: 2e 65 72 72 6f 72 28 34 30 34 29 0a 20 20 20 20  .error(404).    
27a0: 64 65 66 20 65 72 72 6f 72 34 30 34 20 28 65 72  def error404 (er
27b0: 72 6f 72 29 3a 0a 20 20 20 20 20 20 20 20 72 65  ror):.        re
27c0: 74 75 72 6e 20 27 45 72 72 6f 72 20 34 30 34 2e  turn 'Error 404.
27d0: 3c 62 72 2f 3e 27 20 2b 20 73 74 72 28 65 72 72  <br/>' + str(err
27e0: 6f 72 29 0a 0a 20 20 20 20 72 75 6e 28 61 70 70  or)..    run(app
27f0: 2c 20 5c 0a 20 20 20 20 20 20 20 20 68 6f 73 74  , \.        host
2800: 3d 64 53 65 72 76 65 72 4f 70 74 69 6f 6e 73 2e  =dServerOptions.
2810: 67 65 74 28 27 68 6f 73 74 27 2c 20 27 6c 6f 63  get('host', 'loc
2820: 61 6c 68 6f 73 74 27 29 2c 20 5c 0a 20 20 20 20  alhost'), \.    
2830: 20 20 20 20 70 6f 72 74 3d 69 6e 74 28 64 53 65      port=int(dSe
2840: 72 76 65 72 4f 70 74 69 6f 6e 73 2e 67 65 74 28  rverOptions.get(
2850: 27 70 6f 72 74 27 2c 20 38 30 38 30 29 29 29 0a  'port', 8080))).