Grammalecte  Hex Artifact Content

Artifact f2aebf4d4774317d414b879c245de0aafb0def6a52ec62bf6624924a66973c34:


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 29 0a 20 20 20 20 65 63 68 6f 28 22  oad().    echo("
1540: 47 72 61 6d 6d 61 6c 65 63 74 65 20 76 7b 7d 22  Grammalecte v{}"
1550: 2e 66 6f 72 6d 61 74 28 67 63 65 2e 76 65 72 73  .format(gce.vers
1560: 69 6f 6e 29 29 0a 20 20 20 20 64 53 65 72 76 65  ion)).    dServe
1570: 72 4f 70 74 69 6f 6e 73 20 3d 20 67 65 74 53 65  rOptions = getSe
1580: 72 76 65 72 4f 70 74 69 6f 6e 73 28 29 0a 20 20  rverOptions().  
1590: 20 20 64 47 43 4f 70 74 69 6f 6e 73 20 3d 20 67    dGCOptions = g
15a0: 65 74 43 6f 6e 66 69 67 4f 70 74 69 6f 6e 73 28  etConfigOptions(
15b0: 22 66 72 22 29 0a 20 20 20 20 69 66 20 64 47 43  "fr").    if dGC
15c0: 4f 70 74 69 6f 6e 73 3a 0a 20 20 20 20 20 20 20  Options:.       
15d0: 20 67 63 65 2e 73 65 74 4f 70 74 69 6f 6e 73 28   gce.setOptions(
15e0: 64 47 43 4f 70 74 69 6f 6e 73 29 0a 20 20 20 20  dGCOptions).    
15f0: 64 53 65 72 76 65 72 47 43 4f 70 74 69 6f 6e 73  dServerGCOptions
1600: 20 3d 20 67 63 65 2e 67 65 74 4f 70 74 69 6f 6e   = gce.getOption
1610: 73 28 29 0a 20 20 20 20 65 63 68 6f 28 22 47 72  s().    echo("Gr
1620: 61 6d 6d 61 72 20 6f 70 74 69 6f 6e 73 3a 5c 6e  ammar options:\n
1630: 22 20 2b 20 22 20 7c 20 22 2e 6a 6f 69 6e 28 5b  " + " | ".join([
1640: 20 6b 20 2b 20 22 3a 20 22 20 2b 20 73 74 72 28   k + ": " + str(
1650: 76 29 20 20 66 6f 72 20 6b 2c 20 76 20 69 6e 20  v)  for k, v in 
1660: 73 6f 72 74 65 64 28 64 53 65 72 76 65 72 47 43  sorted(dServerGC
1670: 4f 70 74 69 6f 6e 73 2e 69 74 65 6d 73 28 29 29  Options.items())
1680: 20 5d 29 29 0a 20 20 20 20 6f 44 69 63 74 20 3d   ])).    oDict =
1690: 20 67 63 65 2e 67 65 74 44 69 63 74 69 6f 6e 61   gce.getDictiona
16a0: 72 79 28 29 0a 20 20 20 20 6f 54 6f 6b 65 6e 69  ry().    oTokeni
16b0: 7a 65 72 20 3d 20 74 6b 7a 2e 54 6f 6b 65 6e 69  zer = tkz.Tokeni
16c0: 7a 65 72 28 22 66 72 22 29 0a 20 20 20 20 6f 54  zer("fr").    oT
16d0: 46 20 3d 20 74 66 2e 54 65 78 74 46 6f 72 6d 61  F = tf.TextForma
16e0: 74 74 65 72 28 29 0a 20 20 20 20 64 55 73 65 72  tter().    dUser
16f0: 20 3d 20 7b 7d 0a 20 20 20 20 75 73 65 72 47 65   = {}.    userGe
1700: 6e 65 72 61 74 6f 72 20 3d 20 67 65 6e 55 73 65  nerator = genUse
1710: 72 49 64 28 29 0a 0a 20 20 20 20 61 70 70 20 3d  rId()..    app =
1720: 20 42 6f 74 74 6c 65 28 29 0a 0a 20 20 20 20 23   Bottle()..    #
1730: 20 47 45 54 0a 20 20 20 20 40 61 70 70 2e 72 6f   GET.    @app.ro
1740: 75 74 65 28 22 2f 22 29 0a 20 20 20 20 64 65 66  ute("/").    def
1750: 20 6d 61 69 6e 50 61 67 65 20 28 29 3a 0a 20 20   mainPage ():.  
1760: 20 20 20 20 20 20 69 66 20 64 53 65 72 76 65 72        if dServer
1770: 4f 70 74 69 6f 6e 73 2e 67 65 74 28 22 74 65 73  Options.get("tes
1780: 74 70 61 67 65 22 2c 20 46 61 6c 73 65 29 20 3d  tpage", False) =
1790: 3d 20 22 54 72 75 65 22 3a 0a 20 20 20 20 20 20  = "True":.      
17a0: 20 20 20 20 20 20 72 65 74 75 72 6e 20 48 4f 4d        return HOM
17b0: 45 50 41 47 45 0a 20 20 20 20 20 20 20 20 20 20  EPAGE.          
17c0: 20 20 23 72 65 74 75 72 6e 20 74 65 6d 70 6c 61    #return templa
17d0: 74 65 28 22 6d 61 69 6e 22 2c 20 7b 7d 29 0a 20  te("main", {}). 
17e0: 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 53 41         return SA
17f0: 44 4c 49 46 45 4f 46 41 4d 41 43 48 49 4e 45 0a  DLIFEOFAMACHINE.
1800: 0a 20 20 20 20 40 61 70 70 2e 72 6f 75 74 65 28  .    @app.route(
1810: 22 2f 67 65 74 5f 6f 70 74 69 6f 6e 73 2f 66 72  "/get_options/fr
1820: 22 29 0a 20 20 20 20 64 65 66 20 6c 69 73 74 4f  ").    def listO
1830: 70 74 69 6f 6e 73 20 28 29 3a 0a 20 20 20 20 20  ptions ():.     
1840: 20 20 20 73 55 73 65 72 49 64 20 3d 20 72 65 71     sUserId = req
1850: 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65  uest.cookies.use
1860: 72 5f 69 64 0a 20 20 20 20 20 20 20 20 64 4f 70  r_id.        dOp
1870: 74 69 6f 6e 73 20 3d 20 64 55 73 65 72 5b 73 55  tions = dUser[sU
1880: 73 65 72 49 64 5d 5b 22 67 63 5f 6f 70 74 69 6f  serId]["gc_optio
1890: 6e 73 22 5d 20 20 69 66 20 73 55 73 65 72 49 64  ns"]  if sUserId
18a0: 20 61 6e 64 20 73 55 73 65 72 49 64 20 69 6e 20   and sUserId in 
18b0: 64 55 73 65 72 20 20 65 6c 73 65 20 64 53 65 72  dUser  else dSer
18c0: 76 65 72 47 43 4f 70 74 69 6f 6e 73 0a 20 20 20  verGCOptions.   
18d0: 20 20 20 20 20 72 65 74 75 72 6e 20 27 7b 20 22       return '{ "
18e0: 76 61 6c 75 65 73 22 3a 20 27 20 2b 20 6a 73 6f  values": ' + jso
18f0: 6e 2e 64 75 6d 70 73 28 64 4f 70 74 69 6f 6e 73  n.dumps(dOptions
1900: 29 20 2b 20 27 2c 20 22 6c 61 62 65 6c 73 22 3a  ) + ', "labels":
1910: 20 27 20 2b 20 6a 73 6f 6e 2e 64 75 6d 70 73 28   ' + json.dumps(
1920: 67 63 65 2e 67 65 74 4f 70 74 69 6f 6e 73 4c 61  gce.getOptionsLa
1930: 62 65 6c 73 28 22 66 72 22 29 2c 20 65 6e 73 75  bels("fr"), ensu
1940: 72 65 5f 61 73 63 69 69 3d 46 61 6c 73 65 29 20  re_ascii=False) 
1950: 2b 20 27 20 7d 27 0a 0a 0a 20 20 20 20 23 20 50  + ' }'...    # P
1960: 4f 53 54 0a 20 20 20 20 40 61 70 70 2e 72 6f 75  OST.    @app.rou
1970: 74 65 28 22 2f 67 63 5f 74 65 78 74 2f 66 72 22  te("/gc_text/fr"
1980: 2c 20 6d 65 74 68 6f 64 3d 22 50 4f 53 54 22 29  , method="POST")
1990: 0a 20 20 20 20 64 65 66 20 67 63 54 65 78 74 20  .    def gcText 
19a0: 28 29 3a 0a 20 20 20 20 20 20 20 20 23 69 66 20  ():.        #if 
19b0: 6c 65 6e 28 6c 61 6e 67 29 20 21 3d 20 32 20 6f  len(lang) != 2 o
19c0: 72 20 6c 61 6e 67 20 21 3d 20 22 66 72 22 3a 0a  r lang != "fr":.
19d0: 20 20 20 20 20 20 20 20 23 20 20 20 20 61 62 6f          #    abo
19e0: 72 74 28 34 30 34 2c 20 22 4e 6f 20 67 72 61 6d  rt(404, "No gram
19f0: 6d 61 72 20 63 68 65 63 6b 65 72 20 61 76 61 69  mar checker avai
1a00: 6c 61 62 6c 65 20 66 6f 72 20 6c 61 6e 67 20 e2  lable for lang .
1a10: 80 9c 22 20 2b 20 73 74 72 28 6c 61 6e 67 29 20  .." + str(lang) 
1a20: 2b 20 22 e2 80 9d 22 29 0a 20 20 20 20 20 20 20  + "...").       
1a30: 20 62 43 6f 6d 6d 61 20 3d 20 46 61 6c 73 65 0a   bComma = False.
1a40: 20 20 20 20 20 20 20 20 62 54 46 20 3d 20 62 6f          bTF = bo
1a50: 6f 6c 28 72 65 71 75 65 73 74 2e 66 6f 72 6d 73  ol(request.forms
1a60: 2e 74 66 29 0a 20 20 20 20 20 20 20 20 64 4f 70  .tf).        dOp
1a70: 74 69 6f 6e 73 20 3d 20 4e 6f 6e 65 0a 20 20 20  tions = None.   
1a80: 20 20 20 20 20 73 45 72 72 6f 72 20 3d 20 22 22       sError = ""
1a90: 0a 20 20 20 20 20 20 20 20 69 66 20 72 65 71 75  .        if requ
1aa0: 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72  est.cookies.user
1ab0: 5f 69 64 3a 0a 20 20 20 20 20 20 20 20 20 20 20  _id:.           
1ac0: 20 69 66 20 72 65 71 75 65 73 74 2e 63 6f 6f 6b   if request.cook
1ad0: 69 65 73 2e 75 73 65 72 5f 69 64 20 69 6e 20 64  ies.user_id in d
1ae0: 55 73 65 72 3a 0a 20 20 20 20 20 20 20 20 20 20  User:.          
1af0: 20 20 20 20 20 20 64 4f 70 74 69 6f 6e 73 20 3d        dOptions =
1b00: 20 64 55 73 65 72 5b 72 65 71 75 65 73 74 2e 63   dUser[request.c
1b10: 6f 6f 6b 69 65 73 2e 75 73 65 72 5f 69 64 5d 2e  ookies.user_id].
1b20: 67 65 74 28 22 67 63 5f 6f 70 74 69 6f 6e 73 22  get("gc_options"
1b30: 2c 20 4e 6f 6e 65 29 0a 20 20 20 20 20 20 20 20  , None).        
1b40: 20 20 20 20 20 20 20 20 72 65 73 70 6f 6e 73 65          response
1b50: 2e 73 65 74 5f 63 6f 6f 6b 69 65 28 22 75 73 65  .set_cookie("use
1b60: 72 5f 69 64 22 2c 20 72 65 71 75 65 73 74 2e 63  r_id", request.c
1b70: 6f 6f 6b 69 65 73 2e 75 73 65 72 5f 69 64 2c 20  ookies.user_id, 
1b80: 70 61 74 68 3d 22 2f 22 2c 20 6d 61 78 5f 61 67  path="/", max_ag
1b90: 65 3d 38 36 34 30 30 29 20 23 20 77 65 20 72 65  e=86400) # we re
1ba0: 6e 65 77 20 63 6f 6f 6b 69 65 20 66 6f 72 20 32  new cookie for 2
1bb0: 34 68 0a 20 20 20 20 20 20 20 20 20 20 20 20 65  4h.            e
1bc0: 6c 73 65 3a 0a 20 20 20 20 20 20 20 20 20 20 20  lse:.           
1bd0: 20 20 20 20 20 72 65 73 70 6f 6e 73 65 2e 64 65       response.de
1be0: 6c 65 74 65 5f 63 6f 6f 6b 69 65 28 22 75 73 65  lete_cookie("use
1bf0: 72 5f 69 64 22 2c 20 70 61 74 68 3d 22 2f 22 29  r_id", path="/")
1c00: 0a 20 20 20 20 20 20 20 20 69 66 20 72 65 71 75  .        if requ
1c10: 65 73 74 2e 66 6f 72 6d 73 2e 6f 70 74 69 6f 6e  est.forms.option
1c20: 73 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 74  s:.            t
1c30: 72 79 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  ry:.            
1c40: 20 20 20 20 64 4f 70 74 69 6f 6e 73 20 3d 20 64      dOptions = d
1c50: 69 63 74 28 64 53 65 72 76 65 72 47 43 4f 70 74  ict(dServerGCOpt
1c60: 69 6f 6e 73 29 20 20 69 66 20 6e 6f 74 20 64 4f  ions)  if not dO
1c70: 70 74 69 6f 6e 73 20 20 65 6c 73 65 20 64 69 63  ptions  else dic
1c80: 74 28 64 4f 70 74 69 6f 6e 73 29 0a 20 20 20 20  t(dOptions).    
1c90: 20 20 20 20 20 20 20 20 20 20 20 20 64 4f 70 74              dOpt
1ca0: 69 6f 6e 73 2e 75 70 64 61 74 65 28 6a 73 6f 6e  ions.update(json
1cb0: 2e 6c 6f 61 64 73 28 72 65 71 75 65 73 74 2e 66  .loads(request.f
1cc0: 6f 72 6d 73 2e 6f 70 74 69 6f 6e 73 29 29 0a 20  orms.options)). 
1cd0: 20 20 20 20 20 20 20 20 20 20 20 65 78 63 65 70             excep
1ce0: 74 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 20  t:.             
1cf0: 20 20 20 73 45 72 72 6f 72 20 3d 20 22 72 65 71     sError = "req
1d00: 75 65 73 74 20 6f 70 74 69 6f 6e 73 20 6e 6f 74  uest options not
1d10: 20 75 73 65 64 22 0a 20 20 20 20 20 20 20 20 73   used".        s
1d20: 4a 53 4f 4e 20 3d 20 27 7b 20 22 70 72 6f 67 72  JSON = '{ "progr
1d30: 61 6d 22 3a 20 22 67 72 61 6d 6d 61 6c 65 63 74  am": "grammalect
1d40: 65 2d 66 72 22 2c 20 22 76 65 72 73 69 6f 6e 22  e-fr", "version"
1d50: 3a 20 22 27 2b 67 63 65 2e 76 65 72 73 69 6f 6e  : "'+gce.version
1d60: 2b 27 22 2c 20 22 6c 61 6e 67 22 3a 20 22 27 2b  +'", "lang": "'+
1d70: 67 63 65 2e 6c 61 6e 67 2b 27 22 2c 20 22 65 72  gce.lang+'", "er
1d80: 72 6f 72 22 3a 20 22 27 2b 73 45 72 72 6f 72 2b  ror": "'+sError+
1d90: 27 22 2c 20 22 64 61 74 61 22 20 3a 20 5b 5c 6e  '", "data" : [\n
1da0: 27 0a 20 20 20 20 20 20 20 20 66 6f 72 20 69 2c  '.        for i,
1db0: 20 73 54 65 78 74 20 69 6e 20 65 6e 75 6d 65 72   sText in enumer
1dc0: 61 74 65 28 74 78 74 2e 67 65 74 50 61 72 61 67  ate(txt.getParag
1dd0: 72 61 70 68 28 72 65 71 75 65 73 74 2e 66 6f 72  raph(request.for
1de0: 6d 73 2e 74 65 78 74 29 2c 20 31 29 3a 0a 20 20  ms.text), 1):.  
1df0: 20 20 20 20 20 20 20 20 20 20 69 66 20 62 54 46            if bTF
1e00: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  :.              
1e10: 20 20 73 54 65 78 74 20 3d 20 6f 54 46 2e 66 6f    sText = oTF.fo
1e20: 72 6d 61 74 54 65 78 74 28 73 54 65 78 74 29 0a  rmatText(sText).
1e30: 20 20 20 20 20 20 20 20 20 20 20 20 73 54 65 78              sTex
1e40: 74 20 3d 20 70 61 72 73 65 50 61 72 61 67 72 61  t = parseParagra
1e50: 70 68 28 69 2c 20 73 54 65 78 74 2c 20 6f 54 6f  ph(i, sText, oTo
1e60: 6b 65 6e 69 7a 65 72 2c 20 6f 44 69 63 74 2c 20  kenizer, oDict, 
1e70: 64 4f 70 74 69 6f 6e 73 2c 20 62 45 6d 70 74 79  dOptions, bEmpty
1e80: 49 66 4e 6f 45 72 72 6f 72 73 3d 54 72 75 65 29  IfNoErrors=True)
1e90: 0a 20 20 20 20 20 20 20 20 20 20 20 20 69 66 20  .            if 
1ea0: 73 54 65 78 74 3a 0a 20 20 20 20 20 20 20 20 20  sText:.         
1eb0: 20 20 20 20 20 20 20 69 66 20 62 43 6f 6d 6d 61         if bComma
1ec0: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  :.              
1ed0: 20 20 20 20 20 20 73 4a 53 4f 4e 20 2b 3d 20 22        sJSON += "
1ee0: 2c 5c 6e 22 0a 20 20 20 20 20 20 20 20 20 20 20  ,\n".           
1ef0: 20 20 20 20 20 73 4a 53 4f 4e 20 2b 3d 20 73 54       sJSON += sT
1f00: 65 78 74 0a 20 20 20 20 20 20 20 20 20 20 20 20  ext.            
1f10: 20 20 20 20 62 43 6f 6d 6d 61 20 3d 20 54 72 75      bComma = Tru
1f20: 65 0a 20 20 20 20 20 20 20 20 73 4a 53 4f 4e 20  e.        sJSON 
1f30: 2b 3d 20 22 5c 6e 5d 7d 5c 6e 22 0a 20 20 20 20  += "\n]}\n".    
1f40: 20 20 20 20 72 65 74 75 72 6e 20 73 4a 53 4f 4e      return sJSON
1f50: 0a 0a 20 20 20 20 40 61 70 70 2e 72 6f 75 74 65  ..    @app.route
1f60: 28 22 2f 73 65 74 5f 6f 70 74 69 6f 6e 73 2f 66  ("/set_options/f
1f70: 72 22 2c 20 6d 65 74 68 6f 64 3d 22 50 4f 53 54  r", method="POST
1f80: 22 29 0a 20 20 20 20 64 65 66 20 73 65 74 4f 70  ").    def setOp
1f90: 74 69 6f 6e 73 20 28 29 3a 0a 20 20 20 20 20 20  tions ():.      
1fa0: 20 20 69 66 20 72 65 71 75 65 73 74 2e 66 6f 72    if request.for
1fb0: 6d 73 2e 6f 70 74 69 6f 6e 73 3a 0a 20 20 20 20  ms.options:.    
1fc0: 20 20 20 20 20 20 20 20 73 55 73 65 72 49 64 20          sUserId 
1fd0: 3d 20 72 65 71 75 65 73 74 2e 63 6f 6f 6b 69 65  = request.cookie
1fe0: 73 2e 75 73 65 72 5f 69 64 20 20 69 66 20 72 65  s.user_id  if re
1ff0: 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73  quest.cookies.us
2000: 65 72 5f 69 64 20 20 65 6c 73 65 20 6e 65 78 74  er_id  else next
2010: 28 75 73 65 72 47 65 6e 65 72 61 74 6f 72 29 0a  (userGenerator).
2020: 20 20 20 20 20 20 20 20 20 20 20 20 64 4f 70 74              dOpt
2030: 69 6f 6e 73 20 3d 20 64 55 73 65 72 5b 73 55 73  ions = dUser[sUs
2040: 65 72 49 64 5d 5b 22 67 63 5f 6f 70 74 69 6f 6e  erId]["gc_option
2050: 73 22 5d 20 20 69 66 20 73 55 73 65 72 49 64 20  s"]  if sUserId 
2060: 69 6e 20 64 55 73 65 72 20 20 65 6c 73 65 20 64  in dUser  else d
2070: 69 63 74 28 64 53 65 72 76 65 72 47 43 4f 70 74  ict(dServerGCOpt
2080: 69 6f 6e 73 29 0a 20 20 20 20 20 20 20 20 20 20  ions).          
2090: 20 20 74 72 79 3a 0a 20 20 20 20 20 20 20 20 20    try:.         
20a0: 20 20 20 20 20 20 20 64 4f 70 74 69 6f 6e 73 2e         dOptions.
20b0: 75 70 64 61 74 65 28 6a 73 6f 6e 2e 6c 6f 61 64  update(json.load
20c0: 73 28 72 65 71 75 65 73 74 2e 66 6f 72 6d 73 2e  s(request.forms.
20d0: 6f 70 74 69 6f 6e 73 29 29 0a 20 20 20 20 20 20  options)).      
20e0: 20 20 20 20 20 20 20 20 20 20 64 55 73 65 72 5b            dUser[
20f0: 73 55 73 65 72 49 64 5d 20 3d 20 7b 20 22 74 69  sUserId] = { "ti
2100: 6d 65 22 3a 20 69 6e 74 28 74 69 6d 65 2e 74 69  me": int(time.ti
2110: 6d 65 28 29 29 2c 20 22 67 63 5f 6f 70 74 69 6f  me()), "gc_optio
2120: 6e 73 22 3a 20 64 4f 70 74 69 6f 6e 73 20 7d 0a  ns": dOptions }.
2130: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
2140: 72 65 73 70 6f 6e 73 65 2e 73 65 74 5f 63 6f 6f  response.set_coo
2150: 6b 69 65 28 22 75 73 65 72 5f 69 64 22 2c 20 73  kie("user_id", s
2160: 55 73 65 72 49 64 2c 20 70 61 74 68 3d 22 2f 22  UserId, path="/"
2170: 2c 20 6d 61 78 5f 61 67 65 3d 38 36 34 30 30 29  , max_age=86400)
2180: 20 23 20 32 34 68 0a 20 20 20 20 20 20 20 20 20   # 24h.         
2190: 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 6a 73         return js
21a0: 6f 6e 2e 64 75 6d 70 73 28 64 55 73 65 72 5b 73  on.dumps(dUser[s
21b0: 55 73 65 72 49 64 5d 5b 22 67 63 5f 6f 70 74 69  UserId]["gc_opti
21c0: 6f 6e 73 22 5d 29 0a 20 20 20 20 20 20 20 20 20  ons"]).         
21d0: 20 20 20 65 78 63 65 70 74 3a 0a 20 20 20 20 20     except:.     
21e0: 20 20 20 20 20 20 20 20 20 20 20 74 72 61 63 65             trace
21f0: 62 61 63 6b 2e 70 72 69 6e 74 5f 65 78 63 28 29  back.print_exc()
2200: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
2210: 20 72 65 74 75 72 6e 20 27 7b 22 65 72 72 6f 72   return '{"error
2220: 22 3a 20 22 6f 70 74 69 6f 6e 73 20 6e 6f 74 20  ": "options not 
2230: 72 65 67 69 73 74 65 72 65 64 22 7d 27 0a 20 20  registered"}'.  
2240: 20 20 20 20 20 20 72 65 74 75 72 6e 20 27 7b 22        return '{"
2250: 65 72 72 6f 72 22 3a 20 22 6e 6f 20 6f 70 74 69  error": "no opti
2260: 6f 6e 73 20 72 65 63 65 69 76 65 64 22 7d 27 0a  ons received"}'.
2270: 0a 20 20 20 20 40 61 70 70 2e 72 6f 75 74 65 28  .    @app.route(
2280: 22 2f 72 65 73 65 74 5f 6f 70 74 69 6f 6e 73 2f  "/reset_options/
2290: 66 72 22 2c 20 6d 65 74 68 6f 64 3d 22 50 4f 53  fr", method="POS
22a0: 54 22 29 0a 20 20 20 20 64 65 66 20 72 65 73 65  T").    def rese
22b0: 74 4f 70 74 69 6f 6e 73 20 28 29 3a 0a 20 20 20  tOptions ():.   
22c0: 20 20 20 20 20 69 66 20 72 65 71 75 65 73 74 2e       if request.
22d0: 63 6f 6f 6b 69 65 73 2e 75 73 65 72 5f 69 64 20  cookies.user_id 
22e0: 61 6e 64 20 72 65 71 75 65 73 74 2e 63 6f 6f 6b  and request.cook
22f0: 69 65 73 2e 75 73 65 72 5f 69 64 20 69 6e 20 64  ies.user_id in d
2300: 55 73 65 72 3a 0a 20 20 20 20 20 20 20 20 20 20  User:.          
2310: 20 20 64 65 6c 20 64 55 73 65 72 5b 72 65 71 75    del dUser[requ
2320: 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72  est.cookies.user
2330: 5f 69 64 5d 0a 20 20 20 20 20 20 20 20 72 65 74  _id].        ret
2340: 75 72 6e 20 22 64 6f 6e 65 22 0a 0a 20 20 20 20  urn "done"..    
2350: 40 61 70 70 2e 72 6f 75 74 65 28 22 2f 66 6f 72  @app.route("/for
2360: 6d 61 74 5f 74 65 78 74 2f 66 72 22 2c 20 6d 65  mat_text/fr", me
2370: 74 68 6f 64 3d 22 50 4f 53 54 22 29 0a 20 20 20  thod="POST").   
2380: 20 64 65 66 20 66 6f 72 6d 61 74 54 65 78 74 20   def formatText 
2390: 28 29 3a 0a 20 20 20 20 20 20 20 20 72 65 74 75  ():.        retu
23a0: 72 6e 20 6f 54 46 2e 66 6f 72 6d 61 74 54 65 78  rn oTF.formatTex
23b0: 74 28 72 65 71 75 65 73 74 2e 66 6f 72 6d 73 2e  t(request.forms.
23c0: 74 65 78 74 29 0a 0a 20 20 20 20 23 40 61 70 70  text)..    #@app
23d0: 2e 72 6f 75 74 65 28 27 2f 73 74 61 74 69 63 2f  .route('/static/
23e0: 3c 66 69 6c 65 70 61 74 68 3a 70 61 74 68 3e 27  <filepath:path>'
23f0: 29 0a 20 20 20 20 23 64 65 66 20 73 65 72 76 65  ).    #def serve
2400: 72 5f 73 74 61 74 69 63 20 28 66 69 6c 65 70 61  r_static (filepa
2410: 74 68 29 3a 0a 20 20 20 20 23 20 20 20 20 72 65  th):.    #    re
2420: 74 75 72 6e 20 73 74 61 74 69 63 5f 66 69 6c 65  turn static_file
2430: 28 66 69 6c 65 70 61 74 68 2c 20 72 6f 6f 74 3d  (filepath, root=
2440: 27 2e 2f 76 69 65 77 73 2f 73 74 61 74 69 63 27  './views/static'
2450: 29 0a 0a 20 20 20 20 40 61 70 70 2e 72 6f 75 74  )..    @app.rout
2460: 65 28 22 2f 70 75 72 67 65 5f 75 73 65 72 73 22  e("/purge_users"
2470: 2c 20 6d 65 74 68 6f 64 3d 22 50 4f 53 54 22 29  , method="POST")
2480: 0a 20 20 20 20 64 65 66 20 70 75 72 67 65 55 73  .    def purgeUs
2490: 65 72 73 20 28 29 3a 0a 20 20 20 20 20 20 20 20  ers ():.        
24a0: 22 64 65 6c 65 74 65 20 75 73 65 72 20 6f 70 74  "delete user opt
24b0: 69 6f 6e 73 20 6f 6c 64 65 72 20 74 68 61 6e 20  ions older than 
24c0: 6e 20 68 6f 75 72 73 22 0a 20 20 20 20 20 20 20  n hours".       
24d0: 20 69 66 20 6e 6f 74 20 72 65 71 75 65 73 74 2e   if not request.
24e0: 66 6f 72 6d 73 2e 70 61 73 73 77 6f 72 64 20 6f  forms.password o
24f0: 72 20 22 70 61 73 73 77 6f 72 64 22 20 6e 6f 74  r "password" not
2500: 20 69 6e 20 64 53 65 72 76 65 72 4f 70 74 69 6f   in dServerOptio
2510: 6e 73 20 6f 72 20 6e 6f 74 20 72 65 71 75 65 73  ns or not reques
2520: 74 2e 66 6f 72 6d 73 2e 68 6f 75 72 73 3a 0a 20  t.forms.hours:. 
2530: 20 20 20 20 20 20 20 20 20 20 20 72 65 74 75 72             retur
2540: 6e 20 22 77 68 61 74 3f 22 0a 20 20 20 20 20 20  n "what?".      
2550: 20 20 74 72 79 3a 0a 20 20 20 20 20 20 20 20 20    try:.         
2560: 20 20 20 69 66 20 72 65 71 75 65 73 74 2e 66 6f     if request.fo
2570: 72 6d 73 2e 70 61 73 73 77 6f 72 64 20 3d 3d 20  rms.password == 
2580: 64 53 65 72 76 65 72 4f 70 74 69 6f 6e 73 5b 22  dServerOptions["
2590: 70 61 73 73 77 6f 72 64 22 5d 3a 0a 20 20 20 20  password"]:.    
25a0: 20 20 20 20 20 20 20 20 20 20 20 20 6e 4e 6f 77              nNow
25b0: 4d 69 6e 75 73 4e 48 6f 75 72 73 20 3d 20 69 6e  MinusNHours = in
25c0: 74 28 74 69 6d 65 2e 74 69 6d 65 28 29 29 20 2d  t(time.time()) -
25d0: 20 28 69 6e 74 28 72 65 71 75 65 73 74 2e 66 6f   (int(request.fo
25e0: 72 6d 73 2e 68 6f 75 72 73 29 20 2a 20 36 30 20  rms.hours) * 60 
25f0: 2a 20 36 30 29 0a 20 20 20 20 20 20 20 20 20 20  * 60).          
2600: 20 20 20 20 20 20 66 6f 72 20 6e 55 73 65 72 49        for nUserI
2610: 64 2c 20 64 56 61 6c 75 65 20 69 6e 20 64 55 73  d, dValue in dUs
2620: 65 72 2e 69 74 65 6d 73 28 29 3a 0a 20 20 20 20  er.items():.    
2630: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
2640: 69 66 20 64 56 61 6c 75 65 5b 22 74 69 6d 65 22  if dValue["time"
2650: 5d 20 3c 20 6e 4e 6f 77 4d 69 6e 75 73 4e 48 6f  ] < nNowMinusNHo
2660: 75 72 73 3a 0a 20 20 20 20 20 20 20 20 20 20 20  urs:.           
2670: 20 20 20 20 20 20 20 20 20 20 20 20 20 64 65 6c               del
2680: 20 64 55 73 65 72 5b 6e 55 73 65 72 49 64 5d 0a   dUser[nUserId].
2690: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
26a0: 72 65 74 75 72 6e 20 22 64 6f 6e 65 22 0a 20 20  return "done".  
26b0: 20 20 20 20 20 20 20 20 20 20 65 6c 73 65 3a 0a            else:.
26c0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
26d0: 72 65 74 75 72 6e 20 22 6e 6f 22 0a 20 20 20 20  return "no".    
26e0: 20 20 20 20 65 78 63 65 70 74 3a 0a 20 20 20 20      except:.    
26f0: 20 20 20 20 20 20 20 20 74 72 61 63 65 62 61 63          tracebac
2700: 6b 2e 70 72 69 6e 74 5f 65 78 63 28 29 0a 20 20  k.print_exc().  
2710: 20 20 20 20 20 20 20 20 20 20 72 65 74 75 72 6e            return
2720: 20 22 65 72 72 6f 72 22 0a 0a 20 20 20 20 23 20   "error"..    # 
2730: 45 52 52 4f 52 0a 20 20 20 20 40 61 70 70 2e 65  ERROR.    @app.e
2740: 72 72 6f 72 28 34 30 34 29 0a 20 20 20 20 64 65  rror(404).    de
2750: 66 20 65 72 72 6f 72 34 30 34 20 28 65 72 72 6f  f error404 (erro
2760: 72 29 3a 0a 20 20 20 20 20 20 20 20 72 65 74 75  r):.        retu
2770: 72 6e 20 27 45 72 72 6f 72 20 34 30 34 2e 3c 62  rn 'Error 404.<b
2780: 72 2f 3e 27 20 2b 20 73 74 72 28 65 72 72 6f 72  r/>' + str(error
2790: 29 0a 0a 20 20 20 20 72 75 6e 28 61 70 70 2c 20  )..    run(app, 
27a0: 5c 0a 20 20 20 20 20 20 20 20 68 6f 73 74 3d 64  \.        host=d
27b0: 53 65 72 76 65 72 4f 70 74 69 6f 6e 73 2e 67 65  ServerOptions.ge
27c0: 74 28 27 68 6f 73 74 27 2c 20 27 6c 6f 63 61 6c  t('host', 'local
27d0: 68 6f 73 74 27 29 2c 20 5c 0a 20 20 20 20 20 20  host'), \.      
27e0: 20 20 70 6f 72 74 3d 69 6e 74 28 64 53 65 72 76    port=int(dServ
27f0: 65 72 4f 70 74 69 6f 6e 73 2e 67 65 74 28 27 70  erOptions.get('p
2800: 6f 72 74 27 2c 20 38 30 38 30 29 29 29 0a        ort', 8080))).