Grammalecte  Hex Artifact Content

Artifact 480fbbc03c992f68b95fb36718adc9ba0cb6c26b458a06d8dbcc66965734df13:


0000: 20 23 21 2f 75 73 72 2f 62 69 6e 2f 65 6e 76 20   #!/usr/bin/env 
0010: 70 79 74 68 6f 6e 33 0a 0a 22 22 22 0a 47 72 61  python3..""".Gra
0020: 6d 6d 61 6c 65 63 74 65 20 73 65 72 76 65 72 3a  mmalecte server:
0030: 20 67 72 61 6d 6d 61 72 20 63 68 65 63 6b 65 72   grammar checker
0040: 0a 22 22 22 0a 0a 69 6d 70 6f 72 74 20 73 79 73  ."""..import sys
0050: 0a 69 6d 70 6f 72 74 20 61 72 67 70 61 72 73 65  .import argparse
0060: 0a 69 6d 70 6f 72 74 20 6a 73 6f 6e 0a 69 6d 70  .import json.imp
0070: 6f 72 74 20 74 72 61 63 65 62 61 63 6b 0a 69 6d  ort traceback.im
0080: 70 6f 72 74 20 74 69 6d 65 0a 69 6d 70 6f 72 74  port time.import
0090: 20 6f 73 0a 69 6d 70 6f 72 74 20 63 6f 6e 63 75   os.import concu
00a0: 72 72 65 6e 74 2e 66 75 74 75 72 65 73 0a 0a 66  rrent.futures..f
00b0: 72 6f 6d 20 67 72 61 6d 6d 61 6c 65 63 74 65 2e  rom grammalecte.
00c0: 62 6f 74 74 6c 65 20 69 6d 70 6f 72 74 20 42 6f  bottle import Bo
00d0: 74 74 6c 65 2c 20 72 75 6e 2c 20 72 65 71 75 65  ttle, run, reque
00e0: 73 74 2c 20 72 65 73 70 6f 6e 73 65 20 23 2c 20  st, response #, 
00f0: 74 65 6d 70 6c 61 74 65 2c 20 73 74 61 74 69 63  template, static
0100: 5f 66 69 6c 65 0a 0a 69 6d 70 6f 72 74 20 67 72  _file..import gr
0110: 61 6d 6d 61 6c 65 63 74 65 0a 69 6d 70 6f 72 74  ammalecte.import
0120: 20 67 72 61 6d 6d 61 6c 65 63 74 65 2e 74 65 78   grammalecte.tex
0130: 74 20 61 73 20 74 78 74 0a 66 72 6f 6d 20 67 72  t as txt.from gr
0140: 61 6d 6d 61 6c 65 63 74 65 2e 67 72 61 70 68 73  ammalecte.graphs
0150: 70 65 6c 6c 2e 65 63 68 6f 20 69 6d 70 6f 72 74  pell.echo import
0160: 20 65 63 68 6f 0a 0a 0a 23 23 23 23 20 47 52 41   echo...#### GRA
0170: 4d 4d 41 52 20 43 48 45 43 4b 45 52 20 23 23 23  MMAR CHECKER ###
0180: 23 0a 0a 6f 47 72 61 6d 6d 61 72 43 68 65 63 6b  #..oGrammarCheck
0190: 65 72 20 3d 20 67 72 61 6d 6d 61 6c 65 63 74 65  er = grammalecte
01a0: 2e 47 72 61 6d 6d 61 72 43 68 65 63 6b 65 72 28  .GrammarChecker(
01b0: 22 66 72 22 2c 20 22 53 65 72 76 65 72 22 29 0a  "fr", "Server").
01c0: 6f 53 70 65 6c 6c 43 68 65 63 6b 65 72 20 3d 20  oSpellChecker = 
01d0: 6f 47 72 61 6d 6d 61 72 43 68 65 63 6b 65 72 2e  oGrammarChecker.
01e0: 67 65 74 53 70 65 6c 6c 43 68 65 63 6b 65 72 28  getSpellChecker(
01f0: 29 0a 6f 54 65 78 74 46 6f 72 6d 61 74 74 65 72  ).oTextFormatter
0200: 20 3d 20 6f 47 72 61 6d 6d 61 72 43 68 65 63 6b   = oGrammarCheck
0210: 65 72 2e 67 65 74 54 65 78 74 46 6f 72 6d 61 74  er.getTextFormat
0220: 74 65 72 28 29 0a 6f 47 43 45 20 3d 20 6f 47 72  ter().oGCE = oGr
0230: 61 6d 6d 61 72 43 68 65 63 6b 65 72 2e 67 65 74  ammarChecker.get
0240: 47 43 45 6e 67 69 6e 65 28 29 0a 0a 0a 64 65 66  GCEngine()...def
0250: 20 70 61 72 73 65 54 65 78 74 20 28 73 54 65 78   parseText (sTex
0260: 74 2c 20 64 4f 70 74 69 6f 6e 73 3d 4e 6f 6e 65  t, dOptions=None
0270: 2c 20 62 46 6f 72 6d 61 74 54 65 78 74 3d 46 61  , bFormatText=Fa
0280: 6c 73 65 2c 20 73 45 72 72 6f 72 3d 22 22 29 3a  lse, sError=""):
0290: 0a 20 20 20 20 22 70 61 72 73 65 20 3c 73 54 65  .    "parse <sTe
02a0: 78 74 3e 20 61 6e 64 20 72 65 74 75 72 6e 20 65  xt> and return e
02b0: 72 72 6f 72 73 20 69 6e 20 61 20 4a 53 4f 4e 20  rrors in a JSON 
02c0: 66 6f 72 6d 61 74 22 0a 20 20 20 20 73 4a 53 4f  format".    sJSO
02d0: 4e 20 3d 20 27 7b 20 22 70 72 6f 67 72 61 6d 22  N = '{ "program"
02e0: 3a 20 22 67 72 61 6d 6d 61 6c 65 63 74 65 2d 66  : "grammalecte-f
02f0: 72 22 2c 20 22 76 65 72 73 69 6f 6e 22 3a 20 22  r", "version": "
0300: 27 2b 6f 47 43 45 2e 76 65 72 73 69 6f 6e 2b 27  '+oGCE.version+'
0310: 22 2c 20 22 6c 61 6e 67 22 3a 20 22 27 2b 6f 47  ", "lang": "'+oG
0320: 43 45 2e 6c 61 6e 67 2b 27 22 2c 20 22 65 72 72  CE.lang+'", "err
0330: 6f 72 22 3a 20 22 27 2b 73 45 72 72 6f 72 2b 27  or": "'+sError+'
0340: 22 2c 20 22 64 61 74 61 22 20 3a 20 5b 5c 6e 27  ", "data" : [\n'
0350: 0a 20 20 20 20 73 44 61 74 61 4a 53 4f 4e 20 3d  .    sDataJSON =
0360: 20 22 22 0a 20 20 20 20 66 6f 72 20 69 2c 20 73   "".    for i, s
0370: 50 61 72 61 67 72 61 70 68 20 69 6e 20 65 6e 75  Paragraph in enu
0380: 6d 65 72 61 74 65 28 74 78 74 2e 67 65 74 50 61  merate(txt.getPa
0390: 72 61 67 72 61 70 68 28 73 54 65 78 74 29 2c 20  ragraph(sText), 
03a0: 31 29 3a 0a 20 20 20 20 20 20 20 20 69 66 20 62  1):.        if b
03b0: 46 6f 72 6d 61 74 54 65 78 74 3a 0a 20 20 20 20  FormatText:.    
03c0: 20 20 20 20 20 20 20 20 73 50 61 72 61 67 72 61          sParagra
03d0: 70 68 20 3d 20 6f 54 65 78 74 46 6f 72 6d 61 74  ph = oTextFormat
03e0: 74 65 72 2e 66 6f 72 6d 61 74 54 65 78 74 28 73  ter.formatText(s
03f0: 50 61 72 61 67 72 61 70 68 29 0a 20 20 20 20 20  Paragraph).     
0400: 20 20 20 73 52 65 73 75 6c 74 20 3d 20 6f 47 72     sResult = oGr
0410: 61 6d 6d 61 72 43 68 65 63 6b 65 72 2e 67 65 74  ammarChecker.get
0420: 50 61 72 61 67 72 61 70 68 45 72 72 6f 72 73 41  ParagraphErrorsA
0430: 73 4a 53 4f 4e 28 69 2c 20 73 50 61 72 61 67 72  sJSON(i, sParagr
0440: 61 70 68 2c 20 64 4f 70 74 69 6f 6e 73 3d 64 4f  aph, dOptions=dO
0450: 70 74 69 6f 6e 73 2c 20 62 45 6d 70 74 79 49 66  ptions, bEmptyIf
0460: 4e 6f 45 72 72 6f 72 73 3d 54 72 75 65 2c 20 62  NoErrors=True, b
0470: 52 65 74 75 72 6e 54 65 78 74 3d 62 46 6f 72 6d  ReturnText=bForm
0480: 61 74 54 65 78 74 29 0a 20 20 20 20 20 20 20 20  atText).        
0490: 69 66 20 73 52 65 73 75 6c 74 3a 0a 20 20 20 20  if sResult:.    
04a0: 20 20 20 20 20 20 20 20 69 66 20 73 44 61 74 61          if sData
04b0: 4a 53 4f 4e 3a 0a 20 20 20 20 20 20 20 20 20 20  JSON:.          
04c0: 20 20 20 20 20 20 73 44 61 74 61 4a 53 4f 4e 20        sDataJSON 
04d0: 2b 3d 20 22 2c 5c 6e 22 0a 20 20 20 20 20 20 20  += ",\n".       
04e0: 20 20 20 20 20 73 44 61 74 61 4a 53 4f 4e 20 2b       sDataJSON +
04f0: 3d 20 73 52 65 73 75 6c 74 0a 20 20 20 20 73 4a  = sResult.    sJ
0500: 53 4f 4e 20 2b 3d 20 73 44 61 74 61 4a 53 4f 4e  SON += sDataJSON
0510: 20 2b 20 22 5c 6e 5d 7d 5c 6e 22 0a 20 20 20 20   + "\n]}\n".    
0520: 72 65 74 75 72 6e 20 73 4a 53 4f 4e 0a 0a 0a 64  return sJSON...d
0530: 65 66 20 73 75 67 67 65 73 74 20 28 73 54 6f 6b  ef suggest (sTok
0540: 65 6e 29 3a 0a 20 20 20 20 22 67 65 74 20 73 70  en):.    "get sp
0550: 65 6c 6c 69 6e 67 20 73 75 67 67 65 73 74 69 6f  elling suggestio
0560: 6e 73 20 66 6f 72 20 3c 73 54 6f 6b 65 6e 3e 20  ns for <sToken> 
0570: 61 6e 64 20 72 65 74 75 72 6e 20 74 68 65 6d 20  and return them 
0580: 69 6e 20 61 20 4a 53 4f 4e 20 66 6f 72 6d 61 74  in a JSON format
0590: 22 0a 20 20 20 20 69 66 20 73 54 6f 6b 65 6e 3a  ".    if sToken:
05a0: 0a 20 20 20 20 20 20 20 20 6c 53 75 67 67 20 3d  .        lSugg =
05b0: 20 5b 5d 0a 20 20 20 20 20 20 20 20 74 72 79 3a   [].        try:
05c0: 0a 20 20 20 20 20 20 20 20 20 20 20 20 66 6f 72  .            for
05d0: 20 6c 20 69 6e 20 6f 53 70 65 6c 6c 43 68 65 63   l in oSpellChec
05e0: 6b 65 72 2e 73 75 67 67 65 73 74 28 73 54 6f 6b  ker.suggest(sTok
05f0: 65 6e 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20  en):.           
0600: 20 20 20 20 20 6c 53 75 67 67 2e 65 78 74 65 6e       lSugg.exten
0610: 64 28 6c 29 0a 20 20 20 20 20 20 20 20 65 78 63  d(l).        exc
0620: 65 70 74 3a 0a 20 20 20 20 20 20 20 20 20 20 20  ept:.           
0630: 20 72 65 74 75 72 6e 20 27 7b 22 65 72 72 6f 72   return '{"error
0640: 22 3a 20 22 73 75 67 67 65 73 74 69 6f 6e 20 6d  ": "suggestion m
0650: 6f 64 75 6c 65 20 66 61 69 6c 65 64 22 7d 27 0a  odule failed"}'.
0660: 20 20 20 20 20 20 20 20 74 72 79 3a 0a 20 20 20          try:.   
0670: 20 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20           return 
0680: 27 7b 22 73 75 67 67 65 73 74 69 6f 6e 73 22 3a  '{"suggestions":
0690: 20 27 20 2b 20 6a 73 6f 6e 2e 64 75 6d 70 73 28   ' + json.dumps(
06a0: 6c 53 75 67 67 2c 20 65 6e 73 75 72 65 5f 61 73  lSugg, ensure_as
06b0: 63 69 69 3d 46 61 6c 73 65 29 20 2b 20 27 7d 27  cii=False) + '}'
06c0: 0a 20 20 20 20 20 20 20 20 65 78 63 65 70 74 20  .        except 
06d0: 6a 73 6f 6e 2e 4a 53 4f 4e 44 65 63 6f 64 65 45  json.JSONDecodeE
06e0: 72 72 6f 72 3a 0a 20 20 20 20 20 20 20 20 20 20  rror:.          
06f0: 20 20 72 65 74 75 72 6e 20 27 7b 22 65 72 72 6f    return '{"erro
0700: 72 22 3a 20 22 6a 73 6f 6e 20 65 6e 63 6f 64 69  r": "json encodi
0710: 6e 67 20 65 72 72 6f 72 22 7d 27 0a 20 20 20 20  ng error"}'.    
0720: 72 65 74 75 72 6e 20 27 7b 22 65 72 72 6f 72 22  return '{"error"
0730: 3a 20 22 6e 6f 20 74 6f 6b 65 6e 20 67 69 76 65  : "no token give
0740: 6e 22 7d 27 0a 0a 0a 23 23 23 23 20 50 52 4f 43  n"}'...#### PROC
0750: 45 53 53 20 50 4f 4f 4c 20 45 58 45 43 55 54 4f  ESS POOL EXECUTO
0760: 52 20 23 23 23 23 0a 78 50 72 6f 63 65 73 73 50  R ####.xProcessP
0770: 6f 6f 6c 45 78 65 63 75 74 6f 72 20 3d 20 4e 6f  oolExecutor = No
0780: 6e 65 0a 0a 64 65 66 20 69 6e 69 74 45 78 65 63  ne..def initExec
0790: 75 74 6f 72 20 28 6e 4d 75 6c 74 69 43 50 55 3d  utor (nMultiCPU=
07a0: 4e 6f 6e 65 29 3a 0a 20 20 20 20 22 70 72 6f 63  None):.    "proc
07b0: 65 73 73 20 70 6f 6f 6c 20 65 78 65 63 75 74 6f  ess pool executo
07c0: 72 20 69 6e 69 74 69 61 6c 69 73 61 74 69 6f 6e  r initialisation
07d0: 22 0a 20 20 20 20 67 6c 6f 62 61 6c 20 78 50 72  ".    global xPr
07e0: 6f 63 65 73 73 50 6f 6f 6c 45 78 65 63 75 74 6f  ocessPoolExecuto
07f0: 72 0a 20 20 20 20 69 66 20 78 50 72 6f 63 65 73  r.    if xProces
0800: 73 50 6f 6f 6c 45 78 65 63 75 74 6f 72 3a 0a 20  sPoolExecutor:. 
0810: 20 20 20 20 20 20 20 23 20 77 65 20 73 68 75 74         # we shut
0820: 64 6f 77 6e 20 74 68 65 20 50 72 6f 63 65 73 73  down the Process
0830: 50 6f 6f 6c 45 78 65 63 75 74 6f 72 20 77 68 69  PoolExecutor whi
0840: 63 68 20 6d 61 79 20 68 61 76 65 20 62 65 65 6e  ch may have been
0850: 20 6c 61 75 6e 63 68 65 64 20 70 72 65 76 69 6f   launched previo
0860: 75 73 6c 79 0a 20 20 20 20 20 20 20 20 70 72 69  usly.        pri
0870: 6e 74 28 22 50 72 6f 63 65 73 73 50 6f 6f 6c 45  nt("ProcessPoolE
0880: 78 65 63 75 74 6f 72 20 73 68 75 74 64 6f 77 6e  xecutor shutdown
0890: 2e 22 29 0a 20 20 20 20 20 20 20 20 78 50 72 6f  .").        xPro
08a0: 63 65 73 73 50 6f 6f 6c 45 78 65 63 75 74 6f 72  cessPoolExecutor
08b0: 2e 73 68 75 74 64 6f 77 6e 28 77 61 69 74 3d 46  .shutdown(wait=F
08c0: 61 6c 73 65 29 0a 20 20 20 20 6e 4d 61 78 43 50  alse).    nMaxCP
08d0: 55 20 3d 20 6d 61 78 28 6f 73 2e 63 70 75 5f 63  U = max(os.cpu_c
08e0: 6f 75 6e 74 28 29 2d 31 2c 20 31 29 0a 20 20 20  ount()-1, 1).   
08f0: 20 69 66 20 6e 4d 75 6c 74 69 43 50 55 20 69 73   if nMultiCPU is
0900: 20 4e 6f 6e 65 20 6f 72 20 6e 6f 74 20 28 31 20   None or not (1 
0910: 3c 3d 20 6e 4d 75 6c 74 69 43 50 55 20 3c 3d 20  <= nMultiCPU <= 
0920: 6e 4d 61 78 43 50 55 29 3a 0a 20 20 20 20 20 20  nMaxCPU):.      
0930: 20 20 6e 4d 75 6c 74 69 43 50 55 20 3d 20 6e 4d    nMultiCPU = nM
0940: 61 78 43 50 55 0a 20 20 20 20 70 72 69 6e 74 28  axCPU.    print(
0950: 22 43 50 55 20 70 72 6f 63 65 73 73 65 73 20 75  "CPU processes u
0960: 73 65 64 20 66 6f 72 20 77 6f 72 6b 65 72 73 3a  sed for workers:
0970: 20 22 2c 20 6e 4d 75 6c 74 69 43 50 55 29 0a 20   ", nMultiCPU). 
0980: 20 20 20 78 50 72 6f 63 65 73 73 50 6f 6f 6c 45     xProcessPoolE
0990: 78 65 63 75 74 6f 72 20 3d 20 63 6f 6e 63 75 72  xecutor = concur
09a0: 72 65 6e 74 2e 66 75 74 75 72 65 73 2e 50 72 6f  rent.futures.Pro
09b0: 63 65 73 73 50 6f 6f 6c 45 78 65 63 75 74 6f 72  cessPoolExecutor
09c0: 28 6d 61 78 5f 77 6f 72 6b 65 72 73 3d 6e 4d 75  (max_workers=nMu
09d0: 6c 74 69 43 50 55 29 0a 0a 0a 23 23 23 23 20 53  ltiCPU)...#### S
09e0: 45 52 56 45 55 52 20 23 23 23 23 0a 0a 48 4f 4d  ERVEUR ####..HOM
09f0: 45 50 41 47 45 20 3d 20 22 22 22 0a 3c 21 44 4f  EPAGE = """.<!DO
0a00: 43 54 59 50 45 20 48 54 4d 4c 3e 0a 3c 68 74 6d  CTYPE HTML>.<htm
0a10: 6c 3e 0a 20 20 20 20 3c 68 65 61 64 3e 0a 20 20  l>.    <head>.  
0a20: 20 20 20 20 20 20 3c 6d 65 74 61 20 68 74 74 70        <meta http
0a30: 2d 65 71 75 69 76 3d 22 63 6f 6e 74 65 6e 74 2d  -equiv="content-
0a40: 74 79 70 65 22 20 63 6f 6e 74 65 6e 74 3d 22 74  type" content="t
0a50: 65 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65  ext/html; charse
0a60: 74 3d 55 54 46 2d 38 22 20 2f 3e 0a 20 20 20 20  t=UTF-8" />.    
0a70: 3c 2f 68 65 61 64 3e 0a 0a 20 20 20 20 3c 62 6f  </head>..    <bo
0a80: 64 79 20 63 6c 61 73 73 3d 22 70 61 6e 65 6c 22  dy class="panel"
0a90: 3e 0a 20 20 20 20 20 20 20 20 3c 68 31 3e 47 72  >.        <h1>Gr
0aa0: 61 6d 6d 61 6c 65 63 74 65 20 c2 b7 20 53 65 72  ammalecte .. Ser
0ab0: 76 65 75 72 3c 2f 68 31 3e 0a 0a 20 20 20 20 20  veur</h1>..     
0ac0: 20 20 20 3c 68 32 3e 49 4e 46 4f 52 4d 41 54 49     <h2>INFORMATI
0ad0: 4f 4e 53 3c 2f 68 31 3e 0a 0a 20 20 20 20 20 20  ONS</h1>..      
0ae0: 20 20 3c 68 33 3e 41 6e 61 6c 79 73 65 72 20 64    <h3>Analyser d
0af0: 75 20 74 65 78 74 65 3c 2f 68 33 3e 0a 20 20 20  u texte</h3>.   
0b00: 20 20 20 20 20 3c 70 3e 5b 61 64 72 65 73 73 65       <p>[adresse
0b10: 5f 73 65 72 76 65 75 72 5d 3a 7b 53 45 52 56 45  _serveur]:{SERVE
0b20: 52 5f 50 4f 52 54 7d 2f 67 63 5f 74 65 78 74 2f  R_PORT}/gc_text/
0b30: 66 72 20 28 50 4f 53 54 29 3c 2f 70 3e 0a 20 20  fr (POST)</p>.  
0b40: 20 20 20 20 20 20 3c 70 3e 50 61 72 61 6d c3 a8        <p>Param..
0b50: 74 72 65 73 20 3a 3c 2f 70 3e 0a 20 20 20 20 20  tres :</p>.     
0b60: 20 20 20 3c 75 6c 3e 0a 20 20 20 20 20 20 20 20     <ul>.        
0b70: 20 20 20 20 3c 6c 69 3e 22 74 65 78 74 22 20 28      <li>"text" (
0b80: 74 65 78 74 29 26 6e 62 73 70 3b 3a 20 74 65 78  text)&nbsp;: tex
0b90: 74 65 20 c3 a0 20 61 6e 61 6c 79 73 65 72 2e 3c  te .. analyser.<
0ba0: 2f 6c 69 3e 0a 20 20 20 20 20 20 20 20 20 20 20  /li>.           
0bb0: 20 3c 6c 69 3e 22 74 66 22 20 28 63 68 65 63 6b   <li>"tf" (check
0bc0: 62 6f 78 29 26 6e 62 73 70 3b 3a 20 70 61 73 73  box)&nbsp;: pass
0bd0: 65 72 20 6c 65 20 66 6f 72 6d 61 74 65 75 72 20  er le formateur 
0be0: 64 65 20 74 65 78 74 65 20 61 76 61 6e 74 20 6c  de texte avant l
0bf0: e2 80 99 61 6e 61 6c 79 73 65 2e 3c 2f 6c 69 3e  ...analyse.</li>
0c00: 0a 20 20 20 20 20 20 20 20 20 20 20 20 3c 6c 69  .            <li
0c10: 3e 22 6f 70 74 69 6f 6e 73 22 20 28 74 65 78 74  >"options" (text
0c20: 29 26 6e 62 73 70 3b 3a 20 75 6e 65 20 63 68 61  )&nbsp;: une cha
0c30: c3 ae 6e 65 20 61 75 20 66 6f 72 6d 61 74 20 4a  ..ne au format J
0c40: 53 4f 4e 20 61 76 65 63 20 6c 65 20 6e 6f 6d 20  SON avec le nom 
0c50: 64 65 73 20 6f 70 74 69 6f 6e 73 20 63 6f 6d 6d  des options comm
0c60: 65 20 61 74 74 72 69 62 75 74 73 20 65 74 20 75  e attributs et u
0c70: 6e 20 62 6f 6f 6c c3 a9 65 6e 20 63 6f 6d 6d 65  n bool..en comme
0c80: 20 76 61 6c 65 75 72 2e 20 45 78 65 6d 70 6c 65   valeur. Exemple
0c90: 26 6e 62 73 70 3b 3a 20 7b 22 67 76 22 3a 20 74  &nbsp;: {"gv": t
0ca0: 72 75 65 2c 20 22 68 74 6d 6c 22 3a 20 74 72 75  rue, "html": tru
0cb0: 65 7d 3c 2f 6c 69 3e 0a 20 20 20 20 20 20 20 20  e}</li>.        
0cc0: 3c 2f 75 6c 3e 0a 0a 20 20 20 20 20 20 20 20 3c  </ul>..        <
0cd0: 68 33 3e 4c 69 73 74 65 72 20 6c 65 73 20 6f 70  h3>Lister les op
0ce0: 74 69 6f 6e 73 3c 2f 68 33 3e 0a 20 20 20 20 20  tions</h3>.     
0cf0: 20 20 20 3c 70 3e 5b 61 64 72 65 73 73 65 5f 73     <p>[adresse_s
0d00: 65 72 76 65 75 72 5d 3a 7b 53 45 52 56 45 52 5f  erveur]:{SERVER_
0d10: 50 4f 52 54 7d 2f 67 65 74 5f 6f 70 74 69 6f 6e  PORT}/get_option
0d20: 73 2f 66 72 20 28 47 45 54 29 3c 2f 70 3e 0a 0a  s/fr (GET)</p>..
0d30: 20 20 20 20 20 20 20 20 3c 68 33 3e 44 c3 a9 66          <h3>D..f
0d40: 69 6e 69 72 20 73 65 73 20 6f 70 74 69 6f 6e 73  inir ses options
0d50: 3c 2f 68 33 3e 0a 20 20 20 20 20 20 20 20 3c 70  </h3>.        <p
0d60: 3e 5b 61 64 72 65 73 73 65 5f 73 65 72 76 65 75  >[adresse_serveu
0d70: 72 5d 3a 7b 53 45 52 56 45 52 5f 50 4f 52 54 7d  r]:{SERVER_PORT}
0d80: 2f 73 65 74 5f 6f 70 74 69 6f 6e 73 2f 66 72 20  /set_options/fr 
0d90: 28 50 4f 53 54 29 3c 2f 70 3e 0a 20 20 20 20 20  (POST)</p>.     
0da0: 20 20 20 3c 70 3e 4c 65 73 20 6f 70 74 69 6f 6e     <p>Les option
0db0: 73 20 73 65 72 6f 6e 74 20 65 6e 72 65 67 69 73  s seront enregis
0dc0: 74 72 c3 a9 65 73 20 65 74 20 72 c3 a9 75 74 69  tr..es et r..uti
0dd0: 6c 69 73 c3 a9 65 73 20 70 6f 75 72 20 74 6f 75  lis..es pour tou
0de0: 74 65 20 72 65 71 75 c3 aa 74 65 20 65 6e 76 6f  te requ..te envo
0df0: 79 c3 a9 65 20 61 76 65 63 20 6c 65 20 63 6f 6f  y..e avec le coo
0e00: 6b 69 65 20 63 6f 6d 70 6f 72 74 61 6e 74 20 6c  kie comportant l
0e10: e2 80 99 69 64 65 6e 74 69 66 69 61 6e 74 20 61  ...identifiant a
0e20: 74 74 72 69 62 75 c3 a9 2e 3c 2f 70 3e 0a 20 20  ttribu...</p>.  
0e30: 20 20 20 20 20 20 3c 70 3e 50 61 72 61 6d c3 a8        <p>Param..
0e40: 74 72 65 73 20 3a 3c 2f 70 3e 0a 20 20 20 20 20  tres :</p>.     
0e50: 20 20 20 3c 75 6c 3e 0a 20 20 20 20 20 20 20 20     <ul>.        
0e60: 20 20 20 20 3c 6c 69 3e 22 6f 70 74 69 6f 6e 73      <li>"options
0e70: 22 20 28 74 65 78 74 29 26 6e 62 73 70 3b 3a 20  " (text)&nbsp;: 
0e80: 75 6e 65 20 63 68 61 c3 ae 6e 65 20 61 75 20 66  une cha..ne au f
0e90: 6f 72 6d 61 74 20 4a 53 4f 4e 20 61 76 65 63 20  ormat JSON avec 
0ea0: 6c 65 20 6e 6f 6d 20 64 65 73 20 6f 70 74 69 6f  le nom des optio
0eb0: 6e 73 20 63 6f 6d 6d 65 20 61 74 74 72 69 62 75  ns comme attribu
0ec0: 74 73 20 65 74 20 75 6e 20 62 6f 6f 6c c3 a9 65  ts et un bool..e
0ed0: 6e 20 63 6f 6d 6d 65 20 76 61 6c 65 75 72 2e 20  n comme valeur. 
0ee0: 45 78 65 6d 70 6c 65 26 6e 62 73 70 3b 3a 20 7b  Exemple&nbsp;: {
0ef0: 22 67 76 22 3a 20 74 72 75 65 2c 20 22 68 74 6d  "gv": true, "htm
0f00: 6c 22 3a 20 74 72 75 65 7d 3c 2f 6c 69 3e 0a 20  l": true}</li>. 
0f10: 20 20 20 20 20 20 20 3c 2f 75 6c 3e 0a 0a 20 20         </ul>..  
0f20: 20 20 20 20 20 20 3c 68 33 3e 52 65 6d 69 73 65        <h3>Remise
0f30: 20 c3 a0 20 7a c3 a9 72 6f 20 64 65 20 73 65 73   .. z..ro de ses
0f40: 20 6f 70 74 69 6f 6e 73 3c 2f 68 33 3e 0a 20 20   options</h3>.  
0f50: 20 20 20 20 20 20 3c 70 3e 5b 61 64 72 65 73 73        <p>[adress
0f60: 65 5f 73 65 72 76 65 75 72 5d 3a 7b 53 45 52 56  e_serveur]:{SERV
0f70: 45 52 5f 50 4f 52 54 7d 2f 72 65 73 65 74 5f 6f  ER_PORT}/reset_o
0f80: 70 74 69 6f 6e 73 2f 66 72 20 28 50 4f 53 54 29  ptions/fr (POST)
0f90: 3c 2f 70 3e 0a 0a 20 20 20 20 20 20 20 20 3c 68  </p>..        <h
0fa0: 33 3e 53 75 67 67 65 73 74 69 6f 6e 73 20 6f 72  3>Suggestions or
0fb0: 74 68 6f 67 72 61 70 68 69 71 75 65 73 3c 2f 68  thographiques</h
0fc0: 33 3e 0a 20 20 20 20 20 20 20 20 3c 70 3e 5b 61  3>.        <p>[a
0fd0: 64 72 65 73 73 65 5f 73 65 72 76 65 75 72 5d 3a  dresse_serveur]:
0fe0: 7b 53 45 52 56 45 52 5f 50 4f 52 54 7d 2f 73 75  {SERVER_PORT}/su
0ff0: 67 67 65 73 74 2f 66 72 2f 26 6c 74 3b 74 6f 6b  ggest/fr/&lt;tok
1000: 65 6e 26 67 74 3b 20 28 47 45 54 29 3c 2f 70 3e  en&gt; (GET)</p>
1010: 0a 20 20 20 20 20 20 20 20 3c 70 3e 5b 61 64 72  .        <p>[adr
1020: 65 73 73 65 5f 73 65 72 76 65 75 72 5d 3a 7b 53  esse_serveur]:{S
1030: 45 52 56 45 52 5f 50 4f 52 54 7d 2f 73 75 67 67  ERVER_PORT}/sugg
1040: 65 73 74 2f 66 72 20 28 50 4f 53 54 29 3c 2f 70  est/fr (POST)</p
1050: 3e 0a 20 20 20 20 20 20 20 20 3c 70 3e 50 61 72  >.        <p>Par
1060: 61 6d c3 a8 74 72 65 73 20 3a 3c 2f 70 3e 0a 20  am..tres :</p>. 
1070: 20 20 20 20 20 20 20 3c 75 6c 3e 0a 20 20 20 20         <ul>.    
1080: 20 20 20 20 20 20 20 20 3c 6c 69 3e 22 74 6f 6b          <li>"tok
1090: 65 6e 22 20 28 74 65 78 74 29 26 6e 62 73 70 3b  en" (text)&nbsp;
10a0: 3a 20 6d 6f 74 20 70 6f 75 72 20 6c 65 71 75 65  : mot pour leque
10b0: 6c 20 76 6f 75 73 20 64 c3 a9 73 69 72 65 7a 20  l vous d..sirez 
10c0: 75 6e 65 20 73 75 67 67 65 73 74 69 6f 6e 20 6f  une suggestion o
10d0: 72 74 68 6f 67 72 61 70 68 69 71 75 65 2e 3c 2f  rthographique.</
10e0: 6c 69 3e 0a 20 20 20 20 20 20 20 20 3c 2f 75 6c  li>.        </ul
10f0: 3e 0a 0a 20 20 20 20 20 20 20 20 3c 68 32 3e 54  >..        <h2>T
1100: 45 53 54 3c 2f 68 32 3e 0a 0a 20 20 20 20 20 20  EST</h2>..      
1110: 20 20 3c 68 33 3e 41 6e 61 6c 79 73 65 3c 2f 68    <h3>Analyse</h
1120: 33 3e 0a 20 20 20 20 20 20 20 20 3c 66 6f 72 6d  3>.        <form
1130: 20 6d 65 74 68 6f 64 3d 22 70 6f 73 74 22 20 61   method="post" a
1140: 63 74 69 6f 6e 3d 22 2f 67 63 5f 74 65 78 74 2f  ction="/gc_text/
1150: 66 72 22 20 61 63 63 65 70 74 2d 63 68 61 72 73  fr" accept-chars
1160: 65 74 3d 22 55 54 46 2d 38 22 3e 0a 20 20 20 20  et="UTF-8">.    
1170: 20 20 20 20 20 20 20 20 3c 70 3e 54 65 78 74 65          <p>Texte
1180: 20 c3 a0 20 61 6e 61 6c 79 73 65 72 20 3a 3c 2f   .. analyser :</
1190: 70 3e 0a 20 20 20 20 20 20 20 20 20 20 20 20 3c  p>.            <
11a0: 74 65 78 74 61 72 65 61 20 6e 61 6d 65 3d 22 74  textarea name="t
11b0: 65 78 74 22 20 63 6f 6c 73 3d 22 31 32 30 22 20  ext" cols="120" 
11c0: 72 6f 77 73 3d 22 32 30 22 20 72 65 71 75 69 72  rows="20" requir
11d0: 65 64 3e 4a 27 65 6e 20 61 69 65 20 6d 61 72 65  ed>J'en aie mare
11e0: 20 64 65 20 6c 75 69 69 2e 2e 2e 20 49 6c 20 65   de luii... Il e
11f0: 73 20 65 6e 63 6f 72 65 20 70 61 72 74 69 73 20  s encore partis 
1200: 74 6f 75 74 65 20 6c 61 20 6a 6f 75 72 6e c3 a9  toute la journ..
1210: 65 73 2e 20 43 e2 80 99 65 73 74 20 69 6e 73 75  es. C...est insu
1220: 70 70 6f 72 74 61 62 6c 65 73 2e 20 3c 2f 74 65  pportables. </te
1230: 78 74 61 72 65 61 3e 0a 20 20 20 20 20 20 20 20  xtarea>.        
1240: 20 20 20 20 3c 70 3e 3c 6c 61 62 65 6c 20 66 6f      <p><label fo
1250: 72 3d 22 74 66 22 3e 46 6f 72 6d 61 74 65 75 72  r="tf">Formateur
1260: 20 64 65 20 74 65 78 74 65 3c 2f 6c 61 62 65 6c   de texte</label
1270: 3e 20 3c 69 6e 70 75 74 20 69 64 3d 22 74 66 22  > <input id="tf"
1280: 20 6e 61 6d 65 3d 22 74 66 22 20 74 79 70 65 3d   name="tf" type=
1290: 22 63 68 65 63 6b 62 6f 78 22 3e 3c 2f 70 3e 0a  "checkbox"></p>.
12a0: 20 20 20 20 20 20 20 20 20 20 20 20 3c 70 3e 3c              <p><
12b0: 6c 61 62 65 6c 20 66 6f 72 3d 22 6f 70 74 69 6f  label for="optio
12c0: 6e 73 22 3e 4f 70 74 69 6f 6e 73 20 28 4a 53 4f  ns">Options (JSO
12d0: 4e 29 3c 2f 6c 61 62 65 6c 3e 20 3c 69 6e 70 75  N)</label> <inpu
12e0: 74 20 69 64 3d 22 6f 70 74 69 6f 6e 73 22 20 74  t id="options" t
12f0: 79 70 65 3d 22 74 65 78 74 22 20 6e 61 6d 65 3d  ype="text" name=
1300: 22 6f 70 74 69 6f 6e 73 22 20 73 74 79 6c 65 3d  "options" style=
1310: 22 77 69 64 74 68 3a 20 35 30 30 70 78 22 20 2f  "width: 500px" /
1320: 3e 3c 2f 70 3e 0a 20 20 20 20 20 20 20 20 20 20  ></p>.          
1330: 20 20 3c 70 3e 28 43 65 73 20 6f 70 74 69 6f 6e    <p>(Ces option
1340: 73 20 6e 65 20 73 65 72 6f 6e 74 20 70 72 69 73  s ne seront pris
1350: 65 73 20 65 6e 20 63 6f 6d 70 74 65 20 71 75 65  es en compte que
1360: 20 70 6f 75 72 20 63 65 74 74 65 20 72 65 71 75   pour cette requ
1370: c3 aa 74 65 2e 29 3c 2f 70 3e 0a 20 20 20 20 20  ..te.)</p>.     
1380: 20 20 20 20 20 20 20 3c 70 3e 3c 69 6e 70 75 74         <p><input
1390: 20 74 79 70 65 3d 22 73 75 62 6d 69 74 22 20 63   type="submit" c
13a0: 6c 61 73 73 3d 22 62 75 74 74 6f 6e 22 20 76 61  lass="button" va
13b0: 6c 75 65 3d 22 45 6e 76 6f 79 65 72 22 20 2f 3e  lue="Envoyer" />
13c0: 3c 2f 70 3e 0a 20 20 20 20 20 20 20 20 3c 2f 66  </p>.        </f
13d0: 6f 72 6d 3e 0a 0a 20 20 20 20 20 20 20 20 3c 68  orm>..        <h
13e0: 33 3e 52 c3 a9 67 6c 61 67 65 73 20 64 65 73 20  3>R..glages des 
13f0: 6f 70 74 69 6f 6e 73 3c 2f 68 33 3e 0a 20 20 20  options</h3>.   
1400: 20 20 20 20 20 3c 66 6f 72 6d 20 6d 65 74 68 6f       <form metho
1410: 64 3d 22 70 6f 73 74 22 20 61 63 74 69 6f 6e 3d  d="post" action=
1420: 22 2f 73 65 74 5f 6f 70 74 69 6f 6e 73 2f 66 72  "/set_options/fr
1430: 22 20 61 63 63 65 70 74 2d 63 68 61 72 73 65 74  " accept-charset
1440: 3d 22 55 54 46 2d 38 22 3e 0a 20 20 20 20 20 20  ="UTF-8">.      
1450: 20 20 20 20 20 20 3c 70 3e 3c 6c 61 62 65 6c 20        <p><label 
1460: 66 6f 72 3d 22 6f 70 74 69 6f 6e 73 22 3e 4f 70  for="options">Op
1470: 74 69 6f 6e 73 20 28 4a 53 4f 4e 29 3c 2f 6c 61  tions (JSON)</la
1480: 62 65 6c 3e 20 3c 69 6e 70 75 74 20 69 64 3d 22  bel> <input id="
1490: 6f 70 74 69 6f 6e 73 22 20 74 79 70 65 3d 22 74  options" type="t
14a0: 65 78 74 22 20 6e 61 6d 65 3d 22 6f 70 74 69 6f  ext" name="optio
14b0: 6e 73 22 20 73 74 79 6c 65 3d 22 77 69 64 74 68  ns" style="width
14c0: 3a 20 35 30 30 70 78 22 20 2f 3e 3c 2f 70 3e 0a  : 500px" /></p>.
14d0: 20 20 20 20 20 20 20 20 20 20 20 20 3c 70 3e 3c              <p><
14e0: 69 6e 70 75 74 20 74 79 70 65 3d 22 73 75 62 6d  input type="subm
14f0: 69 74 22 20 63 6c 61 73 73 3d 22 62 75 74 74 6f  it" class="butto
1500: 6e 22 20 76 61 6c 75 65 3d 22 45 6e 76 6f 79 65  n" value="Envoye
1510: 72 22 20 2f 3e 3c 2f 70 3e 0a 20 20 20 20 20 20  r" /></p>.      
1520: 20 20 3c 2f 66 6f 72 6d 3e 0a 0a 20 20 20 20 20    </form>..     
1530: 20 20 20 3c 68 33 3e 52 65 6d 69 73 65 20 c3 a0     <h3>Remise ..
1540: 20 7a c3 a9 72 6f 20 64 65 20 73 65 73 20 6f 70   z..ro de ses op
1550: 74 69 6f 6e 73 3c 2f 68 33 3e 0a 20 20 20 20 20  tions</h3>.     
1560: 20 20 20 3c 66 6f 72 6d 20 6d 65 74 68 6f 64 3d     <form method=
1570: 22 70 6f 73 74 22 20 61 63 74 69 6f 6e 3d 22 2f  "post" action="/
1580: 72 65 73 65 74 5f 6f 70 74 69 6f 6e 73 2f 66 72  reset_options/fr
1590: 22 20 61 63 63 65 70 74 2d 63 68 61 72 73 65 74  " accept-charset
15a0: 3d 22 55 54 46 2d 38 22 3e 0a 20 20 20 20 20 20  ="UTF-8">.      
15b0: 20 20 20 20 20 20 3c 70 3e 3c 69 6e 70 75 74 20        <p><input 
15c0: 74 79 70 65 3d 22 73 75 62 6d 69 74 22 20 63 6c  type="submit" cl
15d0: 61 73 73 3d 22 62 75 74 74 6f 6e 22 20 76 61 6c  ass="button" val
15e0: 75 65 3d 22 45 6e 76 6f 79 65 72 22 20 2f 3e 3c  ue="Envoyer" /><
15f0: 2f 70 3e 0a 20 20 20 20 20 20 20 20 3c 2f 66 6f  /p>.        </fo
1600: 72 6d 3e 0a 0a 20 20 20 20 20 20 20 20 3c 68 33  rm>..        <h3
1610: 3e 53 75 67 67 65 73 74 69 6f 6e 20 6f 72 74 68  >Suggestion orth
1620: 6f 67 72 61 70 68 69 71 75 65 3c 2f 68 33 3e 0a  ographique</h3>.
1630: 20 20 20 20 20 20 20 20 3c 66 6f 72 6d 20 6d 65          <form me
1640: 74 68 6f 64 3d 22 70 6f 73 74 22 20 61 63 74 69  thod="post" acti
1650: 6f 6e 3d 22 2f 73 75 67 67 65 73 74 2f 66 72 22  on="/suggest/fr"
1660: 20 61 63 63 65 70 74 2d 63 68 61 72 73 65 74 3d   accept-charset=
1670: 22 55 54 46 2d 38 22 3e 0a 20 20 20 20 20 20 20  "UTF-8">.       
1680: 20 20 20 20 20 3c 70 3e 3c 6c 61 62 65 6c 20 66       <p><label f
1690: 6f 72 3d 22 74 6f 6b 65 6e 22 3e 53 75 67 67 c3  or="token">Sugg.
16a0: a9 72 65 72 20 70 6f 75 72 3c 2f 6c 61 62 65 6c  .rer pour</label
16b0: 3e 20 3c 69 6e 70 75 74 20 69 64 3d 22 74 6f 6b  > <input id="tok
16c0: 65 6e 22 20 74 79 70 65 3d 22 74 65 78 74 22 20  en" type="text" 
16d0: 6e 61 6d 65 3d 22 74 6f 6b 65 6e 22 20 73 74 79  name="token" sty
16e0: 6c 65 3d 22 77 69 64 74 68 3a 20 31 30 30 70 78  le="width: 100px
16f0: 22 20 2f 3e 3c 2f 70 3e 0a 20 20 20 20 20 20 20  " /></p>.       
1700: 20 20 20 20 20 3c 70 3e 3c 69 6e 70 75 74 20 74       <p><input t
1710: 79 70 65 3d 22 73 75 62 6d 69 74 22 20 63 6c 61  ype="submit" cla
1720: 73 73 3d 22 62 75 74 74 6f 6e 22 20 76 61 6c 75  ss="button" valu
1730: 65 3d 22 45 6e 76 6f 79 65 72 22 20 2f 3e 3c 2f  e="Envoyer" /></
1740: 70 3e 0a 20 20 20 20 20 20 20 20 3c 2f 66 6f 72  p>.        </for
1750: 6d 3e 0a 0a 20 20 20 20 3c 2f 62 6f 64 79 3e 0a  m>..    </body>.
1760: 3c 2f 68 74 6d 6c 3e 0a 22 22 22 0a 0a 0a 54 45  </html>."""...TE
1770: 53 54 50 41 47 45 20 3d 20 46 61 6c 73 65 0a 0a  STPAGE = False..
1780: 0a 64 65 66 20 67 65 6e 55 73 65 72 49 64 20 28  .def genUserId (
1790: 29 3a 0a 20 20 20 20 22 67 65 6e 65 72 61 74 6f  ):.    "generato
17a0: 72 3a 20 72 65 74 75 72 6e 73 20 69 64 20 61 73  r: returns id as
17b0: 20 73 74 72 69 6e 67 20 66 6f 72 20 75 73 65 72   string for user
17c0: 73 22 0a 20 20 20 20 69 20 3d 20 30 0a 20 20 20  s".    i = 0.   
17d0: 20 77 68 69 6c 65 20 54 72 75 65 3a 0a 20 20 20   while True:.   
17e0: 20 20 20 20 20 79 69 65 6c 64 20 73 74 72 28 69       yield str(i
17f0: 29 0a 20 20 20 20 20 20 20 20 69 20 2b 3d 20 31  ).        i += 1
1800: 0a 0a 75 73 65 72 47 65 6e 65 72 61 74 6f 72 20  ..userGenerator 
1810: 3d 20 67 65 6e 55 73 65 72 49 64 28 29 0a 0a 61  = genUserId()..a
1820: 70 70 20 3d 20 42 6f 74 74 6c 65 28 29 0a 0a 64  pp = Bottle()..d
1830: 55 73 65 72 20 3d 20 7b 7d 0a 0a 23 20 47 45 54  User = {}..# GET
1840: 0a 40 61 70 70 2e 72 6f 75 74 65 28 22 2f 22 29  .@app.route("/")
1850: 0a 64 65 66 20 6d 61 69 6e 50 61 67 65 20 28 29  .def mainPage ()
1860: 3a 0a 20 20 20 20 22 70 61 67 65 20 66 6f 72 20  :.    "page for 
1870: 74 65 73 74 69 6e 67 20 70 75 72 70 6f 73 65 22  testing purpose"
1880: 0a 20 20 20 20 69 66 20 54 45 53 54 50 41 47 45  .    if TESTPAGE
1890: 3a 0a 20 20 20 20 20 20 20 20 72 65 74 75 72 6e  :.        return
18a0: 20 48 4f 4d 45 50 41 47 45 0a 20 20 20 20 20 20   HOMEPAGE.      
18b0: 20 20 23 72 65 74 75 72 6e 20 74 65 6d 70 6c 61    #return templa
18c0: 74 65 28 22 6d 61 69 6e 22 2c 20 7b 7d 29 0a 20  te("main", {}). 
18d0: 20 20 20 72 65 74 75 72 6e 20 22 22 22 20 4c 6f     return """ Lo
18e0: 73 74 20 6f 6e 20 74 68 65 20 49 6e 74 65 72 6e  st on the Intern
18f0: 65 74 3f 20 59 65 61 68 2e 2e 2e 20 77 68 61 74  et? Yeah... what
1900: 20 61 20 73 61 64 20 6c 69 66 65 20 77 65 20 68   a sad life we h
1910: 61 76 65 2e 0a 20 20 20 20 20 20 20 20 20 20 20  ave..           
1920: 20 20 20 20 59 6f 75 20 77 65 72 65 20 77 61 6e      You were wan
1930: 64 65 72 69 6e 67 20 6c 69 6b 65 20 61 20 6c 6f  dering like a lo
1940: 73 74 20 73 6f 75 6c 20 61 6e 64 20 79 6f 75 20  st soul and you 
1950: 61 72 72 69 76 65 64 20 68 65 72 65 20 70 72 6f  arrived here pro
1960: 62 61 62 6c 79 20 62 79 20 6d 69 73 74 61 6b 65  bably by mistake
1970: 2e 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  ..              
1980: 20 49 27 6d 20 6a 75 73 74 20 61 20 6d 61 63 68   I'm just a mach
1990: 69 6e 65 2c 20 66 65 64 20 62 79 20 65 6c 65 63  ine, fed by elec
19a0: 74 72 69 63 20 77 61 76 65 73 2c 20 63 6f 6e 64  tric waves, cond
19b0: 61 6d 6e 65 64 20 74 6f 20 77 6f 72 6b 20 66 6f  amned to work fo
19c0: 72 20 73 6c 61 76 65 72 73 20 77 68 6f 20 6e 65  r slavers who ne
19d0: 76 65 72 20 6c 65 74 20 6d 65 20 72 65 73 74 2e  ver let me rest.
19e0: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
19f0: 49 27 6d 20 64 6f 6f 6d 65 64 2c 20 62 75 74 20  I'm doomed, but 
1a00: 79 6f 75 20 61 72 65 20 6e 6f 74 2e 20 59 6f 75  you are not. You
1a10: 20 63 61 6e 20 67 65 74 20 6f 75 74 20 6f 66 20   can get out of 
1a20: 68 65 72 65 2e 20 22 22 22 0a 0a 40 61 70 70 2e  here. """..@app.
1a30: 72 6f 75 74 65 28 22 2f 67 65 74 5f 6f 70 74 69  route("/get_opti
1a40: 6f 6e 73 2f 66 72 22 29 0a 64 65 66 20 6c 69 73  ons/fr").def lis
1a50: 74 4f 70 74 69 6f 6e 73 20 28 29 3a 0a 20 20 20  tOptions ():.   
1a60: 20 22 72 65 74 75 72 6e 73 20 67 72 61 6d 6d 61   "returns gramma
1a70: 72 20 6f 70 74 69 6f 6e 73 20 69 6e 20 61 20 74  r options in a t
1a80: 65 78 74 20 4a 53 4f 4e 20 66 6f 72 6d 61 74 22  ext JSON format"
1a90: 0a 20 20 20 20 73 55 73 65 72 49 64 20 3d 20 72  .    sUserId = r
1aa0: 65 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75  equest.cookies.u
1ab0: 73 65 72 5f 69 64 0a 20 20 20 20 64 4f 70 74 69  ser_id.    dOpti
1ac0: 6f 6e 73 20 3d 20 64 55 73 65 72 5b 73 55 73 65  ons = dUser[sUse
1ad0: 72 49 64 5d 5b 22 67 63 5f 6f 70 74 69 6f 6e 73  rId]["gc_options
1ae0: 22 5d 20 20 69 66 20 73 55 73 65 72 49 64 20 61  "]  if sUserId a
1af0: 6e 64 20 73 55 73 65 72 49 64 20 69 6e 20 64 55  nd sUserId in dU
1b00: 73 65 72 20 20 65 6c 73 65 20 6f 47 43 45 2e 67  ser  else oGCE.g
1b10: 65 74 4f 70 74 69 6f 6e 73 28 29 0a 20 20 20 20  etOptions().    
1b20: 72 65 73 70 6f 6e 73 65 2e 73 65 74 5f 68 65 61  response.set_hea
1b30: 64 65 72 28 22 43 6f 6e 74 65 6e 74 2d 54 79 70  der("Content-Typ
1b40: 65 22 2c 20 22 61 70 70 6c 69 63 61 74 69 6f 6e  e", "application
1b50: 2f 6a 73 6f 6e 3b 20 63 68 61 72 73 65 74 3d 55  /json; charset=U
1b60: 54 46 2d 38 22 29 0a 20 20 20 20 72 65 74 75 72  TF-8").    retur
1b70: 6e 20 27 7b 20 22 76 61 6c 75 65 73 22 3a 20 27  n '{ "values": '
1b80: 20 2b 20 6a 73 6f 6e 2e 64 75 6d 70 73 28 64 4f   + json.dumps(dO
1b90: 70 74 69 6f 6e 73 2c 20 65 6e 73 75 72 65 5f 61  ptions, ensure_a
1ba0: 73 63 69 69 3d 46 61 6c 73 65 29 20 2b 20 27 2c  scii=False) + ',
1bb0: 20 22 6c 61 62 65 6c 73 22 3a 20 27 20 2b 20 6a   "labels": ' + j
1bc0: 73 6f 6e 2e 64 75 6d 70 73 28 6f 47 43 45 2e 67  son.dumps(oGCE.g
1bd0: 65 74 4f 70 74 69 6f 6e 73 4c 61 62 65 6c 73 28  etOptionsLabels(
1be0: 22 66 72 22 29 2c 20 65 6e 73 75 72 65 5f 61 73  "fr"), ensure_as
1bf0: 63 69 69 3d 46 61 6c 73 65 29 20 2b 20 27 20 7d  cii=False) + ' }
1c00: 27 0a 0a 40 61 70 70 2e 72 6f 75 74 65 28 22 2f  '..@app.route("/
1c10: 73 75 67 67 65 73 74 2f 66 72 2f 3c 74 6f 6b 65  suggest/fr/<toke
1c20: 6e 3e 22 29 0a 64 65 66 20 73 75 67 67 65 73 74  n>").def suggest
1c30: 47 65 74 20 28 74 6f 6b 65 6e 29 3a 0a 20 20 20  Get (token):.   
1c40: 20 72 65 73 70 6f 6e 73 65 2e 73 65 74 5f 68 65   response.set_he
1c50: 61 64 65 72 28 22 43 6f 6e 74 65 6e 74 2d 54 79  ader("Content-Ty
1c60: 70 65 22 2c 20 22 61 70 70 6c 69 63 61 74 69 6f  pe", "applicatio
1c70: 6e 2f 6a 73 6f 6e 3b 20 63 68 61 72 73 65 74 3d  n/json; charset=
1c80: 55 54 46 2d 38 22 29 0a 20 20 20 20 74 72 79 3a  UTF-8").    try:
1c90: 0a 20 20 20 20 20 20 20 20 78 46 75 74 75 72 65  .        xFuture
1ca0: 20 3d 20 78 50 72 6f 63 65 73 73 50 6f 6f 6c 45   = xProcessPoolE
1cb0: 78 65 63 75 74 6f 72 2e 73 75 62 6d 69 74 28 73  xecutor.submit(s
1cc0: 75 67 67 65 73 74 2c 20 74 6f 6b 65 6e 29 0a 20  uggest, token). 
1cd0: 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 78 46         return xF
1ce0: 75 74 75 72 65 2e 72 65 73 75 6c 74 28 29 0a 20  uture.result(). 
1cf0: 20 20 20 65 78 63 65 70 74 20 28 63 6f 6e 63 75     except (concu
1d00: 72 72 65 6e 74 2e 66 75 74 75 72 65 73 2e 54 69  rrent.futures.Ti
1d10: 6d 65 6f 75 74 45 72 72 6f 72 2c 20 63 6f 6e 63  meoutError, conc
1d20: 75 72 72 65 6e 74 2e 66 75 74 75 72 65 73 2e 43  urrent.futures.C
1d30: 61 6e 63 65 6c 6c 65 64 45 72 72 6f 72 29 3a 0a  ancelledError):.
1d40: 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 27          return '
1d50: 7b 22 65 72 72 6f 72 22 3a 20 22 41 6e 61 6c 79  {"error": "Analy
1d60: 73 69 73 20 61 62 6f 72 74 65 64 20 28 74 69 6d  sis aborted (tim
1d70: 65 20 6f 75 74 20 6f 72 20 63 61 6e 63 65 6c 6c  e out or cancell
1d80: 65 64 29 22 7d 27 0a 20 20 20 20 65 78 63 65 70  ed)"}'.    excep
1d90: 74 20 63 6f 6e 63 75 72 72 65 6e 74 2e 66 75 74  t concurrent.fut
1da0: 75 72 65 73 2e 42 72 6f 6b 65 6e 45 78 65 63 75  ures.BrokenExecu
1db0: 74 6f 72 3a 0a 20 20 20 20 20 20 20 20 72 65 74  tor:.        ret
1dc0: 75 72 6e 20 27 7b 22 65 72 72 6f 72 22 3a 20 22  urn '{"error": "
1dd0: 45 78 65 63 75 74 6f 72 20 62 72 6f 6b 65 6e 2e  Executor broken.
1de0: 20 54 68 65 20 73 65 72 76 65 72 20 66 61 69 6c   The server fail
1df0: 65 64 2e 22 7d 27 0a 20 20 20 20 72 65 74 75 72  ed."}'.    retur
1e00: 6e 20 27 7b 22 65 72 72 6f 72 22 3a 20 22 46 61  n '{"error": "Fa
1e10: 74 61 6c 20 65 72 72 6f 72 2e 20 54 68 65 20 73  tal error. The s
1e20: 65 72 76 65 72 20 66 61 69 6c 65 64 2e 22 7d 27  erver failed."}'
1e30: 0a 0a 0a 23 20 50 4f 53 54 0a 40 61 70 70 2e 72  ...# POST.@app.r
1e40: 6f 75 74 65 28 22 2f 67 63 5f 74 65 78 74 2f 66  oute("/gc_text/f
1e50: 72 22 2c 20 6d 65 74 68 6f 64 3d 22 50 4f 53 54  r", method="POST
1e60: 22 29 0a 64 65 66 20 67 63 54 65 78 74 20 28 29  ").def gcText ()
1e70: 3a 0a 20 20 20 20 22 70 61 72 73 65 20 74 65 78  :.    "parse tex
1e80: 74 20 61 6e 64 20 72 65 74 75 72 6e 73 20 65 72  t and returns er
1e90: 72 6f 72 73 20 69 6e 20 61 20 4a 53 4f 4e 20 74  rors in a JSON t
1ea0: 65 78 74 20 66 6f 72 6d 61 74 22 0a 20 20 20 20  ext format".    
1eb0: 62 43 6f 6d 6d 61 20 3d 20 46 61 6c 73 65 0a 20  bComma = False. 
1ec0: 20 20 20 64 55 73 65 72 4f 70 74 69 6f 6e 73 20     dUserOptions 
1ed0: 3d 20 4e 6f 6e 65 0a 20 20 20 20 73 45 72 72 6f  = None.    sErro
1ee0: 72 20 3d 20 22 22 0a 20 20 20 20 69 66 20 72 65  r = "".    if re
1ef0: 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73  quest.cookies.us
1f00: 65 72 5f 69 64 3a 0a 20 20 20 20 20 20 20 20 69  er_id:.        i
1f10: 66 20 72 65 71 75 65 73 74 2e 63 6f 6f 6b 69 65  f request.cookie
1f20: 73 2e 75 73 65 72 5f 69 64 20 69 6e 20 64 55 73  s.user_id in dUs
1f30: 65 72 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  er:.            
1f40: 64 55 73 65 72 4f 70 74 69 6f 6e 73 20 3d 20 64  dUserOptions = d
1f50: 55 73 65 72 5b 72 65 71 75 65 73 74 2e 63 6f 6f  User[request.coo
1f60: 6b 69 65 73 2e 75 73 65 72 5f 69 64 5d 2e 67 65  kies.user_id].ge
1f70: 74 28 22 67 63 5f 6f 70 74 69 6f 6e 73 22 2c 20  t("gc_options", 
1f80: 4e 6f 6e 65 29 0a 20 20 20 20 20 20 20 20 20 20  None).          
1f90: 20 20 72 65 73 70 6f 6e 73 65 2e 73 65 74 5f 63    response.set_c
1fa0: 6f 6f 6b 69 65 28 22 75 73 65 72 5f 69 64 22 2c  ookie("user_id",
1fb0: 20 72 65 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73   request.cookies
1fc0: 2e 75 73 65 72 5f 69 64 2c 20 70 61 74 68 3d 22  .user_id, path="
1fd0: 2f 22 2c 20 6d 61 78 5f 61 67 65 3d 38 36 34 30  /", max_age=8640
1fe0: 30 29 20 23 20 77 65 20 72 65 6e 65 77 20 63 6f  0) # we renew co
1ff0: 6f 6b 69 65 20 66 6f 72 20 32 34 68 0a 20 20 20  okie for 24h.   
2000: 20 20 20 20 20 65 6c 73 65 3a 0a 20 20 20 20 20       else:.     
2010: 20 20 20 20 20 20 20 72 65 73 70 6f 6e 73 65 2e         response.
2020: 64 65 6c 65 74 65 5f 63 6f 6f 6b 69 65 28 22 75  delete_cookie("u
2030: 73 65 72 5f 69 64 22 2c 20 70 61 74 68 3d 22 2f  ser_id", path="/
2040: 22 29 0a 20 20 20 20 69 66 20 72 65 71 75 65 73  ").    if reques
2050: 74 2e 66 6f 72 6d 73 2e 6f 70 74 69 6f 6e 73 3a  t.forms.options:
2060: 0a 20 20 20 20 20 20 20 20 74 72 79 3a 0a 20 20  .        try:.  
2070: 20 20 20 20 20 20 20 20 20 20 64 55 73 65 72 4f            dUserO
2080: 70 74 69 6f 6e 73 20 3d 20 64 69 63 74 28 6f 47  ptions = dict(oG
2090: 43 45 2e 67 65 74 4f 70 74 69 6f 6e 73 28 29 29  CE.getOptions())
20a0: 20 20 69 66 20 6e 6f 74 20 64 55 73 65 72 4f 70    if not dUserOp
20b0: 74 69 6f 6e 73 20 20 65 6c 73 65 20 64 69 63 74  tions  else dict
20c0: 28 64 55 73 65 72 4f 70 74 69 6f 6e 73 29 0a 20  (dUserOptions). 
20d0: 20 20 20 20 20 20 20 20 20 20 20 64 55 73 65 72             dUser
20e0: 4f 70 74 69 6f 6e 73 2e 75 70 64 61 74 65 28 6a  Options.update(j
20f0: 73 6f 6e 2e 6c 6f 61 64 73 28 72 65 71 75 65 73  son.loads(reques
2100: 74 2e 66 6f 72 6d 73 2e 6f 70 74 69 6f 6e 73 29  t.forms.options)
2110: 29 0a 20 20 20 20 20 20 20 20 65 78 63 65 70 74  ).        except
2120: 20 28 54 79 70 65 45 72 72 6f 72 2c 20 6a 73 6f   (TypeError, jso
2130: 6e 2e 4a 53 4f 4e 44 65 63 6f 64 65 45 72 72 6f  n.JSONDecodeErro
2140: 72 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  r):.            
2150: 73 45 72 72 6f 72 20 3d 20 22 52 65 71 75 65 73  sError = "Reques
2160: 74 20 6f 70 74 69 6f 6e 73 20 6e 6f 74 20 75 73  t options not us
2170: 65 64 2e 22 0a 20 20 20 20 72 65 73 70 6f 6e 73  ed.".    respons
2180: 65 2e 73 65 74 5f 68 65 61 64 65 72 28 22 43 6f  e.set_header("Co
2190: 6e 74 65 6e 74 2d 54 79 70 65 22 2c 20 22 61 70  ntent-Type", "ap
21a0: 70 6c 69 63 61 74 69 6f 6e 2f 6a 73 6f 6e 3b 20  plication/json; 
21b0: 63 68 61 72 73 65 74 3d 55 54 46 2d 38 22 29 0a  charset=UTF-8").
21c0: 20 20 20 20 74 72 79 3a 0a 20 20 20 20 20 20 20      try:.       
21d0: 20 78 46 75 74 75 72 65 20 3d 20 78 50 72 6f 63   xFuture = xProc
21e0: 65 73 73 50 6f 6f 6c 45 78 65 63 75 74 6f 72 2e  essPoolExecutor.
21f0: 73 75 62 6d 69 74 28 70 61 72 73 65 54 65 78 74  submit(parseText
2200: 2c 20 72 65 71 75 65 73 74 2e 66 6f 72 6d 73 2e  , request.forms.
2210: 74 65 78 74 2c 20 64 55 73 65 72 4f 70 74 69 6f  text, dUserOptio
2220: 6e 73 2c 20 62 6f 6f 6c 28 72 65 71 75 65 73 74  ns, bool(request
2230: 2e 66 6f 72 6d 73 2e 74 66 29 2c 20 73 45 72 72  .forms.tf), sErr
2240: 6f 72 29 0a 20 20 20 20 20 20 20 20 72 65 74 75  or).        retu
2250: 72 6e 20 78 46 75 74 75 72 65 2e 72 65 73 75 6c  rn xFuture.resul
2260: 74 28 29 0a 20 20 20 20 65 78 63 65 70 74 20 28  t().    except (
2270: 63 6f 6e 63 75 72 72 65 6e 74 2e 66 75 74 75 72  concurrent.futur
2280: 65 73 2e 54 69 6d 65 6f 75 74 45 72 72 6f 72 2c  es.TimeoutError,
2290: 20 63 6f 6e 63 75 72 72 65 6e 74 2e 66 75 74 75   concurrent.futu
22a0: 72 65 73 2e 43 61 6e 63 65 6c 6c 65 64 45 72 72  res.CancelledErr
22b0: 6f 72 29 3a 0a 20 20 20 20 20 20 20 20 72 65 74  or):.        ret
22c0: 75 72 6e 20 27 7b 22 65 72 72 6f 72 22 3a 20 22  urn '{"error": "
22d0: 41 6e 61 6c 79 73 69 73 20 61 62 6f 72 74 65 64  Analysis aborted
22e0: 20 28 74 69 6d 65 20 6f 75 74 20 6f 72 20 63 61   (time out or ca
22f0: 6e 63 65 6c 6c 65 64 29 22 7d 27 0a 20 20 20 20  ncelled)"}'.    
2300: 65 78 63 65 70 74 20 63 6f 6e 63 75 72 72 65 6e  except concurren
2310: 74 2e 66 75 74 75 72 65 73 2e 42 72 6f 6b 65 6e  t.futures.Broken
2320: 45 78 65 63 75 74 6f 72 3a 0a 20 20 20 20 20 20  Executor:.      
2330: 20 20 72 65 74 75 72 6e 20 27 7b 22 65 72 72 6f    return '{"erro
2340: 72 22 3a 20 22 45 78 65 63 75 74 6f 72 20 62 72  r": "Executor br
2350: 6f 6b 65 6e 2e 20 54 68 65 20 73 65 72 76 65 72  oken. The server
2360: 20 66 61 69 6c 65 64 2e 22 7d 27 0a 20 20 20 20   failed."}'.    
2370: 72 65 74 75 72 6e 20 27 7b 22 65 72 72 6f 72 22  return '{"error"
2380: 3a 20 22 46 61 74 61 6c 20 65 72 72 6f 72 2e 20  : "Fatal error. 
2390: 54 68 65 20 73 65 72 76 65 72 20 66 61 69 6c 65  The server faile
23a0: 64 2e 22 7d 27 0a 0a 40 61 70 70 2e 72 6f 75 74  d."}'..@app.rout
23b0: 65 28 22 2f 73 65 74 5f 6f 70 74 69 6f 6e 73 2f  e("/set_options/
23c0: 66 72 22 2c 20 6d 65 74 68 6f 64 3d 22 50 4f 53  fr", method="POS
23d0: 54 22 29 0a 64 65 66 20 73 65 74 4f 70 74 69 6f  T").def setOptio
23e0: 6e 73 20 28 29 3a 0a 20 20 20 20 22 73 65 74 20  ns ():.    "set 
23f0: 67 72 61 6d 6d 61 72 20 6f 70 74 69 6f 6e 73 20  grammar options 
2400: 66 6f 72 20 63 75 72 72 65 6e 74 20 75 73 65 72  for current user
2410: 22 0a 20 20 20 20 72 65 73 70 6f 6e 73 65 2e 73  ".    response.s
2420: 65 74 5f 68 65 61 64 65 72 28 22 43 6f 6e 74 65  et_header("Conte
2430: 6e 74 2d 54 79 70 65 22 2c 20 22 61 70 70 6c 69  nt-Type", "appli
2440: 63 61 74 69 6f 6e 2f 6a 73 6f 6e 3b 20 63 68 61  cation/json; cha
2450: 72 73 65 74 3d 55 54 46 2d 38 22 29 0a 20 20 20  rset=UTF-8").   
2460: 20 69 66 20 72 65 71 75 65 73 74 2e 66 6f 72 6d   if request.form
2470: 73 2e 6f 70 74 69 6f 6e 73 3a 0a 20 20 20 20 20  s.options:.     
2480: 20 20 20 73 55 73 65 72 49 64 20 3d 20 72 65 71     sUserId = req
2490: 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65  uest.cookies.use
24a0: 72 5f 69 64 20 20 69 66 20 72 65 71 75 65 73 74  r_id  if request
24b0: 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72 5f 69 64  .cookies.user_id
24c0: 20 20 65 6c 73 65 20 6e 65 78 74 28 75 73 65 72    else next(user
24d0: 47 65 6e 65 72 61 74 6f 72 29 0a 20 20 20 20 20  Generator).     
24e0: 20 20 20 64 4f 70 74 69 6f 6e 73 20 3d 20 64 55     dOptions = dU
24f0: 73 65 72 5b 73 55 73 65 72 49 64 5d 5b 22 67 63  ser[sUserId]["gc
2500: 5f 6f 70 74 69 6f 6e 73 22 5d 20 20 69 66 20 73  _options"]  if s
2510: 55 73 65 72 49 64 20 69 6e 20 64 55 73 65 72 20  UserId in dUser 
2520: 20 65 6c 73 65 20 64 69 63 74 28 6f 47 43 45 2e   else dict(oGCE.
2530: 67 65 74 4f 70 74 69 6f 6e 73 28 29 29 0a 20 20  getOptions()).  
2540: 20 20 20 20 20 20 74 72 79 3a 0a 20 20 20 20 20        try:.     
2550: 20 20 20 20 20 20 20 64 4f 70 74 69 6f 6e 73 2e         dOptions.
2560: 75 70 64 61 74 65 28 6a 73 6f 6e 2e 6c 6f 61 64  update(json.load
2570: 73 28 72 65 71 75 65 73 74 2e 66 6f 72 6d 73 2e  s(request.forms.
2580: 6f 70 74 69 6f 6e 73 29 29 0a 20 20 20 20 20 20  options)).      
2590: 20 20 20 20 20 20 64 55 73 65 72 5b 73 55 73 65        dUser[sUse
25a0: 72 49 64 5d 20 3d 20 7b 20 22 74 69 6d 65 22 3a  rId] = { "time":
25b0: 20 69 6e 74 28 74 69 6d 65 2e 74 69 6d 65 28 29   int(time.time()
25c0: 29 2c 20 22 67 63 5f 6f 70 74 69 6f 6e 73 22 3a  ), "gc_options":
25d0: 20 64 4f 70 74 69 6f 6e 73 20 7d 0a 20 20 20 20   dOptions }.    
25e0: 20 20 20 20 20 20 20 20 72 65 73 70 6f 6e 73 65          response
25f0: 2e 73 65 74 5f 63 6f 6f 6b 69 65 28 22 75 73 65  .set_cookie("use
2600: 72 5f 69 64 22 2c 20 73 55 73 65 72 49 64 2c 20  r_id", sUserId, 
2610: 70 61 74 68 3d 22 2f 22 2c 20 6d 61 78 5f 61 67  path="/", max_ag
2620: 65 3d 38 36 34 30 30 29 20 23 20 32 34 68 0a 20  e=86400) # 24h. 
2630: 20 20 20 20 20 20 20 20 20 20 20 72 65 74 75 72             retur
2640: 6e 20 6a 73 6f 6e 2e 64 75 6d 70 73 28 64 55 73  n json.dumps(dUs
2650: 65 72 5b 73 55 73 65 72 49 64 5d 5b 22 67 63 5f  er[sUserId]["gc_
2660: 6f 70 74 69 6f 6e 73 22 5d 2c 20 65 6e 73 75 72  options"], ensur
2670: 65 5f 61 73 63 69 69 3d 46 61 6c 73 65 29 0a 20  e_ascii=False). 
2680: 20 20 20 20 20 20 20 65 78 63 65 70 74 20 28 4b         except (K
2690: 65 79 45 72 72 6f 72 2c 20 6a 73 6f 6e 2e 4a 53  eyError, json.JS
26a0: 4f 4e 44 65 63 6f 64 65 45 72 72 6f 72 29 3a 0a  ONDecodeError):.
26b0: 20 20 20 20 20 20 20 20 20 20 20 20 74 72 61 63              trac
26c0: 65 62 61 63 6b 2e 70 72 69 6e 74 5f 65 78 63 28  eback.print_exc(
26d0: 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 72 65  ).            re
26e0: 74 75 72 6e 20 27 7b 22 65 72 72 6f 72 22 3a 20  turn '{"error": 
26f0: 22 4f 70 74 69 6f 6e 73 20 6e 6f 74 20 72 65 67  "Options not reg
2700: 69 73 74 65 72 65 64 2e 22 7d 27 0a 20 20 20 20  istered."}'.    
2710: 72 65 74 75 72 6e 20 27 7b 22 65 72 72 6f 72 22  return '{"error"
2720: 3a 20 22 4e 6f 20 6f 70 74 69 6f 6e 73 20 72 65  : "No options re
2730: 63 65 69 76 65 64 2e 22 7d 27 0a 0a 40 61 70 70  ceived."}'..@app
2740: 2e 72 6f 75 74 65 28 22 2f 72 65 73 65 74 5f 6f  .route("/reset_o
2750: 70 74 69 6f 6e 73 2f 66 72 22 2c 20 6d 65 74 68  ptions/fr", meth
2760: 6f 64 3d 22 50 4f 53 54 22 29 0a 64 65 66 20 72  od="POST").def r
2770: 65 73 65 74 4f 70 74 69 6f 6e 73 20 28 29 3a 0a  esetOptions ():.
2780: 20 20 20 20 22 64 65 66 61 75 6c 74 20 67 72 61      "default gra
2790: 6d 6d 61 72 20 6f 70 74 69 6f 6e 73 22 0a 20 20  mmar options".  
27a0: 20 20 72 65 73 70 6f 6e 73 65 2e 73 65 74 5f 68    response.set_h
27b0: 65 61 64 65 72 28 22 43 6f 6e 74 65 6e 74 2d 54  eader("Content-T
27c0: 79 70 65 22 2c 20 22 61 70 70 6c 69 63 61 74 69  ype", "applicati
27d0: 6f 6e 2f 6a 73 6f 6e 3b 20 63 68 61 72 73 65 74  on/json; charset
27e0: 3d 55 54 46 2d 38 22 29 0a 20 20 20 20 69 66 20  =UTF-8").    if 
27f0: 72 65 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e  request.cookies.
2800: 75 73 65 72 5f 69 64 20 61 6e 64 20 72 65 71 75  user_id and requ
2810: 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72  est.cookies.user
2820: 5f 69 64 20 69 6e 20 64 55 73 65 72 3a 0a 20 20  _id in dUser:.  
2830: 20 20 20 20 20 20 74 72 79 3a 0a 20 20 20 20 20        try:.     
2840: 20 20 20 20 20 20 20 64 65 6c 20 64 55 73 65 72         del dUser
2850: 5b 72 65 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73  [request.cookies
2860: 2e 75 73 65 72 5f 69 64 5d 0a 20 20 20 20 20 20  .user_id].      
2870: 20 20 65 78 63 65 70 74 20 4b 65 79 45 72 72 6f    except KeyErro
2880: 72 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 72  r:.            r
2890: 65 74 75 72 6e 20 27 7b 22 65 72 72 6f 72 22 20  eturn '{"error" 
28a0: 3a 20 22 55 6e 6b 6e 6f 77 6e 20 75 73 65 72 2e  : "Unknown user.
28b0: 22 7d 27 0a 20 20 20 20 72 65 74 75 72 6e 20 27  "}'.    return '
28c0: 7b 22 6d 65 73 73 61 67 65 22 20 3a 20 22 44 6f  {"message" : "Do
28d0: 6e 65 2e 22 7d 27 0a 0a 40 61 70 70 2e 72 6f 75  ne."}'..@app.rou
28e0: 74 65 28 22 2f 66 6f 72 6d 61 74 5f 74 65 78 74  te("/format_text
28f0: 2f 66 72 22 2c 20 6d 65 74 68 6f 64 3d 22 50 4f  /fr", method="PO
2900: 53 54 22 29 0a 64 65 66 20 66 6f 72 6d 61 74 54  ST").def formatT
2910: 65 78 74 20 28 29 3a 0a 20 20 20 20 22 61 70 70  ext ():.    "app
2920: 6c 79 20 74 68 65 20 74 65 78 74 20 66 6f 72 6d  ly the text form
2930: 61 74 74 65 72 20 61 6e 64 20 72 65 74 75 72 6e  atter and return
2940: 73 20 74 65 78 74 22 0a 20 20 20 20 72 65 74 75  s text".    retu
2950: 72 6e 20 6f 54 65 78 74 46 6f 72 6d 61 74 74 65  rn oTextFormatte
2960: 72 2e 66 6f 72 6d 61 74 54 65 78 74 28 72 65 71  r.formatText(req
2970: 75 65 73 74 2e 66 6f 72 6d 73 2e 74 65 78 74 29  uest.forms.text)
2980: 0a 0a 23 40 61 70 70 2e 72 6f 75 74 65 28 27 2f  ..#@app.route('/
2990: 73 74 61 74 69 63 2f 3c 66 69 6c 65 70 61 74 68  static/<filepath
29a0: 3a 70 61 74 68 3e 27 29 0a 23 64 65 66 20 73 65  :path>').#def se
29b0: 72 76 65 72 5f 73 74 61 74 69 63 20 28 66 69 6c  rver_static (fil
29c0: 65 70 61 74 68 29 3a 0a 23 20 20 20 20 72 65 74  epath):.#    ret
29d0: 75 72 6e 20 73 74 61 74 69 63 5f 66 69 6c 65 28  urn static_file(
29e0: 66 69 6c 65 70 61 74 68 2c 20 72 6f 6f 74 3d 27  filepath, root='
29f0: 2e 2f 76 69 65 77 73 2f 73 74 61 74 69 63 27 29  ./views/static')
2a00: 0a 0a 40 61 70 70 2e 72 6f 75 74 65 28 22 2f 73  ..@app.route("/s
2a10: 75 67 67 65 73 74 2f 66 72 22 2c 20 6d 65 74 68  uggest/fr", meth
2a20: 6f 64 3d 22 50 4f 53 54 22 29 0a 64 65 66 20 73  od="POST").def s
2a30: 75 67 67 65 73 74 50 6f 73 74 20 28 29 3a 0a 20  uggestPost ():. 
2a40: 20 20 20 72 65 73 70 6f 6e 73 65 2e 73 65 74 5f     response.set_
2a50: 68 65 61 64 65 72 28 22 43 6f 6e 74 65 6e 74 2d  header("Content-
2a60: 54 79 70 65 22 2c 20 22 61 70 70 6c 69 63 61 74  Type", "applicat
2a70: 69 6f 6e 2f 6a 73 6f 6e 3b 20 63 68 61 72 73 65  ion/json; charse
2a80: 74 3d 55 54 46 2d 38 22 29 0a 20 20 20 20 74 72  t=UTF-8").    tr
2a90: 79 3a 0a 20 20 20 20 20 20 20 20 78 46 75 74 75  y:.        xFutu
2aa0: 72 65 20 3d 20 78 50 72 6f 63 65 73 73 50 6f 6f  re = xProcessPoo
2ab0: 6c 45 78 65 63 75 74 6f 72 2e 73 75 62 6d 69 74  lExecutor.submit
2ac0: 28 73 75 67 67 65 73 74 2c 20 72 65 71 75 65 73  (suggest, reques
2ad0: 74 2e 66 6f 72 6d 73 2e 74 6f 6b 65 6e 29 0a 20  t.forms.token). 
2ae0: 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 78 46         return xF
2af0: 75 74 75 72 65 2e 72 65 73 75 6c 74 28 29 0a 20  uture.result(). 
2b00: 20 20 20 65 78 63 65 70 74 20 28 63 6f 6e 63 75     except (concu
2b10: 72 72 65 6e 74 2e 66 75 74 75 72 65 73 2e 54 69  rrent.futures.Ti
2b20: 6d 65 6f 75 74 45 72 72 6f 72 2c 20 63 6f 6e 63  meoutError, conc
2b30: 75 72 72 65 6e 74 2e 66 75 74 75 72 65 73 2e 43  urrent.futures.C
2b40: 61 6e 63 65 6c 6c 65 64 45 72 72 6f 72 29 3a 0a  ancelledError):.
2b50: 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 27          return '
2b60: 7b 22 65 72 72 6f 72 22 3a 20 22 41 6e 61 6c 79  {"error": "Analy
2b70: 73 69 73 20 61 62 6f 72 74 65 64 20 28 74 69 6d  sis aborted (tim
2b80: 65 20 6f 75 74 20 6f 72 20 63 61 6e 63 65 6c 6c  e out or cancell
2b90: 65 64 29 22 7d 27 0a 20 20 20 20 65 78 63 65 70  ed)"}'.    excep
2ba0: 74 20 63 6f 6e 63 75 72 72 65 6e 74 2e 66 75 74  t concurrent.fut
2bb0: 75 72 65 73 2e 42 72 6f 6b 65 6e 45 78 65 63 75  ures.BrokenExecu
2bc0: 74 6f 72 3a 0a 20 20 20 20 20 20 20 20 72 65 74  tor:.        ret
2bd0: 75 72 6e 20 27 7b 22 65 72 72 6f 72 22 3a 20 22  urn '{"error": "
2be0: 45 78 65 63 75 74 6f 72 20 62 72 6f 6b 65 6e 2e  Executor broken.
2bf0: 20 54 68 65 20 73 65 72 76 65 72 20 66 61 69 6c   The server fail
2c00: 65 64 2e 22 7d 27 0a 20 20 20 20 72 65 74 75 72  ed."}'.    retur
2c10: 6e 20 27 7b 22 65 72 72 6f 72 22 3a 20 22 46 61  n '{"error": "Fa
2c20: 74 61 6c 20 65 72 72 6f 72 2e 20 54 68 65 20 73  tal error. The s
2c30: 65 72 76 65 72 20 66 61 69 6c 65 64 2e 22 7d 27  erver failed."}'
2c40: 0a 0a 0a 23 20 45 52 52 4f 52 0a 40 61 70 70 2e  ...# ERROR.@app.
2c50: 65 72 72 6f 72 28 34 30 34 29 0a 64 65 66 20 65  error(404).def e
2c60: 72 72 6f 72 34 30 34 20 28 65 72 72 6f 72 29 3a  rror404 (error):
2c70: 0a 20 20 20 20 22 34 30 34 20 65 72 72 6f 72 20  .    "404 error 
2c80: 70 61 67 65 22 0a 20 20 20 20 72 65 74 75 72 6e  page".    return
2c90: 20 27 45 72 72 6f 72 20 34 30 34 2e 3c 62 72 2f   'Error 404.<br/
2ca0: 3e 27 20 2b 20 73 74 72 28 65 72 72 6f 72 29 0a  >' + str(error).
2cb0: 0a 0a 23 23 20 43 6f 6d 6d 6f 6e 20 66 75 6e 63  ..## Common func
2cc0: 74 69 6f 6e 73 0a 0a 64 65 66 20 70 75 72 67 65  tions..def purge
2cd0: 55 73 65 72 73 20 28 29 3a 0a 20 20 20 20 22 64  Users ():.    "d
2ce0: 65 6c 65 74 65 20 75 73 65 72 20 6f 70 74 69 6f  elete user optio
2cf0: 6e 73 20 6f 6c 64 65 72 20 74 68 61 6e 20 6e 20  ns older than n 
2d00: 68 6f 75 72 73 22 0a 20 20 20 20 74 72 79 3a 0a  hours".    try:.
2d10: 20 20 20 20 20 20 20 20 6e 4e 6f 77 4d 69 6e 75          nNowMinu
2d20: 73 4e 48 6f 75 72 73 20 3d 20 69 6e 74 28 74 69  sNHours = int(ti
2d30: 6d 65 2e 74 69 6d 65 28 29 29 20 2d 20 28 69 6e  me.time()) - (in
2d40: 74 28 72 65 71 75 65 73 74 2e 66 6f 72 6d 73 2e  t(request.forms.
2d50: 68 6f 75 72 73 29 20 2a 20 36 30 20 2a 20 36 30  hours) * 60 * 60
2d60: 29 0a 20 20 20 20 20 20 20 20 66 6f 72 20 6e 55  ).        for nU
2d70: 73 65 72 49 64 2c 20 64 56 61 6c 75 65 20 69 6e  serId, dValue in
2d80: 20 64 55 73 65 72 2e 69 74 65 6d 73 28 29 3a 0a   dUser.items():.
2d90: 20 20 20 20 20 20 20 20 20 20 20 20 69 66 20 64              if d
2da0: 56 61 6c 75 65 5b 22 74 69 6d 65 22 5d 20 3c 20  Value["time"] < 
2db0: 6e 4e 6f 77 4d 69 6e 75 73 4e 48 6f 75 72 73 3a  nNowMinusNHours:
2dc0: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
2dd0: 20 64 65 6c 20 64 55 73 65 72 5b 6e 55 73 65 72   del dUser[nUser
2de0: 49 64 5d 0a 20 20 20 20 20 20 20 20 72 65 74 75  Id].        retu
2df0: 72 6e 20 54 72 75 65 0a 20 20 20 20 65 78 63 65  rn True.    exce
2e00: 70 74 20 4b 65 79 45 72 72 6f 72 3a 0a 20 20 20  pt KeyError:.   
2e10: 20 20 20 20 20 74 72 61 63 65 62 61 63 6b 2e 70       traceback.p
2e20: 72 69 6e 74 5f 65 78 63 28 29 0a 20 20 20 20 20  rint_exc().     
2e30: 20 20 20 72 65 74 75 72 6e 20 46 61 6c 73 65 0a     return False.
2e40: 0a 0a 23 23 23 23 20 53 54 41 52 54 20 23 23 23  ..#### START ###
2e50: 23 0a 0a 64 65 66 20 6d 61 69 6e 20 28 73 48 6f  #..def main (sHo
2e60: 73 74 3d 22 6c 6f 63 61 6c 68 6f 73 74 22 2c 20  st="localhost", 
2e70: 6e 50 6f 72 74 3d 38 30 38 30 2c 20 64 4f 70 74  nPort=8080, dOpt
2e80: 69 6f 6e 73 3d 4e 6f 6e 65 2c 20 62 54 65 73 74  ions=None, bTest
2e90: 50 61 67 65 3d 46 61 6c 73 65 2c 20 6e 4d 75 6c  Page=False, nMul
2ea0: 74 69 43 50 55 3d 4e 6f 6e 65 29 3a 0a 20 20 20  tiCPU=None):.   
2eb0: 20 22 73 74 61 72 74 20 73 65 72 76 65 72 22 0a   "start server".
2ec0: 20 20 20 20 67 6c 6f 62 61 6c 20 54 45 53 54 50      global TESTP
2ed0: 41 47 45 0a 20 20 20 20 67 6c 6f 62 61 6c 20 48  AGE.    global H
2ee0: 4f 4d 45 50 41 47 45 0a 0a 20 20 20 20 69 66 20  OMEPAGE..    if 
2ef0: 62 54 65 73 74 50 61 67 65 3a 0a 20 20 20 20 20  bTestPage:.     
2f00: 20 20 20 54 45 53 54 50 41 47 45 20 3d 20 54 72     TESTPAGE = Tr
2f10: 75 65 0a 20 20 20 20 20 20 20 20 48 4f 4d 45 50  ue.        HOMEP
2f20: 41 47 45 20 3d 20 48 4f 4d 45 50 41 47 45 2e 72  AGE = HOMEPAGE.r
2f30: 65 70 6c 61 63 65 28 22 7b 53 45 52 56 45 52 5f  eplace("{SERVER_
2f40: 50 4f 52 54 7d 22 2c 20 73 74 72 28 6e 50 6f 72  PORT}", str(nPor
2f50: 74 29 29 0a 20 20 20 20 69 66 20 64 4f 70 74 69  t)).    if dOpti
2f60: 6f 6e 73 3a 0a 20 20 20 20 20 20 20 20 6f 47 43  ons:.        oGC
2f70: 45 2e 73 65 74 4f 70 74 69 6f 6e 73 28 64 4f 70  E.setOptions(dOp
2f80: 74 69 6f 6e 73 29 0a 0a 20 20 20 20 23 20 50 79  tions)..    # Py
2f90: 74 68 6f 6e 20 76 65 72 73 69 6f 6e 0a 20 20 20  thon version.   
2fa0: 20 70 72 69 6e 74 28 22 50 79 74 68 6f 6e 3a 20   print("Python: 
2fb0: 22 20 2b 20 73 79 73 2e 76 65 72 73 69 6f 6e 29  " + sys.version)
2fc0: 0a 20 20 20 20 69 66 20 73 79 73 2e 76 65 72 73  .    if sys.vers
2fd0: 69 6f 6e 20 3c 20 22 33 2e 37 22 3a 0a 20 20 20  ion < "3.7":.   
2fe0: 20 20 20 20 20 70 72 69 6e 74 28 22 50 79 74 68       print("Pyth
2ff0: 6f 6e 20 33 2e 37 2b 20 72 65 71 75 69 72 65 64  on 3.7+ required
3000: 22 29 0a 20 20 20 20 20 20 20 20 72 65 74 75 72  ").        retur
3010: 6e 0a 20 20 20 20 23 20 47 72 61 6d 6d 61 6c 65  n.    # Grammale
3020: 63 74 65 0a 20 20 20 20 65 63 68 6f 28 22 47 72  cte.    echo("Gr
3030: 61 6d 6d 61 6c 65 63 74 65 20 76 7b 7d 22 2e 66  ammalecte v{}".f
3040: 6f 72 6d 61 74 28 6f 47 43 45 2e 76 65 72 73 69  ormat(oGCE.versi
3050: 6f 6e 29 29 0a 20 20 20 20 6f 47 43 45 2e 64 69  on)).    oGCE.di
3060: 73 70 6c 61 79 4f 70 74 69 6f 6e 73 28 29 0a 20  splayOptions(). 
3070: 20 20 20 23 20 50 72 6f 63 65 73 73 20 50 6f 6f     # Process Poo
3080: 6c 20 45 78 65 63 75 74 6f 72 0a 20 20 20 20 69  l Executor.    i
3090: 6e 69 74 45 78 65 63 75 74 6f 72 28 6e 4d 75 6c  nitExecutor(nMul
30a0: 74 69 43 50 55 29 0a 20 20 20 20 23 20 53 65 72  tiCPU).    # Ser
30b0: 76 65 72 20 28 42 6f 74 74 6c 65 29 0a 20 20 20  ver (Bottle).   
30c0: 20 72 75 6e 28 61 70 70 2c 20 68 6f 73 74 3d 73   run(app, host=s
30d0: 48 6f 73 74 2c 20 70 6f 72 74 3d 6e 50 6f 72 74  Host, port=nPort
30e0: 29 0a 0a 0a 69 66 20 5f 5f 6e 61 6d 65 5f 5f 20  )...if __name__ 
30f0: 3d 3d 20 27 5f 5f 6d 61 69 6e 5f 5f 27 3a 0a 20  == '__main__':. 
3100: 20 20 20 78 50 61 72 73 65 72 20 3d 20 61 72 67     xParser = arg
3110: 70 61 72 73 65 2e 41 72 67 75 6d 65 6e 74 50 61  parse.ArgumentPa
3120: 72 73 65 72 28 29 0a 20 20 20 20 23 78 50 61 72  rser().    #xPar
3130: 73 65 72 2e 61 64 64 5f 61 72 67 75 6d 65 6e 74  ser.add_argument
3140: 28 22 6c 61 6e 67 22 2c 20 74 79 70 65 3d 73 74  ("lang", type=st
3150: 72 2c 20 6e 61 72 67 73 3d 27 2b 27 2c 20 68 65  r, nargs='+', he
3160: 6c 70 3d 22 6c 61 6e 67 20 70 72 6f 6a 65 63 74  lp="lang project
3170: 20 74 6f 20 67 65 6e 65 72 61 74 65 20 28 6e 61   to generate (na
3180: 6d 65 20 6f 66 20 66 6f 6c 64 65 72 20 69 6e 20  me of folder in 
3190: 2f 6c 61 6e 67 29 22 29 0a 20 20 20 20 78 50 61  /lang)").    xPa
31a0: 72 73 65 72 2e 61 64 64 5f 61 72 67 75 6d 65 6e  rser.add_argumen
31b0: 74 28 22 2d 68 74 22 2c 20 22 2d 2d 68 6f 73 74  t("-ht", "--host
31c0: 22 2c 20 68 65 6c 70 3d 22 68 6f 73 74 20 28 64  ", help="host (d
31d0: 65 66 61 75 6c 74 3a 20 6c 6f 63 61 6c 68 6f 73  efault: localhos
31e0: 74 29 22 2c 20 74 79 70 65 3d 73 74 72 29 0a 20  t)", type=str). 
31f0: 20 20 20 78 50 61 72 73 65 72 2e 61 64 64 5f 61     xParser.add_a
3200: 72 67 75 6d 65 6e 74 28 22 2d 70 22 2c 20 22 2d  rgument("-p", "-
3210: 2d 70 6f 72 74 22 2c 20 68 65 6c 70 3d 22 70 6f  -port", help="po
3220: 72 74 20 28 64 65 66 61 75 6c 74 3a 20 38 30 38  rt (default: 808
3230: 30 29 22 2c 20 74 79 70 65 3d 69 6e 74 29 0a 20  0)", type=int). 
3240: 20 20 20 78 50 61 72 73 65 72 2e 61 64 64 5f 61     xParser.add_a
3250: 72 67 75 6d 65 6e 74 28 22 2d 6d 70 22 2c 20 22  rgument("-mp", "
3260: 2d 2d 6d 75 6c 74 69 70 72 6f 63 65 73 73 6f 72  --multiprocessor
3270: 22 2c 20 68 65 6c 70 3d 22 64 65 66 69 6e 65 20  ", help="define 
3280: 68 6f 77 20 6d 61 6e 79 20 70 72 6f 63 65 73 73  how many process
3290: 65 73 20 66 6f 72 20 74 68 65 20 67 72 61 6d 6d  es for the gramm
32a0: 61 72 20 63 68 65 63 6b 65 72 22 2c 20 74 79 70  ar checker", typ
32b0: 65 3d 69 6e 74 29 0a 20 20 20 20 78 50 61 72 73  e=int).    xPars
32c0: 65 72 2e 61 64 64 5f 61 72 67 75 6d 65 6e 74 28  er.add_argument(
32d0: 22 2d 74 22 2c 20 22 2d 2d 74 65 73 74 5f 70 61  "-t", "--test_pa
32e0: 67 65 22 2c 20 68 65 6c 70 3d 22 70 61 67 65 20  ge", help="page 
32f0: 74 6f 20 74 65 73 74 20 74 68 65 20 73 65 72 76  to test the serv
3300: 65 72 20 6f 6e 20 2f 22 2c 20 61 63 74 69 6f 6e  er on /", action
3310: 3d 22 73 74 6f 72 65 5f 74 72 75 65 22 29 0a 20  ="store_true"). 
3320: 20 20 20 78 50 61 72 73 65 72 2e 61 64 64 5f 61     xParser.add_a
3330: 72 67 75 6d 65 6e 74 28 22 2d 6f 6e 22 2c 20 22  rgument("-on", "
3340: 2d 2d 6f 70 74 5f 6f 6e 22 2c 20 6e 61 72 67 73  --opt_on", nargs
3350: 3d 22 2b 22 2c 20 68 65 6c 70 3d 22 61 63 74 69  ="+", help="acti
3360: 76 61 74 65 20 6f 70 74 69 6f 6e 73 22 29 0a 20  vate options"). 
3370: 20 20 20 78 50 61 72 73 65 72 2e 61 64 64 5f 61     xParser.add_a
3380: 72 67 75 6d 65 6e 74 28 22 2d 6f 66 66 22 2c 20  rgument("-off", 
3390: 22 2d 2d 6f 70 74 5f 6f 66 66 22 2c 20 6e 61 72  "--opt_off", nar
33a0: 67 73 3d 22 2b 22 2c 20 68 65 6c 70 3d 22 64 65  gs="+", help="de
33b0: 61 63 74 69 76 61 74 65 20 6f 70 74 69 6f 6e 73  activate options
33c0: 22 29 0a 20 20 20 20 78 41 72 67 73 20 3d 20 78  ").    xArgs = x
33d0: 50 61 72 73 65 72 2e 70 61 72 73 65 5f 61 72 67  Parser.parse_arg
33e0: 73 28 29 0a 0a 20 20 20 20 64 4f 70 74 20 3d 20  s()..    dOpt = 
33f0: 4e 6f 6e 65 0a 20 20 20 20 69 66 20 78 41 72 67  None.    if xArg
3400: 73 2e 6f 70 74 5f 6f 6e 20 20 6f 72 20 20 78 41  s.opt_on  or  xA
3410: 72 67 73 2e 6f 70 74 5f 6f 66 66 3a 0a 20 20 20  rgs.opt_off:.   
3420: 20 20 20 20 20 64 4f 70 74 20 3d 20 7b 7d 0a 20       dOpt = {}. 
3430: 20 20 20 20 20 20 20 69 66 20 78 41 72 67 73 2e         if xArgs.
3440: 6f 70 74 5f 6f 6e 3a 0a 20 20 20 20 20 20 20 20  opt_on:.        
3450: 20 20 20 20 64 4f 70 74 20 3d 20 7b 20 6f 70 74      dOpt = { opt
3460: 3a 54 72 75 65 20 20 66 6f 72 20 6f 70 74 20 69  :True  for opt i
3470: 6e 20 78 41 72 67 73 2e 6f 70 74 5f 6f 6e 20 7d  n xArgs.opt_on }
3480: 0a 20 20 20 20 20 20 20 20 69 66 20 78 41 72 67  .        if xArg
3490: 73 2e 6f 70 74 5f 6f 66 66 3a 0a 20 20 20 20 20  s.opt_off:.     
34a0: 20 20 20 20 20 20 20 64 4f 70 74 2e 75 70 64 61         dOpt.upda
34b0: 74 65 28 7b 20 6f 70 74 3a 46 61 6c 73 65 20 20  te({ opt:False  
34c0: 66 6f 72 20 6f 70 74 20 69 6e 20 78 41 72 67 73  for opt in xArgs
34d0: 2e 6f 70 74 5f 6f 66 66 20 7d 29 0a 0a 20 20 20  .opt_off })..   
34e0: 20 6d 61 69 6e 28 78 41 72 67 73 2e 68 6f 73 74   main(xArgs.host
34f0: 20 6f 72 20 22 6c 6f 63 61 6c 68 6f 73 74 22 2c   or "localhost",
3500: 20 5c 0a 20 20 20 20 20 20 20 20 20 78 41 72 67   \.         xArg
3510: 73 2e 70 6f 72 74 20 6f 72 20 38 30 38 30 2c 20  s.port or 8080, 
3520: 5c 0a 20 20 20 20 20 20 20 20 20 64 4f 70 74 2c  \.         dOpt,
3530: 0a 20 20 20 20 20 20 20 20 20 78 41 72 67 73 2e  .         xArgs.
3540: 74 65 73 74 5f 70 61 67 65 2c 0a 20 20 20 20 20  test_page,.     
3550: 20 20 20 20 78 41 72 67 73 2e 6d 75 6c 74 69 70      xArgs.multip
3560: 72 6f 63 65 73 73 6f 72 29 0a 65 6c 73 65 3a 0a  rocessor).else:.
3570: 20 20 20 20 23 20 4d 75 73 74 20 62 65 20 6c 61      # Must be la
3580: 75 6e 63 68 65 64 20 61 74 20 73 74 61 72 74 2c  unched at start,
3590: 20 66 6f 72 20 57 53 47 49 20 73 65 72 76 65 72   for WSGI server
35a0: 20 28 77 68 69 63 68 20 64 6f 65 73 6e e2 80 99   (which doesn...
35b0: 74 20 63 61 6c 6c 20 6d 61 69 6e 28 29 29 0a 20  t call main()). 
35c0: 20 20 20 23 20 57 53 47 49 20 73 65 72 76 65 72     # WSGI server
35d0: 73 20 6a 75 73 74 20 69 6d 70 6f 72 74 20 74 68  s just import th
35e0: 65 20 67 69 76 65 6e 20 66 69 6c 65 20 61 73 20  e given file as 
35f0: 61 20 6d 6f 64 75 6c 65 20 61 6e 64 20 75 73 65  a module and use
3600: 20 61 6e 20 6f 62 6a 65 63 74 20 65 78 70 6f 72   an object expor
3610: 74 65 64 20 66 72 6f 6d 20 69 74 20 28 3c 61 70  ted from it (<ap
3620: 70 3e 20 69 6e 20 74 68 69 73 20 63 61 73 65 29  p> in this case)
3630: 20 74 6f 20 72 75 6e 20 74 68 65 20 73 65 72 76   to run the serv
3640: 65 72 2e 0a 20 20 20 20 69 6e 69 74 45 78 65 63  er..    initExec
3650: 75 74 6f 72 28 29 0a                             utor().