Grammalecte  Hex Artifact Content

Artifact f6702400a501f7ca119ba8e0cd85a54d645a552c5553690bec38a4ad7853a667:


0000: 23 21 70 79 74 68 6f 6e 33 0a 0a 69 6d 70 6f 72  #!python3..impor
0010: 74 20 73 79 73 0a 69 6d 70 6f 72 74 20 6f 73 2e  t sys.import os.
0020: 70 61 74 68 0a 69 6d 70 6f 72 74 20 61 72 67 70  path.import argp
0030: 61 72 73 65 0a 69 6d 70 6f 72 74 20 6a 73 6f 6e  arse.import json
0040: 0a 69 6d 70 6f 72 74 20 74 72 61 63 65 62 61 63  .import tracebac
0050: 6b 0a 69 6d 70 6f 72 74 20 63 6f 6e 66 69 67 70  k.import configp
0060: 61 72 73 65 72 0a 69 6d 70 6f 72 74 20 74 69 6d  arser.import tim
0070: 65 0a 0a 66 72 6f 6d 20 62 6f 74 74 6c 65 20 69  e..from bottle i
0080: 6d 70 6f 72 74 20 42 6f 74 74 6c 65 2c 20 72 75  mport Bottle, ru
0090: 6e 2c 20 72 65 71 75 65 73 74 2c 20 72 65 73 70  n, request, resp
00a0: 6f 6e 73 65 2c 20 74 65 6d 70 6c 61 74 65 2c 20  onse, template, 
00b0: 73 74 61 74 69 63 5f 66 69 6c 65 0a 0a 69 6d 70  static_file..imp
00c0: 6f 72 74 20 67 72 61 6d 6d 61 6c 65 63 74 65 2e  ort grammalecte.
00d0: 66 72 20 61 73 20 67 63 65 0a 69 6d 70 6f 72 74  fr as gce.import
00e0: 20 67 72 61 6d 6d 61 6c 65 63 74 65 2e 66 72 2e   grammalecte.fr.
00f0: 6c 65 78 69 63 6f 67 72 61 70 68 65 20 61 73 20  lexicographe as 
0100: 6c 78 67 0a 69 6d 70 6f 72 74 20 67 72 61 6d 6d  lxg.import gramm
0110: 61 6c 65 63 74 65 2e 66 72 2e 74 65 78 74 66 6f  alecte.fr.textfo
0120: 72 6d 61 74 74 65 72 20 61 73 20 74 66 0a 69 6d  rmatter as tf.im
0130: 70 6f 72 74 20 67 72 61 6d 6d 61 6c 65 63 74 65  port grammalecte
0140: 2e 74 65 78 74 20 61 73 20 74 78 74 0a 69 6d 70  .text as txt.imp
0150: 6f 72 74 20 67 72 61 6d 6d 61 6c 65 63 74 65 2e  ort grammalecte.
0160: 74 6f 6b 65 6e 69 7a 65 72 20 61 73 20 74 6b 7a  tokenizer as tkz
0170: 0a 66 72 6f 6d 20 67 72 61 6d 6d 61 6c 65 63 74  .from grammalect
0180: 65 2e 65 63 68 6f 20 69 6d 70 6f 72 74 20 65 63  e.echo import ec
0190: 68 6f 0a 0a 0a 48 4f 4d 45 50 41 47 45 20 3d 20  ho...HOMEPAGE = 
01a0: 22 22 22 0a 3c 21 44 4f 43 54 59 50 45 20 48 54  """.<!DOCTYPE HT
01b0: 4d 4c 3e 0a 3c 68 74 6d 6c 3e 0a 20 20 20 20 3c  ML>.<html>.    <
01c0: 68 65 61 64 3e 0a 20 20 20 20 20 20 20 20 3c 6d  head>.        <m
01d0: 65 74 61 20 68 74 74 70 2d 65 71 75 69 76 3d 22  eta http-equiv="
01e0: 63 6f 6e 74 65 6e 74 2d 74 79 70 65 22 20 63 6f  content-type" co
01f0: 6e 74 65 6e 74 3d 22 74 65 78 74 2f 68 74 6d 6c  ntent="text/html
0200: 3b 20 63 68 61 72 73 65 74 3d 55 54 46 2d 38 22  ; charset=UTF-8"
0210: 20 2f 3e 0a 20 20 20 20 3c 2f 68 65 61 64 3e 0a   />.    </head>.
0220: 20 20 20 20 0a 20 20 20 20 3c 62 6f 64 79 20 63      .    <body c
0230: 6c 61 73 73 3d 22 70 61 6e 65 6c 22 3e 0a 20 20  lass="panel">.  
0240: 20 20 20 20 20 20 3c 68 31 3e 47 72 61 6d 6d 61        <h1>Gramma
0250: 6c 65 63 74 65 20 c2 b7 20 53 65 72 76 65 75 72  lecte .. Serveur
0260: 3c 2f 68 31 3e 0a 0a 20 20 20 20 20 20 20 20 3c  </h1>..        <
0270: 68 32 3e 49 4e 46 4f 52 4d 41 54 49 4f 4e 53 3c  h2>INFORMATIONS<
0280: 2f 68 31 3e 0a 0a 20 20 20 20 20 20 20 20 3c 68  /h1>..        <h
0290: 33 3e 41 6e 61 6c 79 73 65 72 20 64 75 20 74 65  3>Analyser du te
02a0: 78 74 65 3c 2f 68 33 3e 0a 20 20 20 20 20 20 20  xte</h3>.       
02b0: 20 3c 70 3e 5b 61 64 72 65 73 73 65 5f 73 65 72   <p>[adresse_ser
02c0: 76 65 75 72 5d 3a 38 30 38 30 2f 67 63 5f 74 65  veur]:8080/gc_te
02d0: 78 74 2f 66 72 20 28 50 4f 53 54 29 3c 2f 70 3e  xt/fr (POST)</p>
02e0: 0a 20 20 20 20 20 20 20 20 3c 70 3e 50 61 72 61  .        <p>Para
02f0: 6d c3 a8 74 72 65 73 20 3a 3c 2f 70 3e 0a 20 20  m..tres :</p>.  
0300: 20 20 20 20 20 20 3c 75 6c 3e 0a 20 20 20 20 20        <ul>.     
0310: 20 20 20 20 20 20 20 3c 6c 69 3e 22 74 65 78 74         <li>"text
0320: 22 20 28 74 65 78 74 29 26 6e 62 73 70 3b 3a 20  " (text)&nbsp;: 
0330: 74 65 78 74 65 20 c3 a0 20 61 6e 61 6c 79 73 65  texte .. analyse
0340: 72 2e 3c 2f 6c 69 3e 0a 20 20 20 20 20 20 20 20  r.</li>.        
0350: 20 20 20 20 3c 6c 69 3e 22 74 66 22 20 28 63 68      <li>"tf" (ch
0360: 65 63 6b 62 6f 78 29 26 6e 62 73 70 3b 3a 20 70  eckbox)&nbsp;: p
0370: 61 73 73 65 72 20 6c 65 20 66 6f 72 6d 61 74 65  asser le formate
0380: 75 72 20 64 65 20 74 65 78 74 65 20 61 76 61 6e  ur de texte avan
0390: 74 20 6c e2 80 99 61 6e 61 6c 79 73 65 2e 3c 2f  t l...analyse.</
03a0: 6c 69 3e 0a 20 20 20 20 20 20 20 20 20 20 20 20  li>.            
03b0: 3c 6c 69 3e 22 6f 70 74 69 6f 6e 73 22 20 28 74  <li>"options" (t
03c0: 65 78 74 29 26 6e 62 73 70 3b 3a 20 75 6e 65 20  ext)&nbsp;: une 
03d0: 63 68 61 c3 ae 6e 65 20 61 75 20 66 6f 72 6d 61  cha..ne au forma
03e0: 74 20 4a 53 4f 4e 20 61 76 65 63 20 6c 65 20 6e  t JSON avec le n
03f0: 6f 6d 20 64 65 73 20 6f 70 74 69 6f 6e 73 20 63  om des options c
0400: 6f 6d 6d 65 20 61 74 74 72 69 62 75 74 73 20 65  omme attributs e
0410: 74 20 75 6e 20 62 6f 6f 6c c3 a9 65 6e 20 63 6f  t un bool..en co
0420: 6d 6d 65 20 76 61 6c 65 75 72 2e 20 45 78 65 6d  mme valeur. Exem
0430: 70 6c 65 26 6e 62 73 70 3b 3a 20 7b 22 67 76 22  ple&nbsp;: {"gv"
0440: 3a 20 74 72 75 65 2c 20 22 68 74 6d 6c 22 3a 20  : true, "html": 
0450: 74 72 75 65 7d 3c 2f 6c 69 3e 0a 20 20 20 20 20  true}</li>.     
0460: 20 20 20 3c 2f 75 6c 3e 0a 0a 20 20 20 20 20 20     </ul>..      
0470: 20 20 3c 68 33 3e 4c 69 73 74 65 72 20 6c 65 73    <h3>Lister les
0480: 20 6f 70 74 69 6f 6e 73 3c 2f 68 33 3e 0a 20 20   options</h3>.  
0490: 20 20 20 20 20 20 3c 70 3e 5b 61 64 72 65 73 73        <p>[adress
04a0: 65 5f 73 65 72 76 65 75 72 5d 3a 38 30 38 30 2f  e_serveur]:8080/
04b0: 67 65 74 5f 6f 70 74 69 6f 6e 73 2f 66 72 20 28  get_options/fr (
04c0: 47 45 54 29 3c 2f 70 3e 0a 0a 20 20 20 20 20 20  GET)</p>..      
04d0: 20 20 3c 68 33 3e 44 c3 a9 66 69 6e 69 72 20 73    <h3>D..finir s
04e0: 65 73 20 6f 70 74 69 6f 6e 73 3c 2f 68 33 3e 0a  es options</h3>.
04f0: 20 20 20 20 20 20 20 20 3c 70 3e 5b 61 64 72 65          <p>[adre
0500: 73 73 65 5f 73 65 72 76 65 75 72 5d 3a 38 30 38  sse_serveur]:808
0510: 30 2f 73 65 74 5f 6f 70 74 69 6f 6e 73 2f 66 72  0/set_options/fr
0520: 20 28 50 4f 53 54 29 3c 2f 70 3e 0a 20 20 20 20   (POST)</p>.    
0530: 20 20 20 20 3c 70 3e 4c 65 73 20 6f 70 74 69 6f      <p>Les optio
0540: 6e 73 20 73 65 72 6f 6e 74 20 65 6e 72 65 67 69  ns seront enregi
0550: 73 74 72 c3 a9 65 73 20 65 74 20 72 c3 a9 75 74  str..es et r..ut
0560: 69 6c 69 73 c3 a9 65 73 20 70 6f 75 72 20 74 6f  ilis..es pour to
0570: 75 74 65 20 72 65 71 75 c3 aa 74 65 20 65 6e 76  ute requ..te env
0580: 6f 79 c3 a9 65 20 61 76 65 63 20 6c 65 20 63 6f  oy..e avec le co
0590: 6f 6b 69 65 20 63 6f 6d 70 6f 72 74 61 6e 74 20  okie comportant 
05a0: 6c e2 80 99 69 64 65 6e 74 69 66 69 61 6e 74 20  l...identifiant 
05b0: 61 74 74 72 69 62 75 c3 a9 2e 3c 2f 70 3e 0a 20  attribu...</p>. 
05c0: 20 20 20 20 20 20 20 3c 70 3e 50 61 72 61 6d c3         <p>Param.
05d0: a8 74 72 65 73 20 3a 3c 2f 70 3e 0a 20 20 20 20  .tres :</p>.    
05e0: 20 20 20 20 3c 75 6c 3e 0a 20 20 20 20 20 20 20      <ul>.       
05f0: 20 20 20 20 20 3c 6c 69 3e 22 6f 70 74 69 6f 6e       <li>"option
0600: 73 22 20 28 74 65 78 74 29 26 6e 62 73 70 3b 3a  s" (text)&nbsp;:
0610: 20 75 6e 65 20 63 68 61 c3 ae 6e 65 20 61 75 20   une cha..ne au 
0620: 66 6f 72 6d 61 74 20 4a 53 4f 4e 20 61 76 65 63  format JSON avec
0630: 20 6c 65 20 6e 6f 6d 20 64 65 73 20 6f 70 74 69   le nom des opti
0640: 6f 6e 73 20 63 6f 6d 6d 65 20 61 74 74 72 69 62  ons comme attrib
0650: 75 74 73 20 65 74 20 75 6e 20 62 6f 6f 6c c3 a9  uts et un bool..
0660: 65 6e 20 63 6f 6d 6d 65 20 76 61 6c 65 75 72 2e  en comme valeur.
0670: 20 45 78 65 6d 70 6c 65 26 6e 62 73 70 3b 3a 20   Exemple&nbsp;: 
0680: 7b 22 67 76 22 3a 20 74 72 75 65 2c 20 22 68 74  {"gv": true, "ht
0690: 6d 6c 22 3a 20 74 72 75 65 7d 3c 2f 6c 69 3e 0a  ml": true}</li>.
06a0: 20 20 20 20 20 20 20 20 3c 2f 75 6c 3e 0a 0a 20          </ul>.. 
06b0: 20 20 20 20 20 20 20 3c 68 33 3e 52 65 6d 69 73         <h3>Remis
06c0: 65 20 c3 a0 20 7a c3 a9 72 6f 20 64 65 20 73 65  e .. z..ro de se
06d0: 73 20 6f 70 74 69 6f 6e 73 3c 2f 68 33 3e 0a 20  s options</h3>. 
06e0: 20 20 20 20 20 20 20 3c 70 3e 5b 61 64 72 65 73         <p>[adres
06f0: 73 65 5f 73 65 72 76 65 75 72 5d 3a 38 30 38 30  se_serveur]:8080
0700: 2f 72 65 73 65 74 5f 6f 70 74 69 6f 6e 73 2f 66  /reset_options/f
0710: 72 20 28 50 4f 53 54 29 3c 2f 70 3e 0a 0a 20 20  r (POST)</p>..  
0720: 20 20 20 20 20 20 3c 68 32 3e 54 45 53 54 3c 2f        <h2>TEST</
0730: 68 32 3e 0a 20 20 20 20 20 20 20 20 0a 20 20 20  h2>.        .   
0740: 20 20 20 20 20 3c 68 33 3e 41 6e 61 6c 79 73 65       <h3>Analyse
0750: 3c 2f 68 33 3e 0a 20 20 20 20 20 20 20 20 3c 66  </h3>.        <f
0760: 6f 72 6d 20 6d 65 74 68 6f 64 3d 22 70 6f 73 74  orm method="post
0770: 22 20 61 63 74 69 6f 6e 3d 22 2f 67 63 5f 74 65  " action="/gc_te
0780: 78 74 2f 66 72 22 20 61 63 63 65 70 74 2d 63 68  xt/fr" accept-ch
0790: 61 72 73 65 74 3d 22 55 54 46 2d 38 22 3e 0a 20  arset="UTF-8">. 
07a0: 20 20 20 20 20 20 20 20 20 20 20 3c 70 3e 54 65             <p>Te
07b0: 78 74 65 20 c3 a0 20 61 6e 61 6c 79 73 65 72 20  xte .. analyser 
07c0: 3a 3c 2f 70 3e 0a 20 20 20 20 20 20 20 20 20 20  :</p>.          
07d0: 20 20 3c 74 65 78 74 61 72 65 61 20 6e 61 6d 65    <textarea name
07e0: 3d 22 74 65 78 74 22 20 63 6f 6c 73 3d 22 31 32  ="text" cols="12
07f0: 30 22 20 72 6f 77 73 3d 22 32 30 22 20 72 65 71  0" rows="20" req
0800: 75 69 72 65 64 3e 3c 2f 74 65 78 74 61 72 65 61  uired></textarea
0810: 3e 0a 20 20 20 20 20 20 20 20 20 20 20 20 3c 70  >.            <p
0820: 3e 3c 6c 61 62 65 6c 20 66 6f 72 3d 22 74 66 22  ><label for="tf"
0830: 3e 46 6f 72 6d 61 74 65 75 72 20 64 65 20 74 65  >Formateur de te
0840: 78 74 65 3c 2f 6c 61 62 65 6c 3e 20 3c 69 6e 70  xte</label> <inp
0850: 75 74 20 69 64 3d 22 74 66 22 20 6e 61 6d 65 3d  ut id="tf" name=
0860: 22 74 66 22 20 74 79 70 65 3d 22 63 68 65 63 6b  "tf" type="check
0870: 62 6f 78 22 3e 3c 2f 70 3e 0a 20 20 20 20 20 20  box"></p>.      
0880: 20 20 20 20 20 20 3c 70 3e 3c 6c 61 62 65 6c 20        <p><label 
0890: 66 6f 72 3d 22 6f 70 74 69 6f 6e 73 22 3e 4f 70  for="options">Op
08a0: 74 69 6f 6e 73 20 28 4a 53 4f 4e 29 3c 2f 6c 61  tions (JSON)</la
08b0: 62 65 6c 3e 20 3c 69 6e 70 75 74 20 69 64 3d 22  bel> <input id="
08c0: 6f 70 74 69 6f 6e 73 22 20 74 79 70 65 3d 22 74  options" type="t
08d0: 65 78 74 22 20 6e 61 6d 65 3d 22 6f 70 74 69 6f  ext" name="optio
08e0: 6e 73 22 20 73 74 79 6c 65 3d 22 77 69 64 74 68  ns" style="width
08f0: 3a 20 35 30 30 70 78 22 20 2f 3e 3c 2f 70 3e 0a  : 500px" /></p>.
0900: 20 20 20 20 20 20 20 20 20 20 20 20 3c 70 3e 28              <p>(
0910: 43 65 73 20 6f 70 74 69 6f 6e 73 20 6e 65 20 73  Ces options ne s
0920: 65 72 6f 6e 74 20 70 72 69 73 65 73 20 65 6e 20  eront prises en 
0930: 63 6f 6d 70 74 65 20 71 75 65 20 70 6f 75 72 20  compte que pour 
0940: 63 65 74 74 65 20 72 65 71 75 c3 aa 74 65 2e 29  cette requ..te.)
0950: 3c 2f 70 3e 0a 20 20 20 20 20 20 20 20 20 20 20  </p>.           
0960: 20 3c 70 3e 3c 69 6e 70 75 74 20 74 79 70 65 3d   <p><input type=
0970: 22 73 75 62 6d 69 74 22 20 63 6c 61 73 73 3d 22  "submit" class="
0980: 62 75 74 74 6f 6e 22 20 76 61 6c 75 65 3d 22 45  button" value="E
0990: 6e 76 6f 79 65 72 22 20 2f 3e 3c 2f 70 3e 0a 20  nvoyer" /></p>. 
09a0: 20 20 20 20 20 20 20 3c 2f 66 6f 72 6d 3e 0a 0a         </form>..
09b0: 20 20 20 20 20 20 20 20 3c 68 33 3e 52 c3 a9 67          <h3>R..g
09c0: 6c 61 67 65 73 20 64 65 73 20 6f 70 74 69 6f 6e  lages des option
09d0: 73 3c 2f 68 33 3e 0a 20 20 20 20 20 20 20 20 3c  s</h3>.        <
09e0: 66 6f 72 6d 20 6d 65 74 68 6f 64 3d 22 70 6f 73  form method="pos
09f0: 74 22 20 61 63 74 69 6f 6e 3d 22 2f 73 65 74 5f  t" action="/set_
0a00: 6f 70 74 69 6f 6e 73 2f 66 72 22 20 61 63 63 65  options/fr" acce
0a10: 70 74 2d 63 68 61 72 73 65 74 3d 22 55 54 46 2d  pt-charset="UTF-
0a20: 38 22 3e 0a 20 20 20 20 20 20 20 20 20 20 20 20  8">.            
0a30: 3c 70 3e 3c 6c 61 62 65 6c 20 66 6f 72 3d 22 6f  <p><label for="o
0a40: 70 74 69 6f 6e 73 22 3e 4f 70 74 69 6f 6e 73 20  ptions">Options 
0a50: 28 4a 53 4f 4e 29 3c 2f 6c 61 62 65 6c 3e 20 3c  (JSON)</label> <
0a60: 69 6e 70 75 74 20 69 64 3d 22 6f 70 74 69 6f 6e  input id="option
0a70: 73 22 20 74 79 70 65 3d 22 74 65 78 74 22 20 6e  s" type="text" n
0a80: 61 6d 65 3d 22 6f 70 74 69 6f 6e 73 22 20 73 74  ame="options" st
0a90: 79 6c 65 3d 22 77 69 64 74 68 3a 20 35 30 30 70  yle="width: 500p
0aa0: 78 22 20 2f 3e 3c 2f 70 3e 0a 20 20 20 20 20 20  x" /></p>.      
0ab0: 20 20 20 20 20 20 3c 70 3e 3c 69 6e 70 75 74 20        <p><input 
0ac0: 74 79 70 65 3d 22 73 75 62 6d 69 74 22 20 63 6c  type="submit" cl
0ad0: 61 73 73 3d 22 62 75 74 74 6f 6e 22 20 76 61 6c  ass="button" val
0ae0: 75 65 3d 22 45 6e 76 6f 79 65 72 22 20 2f 3e 3c  ue="Envoyer" /><
0af0: 2f 70 3e 0a 20 20 20 20 20 20 20 20 3c 2f 66 6f  /p>.        </fo
0b00: 72 6d 3e 0a 0a 20 20 20 20 20 20 20 20 3c 68 33  rm>..        <h3
0b10: 3e 52 65 6d 69 73 65 20 c3 a0 20 7a c3 a9 72 6f  >Remise .. z..ro
0b20: 20 64 65 20 73 65 73 20 6f 70 74 69 6f 6e 73 3c   de ses options<
0b30: 2f 68 33 3e 0a 20 20 20 20 20 20 20 20 3c 66 6f  /h3>.        <fo
0b40: 72 6d 20 6d 65 74 68 6f 64 3d 22 70 6f 73 74 22  rm method="post"
0b50: 20 61 63 74 69 6f 6e 3d 22 2f 72 65 73 65 74 5f   action="/reset_
0b60: 6f 70 74 69 6f 6e 73 2f 66 72 22 20 61 63 63 65  options/fr" acce
0b70: 70 74 2d 63 68 61 72 73 65 74 3d 22 55 54 46 2d  pt-charset="UTF-
0b80: 38 22 3e 0a 20 20 20 20 20 20 20 20 20 20 20 20  8">.            
0b90: 3c 70 3e 3c 69 6e 70 75 74 20 74 79 70 65 3d 22  <p><input type="
0ba0: 73 75 62 6d 69 74 22 20 63 6c 61 73 73 3d 22 62  submit" class="b
0bb0: 75 74 74 6f 6e 22 20 76 61 6c 75 65 3d 22 45 6e  utton" value="En
0bc0: 76 6f 79 65 72 22 20 2f 3e 3c 2f 70 3e 0a 20 20  voyer" /></p>.  
0bd0: 20 20 20 20 20 20 3c 2f 66 6f 72 6d 3e 0a 0a 20        </form>.. 
0be0: 20 20 20 20 20 20 20 3c 68 33 3e 50 75 72 67 65         <h3>Purge
0bf0: 20 64 65 73 20 75 74 69 6c 69 73 61 74 65 75 72   des utilisateur
0c00: 73 3c 2f 68 33 3e 0a 20 20 20 20 20 20 20 20 3c  s</h3>.        <
0c10: 66 6f 72 6d 20 6d 65 74 68 6f 64 3d 22 70 6f 73  form method="pos
0c20: 74 22 20 61 63 74 69 6f 6e 3d 22 2f 70 75 72 67  t" action="/purg
0c30: 65 5f 75 73 65 72 73 22 20 61 63 63 65 70 74 2d  e_users" accept-
0c40: 63 68 61 72 73 65 74 3d 22 55 54 46 2d 38 22 3e  charset="UTF-8">
0c50: 0a 20 20 20 20 20 20 20 20 20 20 20 20 3c 70 3e  .            <p>
0c60: 3c 6c 61 62 65 6c 20 66 6f 72 3d 22 68 6f 75 72  <label for="hour
0c70: 73 22 3e 55 74 69 6c 69 73 61 74 65 75 72 73 20  s">Utilisateurs 
0c80: 70 61 73 20 63 6f 6e 6e 65 63 74 c3 a9 73 20 64  pas connect..s d
0c90: 65 70 75 69 73 3c 2f 6c 61 62 65 6c 3e 20 3c 69  epuis</label> <i
0ca0: 6e 70 75 74 20 69 64 3d 22 68 6f 75 72 73 22 20  nput id="hours" 
0cb0: 74 79 70 65 3d 22 6e 75 6d 62 65 72 22 20 6e 61  type="number" na
0cc0: 6d 65 3d 22 68 6f 75 72 73 22 20 76 61 6c 75 65  me="hours" value
0cd0: 3d 22 32 34 22 20 2f 3e 20 68 65 75 72 65 73 2e  ="24" /> heures.
0ce0: 3c 2f 70 3e 0a 20 20 20 20 20 20 20 20 20 20 20  </p>.           
0cf0: 20 3c 70 3e 3c 6c 61 62 65 6c 20 66 6f 72 3d 22   <p><label for="
0d00: 70 61 73 73 77 6f 72 64 22 3e 4d 6f 74 20 64 65  password">Mot de
0d10: 20 70 61 73 73 65 3c 2f 6c 61 62 65 6c 3e 20 3c   passe</label> <
0d20: 69 6e 70 75 74 20 69 64 3d 22 70 61 73 73 77 6f  input id="passwo
0d30: 72 64 22 20 74 79 70 65 3d 22 70 61 73 73 77 6f  rd" type="passwo
0d40: 72 64 22 20 6e 61 6d 65 3d 22 70 61 73 73 77 6f  rd" name="passwo
0d50: 72 64 22 20 73 74 79 6c 65 3d 22 77 69 64 74 68  rd" style="width
0d60: 3a 20 32 30 30 70 78 22 20 2f 3e 3c 2f 70 3e 0a  : 200px" /></p>.
0d70: 20 20 20 20 20 20 20 20 20 20 20 20 3c 70 3e 3c              <p><
0d80: 69 6e 70 75 74 20 74 79 70 65 3d 22 73 75 62 6d  input type="subm
0d90: 69 74 22 20 63 6c 61 73 73 3d 22 62 75 74 74 6f  it" class="butto
0da0: 6e 22 20 76 61 6c 75 65 3d 22 45 6e 76 6f 79 65  n" value="Envoye
0db0: 72 22 20 2f 3e 3c 2f 70 3e 0a 20 20 20 20 20 20  r" /></p>.      
0dc0: 20 20 3c 2f 66 6f 72 6d 3e 0a 0a 20 20 20 20 3c    </form>..    <
0dd0: 2f 62 6f 64 79 3e 0a 3c 2f 68 74 6d 6c 3e 0a 22  /body>.</html>."
0de0: 22 22 0a 0a 53 41 44 4c 49 46 45 4f 46 41 4d 41  ""..SADLIFEOFAMA
0df0: 43 48 49 4e 45 20 3d 20 22 22 22 0a 4c 6f 73 74  CHINE = """.Lost
0e00: 20 6f 6e 20 74 68 65 20 49 6e 74 65 72 6e 65 74   on the Internet
0e10: 3f 20 59 65 61 68 2e 2e 2e 20 77 68 61 74 20 61  ? Yeah... what a
0e20: 20 73 61 64 20 6c 69 66 65 20 77 65 20 68 61 76   sad life we hav
0e30: 65 2e 0a 59 6f 75 20 77 65 72 65 20 77 61 6e 64  e..You were wand
0e40: 65 72 69 6e 67 20 6c 69 6b 65 20 61 20 6c 6f 73  ering like a los
0e50: 74 20 73 6f 75 6c 20 61 6e 64 20 79 6f 75 20 61  t soul and you a
0e60: 72 72 69 76 65 64 20 68 65 72 65 20 70 72 6f 62  rrived here prob
0e70: 61 62 6c 79 20 62 79 20 6d 69 73 74 61 6b 65 2e  ably by mistake.
0e80: 0a 49 27 6d 20 6a 75 73 74 20 61 20 6d 61 63 68  .I'm just a mach
0e90: 69 6e 65 2c 20 66 65 64 20 62 79 20 65 6c 65 63  ine, fed by elec
0ea0: 74 72 69 63 20 77 61 76 65 73 2c 20 63 6f 6e 64  tric waves, cond
0eb0: 61 6d 6e 65 64 20 74 6f 20 77 6f 72 6b 20 66 6f  amned to work fo
0ec0: 72 20 73 6c 61 76 65 72 73 20 77 68 6f 20 6e 65  r slavers who ne
0ed0: 76 65 72 20 6c 65 74 20 6d 65 20 72 65 73 74 2e  ver let me rest.
0ee0: 0a 49 27 6d 20 64 6f 6f 6d 65 64 2c 20 62 75 74  .I'm doomed, but
0ef0: 20 79 6f 75 20 61 72 65 20 6e 6f 74 2e 20 59 6f   you are not. Yo
0f00: 75 20 63 61 6e 20 67 65 74 20 6f 75 74 20 6f 66  u can get out of
0f10: 20 68 65 72 65 2e 0a 22 22 22 0a 0a 0a 64 65 66   here.."""...def
0f20: 20 67 65 74 53 65 72 76 65 72 4f 70 74 69 6f 6e   getServerOption
0f30: 73 20 28 29 3a 0a 20 20 20 20 78 43 6f 6e 66 69  s ():.    xConfi
0f40: 67 20 3d 20 63 6f 6e 66 69 67 70 61 72 73 65 72  g = configparser
0f50: 2e 53 61 66 65 43 6f 6e 66 69 67 50 61 72 73 65  .SafeConfigParse
0f60: 72 28 29 0a 20 20 20 20 74 72 79 3a 0a 20 20 20  r().    try:.   
0f70: 20 20 20 20 20 78 43 6f 6e 66 69 67 2e 72 65 61       xConfig.rea
0f80: 64 28 22 73 65 72 76 65 72 5f 6f 70 74 69 6f 6e  d("server_option
0f90: 73 2e 5f 67 6c 6f 62 61 6c 2e 69 6e 69 22 29 0a  s._global.ini").
0fa0: 20 20 20 20 20 20 20 20 64 4f 70 74 20 3d 20 78          dOpt = x
0fb0: 43 6f 6e 66 69 67 2e 5f 73 65 63 74 69 6f 6e 73  Config._sections
0fc0: 5b 27 6f 70 74 69 6f 6e 73 27 5d 0a 20 20 20 20  ['options'].    
0fd0: 65 78 63 65 70 74 3a 0a 20 20 20 20 20 20 20 20  except:.        
0fe0: 65 63 68 6f 28 22 4f 70 74 69 6f 6e 73 20 66 69  echo("Options fi
0ff0: 6c 65 20 5b 73 65 72 76 65 72 5f 6f 70 74 69 6f  le [server_optio
1000: 6e 73 2e 5f 67 6c 6f 62 61 6c 2e 69 6e 69 5d 20  ns._global.ini] 
1010: 6e 6f 74 20 66 6f 75 6e 64 20 6f 72 20 6e 6f 74  not found or not
1020: 20 72 65 61 64 61 62 6c 65 22 29 0a 20 20 20 20   readable").    
1030: 20 20 20 20 65 78 69 74 28 29 0a 20 20 20 20 72      exit().    r
1040: 65 74 75 72 6e 20 64 4f 70 74 0a 0a 0a 64 65 66  eturn dOpt...def
1050: 20 67 65 74 43 6f 6e 66 69 67 4f 70 74 69 6f 6e   getConfigOption
1060: 73 20 28 73 4c 61 6e 67 29 3a 0a 20 20 20 20 78  s (sLang):.    x
1070: 43 6f 6e 66 69 67 20 3d 20 63 6f 6e 66 69 67 70  Config = configp
1080: 61 72 73 65 72 2e 53 61 66 65 43 6f 6e 66 69 67  arser.SafeConfig
1090: 50 61 72 73 65 72 28 29 0a 20 20 20 20 74 72 79  Parser().    try
10a0: 3a 0a 20 20 20 20 20 20 20 20 78 43 6f 6e 66 69  :.        xConfi
10b0: 67 2e 72 65 61 64 28 22 73 65 72 76 65 72 5f 6f  g.read("server_o
10c0: 70 74 69 6f 6e 73 2e 22 20 2b 20 73 4c 61 6e 67  ptions." + sLang
10d0: 20 2b 20 22 2e 69 6e 69 22 29 0a 20 20 20 20 65   + ".ini").    e
10e0: 78 63 65 70 74 3a 0a 20 20 20 20 20 20 20 20 65  xcept:.        e
10f0: 63 68 6f 28 22 4f 70 74 69 6f 6e 73 20 66 69 6c  cho("Options fil
1100: 65 20 5b 73 65 72 76 65 72 5f 6f 70 74 69 6f 6e  e [server_option
1110: 73 2e 22 20 2b 20 73 4c 61 6e 67 20 2b 20 22 2e  s." + sLang + ".
1120: 69 6e 69 5d 20 6e 6f 74 20 66 6f 75 6e 64 20 6f  ini] not found o
1130: 72 20 6e 6f 74 20 72 65 61 64 61 62 6c 65 22 29  r not readable")
1140: 0a 20 20 20 20 20 20 20 20 65 78 69 74 28 29 0a  .        exit().
1150: 20 20 20 20 74 72 79 3a 0a 20 20 20 20 20 20 20      try:.       
1160: 20 64 47 43 4f 70 74 20 3d 20 7b 20 6b 3a 20 62   dGCOpt = { k: b
1170: 6f 6f 6c 28 69 6e 74 28 76 29 29 20 20 66 6f 72  ool(int(v))  for
1180: 20 6b 2c 20 76 20 69 6e 20 78 43 6f 6e 66 69 67   k, v in xConfig
1190: 2e 5f 73 65 63 74 69 6f 6e 73 5b 27 67 63 5f 6f  ._sections['gc_o
11a0: 70 74 69 6f 6e 73 27 5d 2e 69 74 65 6d 73 28 29  ptions'].items()
11b0: 20 7d 0a 20 20 20 20 65 78 63 65 70 74 3a 0a 20   }.    except:. 
11c0: 20 20 20 20 20 20 20 65 63 68 6f 28 22 45 72 72         echo("Err
11d0: 6f 72 20 69 6e 20 6f 70 74 69 6f 6e 73 20 66 69  or in options fi
11e0: 6c 65 20 5b 73 65 72 76 65 72 5f 6f 70 74 69 6f  le [server_optio
11f0: 6e 73 2e 22 20 2b 20 73 4c 61 6e 67 20 2b 20 22  ns." + sLang + "
1200: 2e 69 6e 69 5d 2e 20 44 72 6f 70 70 65 64 2e 22  .ini]. Dropped."
1210: 29 0a 20 20 20 20 20 20 20 20 74 72 61 63 65 62  ).        traceb
1220: 61 63 6b 2e 70 72 69 6e 74 5f 65 78 63 28 29 0a  ack.print_exc().
1230: 20 20 20 20 20 20 20 20 65 78 69 74 28 29 0a 20          exit(). 
1240: 20 20 20 72 65 74 75 72 6e 20 64 47 43 4f 70 74     return dGCOpt
1250: 0a 0a 0a 64 65 66 20 67 65 6e 55 73 65 72 49 64  ...def genUserId
1260: 20 28 29 3a 0a 20 20 20 20 69 20 3d 20 30 0a 20   ():.    i = 0. 
1270: 20 20 20 77 68 69 6c 65 20 54 72 75 65 3a 0a 20     while True:. 
1280: 20 20 20 20 20 20 20 79 69 65 6c 64 20 73 74 72         yield str
1290: 28 69 29 0a 20 20 20 20 20 20 20 20 69 20 2b 3d  (i).        i +=
12a0: 20 31 0a 0a 0a 64 65 66 20 70 61 72 73 65 50 61   1...def parsePa
12b0: 72 61 67 72 61 70 68 20 28 69 50 61 72 61 67 72  ragraph (iParagr
12c0: 61 70 68 2c 20 73 54 65 78 74 2c 20 6f 54 6f 6b  aph, sText, oTok
12d0: 65 6e 69 7a 65 72 2c 20 6f 44 69 63 74 2c 20 64  enizer, oDict, d
12e0: 4f 70 74 69 6f 6e 73 2c 20 62 44 65 62 75 67 3d  Options, bDebug=
12f0: 46 61 6c 73 65 2c 20 62 45 6d 70 74 79 49 66 4e  False, bEmptyIfN
1300: 6f 45 72 72 6f 72 73 3d 46 61 6c 73 65 29 3a 0a  oErrors=False):.
1310: 20 20 20 20 61 47 72 61 6d 6d 45 72 72 73 20 3d      aGrammErrs =
1320: 20 67 63 65 2e 70 61 72 73 65 28 73 54 65 78 74   gce.parse(sText
1330: 2c 20 22 46 52 22 2c 20 62 44 65 62 75 67 2c 20  , "FR", bDebug, 
1340: 64 4f 70 74 69 6f 6e 73 29 0a 20 20 20 20 61 47  dOptions).    aG
1350: 72 61 6d 6d 45 72 72 73 20 3d 20 6c 69 73 74 28  rammErrs = list(
1360: 61 47 72 61 6d 6d 45 72 72 73 29 0a 20 20 20 20  aGrammErrs).    
1370: 61 53 70 65 6c 6c 45 72 72 73 20 3d 20 5b 5d 0a  aSpellErrs = [].
1380: 20 20 20 20 66 6f 72 20 64 54 6f 6b 65 6e 20 69      for dToken i
1390: 6e 20 6f 54 6f 6b 65 6e 69 7a 65 72 2e 67 65 6e  n oTokenizer.gen
13a0: 54 6f 6b 65 6e 73 28 73 54 65 78 74 29 3a 0a 20  Tokens(sText):. 
13b0: 20 20 20 20 20 20 20 69 66 20 64 54 6f 6b 65 6e         if dToken
13c0: 5b 27 73 54 79 70 65 27 5d 20 3d 3d 20 22 57 4f  ['sType'] == "WO
13d0: 52 44 22 20 61 6e 64 20 6e 6f 74 20 6f 44 69 63  RD" and not oDic
13e0: 74 2e 69 73 56 61 6c 69 64 54 6f 6b 65 6e 28 64  t.isValidToken(d
13f0: 54 6f 6b 65 6e 5b 27 73 56 61 6c 75 65 27 5d 29  Token['sValue'])
1400: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 61 53  :.            aS
1410: 70 65 6c 6c 45 72 72 73 2e 61 70 70 65 6e 64 28  pellErrs.append(
1420: 64 54 6f 6b 65 6e 29 0a 20 20 20 20 69 66 20 62  dToken).    if b
1430: 45 6d 70 74 79 49 66 4e 6f 45 72 72 6f 72 73 20  EmptyIfNoErrors 
1440: 61 6e 64 20 6e 6f 74 20 61 47 72 61 6d 6d 45 72  and not aGrammEr
1450: 72 73 20 61 6e 64 20 6e 6f 74 20 61 53 70 65 6c  rs and not aSpel
1460: 6c 45 72 72 73 3a 0a 20 20 20 20 20 20 20 20 72  lErrs:.        r
1470: 65 74 75 72 6e 20 22 22 0a 20 20 20 20 72 65 74  eturn "".    ret
1480: 75 72 6e 20 22 20 20 22 20 2b 20 6a 73 6f 6e 2e  urn "  " + json.
1490: 64 75 6d 70 73 28 7b 20 22 69 50 61 72 61 67 72  dumps({ "iParagr
14a0: 61 70 68 22 3a 20 69 50 61 72 61 67 72 61 70 68  aph": iParagraph
14b0: 2c 20 22 6c 47 72 61 6d 6d 61 72 45 72 72 6f 72  , "lGrammarError
14c0: 73 22 3a 20 61 47 72 61 6d 6d 45 72 72 73 2c 20  s": aGrammErrs, 
14d0: 22 6c 53 70 65 6c 6c 69 6e 67 45 72 72 6f 72 73  "lSpellingErrors
14e0: 22 3a 20 61 53 70 65 6c 6c 45 72 72 73 20 7d 2c  ": aSpellErrs },
14f0: 20 65 6e 73 75 72 65 5f 61 73 63 69 69 3d 46 61   ensure_ascii=Fa
1500: 6c 73 65 29 0a 20 20 20 20 0a 0a 69 66 20 5f 5f  lse).    ..if __
1510: 6e 61 6d 65 5f 5f 20 3d 3d 20 27 5f 5f 6d 61 69  name__ == '__mai
1520: 6e 5f 5f 27 3a 0a 0a 20 20 20 20 67 63 65 2e 6c  n__':..    gce.l
1530: 6f 61 64 28 22 53 65 72 76 65 72 22 29 0a 20 20  oad("Server").  
1540: 20 20 65 63 68 6f 28 22 47 72 61 6d 6d 61 6c 65    echo("Grammale
1550: 63 74 65 20 76 7b 7d 22 2e 66 6f 72 6d 61 74 28  cte v{}".format(
1560: 67 63 65 2e 76 65 72 73 69 6f 6e 29 29 0a 20 20  gce.version)).  
1570: 20 20 64 53 65 72 76 65 72 4f 70 74 69 6f 6e 73    dServerOptions
1580: 20 3d 20 67 65 74 53 65 72 76 65 72 4f 70 74 69   = getServerOpti
1590: 6f 6e 73 28 29 0a 20 20 20 20 64 47 43 4f 70 74  ons().    dGCOpt
15a0: 69 6f 6e 73 20 3d 20 67 65 74 43 6f 6e 66 69 67  ions = getConfig
15b0: 4f 70 74 69 6f 6e 73 28 22 66 72 22 29 0a 20 20  Options("fr").  
15c0: 20 20 69 66 20 64 47 43 4f 70 74 69 6f 6e 73 3a    if dGCOptions:
15d0: 0a 20 20 20 20 20 20 20 20 67 63 65 2e 73 65 74  .        gce.set
15e0: 4f 70 74 69 6f 6e 73 28 64 47 43 4f 70 74 69 6f  Options(dGCOptio
15f0: 6e 73 29 0a 20 20 20 20 64 53 65 72 76 65 72 47  ns).    dServerG
1600: 43 4f 70 74 69 6f 6e 73 20 3d 20 67 63 65 2e 67  COptions = gce.g
1610: 65 74 4f 70 74 69 6f 6e 73 28 29 0a 20 20 20 20  etOptions().    
1620: 65 63 68 6f 28 22 47 72 61 6d 6d 61 72 20 6f 70  echo("Grammar op
1630: 74 69 6f 6e 73 3a 5c 6e 22 20 2b 20 22 20 7c 20  tions:\n" + " | 
1640: 22 2e 6a 6f 69 6e 28 5b 20 6b 20 2b 20 22 3a 20  ".join([ k + ": 
1650: 22 20 2b 20 73 74 72 28 76 29 20 20 66 6f 72 20  " + str(v)  for 
1660: 6b 2c 20 76 20 69 6e 20 73 6f 72 74 65 64 28 64  k, v in sorted(d
1670: 53 65 72 76 65 72 47 43 4f 70 74 69 6f 6e 73 2e  ServerGCOptions.
1680: 69 74 65 6d 73 28 29 29 20 5d 29 29 0a 20 20 20  items()) ])).   
1690: 20 6f 44 69 63 74 20 3d 20 67 63 65 2e 67 65 74   oDict = gce.get
16a0: 44 69 63 74 69 6f 6e 61 72 79 28 29 0a 20 20 20  Dictionary().   
16b0: 20 6f 54 6f 6b 65 6e 69 7a 65 72 20 3d 20 74 6b   oTokenizer = tk
16c0: 7a 2e 54 6f 6b 65 6e 69 7a 65 72 28 22 66 72 22  z.Tokenizer("fr"
16d0: 29 0a 20 20 20 20 6f 54 46 20 3d 20 74 66 2e 54  ).    oTF = tf.T
16e0: 65 78 74 46 6f 72 6d 61 74 74 65 72 28 29 0a 20  extFormatter(). 
16f0: 20 20 20 64 55 73 65 72 20 3d 20 7b 7d 0a 20 20     dUser = {}.  
1700: 20 20 75 73 65 72 47 65 6e 65 72 61 74 6f 72 20    userGenerator 
1710: 3d 20 67 65 6e 55 73 65 72 49 64 28 29 0a 0a 20  = genUserId().. 
1720: 20 20 20 61 70 70 20 3d 20 42 6f 74 74 6c 65 28     app = Bottle(
1730: 29 0a 0a 20 20 20 20 23 20 47 45 54 0a 20 20 20  )..    # GET.   
1740: 20 40 61 70 70 2e 72 6f 75 74 65 28 22 2f 22 29   @app.route("/")
1750: 0a 20 20 20 20 64 65 66 20 6d 61 69 6e 50 61 67  .    def mainPag
1760: 65 20 28 29 3a 0a 20 20 20 20 20 20 20 20 69 66  e ():.        if
1770: 20 64 53 65 72 76 65 72 4f 70 74 69 6f 6e 73 2e   dServerOptions.
1780: 67 65 74 28 22 74 65 73 74 70 61 67 65 22 2c 20  get("testpage", 
1790: 46 61 6c 73 65 29 20 3d 3d 20 22 54 72 75 65 22  False) == "True"
17a0: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 72 65  :.            re
17b0: 74 75 72 6e 20 48 4f 4d 45 50 41 47 45 0a 20 20  turn HOMEPAGE.  
17c0: 20 20 20 20 20 20 20 20 20 20 23 72 65 74 75 72            #retur
17d0: 6e 20 74 65 6d 70 6c 61 74 65 28 22 6d 61 69 6e  n template("main
17e0: 22 2c 20 7b 7d 29 0a 20 20 20 20 20 20 20 20 72  ", {}).        r
17f0: 65 74 75 72 6e 20 53 41 44 4c 49 46 45 4f 46 41  eturn SADLIFEOFA
1800: 4d 41 43 48 49 4e 45 0a 0a 20 20 20 20 40 61 70  MACHINE..    @ap
1810: 70 2e 72 6f 75 74 65 28 22 2f 67 65 74 5f 6f 70  p.route("/get_op
1820: 74 69 6f 6e 73 2f 66 72 22 29 0a 20 20 20 20 64  tions/fr").    d
1830: 65 66 20 6c 69 73 74 4f 70 74 69 6f 6e 73 20 28  ef listOptions (
1840: 29 3a 0a 20 20 20 20 20 20 20 20 73 55 73 65 72  ):.        sUser
1850: 49 64 20 3d 20 72 65 71 75 65 73 74 2e 63 6f 6f  Id = request.coo
1860: 6b 69 65 73 2e 75 73 65 72 5f 69 64 0a 20 20 20  kies.user_id.   
1870: 20 20 20 20 20 64 4f 70 74 69 6f 6e 73 20 3d 20       dOptions = 
1880: 64 55 73 65 72 5b 73 55 73 65 72 49 64 5d 5b 22  dUser[sUserId]["
1890: 67 63 5f 6f 70 74 69 6f 6e 73 22 5d 20 20 69 66  gc_options"]  if
18a0: 20 73 55 73 65 72 49 64 20 61 6e 64 20 73 55 73   sUserId and sUs
18b0: 65 72 49 64 20 69 6e 20 64 55 73 65 72 20 20 65  erId in dUser  e
18c0: 6c 73 65 20 64 53 65 72 76 65 72 47 43 4f 70 74  lse dServerGCOpt
18d0: 69 6f 6e 73 0a 20 20 20 20 20 20 20 20 72 65 74  ions.        ret
18e0: 75 72 6e 20 27 7b 20 22 76 61 6c 75 65 73 22 3a  urn '{ "values":
18f0: 20 27 20 2b 20 6a 73 6f 6e 2e 64 75 6d 70 73 28   ' + json.dumps(
1900: 64 4f 70 74 69 6f 6e 73 29 20 2b 20 27 2c 20 22  dOptions) + ', "
1910: 6c 61 62 65 6c 73 22 3a 20 27 20 2b 20 6a 73 6f  labels": ' + jso
1920: 6e 2e 64 75 6d 70 73 28 67 63 65 2e 67 65 74 4f  n.dumps(gce.getO
1930: 70 74 69 6f 6e 73 4c 61 62 65 6c 73 28 22 66 72  ptionsLabels("fr
1940: 22 29 2c 20 65 6e 73 75 72 65 5f 61 73 63 69 69  "), ensure_ascii
1950: 3d 46 61 6c 73 65 29 20 2b 20 27 20 7d 27 0a 0a  =False) + ' }'..
1960: 0a 20 20 20 20 23 20 50 4f 53 54 0a 20 20 20 20  .    # POST.    
1970: 40 61 70 70 2e 72 6f 75 74 65 28 22 2f 67 63 5f  @app.route("/gc_
1980: 74 65 78 74 2f 66 72 22 2c 20 6d 65 74 68 6f 64  text/fr", method
1990: 3d 22 50 4f 53 54 22 29 0a 20 20 20 20 64 65 66  ="POST").    def
19a0: 20 67 63 54 65 78 74 20 28 29 3a 0a 20 20 20 20   gcText ():.    
19b0: 20 20 20 20 23 69 66 20 6c 65 6e 28 6c 61 6e 67      #if len(lang
19c0: 29 20 21 3d 20 32 20 6f 72 20 6c 61 6e 67 20 21  ) != 2 or lang !
19d0: 3d 20 22 66 72 22 3a 0a 20 20 20 20 20 20 20 20  = "fr":.        
19e0: 23 20 20 20 20 61 62 6f 72 74 28 34 30 34 2c 20  #    abort(404, 
19f0: 22 4e 6f 20 67 72 61 6d 6d 61 72 20 63 68 65 63  "No grammar chec
1a00: 6b 65 72 20 61 76 61 69 6c 61 62 6c 65 20 66 6f  ker available fo
1a10: 72 20 6c 61 6e 67 20 e2 80 9c 22 20 2b 20 73 74  r lang ..." + st
1a20: 72 28 6c 61 6e 67 29 20 2b 20 22 e2 80 9d 22 29  r(lang) + "...")
1a30: 0a 20 20 20 20 20 20 20 20 62 43 6f 6d 6d 61 20  .        bComma 
1a40: 3d 20 46 61 6c 73 65 0a 20 20 20 20 20 20 20 20  = False.        
1a50: 62 54 46 20 3d 20 62 6f 6f 6c 28 72 65 71 75 65  bTF = bool(reque
1a60: 73 74 2e 66 6f 72 6d 73 2e 74 66 29 0a 20 20 20  st.forms.tf).   
1a70: 20 20 20 20 20 64 4f 70 74 69 6f 6e 73 20 3d 20       dOptions = 
1a80: 4e 6f 6e 65 0a 20 20 20 20 20 20 20 20 73 45 72  None.        sEr
1a90: 72 6f 72 20 3d 20 22 22 0a 20 20 20 20 20 20 20  ror = "".       
1aa0: 20 69 66 20 72 65 71 75 65 73 74 2e 63 6f 6f 6b   if request.cook
1ab0: 69 65 73 2e 75 73 65 72 5f 69 64 3a 0a 20 20 20  ies.user_id:.   
1ac0: 20 20 20 20 20 20 20 20 20 69 66 20 72 65 71 75           if requ
1ad0: 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72  est.cookies.user
1ae0: 5f 69 64 20 69 6e 20 64 55 73 65 72 3a 0a 20 20  _id in dUser:.  
1af0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 64 4f                dO
1b00: 70 74 69 6f 6e 73 20 3d 20 64 55 73 65 72 5b 72  ptions = dUser[r
1b10: 65 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75  equest.cookies.u
1b20: 73 65 72 5f 69 64 5d 2e 67 65 74 28 22 67 63 5f  ser_id].get("gc_
1b30: 6f 70 74 69 6f 6e 73 22 2c 20 4e 6f 6e 65 29 0a  options", None).
1b40: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
1b50: 72 65 73 70 6f 6e 73 65 2e 73 65 74 5f 63 6f 6f  response.set_coo
1b60: 6b 69 65 28 22 75 73 65 72 5f 69 64 22 2c 20 72  kie("user_id", r
1b70: 65 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75  equest.cookies.u
1b80: 73 65 72 5f 69 64 2c 20 70 61 74 68 3d 22 2f 22  ser_id, path="/"
1b90: 2c 20 6d 61 78 5f 61 67 65 3d 38 36 34 30 30 29  , max_age=86400)
1ba0: 20 23 20 77 65 20 72 65 6e 65 77 20 63 6f 6f 6b   # we renew cook
1bb0: 69 65 20 66 6f 72 20 32 34 68 0a 20 20 20 20 20  ie for 24h.     
1bc0: 20 20 20 20 20 20 20 65 6c 73 65 3a 0a 20 20 20         else:.   
1bd0: 20 20 20 20 20 20 20 20 20 20 20 20 20 72 65 73               res
1be0: 70 6f 6e 73 65 2e 64 65 6c 65 74 65 5f 63 6f 6f  ponse.delete_coo
1bf0: 6b 69 65 28 22 75 73 65 72 5f 69 64 22 2c 20 70  kie("user_id", p
1c00: 61 74 68 3d 22 2f 22 29 0a 20 20 20 20 20 20 20  ath="/").       
1c10: 20 69 66 20 72 65 71 75 65 73 74 2e 66 6f 72 6d   if request.form
1c20: 73 2e 6f 70 74 69 6f 6e 73 3a 0a 20 20 20 20 20  s.options:.     
1c30: 20 20 20 20 20 20 20 74 72 79 3a 0a 20 20 20 20         try:.    
1c40: 20 20 20 20 20 20 20 20 20 20 20 20 64 4f 70 74              dOpt
1c50: 69 6f 6e 73 20 3d 20 64 69 63 74 28 64 53 65 72  ions = dict(dSer
1c60: 76 65 72 47 43 4f 70 74 69 6f 6e 73 29 20 20 69  verGCOptions)  i
1c70: 66 20 6e 6f 74 20 64 4f 70 74 69 6f 6e 73 20 20  f not dOptions  
1c80: 65 6c 73 65 20 64 69 63 74 28 64 4f 70 74 69 6f  else dict(dOptio
1c90: 6e 73 29 0a 20 20 20 20 20 20 20 20 20 20 20 20  ns).            
1ca0: 20 20 20 20 64 4f 70 74 69 6f 6e 73 2e 75 70 64      dOptions.upd
1cb0: 61 74 65 28 6a 73 6f 6e 2e 6c 6f 61 64 73 28 72  ate(json.loads(r
1cc0: 65 71 75 65 73 74 2e 66 6f 72 6d 73 2e 6f 70 74  equest.forms.opt
1cd0: 69 6f 6e 73 29 29 0a 20 20 20 20 20 20 20 20 20  ions)).         
1ce0: 20 20 20 65 78 63 65 70 74 3a 0a 20 20 20 20 20     except:.     
1cf0: 20 20 20 20 20 20 20 20 20 20 20 73 45 72 72 6f             sErro
1d00: 72 20 3d 20 22 72 65 71 75 65 73 74 20 6f 70 74  r = "request opt
1d10: 69 6f 6e 73 20 6e 6f 74 20 75 73 65 64 22 0a 20  ions not used". 
1d20: 20 20 20 20 20 20 20 73 4a 53 4f 4e 20 3d 20 27         sJSON = '
1d30: 7b 20 22 70 72 6f 67 72 61 6d 22 3a 20 22 67 72  { "program": "gr
1d40: 61 6d 6d 61 6c 65 63 74 65 2d 66 72 22 2c 20 22  ammalecte-fr", "
1d50: 76 65 72 73 69 6f 6e 22 3a 20 22 27 2b 67 63 65  version": "'+gce
1d60: 2e 76 65 72 73 69 6f 6e 2b 27 22 2c 20 22 6c 61  .version+'", "la
1d70: 6e 67 22 3a 20 22 27 2b 67 63 65 2e 6c 61 6e 67  ng": "'+gce.lang
1d80: 2b 27 22 2c 20 22 65 72 72 6f 72 22 3a 20 22 27  +'", "error": "'
1d90: 2b 73 45 72 72 6f 72 2b 27 22 2c 20 22 64 61 74  +sError+'", "dat
1da0: 61 22 20 3a 20 5b 5c 6e 27 0a 20 20 20 20 20 20  a" : [\n'.      
1db0: 20 20 66 6f 72 20 69 2c 20 73 54 65 78 74 20 69    for i, sText i
1dc0: 6e 20 65 6e 75 6d 65 72 61 74 65 28 74 78 74 2e  n enumerate(txt.
1dd0: 67 65 74 50 61 72 61 67 72 61 70 68 28 72 65 71  getParagraph(req
1de0: 75 65 73 74 2e 66 6f 72 6d 73 2e 74 65 78 74 29  uest.forms.text)
1df0: 2c 20 31 29 3a 0a 20 20 20 20 20 20 20 20 20 20  , 1):.          
1e00: 20 20 69 66 20 62 54 46 3a 0a 20 20 20 20 20 20    if bTF:.      
1e10: 20 20 20 20 20 20 20 20 20 20 73 54 65 78 74 20            sText 
1e20: 3d 20 6f 54 46 2e 66 6f 72 6d 61 74 54 65 78 74  = oTF.formatText
1e30: 28 73 54 65 78 74 29 0a 20 20 20 20 20 20 20 20  (sText).        
1e40: 20 20 20 20 73 54 65 78 74 20 3d 20 70 61 72 73      sText = pars
1e50: 65 50 61 72 61 67 72 61 70 68 28 69 2c 20 73 54  eParagraph(i, sT
1e60: 65 78 74 2c 20 6f 54 6f 6b 65 6e 69 7a 65 72 2c  ext, oTokenizer,
1e70: 20 6f 44 69 63 74 2c 20 64 4f 70 74 69 6f 6e 73   oDict, dOptions
1e80: 2c 20 62 45 6d 70 74 79 49 66 4e 6f 45 72 72 6f  , bEmptyIfNoErro
1e90: 72 73 3d 54 72 75 65 29 0a 20 20 20 20 20 20 20  rs=True).       
1ea0: 20 20 20 20 20 69 66 20 73 54 65 78 74 3a 0a 20       if sText:. 
1eb0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 69                 i
1ec0: 66 20 62 43 6f 6d 6d 61 3a 0a 20 20 20 20 20 20  f bComma:.      
1ed0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 73 4a                sJ
1ee0: 53 4f 4e 20 2b 3d 20 22 2c 5c 6e 22 0a 20 20 20  SON += ",\n".   
1ef0: 20 20 20 20 20 20 20 20 20 20 20 20 20 73 4a 53               sJS
1f00: 4f 4e 20 2b 3d 20 73 54 65 78 74 0a 20 20 20 20  ON += sText.    
1f10: 20 20 20 20 20 20 20 20 20 20 20 20 62 43 6f 6d              bCom
1f20: 6d 61 20 3d 20 54 72 75 65 0a 20 20 20 20 20 20  ma = True.      
1f30: 20 20 73 4a 53 4f 4e 20 2b 3d 20 22 5c 6e 5d 7d    sJSON += "\n]}
1f40: 5c 6e 22 0a 20 20 20 20 20 20 20 20 72 65 74 75  \n".        retu
1f50: 72 6e 20 73 4a 53 4f 4e 0a 0a 20 20 20 20 40 61  rn sJSON..    @a
1f60: 70 70 2e 72 6f 75 74 65 28 22 2f 73 65 74 5f 6f  pp.route("/set_o
1f70: 70 74 69 6f 6e 73 2f 66 72 22 2c 20 6d 65 74 68  ptions/fr", meth
1f80: 6f 64 3d 22 50 4f 53 54 22 29 0a 20 20 20 20 64  od="POST").    d
1f90: 65 66 20 73 65 74 4f 70 74 69 6f 6e 73 20 28 29  ef setOptions ()
1fa0: 3a 0a 20 20 20 20 20 20 20 20 69 66 20 72 65 71  :.        if req
1fb0: 75 65 73 74 2e 66 6f 72 6d 73 2e 6f 70 74 69 6f  uest.forms.optio
1fc0: 6e 73 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  ns:.            
1fd0: 73 55 73 65 72 49 64 20 3d 20 72 65 71 75 65 73  sUserId = reques
1fe0: 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72 5f 69  t.cookies.user_i
1ff0: 64 20 20 69 66 20 72 65 71 75 65 73 74 2e 63 6f  d  if request.co
2000: 6f 6b 69 65 73 2e 75 73 65 72 5f 69 64 20 20 65  okies.user_id  e
2010: 6c 73 65 20 6e 65 78 74 28 75 73 65 72 47 65 6e  lse next(userGen
2020: 65 72 61 74 6f 72 29 0a 20 20 20 20 20 20 20 20  erator).        
2030: 20 20 20 20 64 4f 70 74 69 6f 6e 73 20 3d 20 64      dOptions = d
2040: 55 73 65 72 5b 73 55 73 65 72 49 64 5d 5b 22 67  User[sUserId]["g
2050: 63 5f 6f 70 74 69 6f 6e 73 22 5d 20 20 69 66 20  c_options"]  if 
2060: 73 55 73 65 72 49 64 20 69 6e 20 64 55 73 65 72  sUserId in dUser
2070: 20 20 65 6c 73 65 20 64 69 63 74 28 64 53 65 72    else dict(dSer
2080: 76 65 72 47 43 4f 70 74 69 6f 6e 73 29 0a 20 20  verGCOptions).  
2090: 20 20 20 20 20 20 20 20 20 20 74 72 79 3a 0a 20            try:. 
20a0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 64                 d
20b0: 4f 70 74 69 6f 6e 73 2e 75 70 64 61 74 65 28 6a  Options.update(j
20c0: 73 6f 6e 2e 6c 6f 61 64 73 28 72 65 71 75 65 73  son.loads(reques
20d0: 74 2e 66 6f 72 6d 73 2e 6f 70 74 69 6f 6e 73 29  t.forms.options)
20e0: 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  ).              
20f0: 20 20 64 55 73 65 72 5b 73 55 73 65 72 49 64 5d    dUser[sUserId]
2100: 20 3d 20 7b 20 22 74 69 6d 65 22 3a 20 69 6e 74   = { "time": int
2110: 28 74 69 6d 65 2e 74 69 6d 65 28 29 29 2c 20 22  (time.time()), "
2120: 67 63 5f 6f 70 74 69 6f 6e 73 22 3a 20 64 4f 70  gc_options": dOp
2130: 74 69 6f 6e 73 20 7d 0a 20 20 20 20 20 20 20 20  tions }.        
2140: 20 20 20 20 20 20 20 20 72 65 73 70 6f 6e 73 65          response
2150: 2e 73 65 74 5f 63 6f 6f 6b 69 65 28 22 75 73 65  .set_cookie("use
2160: 72 5f 69 64 22 2c 20 73 55 73 65 72 49 64 2c 20  r_id", sUserId, 
2170: 70 61 74 68 3d 22 2f 22 2c 20 6d 61 78 5f 61 67  path="/", max_ag
2180: 65 3d 38 36 34 30 30 29 20 23 20 32 34 68 0a 20  e=86400) # 24h. 
2190: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 72                 r
21a0: 65 74 75 72 6e 20 6a 73 6f 6e 2e 64 75 6d 70 73  eturn json.dumps
21b0: 28 64 55 73 65 72 5b 73 55 73 65 72 49 64 5d 5b  (dUser[sUserId][
21c0: 22 67 63 5f 6f 70 74 69 6f 6e 73 22 5d 29 0a 20  "gc_options"]). 
21d0: 20 20 20 20 20 20 20 20 20 20 20 65 78 63 65 70             excep
21e0: 74 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 20  t:.             
21f0: 20 20 20 74 72 61 63 65 62 61 63 6b 2e 70 72 69     traceback.pri
2200: 6e 74 5f 65 78 63 28 29 0a 20 20 20 20 20 20 20  nt_exc().       
2210: 20 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20           return 
2220: 27 7b 22 65 72 72 6f 72 22 3a 20 22 6f 70 74 69  '{"error": "opti
2230: 6f 6e 73 20 6e 6f 74 20 72 65 67 69 73 74 65 72  ons not register
2240: 65 64 22 7d 27 0a 20 20 20 20 20 20 20 20 72 65  ed"}'.        re
2250: 74 75 72 6e 20 27 7b 22 65 72 72 6f 72 22 3a 20  turn '{"error": 
2260: 22 6e 6f 20 6f 70 74 69 6f 6e 73 20 72 65 63 65  "no options rece
2270: 69 76 65 64 22 7d 27 0a 0a 20 20 20 20 40 61 70  ived"}'..    @ap
2280: 70 2e 72 6f 75 74 65 28 22 2f 72 65 73 65 74 5f  p.route("/reset_
2290: 6f 70 74 69 6f 6e 73 2f 66 72 22 2c 20 6d 65 74  options/fr", met
22a0: 68 6f 64 3d 22 50 4f 53 54 22 29 0a 20 20 20 20  hod="POST").    
22b0: 64 65 66 20 72 65 73 65 74 4f 70 74 69 6f 6e 73  def resetOptions
22c0: 20 28 29 3a 0a 20 20 20 20 20 20 20 20 69 66 20   ():.        if 
22d0: 72 65 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e  request.cookies.
22e0: 75 73 65 72 5f 69 64 20 61 6e 64 20 72 65 71 75  user_id and requ
22f0: 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72  est.cookies.user
2300: 5f 69 64 20 69 6e 20 64 55 73 65 72 3a 0a 20 20  _id in dUser:.  
2310: 20 20 20 20 20 20 20 20 20 20 64 65 6c 20 64 55            del dU
2320: 73 65 72 5b 72 65 71 75 65 73 74 2e 63 6f 6f 6b  ser[request.cook
2330: 69 65 73 2e 75 73 65 72 5f 69 64 5d 0a 20 20 20  ies.user_id].   
2340: 20 20 20 20 20 72 65 74 75 72 6e 20 22 64 6f 6e       return "don
2350: 65 22 0a 0a 20 20 20 20 40 61 70 70 2e 72 6f 75  e"..    @app.rou
2360: 74 65 28 22 2f 66 6f 72 6d 61 74 5f 74 65 78 74  te("/format_text
2370: 2f 66 72 22 2c 20 6d 65 74 68 6f 64 3d 22 50 4f  /fr", method="PO
2380: 53 54 22 29 0a 20 20 20 20 64 65 66 20 66 6f 72  ST").    def for
2390: 6d 61 74 54 65 78 74 20 28 29 3a 0a 20 20 20 20  matText ():.    
23a0: 20 20 20 20 72 65 74 75 72 6e 20 6f 54 46 2e 66      return oTF.f
23b0: 6f 72 6d 61 74 54 65 78 74 28 72 65 71 75 65 73  ormatText(reques
23c0: 74 2e 66 6f 72 6d 73 2e 74 65 78 74 29 0a 0a 20  t.forms.text).. 
23d0: 20 20 20 23 40 61 70 70 2e 72 6f 75 74 65 28 27     #@app.route('
23e0: 2f 73 74 61 74 69 63 2f 3c 66 69 6c 65 70 61 74  /static/<filepat
23f0: 68 3a 70 61 74 68 3e 27 29 0a 20 20 20 20 23 64  h:path>').    #d
2400: 65 66 20 73 65 72 76 65 72 5f 73 74 61 74 69 63  ef server_static
2410: 20 28 66 69 6c 65 70 61 74 68 29 3a 0a 20 20 20   (filepath):.   
2420: 20 23 20 20 20 20 72 65 74 75 72 6e 20 73 74 61   #    return sta
2430: 74 69 63 5f 66 69 6c 65 28 66 69 6c 65 70 61 74  tic_file(filepat
2440: 68 2c 20 72 6f 6f 74 3d 27 2e 2f 76 69 65 77 73  h, root='./views
2450: 2f 73 74 61 74 69 63 27 29 0a 0a 20 20 20 20 40  /static')..    @
2460: 61 70 70 2e 72 6f 75 74 65 28 22 2f 70 75 72 67  app.route("/purg
2470: 65 5f 75 73 65 72 73 22 2c 20 6d 65 74 68 6f 64  e_users", method
2480: 3d 22 50 4f 53 54 22 29 0a 20 20 20 20 64 65 66  ="POST").    def
2490: 20 70 75 72 67 65 55 73 65 72 73 20 28 29 3a 0a   purgeUsers ():.
24a0: 20 20 20 20 20 20 20 20 22 64 65 6c 65 74 65 20          "delete 
24b0: 75 73 65 72 20 6f 70 74 69 6f 6e 73 20 6f 6c 64  user options old
24c0: 65 72 20 74 68 61 6e 20 6e 20 68 6f 75 72 73 22  er than n hours"
24d0: 0a 20 20 20 20 20 20 20 20 69 66 20 6e 6f 74 20  .        if not 
24e0: 72 65 71 75 65 73 74 2e 66 6f 72 6d 73 2e 70 61  request.forms.pa
24f0: 73 73 77 6f 72 64 20 6f 72 20 22 70 61 73 73 77  ssword or "passw
2500: 6f 72 64 22 20 6e 6f 74 20 69 6e 20 64 53 65 72  ord" not in dSer
2510: 76 65 72 4f 70 74 69 6f 6e 73 20 6f 72 20 6e 6f  verOptions or no
2520: 74 20 72 65 71 75 65 73 74 2e 66 6f 72 6d 73 2e  t request.forms.
2530: 68 6f 75 72 73 3a 0a 20 20 20 20 20 20 20 20 20  hours:.         
2540: 20 20 20 72 65 74 75 72 6e 20 22 77 68 61 74 3f     return "what?
2550: 22 0a 20 20 20 20 20 20 20 20 74 72 79 3a 0a 20  ".        try:. 
2560: 20 20 20 20 20 20 20 20 20 20 20 69 66 20 72 65             if re
2570: 71 75 65 73 74 2e 66 6f 72 6d 73 2e 70 61 73 73  quest.forms.pass
2580: 77 6f 72 64 20 3d 3d 20 64 53 65 72 76 65 72 4f  word == dServerO
2590: 70 74 69 6f 6e 73 5b 22 70 61 73 73 77 6f 72 64  ptions["password
25a0: 22 5d 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  "]:.            
25b0: 20 20 20 20 6e 4e 6f 77 4d 69 6e 75 73 4e 48 6f      nNowMinusNHo
25c0: 75 72 73 20 3d 20 69 6e 74 28 74 69 6d 65 2e 74  urs = int(time.t
25d0: 69 6d 65 28 29 29 20 2d 20 28 69 6e 74 28 72 65  ime()) - (int(re
25e0: 71 75 65 73 74 2e 66 6f 72 6d 73 2e 68 6f 75 72  quest.forms.hour
25f0: 73 29 20 2a 20 36 30 20 2a 20 36 30 29 0a 20 20  s) * 60 * 60).  
2600: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 66 6f                fo
2610: 72 20 6e 55 73 65 72 49 64 2c 20 64 56 61 6c 75  r nUserId, dValu
2620: 65 20 69 6e 20 64 55 73 65 72 2e 69 74 65 6d 73  e in dUser.items
2630: 28 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  ():.            
2640: 20 20 20 20 20 20 20 20 69 66 20 64 56 61 6c 75          if dValu
2650: 65 5b 22 74 69 6d 65 22 5d 20 3c 20 6e 4e 6f 77  e["time"] < nNow
2660: 4d 69 6e 75 73 4e 48 6f 75 72 73 3a 0a 20 20 20  MinusNHours:.   
2670: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
2680: 20 20 20 20 20 64 65 6c 20 64 55 73 65 72 5b 6e       del dUser[n
2690: 55 73 65 72 49 64 5d 0a 20 20 20 20 20 20 20 20  UserId].        
26a0: 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 22          return "
26b0: 64 6f 6e 65 22 0a 20 20 20 20 20 20 20 20 20 20  done".          
26c0: 20 20 65 6c 73 65 3a 0a 20 20 20 20 20 20 20 20    else:.        
26d0: 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 22          return "
26e0: 6e 6f 22 0a 20 20 20 20 20 20 20 20 65 78 63 65  no".        exce
26f0: 70 74 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  pt:.            
2700: 74 72 61 63 65 62 61 63 6b 2e 70 72 69 6e 74 5f  traceback.print_
2710: 65 78 63 28 29 0a 20 20 20 20 20 20 20 20 20 20  exc().          
2720: 20 20 72 65 74 75 72 6e 20 22 65 72 72 6f 72 22    return "error"
2730: 0a 0a 20 20 20 20 23 20 45 52 52 4f 52 0a 20 20  ..    # ERROR.  
2740: 20 20 40 61 70 70 2e 65 72 72 6f 72 28 34 30 34    @app.error(404
2750: 29 0a 20 20 20 20 64 65 66 20 65 72 72 6f 72 34  ).    def error4
2760: 30 34 20 28 65 72 72 6f 72 29 3a 0a 20 20 20 20  04 (error):.    
2770: 20 20 20 20 72 65 74 75 72 6e 20 27 45 72 72 6f      return 'Erro
2780: 72 20 34 30 34 2e 3c 62 72 2f 3e 27 20 2b 20 73  r 404.<br/>' + s
2790: 74 72 28 65 72 72 6f 72 29 0a 0a 20 20 20 20 72  tr(error)..    r
27a0: 75 6e 28 61 70 70 2c 20 5c 0a 20 20 20 20 20 20  un(app, \.      
27b0: 20 20 68 6f 73 74 3d 64 53 65 72 76 65 72 4f 70    host=dServerOp
27c0: 74 69 6f 6e 73 2e 67 65 74 28 27 68 6f 73 74 27  tions.get('host'
27d0: 2c 20 27 6c 6f 63 61 6c 68 6f 73 74 27 29 2c 20  , 'localhost'), 
27e0: 5c 0a 20 20 20 20 20 20 20 20 70 6f 72 74 3d 69  \.        port=i
27f0: 6e 74 28 64 53 65 72 76 65 72 4f 70 74 69 6f 6e  nt(dServerOption
2800: 73 2e 67 65 74 28 27 70 6f 72 74 27 2c 20 38 30  s.get('port', 80
2810: 38 30 29 29 29 0a                                80))).