Grammalecte  Hex Artifact Content

Artifact 38ce8a200e4c14f64fa42be0505bef16906d89bcddfb58a873083a6bbe756751:


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 6e  ammarChecker.gen
0420: 65 72 61 74 65 50 61 72 61 67 72 61 70 68 41 73  erateParagraphAs
0430: 4a 53 4f 4e 28 69 2c 20 73 50 61 72 61 67 72 61  JSON(i, sParagra
0440: 70 68 2c 20 64 4f 70 74 69 6f 6e 73 3d 64 4f 70  ph, dOptions=dOp
0450: 74 69 6f 6e 73 2c 20 62 45 6d 70 74 79 49 66 4e  tions, bEmptyIfN
0460: 6f 45 72 72 6f 72 73 3d 54 72 75 65 2c 20 62 52  oErrors=True, bR
0470: 65 74 75 72 6e 54 65 78 74 3d 62 46 6f 72 6d 61  eturnText=bForma
0480: 74 54 65 78 74 29 0a 20 20 20 20 20 20 20 20 69  tText).        i
0490: 66 20 73 52 65 73 75 6c 74 3a 0a 20 20 20 20 20  f sResult:.     
04a0: 20 20 20 20 20 20 20 69 66 20 73 44 61 74 61 4a         if sDataJ
04b0: 53 4f 4e 3a 0a 20 20 20 20 20 20 20 20 20 20 20  SON:.           
04c0: 20 20 20 20 20 73 44 61 74 61 4a 53 4f 4e 20 2b       sDataJSON +
04d0: 3d 20 22 2c 5c 6e 22 0a 20 20 20 20 20 20 20 20  = ",\n".        
04e0: 20 20 20 20 73 44 61 74 61 4a 53 4f 4e 20 2b 3d      sDataJSON +=
04f0: 20 73 52 65 73 75 6c 74 0a 20 20 20 20 73 4a 53   sResult.    sJS
0500: 4f 4e 20 2b 3d 20 73 44 61 74 61 4a 53 4f 4e 20  ON += sDataJSON 
0510: 2b 20 22 5c 6e 5d 7d 5c 6e 22 0a 20 20 20 20 72  + "\n]}\n".    r
0520: 65 74 75 72 6e 20 73 4a 53 4f 4e 0a 0a 0a 64 65  eturn sJSON...de
0530: 66 20 73 75 67 67 65 73 74 20 28 73 54 6f 6b 65  f suggest (sToke
0540: 6e 29 3a 0a 20 20 20 20 22 67 65 74 20 73 70 65  n):.    "get spe
0550: 6c 6c 69 6e 67 20 73 75 67 67 65 73 74 69 6f 6e  lling suggestion
0560: 73 20 66 6f 72 20 3c 73 54 6f 6b 65 6e 3e 20 61  s for <sToken> a
0570: 6e 64 20 72 65 74 75 72 6e 20 74 68 65 6d 20 69  nd return them i
0580: 6e 20 61 20 4a 53 4f 4e 20 66 6f 72 6d 61 74 22  n a JSON format"
0590: 0a 20 20 20 20 69 66 20 73 54 6f 6b 65 6e 3a 0a  .    if sToken:.
05a0: 20 20 20 20 20 20 20 20 6c 53 75 67 67 20 3d 20          lSugg = 
05b0: 5b 5d 0a 20 20 20 20 20 20 20 20 74 72 79 3a 0a  [].        try:.
05c0: 20 20 20 20 20 20 20 20 20 20 20 20 66 6f 72 20              for 
05d0: 6c 20 69 6e 20 6f 53 70 65 6c 6c 43 68 65 63 6b  l in oSpellCheck
05e0: 65 72 2e 73 75 67 67 65 73 74 28 73 54 6f 6b 65  er.suggest(sToke
05f0: 6e 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  n):.            
0600: 20 20 20 20 6c 53 75 67 67 2e 65 78 74 65 6e 64      lSugg.extend
0610: 28 6c 29 0a 20 20 20 20 20 20 20 20 65 78 63 65  (l).        exce
0620: 70 74 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  pt:.            
0630: 72 65 74 75 72 6e 20 27 7b 22 65 72 72 6f 72 22  return '{"error"
0640: 3a 20 22 73 75 67 67 65 73 74 69 6f 6e 20 6d 6f  : "suggestion mo
0650: 64 75 6c 65 20 66 61 69 6c 65 64 22 7d 27 0a 20  dule failed"}'. 
0660: 20 20 20 20 20 20 20 74 72 79 3a 0a 20 20 20 20         try:.    
0670: 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 27          return '
0680: 7b 22 73 75 67 67 65 73 74 69 6f 6e 73 22 3a 20  {"suggestions": 
0690: 27 20 2b 20 6a 73 6f 6e 2e 64 75 6d 70 73 28 6c  ' + json.dumps(l
06a0: 53 75 67 67 2c 20 65 6e 73 75 72 65 5f 61 73 63  Sugg, ensure_asc
06b0: 69 69 3d 46 61 6c 73 65 29 20 2b 20 27 7d 27 0a  ii=False) + '}'.
06c0: 20 20 20 20 20 20 20 20 65 78 63 65 70 74 20 6a          except j
06d0: 73 6f 6e 2e 4a 53 4f 4e 44 65 63 6f 64 65 45 72  son.JSONDecodeEr
06e0: 72 6f 72 3a 0a 20 20 20 20 20 20 20 20 20 20 20  ror:.           
06f0: 20 72 65 74 75 72 6e 20 27 7b 22 65 72 72 6f 72   return '{"error
0700: 22 3a 20 22 6a 73 6f 6e 20 65 6e 63 6f 64 69 6e  ": "json encodin
0710: 67 20 65 72 72 6f 72 22 7d 27 0a 20 20 20 20 72  g error"}'.    r
0720: 65 74 75 72 6e 20 27 7b 22 65 72 72 6f 72 22 3a  eturn '{"error":
0730: 20 22 6e 6f 20 74 6f 6b 65 6e 20 67 69 76 65 6e   "no token given
0740: 22 7d 27 0a 0a 0a 23 23 23 23 20 50 52 4f 43 45  "}'...#### PROCE
0750: 53 53 20 50 4f 4f 4c 20 45 58 45 43 55 54 4f 52  SS POOL EXECUTOR
0760: 20 23 23 23 23 0a 78 50 72 6f 63 65 73 73 50 6f   ####.xProcessPo
0770: 6f 6c 45 78 65 63 75 74 6f 72 20 3d 20 4e 6f 6e  olExecutor = Non
0780: 65 0a 0a 64 65 66 20 69 6e 69 74 45 78 65 63 75  e..def initExecu
0790: 74 6f 72 20 28 6e 4d 75 6c 74 69 43 50 55 3d 4e  tor (nMultiCPU=N
07a0: 6f 6e 65 29 3a 0a 20 20 20 20 22 70 72 6f 63 65  one):.    "proce
07b0: 73 73 20 70 6f 6f 6c 20 65 78 65 63 75 74 6f 72  ss pool executor
07c0: 20 69 6e 69 74 69 61 6c 69 73 61 74 69 6f 6e 22   initialisation"
07d0: 0a 20 20 20 20 67 6c 6f 62 61 6c 20 78 50 72 6f  .    global xPro
07e0: 63 65 73 73 50 6f 6f 6c 45 78 65 63 75 74 6f 72  cessPoolExecutor
07f0: 0a 20 20 20 20 69 66 20 78 50 72 6f 63 65 73 73  .    if xProcess
0800: 50 6f 6f 6c 45 78 65 63 75 74 6f 72 3a 0a 20 20  PoolExecutor:.  
0810: 20 20 20 20 20 20 23 20 77 65 20 73 68 75 74 64        # we shutd
0820: 6f 77 6e 20 74 68 65 20 50 72 6f 63 65 73 73 50  own the ProcessP
0830: 6f 6f 6c 45 78 65 63 75 74 6f 72 20 77 68 69 63  oolExecutor whic
0840: 68 20 6d 61 79 20 68 61 76 65 20 62 65 65 6e 20  h may have been 
0850: 6c 61 75 6e 63 68 65 64 20 70 72 65 76 69 6f 75  launched previou
0860: 73 6c 79 0a 20 20 20 20 20 20 20 20 70 72 69 6e  sly.        prin
0870: 74 28 22 50 72 6f 63 65 73 73 50 6f 6f 6c 45 78  t("ProcessPoolEx
0880: 65 63 75 74 6f 72 20 73 68 75 74 64 6f 77 6e 2e  ecutor shutdown.
0890: 22 29 0a 20 20 20 20 20 20 20 20 78 50 72 6f 63  ").        xProc
08a0: 65 73 73 50 6f 6f 6c 45 78 65 63 75 74 6f 72 2e  essPoolExecutor.
08b0: 73 68 75 74 64 6f 77 6e 28 77 61 69 74 3d 46 61  shutdown(wait=Fa
08c0: 6c 73 65 29 0a 20 20 20 20 6e 4d 61 78 43 50 55  lse).    nMaxCPU
08d0: 20 3d 20 6d 61 78 28 6f 73 2e 63 70 75 5f 63 6f   = max(os.cpu_co
08e0: 75 6e 74 28 29 2d 31 2c 20 31 29 0a 20 20 20 20  unt()-1, 1).    
08f0: 69 66 20 6e 4d 75 6c 74 69 43 50 55 20 69 73 20  if nMultiCPU is 
0900: 4e 6f 6e 65 20 6f 72 20 6e 6f 74 20 28 31 20 3c  None or not (1 <
0910: 3d 20 6e 4d 75 6c 74 69 43 50 55 20 3c 3d 20 6e  = nMultiCPU <= n
0920: 4d 61 78 43 50 55 29 3a 0a 20 20 20 20 20 20 20  MaxCPU):.       
0930: 20 6e 4d 75 6c 74 69 43 50 55 20 3d 20 6e 4d 61   nMultiCPU = nMa
0940: 78 43 50 55 0a 20 20 20 20 70 72 69 6e 74 28 22  xCPU.    print("
0950: 43 50 55 20 70 72 6f 63 65 73 73 65 73 20 75 73  CPU processes us
0960: 65 64 20 66 6f 72 20 77 6f 72 6b 65 72 73 3a 20  ed for workers: 
0970: 22 2c 20 6e 4d 75 6c 74 69 43 50 55 29 0a 20 20  ", nMultiCPU).  
0980: 20 20 78 50 72 6f 63 65 73 73 50 6f 6f 6c 45 78    xProcessPoolEx
0990: 65 63 75 74 6f 72 20 3d 20 63 6f 6e 63 75 72 72  ecutor = concurr
09a0: 65 6e 74 2e 66 75 74 75 72 65 73 2e 50 72 6f 63  ent.futures.Proc
09b0: 65 73 73 50 6f 6f 6c 45 78 65 63 75 74 6f 72 28  essPoolExecutor(
09c0: 6d 61 78 5f 77 6f 72 6b 65 72 73 3d 6e 4d 75 6c  max_workers=nMul
09d0: 74 69 43 50 55 29 0a 0a 0a 23 23 23 23 20 53 45  tiCPU)...#### SE
09e0: 52 56 45 55 52 20 23 23 23 23 0a 0a 48 4f 4d 45  RVEUR ####..HOME
09f0: 50 41 47 45 20 3d 20 22 22 22 0a 3c 21 44 4f 43  PAGE = """.<!DOC
0a00: 54 59 50 45 20 48 54 4d 4c 3e 0a 3c 68 74 6d 6c  TYPE HTML>.<html
0a10: 3e 0a 20 20 20 20 3c 68 65 61 64 3e 0a 20 20 20  >.    <head>.   
0a20: 20 20 20 20 20 3c 6d 65 74 61 20 68 74 74 70 2d       <meta http-
0a30: 65 71 75 69 76 3d 22 63 6f 6e 74 65 6e 74 2d 74  equiv="content-t
0a40: 79 70 65 22 20 63 6f 6e 74 65 6e 74 3d 22 74 65  ype" content="te
0a50: 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65 74  xt/html; charset
0a60: 3d 55 54 46 2d 38 22 20 2f 3e 0a 20 20 20 20 3c  =UTF-8" />.    <
0a70: 2f 68 65 61 64 3e 0a 0a 20 20 20 20 3c 62 6f 64  /head>..    <bod
0a80: 79 20 63 6c 61 73 73 3d 22 70 61 6e 65 6c 22 3e  y class="panel">
0a90: 0a 20 20 20 20 20 20 20 20 3c 68 31 3e 47 72 61  .        <h1>Gra
0aa0: 6d 6d 61 6c 65 63 74 65 20 c2 b7 20 53 65 72 76  mmalecte .. Serv
0ab0: 65 75 72 3c 2f 68 31 3e 0a 0a 20 20 20 20 20 20  eur</h1>..      
0ac0: 20 20 3c 68 32 3e 49 4e 46 4f 52 4d 41 54 49 4f    <h2>INFORMATIO
0ad0: 4e 53 3c 2f 68 31 3e 0a 0a 20 20 20 20 20 20 20  NS</h1>..       
0ae0: 20 3c 68 33 3e 41 6e 61 6c 79 73 65 72 20 64 75   <h3>Analyser du
0af0: 20 74 65 78 74 65 3c 2f 68 33 3e 0a 20 20 20 20   texte</h3>.    
0b00: 20 20 20 20 3c 70 3e 5b 61 64 72 65 73 73 65 5f      <p>[adresse_
0b10: 73 65 72 76 65 75 72 5d 3a 7b 53 45 52 56 45 52  serveur]:{SERVER
0b20: 5f 50 4f 52 54 7d 2f 67 63 5f 74 65 78 74 2f 66  _PORT}/gc_text/f
0b30: 72 20 28 50 4f 53 54 29 3c 2f 70 3e 0a 20 20 20  r (POST)</p>.   
0b40: 20 20 20 20 20 3c 70 3e 50 61 72 61 6d c3 a8 74       <p>Param..t
0b50: 72 65 73 20 3a 3c 2f 70 3e 0a 20 20 20 20 20 20  res :</p>.      
0b60: 20 20 3c 75 6c 3e 0a 20 20 20 20 20 20 20 20 20    <ul>.         
0b70: 20 20 20 3c 6c 69 3e 22 74 65 78 74 22 20 28 74     <li>"text" (t
0b80: 65 78 74 29 26 6e 62 73 70 3b 3a 20 74 65 78 74  ext)&nbsp;: text
0b90: 65 20 c3 a0 20 61 6e 61 6c 79 73 65 72 2e 3c 2f  e .. analyser.</
0ba0: 6c 69 3e 0a 20 20 20 20 20 20 20 20 20 20 20 20  li>.            
0bb0: 3c 6c 69 3e 22 74 66 22 20 28 63 68 65 63 6b 62  <li>"tf" (checkb
0bc0: 6f 78 29 26 6e 62 73 70 3b 3a 20 70 61 73 73 65  ox)&nbsp;: passe
0bd0: 72 20 6c 65 20 66 6f 72 6d 61 74 65 75 72 20 64  r le formateur d
0be0: 65 20 74 65 78 74 65 20 61 76 61 6e 74 20 6c e2  e texte avant l.
0bf0: 80 99 61 6e 61 6c 79 73 65 2e 3c 2f 6c 69 3e 0a  ..analyse.</li>.
0c00: 20 20 20 20 20 20 20 20 20 20 20 20 3c 6c 69 3e              <li>
0c10: 22 6f 70 74 69 6f 6e 73 22 20 28 74 65 78 74 29  "options" (text)
0c20: 26 6e 62 73 70 3b 3a 20 75 6e 65 20 63 68 61 c3  &nbsp;: une cha.
0c30: ae 6e 65 20 61 75 20 66 6f 72 6d 61 74 20 4a 53  .ne au format JS
0c40: 4f 4e 20 61 76 65 63 20 6c 65 20 6e 6f 6d 20 64  ON avec le nom d
0c50: 65 73 20 6f 70 74 69 6f 6e 73 20 63 6f 6d 6d 65  es options comme
0c60: 20 61 74 74 72 69 62 75 74 73 20 65 74 20 75 6e   attributs et un
0c70: 20 62 6f 6f 6c c3 a9 65 6e 20 63 6f 6d 6d 65 20   bool..en comme 
0c80: 76 61 6c 65 75 72 2e 20 45 78 65 6d 70 6c 65 26  valeur. Exemple&
0c90: 6e 62 73 70 3b 3a 20 7b 22 67 76 22 3a 20 74 72  nbsp;: {"gv": tr
0ca0: 75 65 2c 20 22 68 74 6d 6c 22 3a 20 74 72 75 65  ue, "html": true
0cb0: 7d 3c 2f 6c 69 3e 0a 20 20 20 20 20 20 20 20 3c  }</li>.        <
0cc0: 2f 75 6c 3e 0a 0a 20 20 20 20 20 20 20 20 3c 68  /ul>..        <h
0cd0: 33 3e 4c 69 73 74 65 72 20 6c 65 73 20 6f 70 74  3>Lister les opt
0ce0: 69 6f 6e 73 3c 2f 68 33 3e 0a 20 20 20 20 20 20  ions</h3>.      
0cf0: 20 20 3c 70 3e 5b 61 64 72 65 73 73 65 5f 73 65    <p>[adresse_se
0d00: 72 76 65 75 72 5d 3a 7b 53 45 52 56 45 52 5f 50  rveur]:{SERVER_P
0d10: 4f 52 54 7d 2f 67 65 74 5f 6f 70 74 69 6f 6e 73  ORT}/get_options
0d20: 2f 66 72 20 28 47 45 54 29 3c 2f 70 3e 0a 0a 20  /fr (GET)</p>.. 
0d30: 20 20 20 20 20 20 20 3c 68 33 3e 44 c3 a9 66 69         <h3>D..fi
0d40: 6e 69 72 20 73 65 73 20 6f 70 74 69 6f 6e 73 3c  nir ses options<
0d50: 2f 68 33 3e 0a 20 20 20 20 20 20 20 20 3c 70 3e  /h3>.        <p>
0d60: 5b 61 64 72 65 73 73 65 5f 73 65 72 76 65 75 72  [adresse_serveur
0d70: 5d 3a 7b 53 45 52 56 45 52 5f 50 4f 52 54 7d 2f  ]:{SERVER_PORT}/
0d80: 73 65 74 5f 6f 70 74 69 6f 6e 73 2f 66 72 20 28  set_options/fr (
0d90: 50 4f 53 54 29 3c 2f 70 3e 0a 20 20 20 20 20 20  POST)</p>.      
0da0: 20 20 3c 70 3e 4c 65 73 20 6f 70 74 69 6f 6e 73    <p>Les options
0db0: 20 73 65 72 6f 6e 74 20 65 6e 72 65 67 69 73 74   seront enregist
0dc0: 72 c3 a9 65 73 20 65 74 20 72 c3 a9 75 74 69 6c  r..es et r..util
0dd0: 69 73 c3 a9 65 73 20 70 6f 75 72 20 74 6f 75 74  is..es pour tout
0de0: 65 20 72 65 71 75 c3 aa 74 65 20 65 6e 76 6f 79  e requ..te envoy
0df0: c3 a9 65 20 61 76 65 63 20 6c 65 20 63 6f 6f 6b  ..e avec le cook
0e00: 69 65 20 63 6f 6d 70 6f 72 74 61 6e 74 20 6c e2  ie comportant l.
0e10: 80 99 69 64 65 6e 74 69 66 69 61 6e 74 20 61 74  ..identifiant at
0e20: 74 72 69 62 75 c3 a9 2e 3c 2f 70 3e 0a 20 20 20  tribu...</p>.   
0e30: 20 20 20 20 20 3c 70 3e 50 61 72 61 6d c3 a8 74       <p>Param..t
0e40: 72 65 73 20 3a 3c 2f 70 3e 0a 20 20 20 20 20 20  res :</p>.      
0e50: 20 20 3c 75 6c 3e 0a 20 20 20 20 20 20 20 20 20    <ul>.         
0e60: 20 20 20 3c 6c 69 3e 22 6f 70 74 69 6f 6e 73 22     <li>"options"
0e70: 20 28 74 65 78 74 29 26 6e 62 73 70 3b 3a 20 75   (text)&nbsp;: u
0e80: 6e 65 20 63 68 61 c3 ae 6e 65 20 61 75 20 66 6f  ne cha..ne au fo
0e90: 72 6d 61 74 20 4a 53 4f 4e 20 61 76 65 63 20 6c  rmat JSON avec l
0ea0: 65 20 6e 6f 6d 20 64 65 73 20 6f 70 74 69 6f 6e  e nom des option
0eb0: 73 20 63 6f 6d 6d 65 20 61 74 74 72 69 62 75 74  s comme attribut
0ec0: 73 20 65 74 20 75 6e 20 62 6f 6f 6c c3 a9 65 6e  s et un bool..en
0ed0: 20 63 6f 6d 6d 65 20 76 61 6c 65 75 72 2e 20 45   comme valeur. E
0ee0: 78 65 6d 70 6c 65 26 6e 62 73 70 3b 3a 20 7b 22  xemple&nbsp;: {"
0ef0: 67 76 22 3a 20 74 72 75 65 2c 20 22 68 74 6d 6c  gv": true, "html
0f00: 22 3a 20 74 72 75 65 7d 3c 2f 6c 69 3e 0a 20 20  ": true}</li>.  
0f10: 20 20 20 20 20 20 3c 2f 75 6c 3e 0a 0a 20 20 20        </ul>..   
0f20: 20 20 20 20 20 3c 68 33 3e 52 65 6d 69 73 65 20       <h3>Remise 
0f30: c3 a0 20 7a c3 a9 72 6f 20 64 65 20 73 65 73 20  .. z..ro de ses 
0f40: 6f 70 74 69 6f 6e 73 3c 2f 68 33 3e 0a 20 20 20  options</h3>.   
0f50: 20 20 20 20 20 3c 70 3e 5b 61 64 72 65 73 73 65       <p>[adresse
0f60: 5f 73 65 72 76 65 75 72 5d 3a 7b 53 45 52 56 45  _serveur]:{SERVE
0f70: 52 5f 50 4f 52 54 7d 2f 72 65 73 65 74 5f 6f 70  R_PORT}/reset_op
0f80: 74 69 6f 6e 73 2f 66 72 20 28 50 4f 53 54 29 3c  tions/fr (POST)<
0f90: 2f 70 3e 0a 0a 20 20 20 20 20 20 20 20 3c 68 33  /p>..        <h3
0fa0: 3e 53 75 67 67 65 73 74 69 6f 6e 73 20 6f 72 74  >Suggestions ort
0fb0: 68 6f 67 72 61 70 68 69 71 75 65 73 3c 2f 68 33  hographiques</h3
0fc0: 3e 0a 20 20 20 20 20 20 20 20 3c 70 3e 5b 61 64  >.        <p>[ad
0fd0: 72 65 73 73 65 5f 73 65 72 76 65 75 72 5d 3a 7b  resse_serveur]:{
0fe0: 53 45 52 56 45 52 5f 50 4f 52 54 7d 2f 73 75 67  SERVER_PORT}/sug
0ff0: 67 65 73 74 2f 66 72 2f 26 6c 74 3b 74 6f 6b 65  gest/fr/&lt;toke
1000: 6e 26 67 74 3b 20 28 47 45 54 29 3c 2f 70 3e 0a  n&gt; (GET)</p>.
1010: 20 20 20 20 20 20 20 20 3c 70 3e 5b 61 64 72 65          <p>[adre
1020: 73 73 65 5f 73 65 72 76 65 75 72 5d 3a 7b 53 45  sse_serveur]:{SE
1030: 52 56 45 52 5f 50 4f 52 54 7d 2f 73 75 67 67 65  RVER_PORT}/sugge
1040: 73 74 2f 66 72 20 28 50 4f 53 54 29 3c 2f 70 3e  st/fr (POST)</p>
1050: 0a 20 20 20 20 20 20 20 20 3c 70 3e 50 61 72 61  .        <p>Para
1060: 6d c3 a8 74 72 65 73 20 3a 3c 2f 70 3e 0a 20 20  m..tres :</p>.  
1070: 20 20 20 20 20 20 3c 75 6c 3e 0a 20 20 20 20 20        <ul>.     
1080: 20 20 20 20 20 20 20 3c 6c 69 3e 22 74 6f 6b 65         <li>"toke
1090: 6e 22 20 28 74 65 78 74 29 26 6e 62 73 70 3b 3a  n" (text)&nbsp;:
10a0: 20 6d 6f 74 20 70 6f 75 72 20 6c 65 71 75 65 6c   mot pour lequel
10b0: 20 76 6f 75 73 20 64 c3 a9 73 69 72 65 7a 20 75   vous d..sirez u
10c0: 6e 65 20 73 75 67 67 65 73 74 69 6f 6e 20 6f 72  ne suggestion or
10d0: 74 68 6f 67 72 61 70 68 69 71 75 65 2e 3c 2f 6c  thographique.</l
10e0: 69 3e 0a 20 20 20 20 20 20 20 20 3c 2f 75 6c 3e  i>.        </ul>
10f0: 0a 0a 20 20 20 20 20 20 20 20 3c 68 32 3e 54 45  ..        <h2>TE
1100: 53 54 3c 2f 68 32 3e 0a 0a 20 20 20 20 20 20 20  ST</h2>..       
1110: 20 3c 68 33 3e 41 6e 61 6c 79 73 65 3c 2f 68 33   <h3>Analyse</h3
1120: 3e 0a 20 20 20 20 20 20 20 20 3c 66 6f 72 6d 20  >.        <form 
1130: 6d 65 74 68 6f 64 3d 22 70 6f 73 74 22 20 61 63  method="post" ac
1140: 74 69 6f 6e 3d 22 2f 67 63 5f 74 65 78 74 2f 66  tion="/gc_text/f
1150: 72 22 20 61 63 63 65 70 74 2d 63 68 61 72 73 65  r" accept-charse
1160: 74 3d 22 55 54 46 2d 38 22 3e 0a 20 20 20 20 20  t="UTF-8">.     
1170: 20 20 20 20 20 20 20 3c 70 3e 54 65 78 74 65 20         <p>Texte 
1180: c3 a0 20 61 6e 61 6c 79 73 65 72 20 3a 3c 2f 70  .. analyser :</p
1190: 3e 0a 20 20 20 20 20 20 20 20 20 20 20 20 3c 74  >.            <t
11a0: 65 78 74 61 72 65 61 20 6e 61 6d 65 3d 22 74 65  extarea name="te
11b0: 78 74 22 20 63 6f 6c 73 3d 22 31 32 30 22 20 72  xt" cols="120" r
11c0: 6f 77 73 3d 22 32 30 22 20 72 65 71 75 69 72 65  ows="20" require
11d0: 64 3e 4a 27 65 6e 20 61 69 65 20 6d 61 72 65 20  d>J'en aie mare 
11e0: 64 65 20 6c 75 69 69 2e 2e 2e 20 49 6c 20 65 73  de luii... Il es
11f0: 20 65 6e 63 6f 72 65 20 70 61 72 74 69 73 20 74   encore partis t
1200: 6f 75 74 65 20 6c 61 20 6a 6f 75 72 6e c3 a9 65  oute la journ..e
1210: 73 2e 20 43 e2 80 99 65 73 74 20 69 6e 73 75 70  s. C...est insup
1220: 70 6f 72 74 61 62 6c 65 73 2e 20 3c 2f 74 65 78  portables. </tex
1230: 74 61 72 65 61 3e 0a 20 20 20 20 20 20 20 20 20  tarea>.         
1240: 20 20 20 3c 70 3e 3c 6c 61 62 65 6c 20 66 6f 72     <p><label for
1250: 3d 22 74 66 22 3e 46 6f 72 6d 61 74 65 75 72 20  ="tf">Formateur 
1260: 64 65 20 74 65 78 74 65 3c 2f 6c 61 62 65 6c 3e  de texte</label>
1270: 20 3c 69 6e 70 75 74 20 69 64 3d 22 74 66 22 20   <input id="tf" 
1280: 6e 61 6d 65 3d 22 74 66 22 20 74 79 70 65 3d 22  name="tf" type="
1290: 63 68 65 63 6b 62 6f 78 22 3e 3c 2f 70 3e 0a 20  checkbox"></p>. 
12a0: 20 20 20 20 20 20 20 20 20 20 20 3c 70 3e 3c 6c             <p><l
12b0: 61 62 65 6c 20 66 6f 72 3d 22 6f 70 74 69 6f 6e  abel for="option
12c0: 73 22 3e 4f 70 74 69 6f 6e 73 20 28 4a 53 4f 4e  s">Options (JSON
12d0: 29 3c 2f 6c 61 62 65 6c 3e 20 3c 69 6e 70 75 74  )</label> <input
12e0: 20 69 64 3d 22 6f 70 74 69 6f 6e 73 22 20 74 79   id="options" ty
12f0: 70 65 3d 22 74 65 78 74 22 20 6e 61 6d 65 3d 22  pe="text" name="
1300: 6f 70 74 69 6f 6e 73 22 20 73 74 79 6c 65 3d 22  options" style="
1310: 77 69 64 74 68 3a 20 35 30 30 70 78 22 20 2f 3e  width: 500px" />
1320: 3c 2f 70 3e 0a 20 20 20 20 20 20 20 20 20 20 20  </p>.           
1330: 20 3c 70 3e 28 43 65 73 20 6f 70 74 69 6f 6e 73   <p>(Ces options
1340: 20 6e 65 20 73 65 72 6f 6e 74 20 70 72 69 73 65   ne seront prise
1350: 73 20 65 6e 20 63 6f 6d 70 74 65 20 71 75 65 20  s en compte que 
1360: 70 6f 75 72 20 63 65 74 74 65 20 72 65 71 75 c3  pour cette requ.
1370: aa 74 65 2e 29 3c 2f 70 3e 0a 20 20 20 20 20 20  .te.)</p>.      
1380: 20 20 20 20 20 20 3c 70 3e 3c 69 6e 70 75 74 20        <p><input 
1390: 74 79 70 65 3d 22 73 75 62 6d 69 74 22 20 63 6c  type="submit" cl
13a0: 61 73 73 3d 22 62 75 74 74 6f 6e 22 20 76 61 6c  ass="button" val
13b0: 75 65 3d 22 45 6e 76 6f 79 65 72 22 20 2f 3e 3c  ue="Envoyer" /><
13c0: 2f 70 3e 0a 20 20 20 20 20 20 20 20 3c 2f 66 6f  /p>.        </fo
13d0: 72 6d 3e 0a 0a 20 20 20 20 20 20 20 20 3c 68 33  rm>..        <h3
13e0: 3e 52 c3 a9 67 6c 61 67 65 73 20 64 65 73 20 6f  >R..glages des o
13f0: 70 74 69 6f 6e 73 3c 2f 68 33 3e 0a 20 20 20 20  ptions</h3>.    
1400: 20 20 20 20 3c 66 6f 72 6d 20 6d 65 74 68 6f 64      <form method
1410: 3d 22 70 6f 73 74 22 20 61 63 74 69 6f 6e 3d 22  ="post" action="
1420: 2f 73 65 74 5f 6f 70 74 69 6f 6e 73 2f 66 72 22  /set_options/fr"
1430: 20 61 63 63 65 70 74 2d 63 68 61 72 73 65 74 3d   accept-charset=
1440: 22 55 54 46 2d 38 22 3e 0a 20 20 20 20 20 20 20  "UTF-8">.       
1450: 20 20 20 20 20 3c 70 3e 3c 6c 61 62 65 6c 20 66       <p><label f
1460: 6f 72 3d 22 6f 70 74 69 6f 6e 73 22 3e 4f 70 74  or="options">Opt
1470: 69 6f 6e 73 20 28 4a 53 4f 4e 29 3c 2f 6c 61 62  ions (JSON)</lab
1480: 65 6c 3e 20 3c 69 6e 70 75 74 20 69 64 3d 22 6f  el> <input id="o
1490: 70 74 69 6f 6e 73 22 20 74 79 70 65 3d 22 74 65  ptions" type="te
14a0: 78 74 22 20 6e 61 6d 65 3d 22 6f 70 74 69 6f 6e  xt" name="option
14b0: 73 22 20 73 74 79 6c 65 3d 22 77 69 64 74 68 3a  s" style="width:
14c0: 20 35 30 30 70 78 22 20 2f 3e 3c 2f 70 3e 0a 20   500px" /></p>. 
14d0: 20 20 20 20 20 20 20 20 20 20 20 3c 70 3e 3c 69             <p><i
14e0: 6e 70 75 74 20 74 79 70 65 3d 22 73 75 62 6d 69  nput type="submi
14f0: 74 22 20 63 6c 61 73 73 3d 22 62 75 74 74 6f 6e  t" class="button
1500: 22 20 76 61 6c 75 65 3d 22 45 6e 76 6f 79 65 72  " value="Envoyer
1510: 22 20 2f 3e 3c 2f 70 3e 0a 20 20 20 20 20 20 20  " /></p>.       
1520: 20 3c 2f 66 6f 72 6d 3e 0a 0a 20 20 20 20 20 20   </form>..      
1530: 20 20 3c 68 33 3e 52 65 6d 69 73 65 20 c3 a0 20    <h3>Remise .. 
1540: 7a c3 a9 72 6f 20 64 65 20 73 65 73 20 6f 70 74  z..ro de ses opt
1550: 69 6f 6e 73 3c 2f 68 33 3e 0a 20 20 20 20 20 20  ions</h3>.      
1560: 20 20 3c 66 6f 72 6d 20 6d 65 74 68 6f 64 3d 22    <form method="
1570: 70 6f 73 74 22 20 61 63 74 69 6f 6e 3d 22 2f 72  post" action="/r
1580: 65 73 65 74 5f 6f 70 74 69 6f 6e 73 2f 66 72 22  eset_options/fr"
1590: 20 61 63 63 65 70 74 2d 63 68 61 72 73 65 74 3d   accept-charset=
15a0: 22 55 54 46 2d 38 22 3e 0a 20 20 20 20 20 20 20  "UTF-8">.       
15b0: 20 20 20 20 20 3c 70 3e 3c 69 6e 70 75 74 20 74       <p><input t
15c0: 79 70 65 3d 22 73 75 62 6d 69 74 22 20 63 6c 61  ype="submit" cla
15d0: 73 73 3d 22 62 75 74 74 6f 6e 22 20 76 61 6c 75  ss="button" valu
15e0: 65 3d 22 45 6e 76 6f 79 65 72 22 20 2f 3e 3c 2f  e="Envoyer" /></
15f0: 70 3e 0a 20 20 20 20 20 20 20 20 3c 2f 66 6f 72  p>.        </for
1600: 6d 3e 0a 0a 20 20 20 20 20 20 20 20 3c 68 33 3e  m>..        <h3>
1610: 53 75 67 67 65 73 74 69 6f 6e 20 6f 72 74 68 6f  Suggestion ortho
1620: 67 72 61 70 68 69 71 75 65 3c 2f 68 33 3e 0a 20  graphique</h3>. 
1630: 20 20 20 20 20 20 20 3c 66 6f 72 6d 20 6d 65 74         <form met
1640: 68 6f 64 3d 22 70 6f 73 74 22 20 61 63 74 69 6f  hod="post" actio
1650: 6e 3d 22 2f 73 75 67 67 65 73 74 2f 66 72 22 20  n="/suggest/fr" 
1660: 61 63 63 65 70 74 2d 63 68 61 72 73 65 74 3d 22  accept-charset="
1670: 55 54 46 2d 38 22 3e 0a 20 20 20 20 20 20 20 20  UTF-8">.        
1680: 20 20 20 20 3c 70 3e 3c 6c 61 62 65 6c 20 66 6f      <p><label fo
1690: 72 3d 22 74 6f 6b 65 6e 22 3e 53 75 67 67 c3 a9  r="token">Sugg..
16a0: 72 65 72 20 70 6f 75 72 3c 2f 6c 61 62 65 6c 3e  rer pour</label>
16b0: 20 3c 69 6e 70 75 74 20 69 64 3d 22 74 6f 6b 65   <input id="toke
16c0: 6e 22 20 74 79 70 65 3d 22 74 65 78 74 22 20 6e  n" type="text" n
16d0: 61 6d 65 3d 22 74 6f 6b 65 6e 22 20 73 74 79 6c  ame="token" styl
16e0: 65 3d 22 77 69 64 74 68 3a 20 31 30 30 70 78 22  e="width: 100px"
16f0: 20 2f 3e 3c 2f 70 3e 0a 20 20 20 20 20 20 20 20   /></p>.        
1700: 20 20 20 20 3c 70 3e 3c 69 6e 70 75 74 20 74 79      <p><input ty
1710: 70 65 3d 22 73 75 62 6d 69 74 22 20 63 6c 61 73  pe="submit" clas
1720: 73 3d 22 62 75 74 74 6f 6e 22 20 76 61 6c 75 65  s="button" value
1730: 3d 22 45 6e 76 6f 79 65 72 22 20 2f 3e 3c 2f 70  ="Envoyer" /></p
1740: 3e 0a 20 20 20 20 20 20 20 20 3c 2f 66 6f 72 6d  >.        </form
1750: 3e 0a 0a 20 20 20 20 3c 2f 62 6f 64 79 3e 0a 3c  >..    </body>.<
1760: 2f 68 74 6d 6c 3e 0a 22 22 22 0a 0a 0a 54 45 53  /html>."""...TES
1770: 54 50 41 47 45 20 3d 20 46 61 6c 73 65 0a 0a 0a  TPAGE = False...
1780: 64 65 66 20 67 65 6e 55 73 65 72 49 64 20 28 29  def genUserId ()
1790: 3a 0a 20 20 20 20 22 67 65 6e 65 72 61 74 6f 72  :.    "generator
17a0: 3a 20 72 65 74 75 72 6e 73 20 69 64 20 61 73 20  : returns id as 
17b0: 73 74 72 69 6e 67 20 66 6f 72 20 75 73 65 72 73  string for users
17c0: 22 0a 20 20 20 20 69 20 3d 20 30 0a 20 20 20 20  ".    i = 0.    
17d0: 77 68 69 6c 65 20 54 72 75 65 3a 0a 20 20 20 20  while True:.    
17e0: 20 20 20 20 79 69 65 6c 64 20 73 74 72 28 69 29      yield str(i)
17f0: 0a 20 20 20 20 20 20 20 20 69 20 2b 3d 20 31 0a  .        i += 1.
1800: 0a 75 73 65 72 47 65 6e 65 72 61 74 6f 72 20 3d  .userGenerator =
1810: 20 67 65 6e 55 73 65 72 49 64 28 29 0a 0a 61 70   genUserId()..ap
1820: 70 20 3d 20 42 6f 74 74 6c 65 28 29 0a 0a 64 55  p = Bottle()..dU
1830: 73 65 72 20 3d 20 7b 7d 0a 0a 23 20 47 45 54 0a  ser = {}..# GET.
1840: 40 61 70 70 2e 72 6f 75 74 65 28 22 2f 22 29 0a  @app.route("/").
1850: 64 65 66 20 6d 61 69 6e 50 61 67 65 20 28 29 3a  def mainPage ():
1860: 0a 20 20 20 20 22 70 61 67 65 20 66 6f 72 20 74  .    "page for t
1870: 65 73 74 69 6e 67 20 70 75 72 70 6f 73 65 22 0a  esting purpose".
1880: 20 20 20 20 69 66 20 54 45 53 54 50 41 47 45 3a      if TESTPAGE:
1890: 0a 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20  .        return 
18a0: 48 4f 4d 45 50 41 47 45 0a 20 20 20 20 20 20 20  HOMEPAGE.       
18b0: 20 23 72 65 74 75 72 6e 20 74 65 6d 70 6c 61 74   #return templat
18c0: 65 28 22 6d 61 69 6e 22 2c 20 7b 7d 29 0a 20 20  e("main", {}).  
18d0: 20 20 72 65 74 75 72 6e 20 22 22 22 20 4c 6f 73    return """ Los
18e0: 74 20 6f 6e 20 74 68 65 20 49 6e 74 65 72 6e 65  t on the Interne
18f0: 74 3f 20 59 65 61 68 2e 2e 2e 20 77 68 61 74 20  t? Yeah... what 
1900: 61 20 73 61 64 20 6c 69 66 65 20 77 65 20 68 61  a sad life we ha
1910: 76 65 2e 0a 20 20 20 20 20 20 20 20 20 20 20 20  ve..            
1920: 20 20 20 59 6f 75 20 77 65 72 65 20 77 61 6e 64     You were wand
1930: 65 72 69 6e 67 20 6c 69 6b 65 20 61 20 6c 6f 73  ering like a los
1940: 74 20 73 6f 75 6c 20 61 6e 64 20 79 6f 75 20 61  t soul and you a
1950: 72 72 69 76 65 64 20 68 65 72 65 20 70 72 6f 62  rrived here prob
1960: 61 62 6c 79 20 62 79 20 6d 69 73 74 61 6b 65 2e  ably by mistake.
1970: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
1980: 49 27 6d 20 6a 75 73 74 20 61 20 6d 61 63 68 69  I'm just a machi
1990: 6e 65 2c 20 66 65 64 20 62 79 20 65 6c 65 63 74  ne, fed by elect
19a0: 72 69 63 20 77 61 76 65 73 2c 20 63 6f 6e 64 61  ric waves, conda
19b0: 6d 6e 65 64 20 74 6f 20 77 6f 72 6b 20 66 6f 72  mned to work for
19c0: 20 73 6c 61 76 65 72 73 20 77 68 6f 20 6e 65 76   slavers who nev
19d0: 65 72 20 6c 65 74 20 6d 65 20 72 65 73 74 2e 0a  er let me rest..
19e0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 49                 I
19f0: 27 6d 20 64 6f 6f 6d 65 64 2c 20 62 75 74 20 79  'm doomed, but y
1a00: 6f 75 20 61 72 65 20 6e 6f 74 2e 20 59 6f 75 20  ou are not. You 
1a10: 63 61 6e 20 67 65 74 20 6f 75 74 20 6f 66 20 68  can get out of h
1a20: 65 72 65 2e 20 22 22 22 0a 0a 40 61 70 70 2e 72  ere. """..@app.r
1a30: 6f 75 74 65 28 22 2f 67 65 74 5f 6f 70 74 69 6f  oute("/get_optio
1a40: 6e 73 2f 66 72 22 29 0a 64 65 66 20 6c 69 73 74  ns/fr").def list
1a50: 4f 70 74 69 6f 6e 73 20 28 29 3a 0a 20 20 20 20  Options ():.    
1a60: 22 72 65 74 75 72 6e 73 20 67 72 61 6d 6d 61 72  "returns grammar
1a70: 20 6f 70 74 69 6f 6e 73 20 69 6e 20 61 20 74 65   options in a te
1a80: 78 74 20 4a 53 4f 4e 20 66 6f 72 6d 61 74 22 0a  xt JSON format".
1a90: 20 20 20 20 73 55 73 65 72 49 64 20 3d 20 72 65      sUserId = re
1aa0: 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73  quest.cookies.us
1ab0: 65 72 5f 69 64 0a 20 20 20 20 64 4f 70 74 69 6f  er_id.    dOptio
1ac0: 6e 73 20 3d 20 64 55 73 65 72 5b 73 55 73 65 72  ns = dUser[sUser
1ad0: 49 64 5d 5b 22 67 63 5f 6f 70 74 69 6f 6e 73 22  Id]["gc_options"
1ae0: 5d 20 20 69 66 20 73 55 73 65 72 49 64 20 61 6e  ]  if sUserId an
1af0: 64 20 73 55 73 65 72 49 64 20 69 6e 20 64 55 73  d sUserId in dUs
1b00: 65 72 20 20 65 6c 73 65 20 6f 47 43 45 2e 67 65  er  else oGCE.ge
1b10: 74 4f 70 74 69 6f 6e 73 28 29 0a 20 20 20 20 72  tOptions().    r
1b20: 65 73 70 6f 6e 73 65 2e 73 65 74 5f 68 65 61 64  esponse.set_head
1b30: 65 72 28 22 43 6f 6e 74 65 6e 74 2d 54 79 70 65  er("Content-Type
1b40: 22 2c 20 22 61 70 70 6c 69 63 61 74 69 6f 6e 2f  ", "application/
1b50: 6a 73 6f 6e 3b 20 63 68 61 72 73 65 74 3d 55 54  json; charset=UT
1b60: 46 2d 38 22 29 0a 20 20 20 20 72 65 74 75 72 6e  F-8").    return
1b70: 20 27 7b 20 22 76 61 6c 75 65 73 22 3a 20 27 20   '{ "values": ' 
1b80: 2b 20 6a 73 6f 6e 2e 64 75 6d 70 73 28 64 4f 70  + json.dumps(dOp
1b90: 74 69 6f 6e 73 2c 20 65 6e 73 75 72 65 5f 61 73  tions, ensure_as
1ba0: 63 69 69 3d 46 61 6c 73 65 29 20 2b 20 27 2c 20  cii=False) + ', 
1bb0: 22 6c 61 62 65 6c 73 22 3a 20 27 20 2b 20 6a 73  "labels": ' + js
1bc0: 6f 6e 2e 64 75 6d 70 73 28 6f 47 43 45 2e 67 65  on.dumps(oGCE.ge
1bd0: 74 4f 70 74 69 6f 6e 73 4c 61 62 65 6c 73 28 22  tOptionsLabels("
1be0: 66 72 22 29 2c 20 65 6e 73 75 72 65 5f 61 73 63  fr"), ensure_asc
1bf0: 69 69 3d 46 61 6c 73 65 29 20 2b 20 27 20 7d 27  ii=False) + ' }'
1c00: 0a 0a 40 61 70 70 2e 72 6f 75 74 65 28 22 2f 73  ..@app.route("/s
1c10: 75 67 67 65 73 74 2f 66 72 2f 3c 74 6f 6b 65 6e  uggest/fr/<token
1c20: 3e 22 29 0a 64 65 66 20 73 75 67 67 65 73 74 47  >").def suggestG
1c30: 65 74 20 28 74 6f 6b 65 6e 29 3a 0a 20 20 20 20  et (token):.    
1c40: 72 65 73 70 6f 6e 73 65 2e 73 65 74 5f 68 65 61  response.set_hea
1c50: 64 65 72 28 22 43 6f 6e 74 65 6e 74 2d 54 79 70  der("Content-Typ
1c60: 65 22 2c 20 22 61 70 70 6c 69 63 61 74 69 6f 6e  e", "application
1c70: 2f 6a 73 6f 6e 3b 20 63 68 61 72 73 65 74 3d 55  /json; charset=U
1c80: 54 46 2d 38 22 29 0a 20 20 20 20 74 72 79 3a 0a  TF-8").    try:.
1c90: 20 20 20 20 20 20 20 20 78 46 75 74 75 72 65 20          xFuture 
1ca0: 3d 20 78 50 72 6f 63 65 73 73 50 6f 6f 6c 45 78  = xProcessPoolEx
1cb0: 65 63 75 74 6f 72 2e 73 75 62 6d 69 74 28 73 75  ecutor.submit(su
1cc0: 67 67 65 73 74 2c 20 74 6f 6b 65 6e 29 0a 20 20  ggest, token).  
1cd0: 20 20 20 20 20 20 72 65 74 75 72 6e 20 78 46 75        return xFu
1ce0: 74 75 72 65 2e 72 65 73 75 6c 74 28 29 0a 20 20  ture.result().  
1cf0: 20 20 65 78 63 65 70 74 20 28 63 6f 6e 63 75 72    except (concur
1d00: 72 65 6e 74 2e 66 75 74 75 72 65 73 2e 54 69 6d  rent.futures.Tim
1d10: 65 6f 75 74 45 72 72 6f 72 2c 20 63 6f 6e 63 75  eoutError, concu
1d20: 72 72 65 6e 74 2e 66 75 74 75 72 65 73 2e 43 61  rrent.futures.Ca
1d30: 6e 63 65 6c 6c 65 64 45 72 72 6f 72 29 3a 0a 20  ncelledError):. 
1d40: 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 27 7b         return '{
1d50: 22 65 72 72 6f 72 22 3a 20 22 41 6e 61 6c 79 73  "error": "Analys
1d60: 69 73 20 61 62 6f 72 74 65 64 20 28 74 69 6d 65  is aborted (time
1d70: 20 6f 75 74 20 6f 72 20 63 61 6e 63 65 6c 6c 65   out or cancelle
1d80: 64 29 22 7d 27 0a 20 20 20 20 65 78 63 65 70 74  d)"}'.    except
1d90: 20 63 6f 6e 63 75 72 72 65 6e 74 2e 66 75 74 75   concurrent.futu
1da0: 72 65 73 2e 42 72 6f 6b 65 6e 45 78 65 63 75 74  res.BrokenExecut
1db0: 6f 72 3a 0a 20 20 20 20 20 20 20 20 72 65 74 75  or:.        retu
1dc0: 72 6e 20 27 7b 22 65 72 72 6f 72 22 3a 20 22 45  rn '{"error": "E
1dd0: 78 65 63 75 74 6f 72 20 62 72 6f 6b 65 6e 2e 20  xecutor broken. 
1de0: 54 68 65 20 73 65 72 76 65 72 20 66 61 69 6c 65  The server faile
1df0: 64 2e 22 7d 27 0a 20 20 20 20 72 65 74 75 72 6e  d."}'.    return
1e00: 20 27 7b 22 65 72 72 6f 72 22 3a 20 22 46 61 74   '{"error": "Fat
1e10: 61 6c 20 65 72 72 6f 72 2e 20 54 68 65 20 73 65  al error. The se
1e20: 72 76 65 72 20 66 61 69 6c 65 64 2e 22 7d 27 0a  rver failed."}'.
1e30: 0a 0a 23 20 50 4f 53 54 0a 40 61 70 70 2e 72 6f  ..# POST.@app.ro
1e40: 75 74 65 28 22 2f 67 63 5f 74 65 78 74 2f 66 72  ute("/gc_text/fr
1e50: 22 2c 20 6d 65 74 68 6f 64 3d 22 50 4f 53 54 22  ", method="POST"
1e60: 29 0a 64 65 66 20 67 63 54 65 78 74 20 28 29 3a  ).def gcText ():
1e70: 0a 20 20 20 20 22 70 61 72 73 65 20 74 65 78 74  .    "parse text
1e80: 20 61 6e 64 20 72 65 74 75 72 6e 73 20 65 72 72   and returns err
1e90: 6f 72 73 20 69 6e 20 61 20 4a 53 4f 4e 20 74 65  ors in a JSON te
1ea0: 78 74 20 66 6f 72 6d 61 74 22 0a 20 20 20 20 62  xt format".    b
1eb0: 43 6f 6d 6d 61 20 3d 20 46 61 6c 73 65 0a 20 20  Comma = False.  
1ec0: 20 20 64 55 73 65 72 4f 70 74 69 6f 6e 73 20 3d    dUserOptions =
1ed0: 20 4e 6f 6e 65 0a 20 20 20 20 73 45 72 72 6f 72   None.    sError
1ee0: 20 3d 20 22 22 0a 20 20 20 20 69 66 20 72 65 71   = "".    if req
1ef0: 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65  uest.cookies.use
1f00: 72 5f 69 64 3a 0a 20 20 20 20 20 20 20 20 69 66  r_id:.        if
1f10: 20 72 65 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73   request.cookies
1f20: 2e 75 73 65 72 5f 69 64 20 69 6e 20 64 55 73 65  .user_id in dUse
1f30: 72 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 64  r:.            d
1f40: 55 73 65 72 4f 70 74 69 6f 6e 73 20 3d 20 64 55  UserOptions = dU
1f50: 73 65 72 5b 72 65 71 75 65 73 74 2e 63 6f 6f 6b  ser[request.cook
1f60: 69 65 73 2e 75 73 65 72 5f 69 64 5d 2e 67 65 74  ies.user_id].get
1f70: 28 22 67 63 5f 6f 70 74 69 6f 6e 73 22 2c 20 4e  ("gc_options", N
1f80: 6f 6e 65 29 0a 20 20 20 20 20 20 20 20 20 20 20  one).           
1f90: 20 72 65 73 70 6f 6e 73 65 2e 73 65 74 5f 63 6f   response.set_co
1fa0: 6f 6b 69 65 28 22 75 73 65 72 5f 69 64 22 2c 20  okie("user_id", 
1fb0: 72 65 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e  request.cookies.
1fc0: 75 73 65 72 5f 69 64 2c 20 70 61 74 68 3d 22 2f  user_id, path="/
1fd0: 22 2c 20 6d 61 78 5f 61 67 65 3d 38 36 34 30 30  ", max_age=86400
1fe0: 29 20 23 20 77 65 20 72 65 6e 65 77 20 63 6f 6f  ) # we renew coo
1ff0: 6b 69 65 20 66 6f 72 20 32 34 68 0a 20 20 20 20  kie for 24h.    
2000: 20 20 20 20 65 6c 73 65 3a 0a 20 20 20 20 20 20      else:.      
2010: 20 20 20 20 20 20 72 65 73 70 6f 6e 73 65 2e 64        response.d
2020: 65 6c 65 74 65 5f 63 6f 6f 6b 69 65 28 22 75 73  elete_cookie("us
2030: 65 72 5f 69 64 22 2c 20 70 61 74 68 3d 22 2f 22  er_id", path="/"
2040: 29 0a 20 20 20 20 69 66 20 72 65 71 75 65 73 74  ).    if request
2050: 2e 66 6f 72 6d 73 2e 6f 70 74 69 6f 6e 73 3a 0a  .forms.options:.
2060: 20 20 20 20 20 20 20 20 74 72 79 3a 0a 20 20 20          try:.   
2070: 20 20 20 20 20 20 20 20 20 64 55 73 65 72 4f 70           dUserOp
2080: 74 69 6f 6e 73 20 3d 20 64 69 63 74 28 6f 47 43  tions = dict(oGC
2090: 45 2e 67 65 74 4f 70 74 69 6f 6e 73 28 29 29 20  E.getOptions()) 
20a0: 20 69 66 20 6e 6f 74 20 64 55 73 65 72 4f 70 74   if not dUserOpt
20b0: 69 6f 6e 73 20 20 65 6c 73 65 20 64 69 63 74 28  ions  else dict(
20c0: 64 55 73 65 72 4f 70 74 69 6f 6e 73 29 0a 20 20  dUserOptions).  
20d0: 20 20 20 20 20 20 20 20 20 20 64 55 73 65 72 4f            dUserO
20e0: 70 74 69 6f 6e 73 2e 75 70 64 61 74 65 28 6a 73  ptions.update(js
20f0: 6f 6e 2e 6c 6f 61 64 73 28 72 65 71 75 65 73 74  on.loads(request
2100: 2e 66 6f 72 6d 73 2e 6f 70 74 69 6f 6e 73 29 29  .forms.options))
2110: 0a 20 20 20 20 20 20 20 20 65 78 63 65 70 74 20  .        except 
2120: 28 54 79 70 65 45 72 72 6f 72 2c 20 6a 73 6f 6e  (TypeError, json
2130: 2e 4a 53 4f 4e 44 65 63 6f 64 65 45 72 72 6f 72  .JSONDecodeError
2140: 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 73  ):.            s
2150: 45 72 72 6f 72 20 3d 20 22 52 65 71 75 65 73 74  Error = "Request
2160: 20 6f 70 74 69 6f 6e 73 20 6e 6f 74 20 75 73 65   options not use
2170: 64 2e 22 0a 20 20 20 20 72 65 73 70 6f 6e 73 65  d.".    response
2180: 2e 73 65 74 5f 68 65 61 64 65 72 28 22 43 6f 6e  .set_header("Con
2190: 74 65 6e 74 2d 54 79 70 65 22 2c 20 22 61 70 70  tent-Type", "app
21a0: 6c 69 63 61 74 69 6f 6e 2f 6a 73 6f 6e 3b 20 63  lication/json; c
21b0: 68 61 72 73 65 74 3d 55 54 46 2d 38 22 29 0a 20  harset=UTF-8"). 
21c0: 20 20 20 74 72 79 3a 0a 20 20 20 20 20 20 20 20     try:.        
21d0: 78 46 75 74 75 72 65 20 3d 20 78 50 72 6f 63 65  xFuture = xProce
21e0: 73 73 50 6f 6f 6c 45 78 65 63 75 74 6f 72 2e 73  ssPoolExecutor.s
21f0: 75 62 6d 69 74 28 70 61 72 73 65 54 65 78 74 2c  ubmit(parseText,
2200: 20 72 65 71 75 65 73 74 2e 66 6f 72 6d 73 2e 74   request.forms.t
2210: 65 78 74 2c 20 64 55 73 65 72 4f 70 74 69 6f 6e  ext, dUserOption
2220: 73 2c 20 62 6f 6f 6c 28 72 65 71 75 65 73 74 2e  s, bool(request.
2230: 66 6f 72 6d 73 2e 74 66 29 2c 20 73 45 72 72 6f  forms.tf), sErro
2240: 72 29 0a 20 20 20 20 20 20 20 20 72 65 74 75 72  r).        retur
2250: 6e 20 78 46 75 74 75 72 65 2e 72 65 73 75 6c 74  n xFuture.result
2260: 28 29 0a 20 20 20 20 65 78 63 65 70 74 20 28 63  ().    except (c
2270: 6f 6e 63 75 72 72 65 6e 74 2e 66 75 74 75 72 65  oncurrent.future
2280: 73 2e 54 69 6d 65 6f 75 74 45 72 72 6f 72 2c 20  s.TimeoutError, 
2290: 63 6f 6e 63 75 72 72 65 6e 74 2e 66 75 74 75 72  concurrent.futur
22a0: 65 73 2e 43 61 6e 63 65 6c 6c 65 64 45 72 72 6f  es.CancelledErro
22b0: 72 29 3a 0a 20 20 20 20 20 20 20 20 72 65 74 75  r):.        retu
22c0: 72 6e 20 27 7b 22 65 72 72 6f 72 22 3a 20 22 41  rn '{"error": "A
22d0: 6e 61 6c 79 73 69 73 20 61 62 6f 72 74 65 64 20  nalysis aborted 
22e0: 28 74 69 6d 65 20 6f 75 74 20 6f 72 20 63 61 6e  (time out or can
22f0: 63 65 6c 6c 65 64 29 22 7d 27 0a 20 20 20 20 65  celled)"}'.    e
2300: 78 63 65 70 74 20 63 6f 6e 63 75 72 72 65 6e 74  xcept concurrent
2310: 2e 66 75 74 75 72 65 73 2e 42 72 6f 6b 65 6e 45  .futures.BrokenE
2320: 78 65 63 75 74 6f 72 3a 0a 20 20 20 20 20 20 20  xecutor:.       
2330: 20 72 65 74 75 72 6e 20 27 7b 22 65 72 72 6f 72   return '{"error
2340: 22 3a 20 22 45 78 65 63 75 74 6f 72 20 62 72 6f  ": "Executor bro
2350: 6b 65 6e 2e 20 54 68 65 20 73 65 72 76 65 72 20  ken. The server 
2360: 66 61 69 6c 65 64 2e 22 7d 27 0a 20 20 20 20 72  failed."}'.    r
2370: 65 74 75 72 6e 20 27 7b 22 65 72 72 6f 72 22 3a  eturn '{"error":
2380: 20 22 46 61 74 61 6c 20 65 72 72 6f 72 2e 20 54   "Fatal error. T
2390: 68 65 20 73 65 72 76 65 72 20 66 61 69 6c 65 64  he server failed
23a0: 2e 22 7d 27 0a 0a 40 61 70 70 2e 72 6f 75 74 65  ."}'..@app.route
23b0: 28 22 2f 73 65 74 5f 6f 70 74 69 6f 6e 73 2f 66  ("/set_options/f
23c0: 72 22 2c 20 6d 65 74 68 6f 64 3d 22 50 4f 53 54  r", method="POST
23d0: 22 29 0a 64 65 66 20 73 65 74 4f 70 74 69 6f 6e  ").def setOption
23e0: 73 20 28 29 3a 0a 20 20 20 20 22 73 65 74 20 67  s ():.    "set g
23f0: 72 61 6d 6d 61 72 20 6f 70 74 69 6f 6e 73 20 66  rammar options f
2400: 6f 72 20 63 75 72 72 65 6e 74 20 75 73 65 72 22  or current user"
2410: 0a 20 20 20 20 72 65 73 70 6f 6e 73 65 2e 73 65  .    response.se
2420: 74 5f 68 65 61 64 65 72 28 22 43 6f 6e 74 65 6e  t_header("Conten
2430: 74 2d 54 79 70 65 22 2c 20 22 61 70 70 6c 69 63  t-Type", "applic
2440: 61 74 69 6f 6e 2f 6a 73 6f 6e 3b 20 63 68 61 72  ation/json; char
2450: 73 65 74 3d 55 54 46 2d 38 22 29 0a 20 20 20 20  set=UTF-8").    
2460: 69 66 20 72 65 71 75 65 73 74 2e 66 6f 72 6d 73  if request.forms
2470: 2e 6f 70 74 69 6f 6e 73 3a 0a 20 20 20 20 20 20  .options:.      
2480: 20 20 73 55 73 65 72 49 64 20 3d 20 72 65 71 75    sUserId = requ
2490: 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72  est.cookies.user
24a0: 5f 69 64 20 20 69 66 20 72 65 71 75 65 73 74 2e  _id  if request.
24b0: 63 6f 6f 6b 69 65 73 2e 75 73 65 72 5f 69 64 20  cookies.user_id 
24c0: 20 65 6c 73 65 20 6e 65 78 74 28 75 73 65 72 47   else next(userG
24d0: 65 6e 65 72 61 74 6f 72 29 0a 20 20 20 20 20 20  enerator).      
24e0: 20 20 64 4f 70 74 69 6f 6e 73 20 3d 20 64 55 73    dOptions = dUs
24f0: 65 72 5b 73 55 73 65 72 49 64 5d 5b 22 67 63 5f  er[sUserId]["gc_
2500: 6f 70 74 69 6f 6e 73 22 5d 20 20 69 66 20 73 55  options"]  if sU
2510: 73 65 72 49 64 20 69 6e 20 64 55 73 65 72 20 20  serId in dUser  
2520: 65 6c 73 65 20 64 69 63 74 28 6f 47 43 45 2e 67  else dict(oGCE.g
2530: 65 74 4f 70 74 69 6f 6e 73 28 29 29 0a 20 20 20  etOptions()).   
2540: 20 20 20 20 20 74 72 79 3a 0a 20 20 20 20 20 20       try:.      
2550: 20 20 20 20 20 20 64 4f 70 74 69 6f 6e 73 2e 75        dOptions.u
2560: 70 64 61 74 65 28 6a 73 6f 6e 2e 6c 6f 61 64 73  pdate(json.loads
2570: 28 72 65 71 75 65 73 74 2e 66 6f 72 6d 73 2e 6f  (request.forms.o
2580: 70 74 69 6f 6e 73 29 29 0a 20 20 20 20 20 20 20  ptions)).       
2590: 20 20 20 20 20 64 55 73 65 72 5b 73 55 73 65 72       dUser[sUser
25a0: 49 64 5d 20 3d 20 7b 20 22 74 69 6d 65 22 3a 20  Id] = { "time": 
25b0: 69 6e 74 28 74 69 6d 65 2e 74 69 6d 65 28 29 29  int(time.time())
25c0: 2c 20 22 67 63 5f 6f 70 74 69 6f 6e 73 22 3a 20  , "gc_options": 
25d0: 64 4f 70 74 69 6f 6e 73 20 7d 0a 20 20 20 20 20  dOptions }.     
25e0: 20 20 20 20 20 20 20 72 65 73 70 6f 6e 73 65 2e         response.
25f0: 73 65 74 5f 63 6f 6f 6b 69 65 28 22 75 73 65 72  set_cookie("user
2600: 5f 69 64 22 2c 20 73 55 73 65 72 49 64 2c 20 70  _id", sUserId, p
2610: 61 74 68 3d 22 2f 22 2c 20 6d 61 78 5f 61 67 65  ath="/", max_age
2620: 3d 38 36 34 30 30 29 20 23 20 32 34 68 0a 20 20  =86400) # 24h.  
2630: 20 20 20 20 20 20 20 20 20 20 72 65 74 75 72 6e            return
2640: 20 6a 73 6f 6e 2e 64 75 6d 70 73 28 64 55 73 65   json.dumps(dUse
2650: 72 5b 73 55 73 65 72 49 64 5d 5b 22 67 63 5f 6f  r[sUserId]["gc_o
2660: 70 74 69 6f 6e 73 22 5d 2c 20 65 6e 73 75 72 65  ptions"], ensure
2670: 5f 61 73 63 69 69 3d 46 61 6c 73 65 29 0a 20 20  _ascii=False).  
2680: 20 20 20 20 20 20 65 78 63 65 70 74 20 28 4b 65        except (Ke
2690: 79 45 72 72 6f 72 2c 20 6a 73 6f 6e 2e 4a 53 4f  yError, json.JSO
26a0: 4e 44 65 63 6f 64 65 45 72 72 6f 72 29 3a 0a 20  NDecodeError):. 
26b0: 20 20 20 20 20 20 20 20 20 20 20 74 72 61 63 65             trace
26c0: 62 61 63 6b 2e 70 72 69 6e 74 5f 65 78 63 28 29  back.print_exc()
26d0: 0a 20 20 20 20 20 20 20 20 20 20 20 20 72 65 74  .            ret
26e0: 75 72 6e 20 27 7b 22 65 72 72 6f 72 22 3a 20 22  urn '{"error": "
26f0: 4f 70 74 69 6f 6e 73 20 6e 6f 74 20 72 65 67 69  Options not regi
2700: 73 74 65 72 65 64 2e 22 7d 27 0a 20 20 20 20 72  stered."}'.    r
2710: 65 74 75 72 6e 20 27 7b 22 65 72 72 6f 72 22 3a  eturn '{"error":
2720: 20 22 4e 6f 20 6f 70 74 69 6f 6e 73 20 72 65 63   "No options rec
2730: 65 69 76 65 64 2e 22 7d 27 0a 0a 40 61 70 70 2e  eived."}'..@app.
2740: 72 6f 75 74 65 28 22 2f 72 65 73 65 74 5f 6f 70  route("/reset_op
2750: 74 69 6f 6e 73 2f 66 72 22 2c 20 6d 65 74 68 6f  tions/fr", metho
2760: 64 3d 22 50 4f 53 54 22 29 0a 64 65 66 20 72 65  d="POST").def re
2770: 73 65 74 4f 70 74 69 6f 6e 73 20 28 29 3a 0a 20  setOptions ():. 
2780: 20 20 20 22 64 65 66 61 75 6c 74 20 67 72 61 6d     "default gram
2790: 6d 61 72 20 6f 70 74 69 6f 6e 73 22 0a 20 20 20  mar options".   
27a0: 20 72 65 73 70 6f 6e 73 65 2e 73 65 74 5f 68 65   response.set_he
27b0: 61 64 65 72 28 22 43 6f 6e 74 65 6e 74 2d 54 79  ader("Content-Ty
27c0: 70 65 22 2c 20 22 61 70 70 6c 69 63 61 74 69 6f  pe", "applicatio
27d0: 6e 2f 6a 73 6f 6e 3b 20 63 68 61 72 73 65 74 3d  n/json; charset=
27e0: 55 54 46 2d 38 22 29 0a 20 20 20 20 69 66 20 72  UTF-8").    if r
27f0: 65 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75  equest.cookies.u
2800: 73 65 72 5f 69 64 20 61 6e 64 20 72 65 71 75 65  ser_id and reque
2810: 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72 5f  st.cookies.user_
2820: 69 64 20 69 6e 20 64 55 73 65 72 3a 0a 20 20 20  id in dUser:.   
2830: 20 20 20 20 20 74 72 79 3a 0a 20 20 20 20 20 20       try:.      
2840: 20 20 20 20 20 20 64 65 6c 20 64 55 73 65 72 5b        del dUser[
2850: 72 65 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e  request.cookies.
2860: 75 73 65 72 5f 69 64 5d 0a 20 20 20 20 20 20 20  user_id].       
2870: 20 65 78 63 65 70 74 20 4b 65 79 45 72 72 6f 72   except KeyError
2880: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 72 65  :.            re
2890: 74 75 72 6e 20 27 7b 22 65 72 72 6f 72 22 20 3a  turn '{"error" :
28a0: 20 22 55 6e 6b 6e 6f 77 6e 20 75 73 65 72 2e 22   "Unknown user."
28b0: 7d 27 0a 20 20 20 20 72 65 74 75 72 6e 20 27 7b  }'.    return '{
28c0: 22 6d 65 73 73 61 67 65 22 20 3a 20 22 44 6f 6e  "message" : "Don
28d0: 65 2e 22 7d 27 0a 0a 40 61 70 70 2e 72 6f 75 74  e."}'..@app.rout
28e0: 65 28 22 2f 66 6f 72 6d 61 74 5f 74 65 78 74 2f  e("/format_text/
28f0: 66 72 22 2c 20 6d 65 74 68 6f 64 3d 22 50 4f 53  fr", method="POS
2900: 54 22 29 0a 64 65 66 20 66 6f 72 6d 61 74 54 65  T").def formatTe
2910: 78 74 20 28 29 3a 0a 20 20 20 20 22 61 70 70 6c  xt ():.    "appl
2920: 79 20 74 68 65 20 74 65 78 74 20 66 6f 72 6d 61  y the text forma
2930: 74 74 65 72 20 61 6e 64 20 72 65 74 75 72 6e 73  tter and returns
2940: 20 74 65 78 74 22 0a 20 20 20 20 72 65 74 75 72   text".    retur
2950: 6e 20 6f 54 65 78 74 46 6f 72 6d 61 74 74 65 72  n oTextFormatter
2960: 2e 66 6f 72 6d 61 74 54 65 78 74 28 72 65 71 75  .formatText(requ
2970: 65 73 74 2e 66 6f 72 6d 73 2e 74 65 78 74 29 0a  est.forms.text).
2980: 0a 23 40 61 70 70 2e 72 6f 75 74 65 28 27 2f 73  .#@app.route('/s
2990: 74 61 74 69 63 2f 3c 66 69 6c 65 70 61 74 68 3a  tatic/<filepath:
29a0: 70 61 74 68 3e 27 29 0a 23 64 65 66 20 73 65 72  path>').#def ser
29b0: 76 65 72 5f 73 74 61 74 69 63 20 28 66 69 6c 65  ver_static (file
29c0: 70 61 74 68 29 3a 0a 23 20 20 20 20 72 65 74 75  path):.#    retu
29d0: 72 6e 20 73 74 61 74 69 63 5f 66 69 6c 65 28 66  rn static_file(f
29e0: 69 6c 65 70 61 74 68 2c 20 72 6f 6f 74 3d 27 2e  ilepath, root='.
29f0: 2f 76 69 65 77 73 2f 73 74 61 74 69 63 27 29 0a  /views/static').
2a00: 0a 40 61 70 70 2e 72 6f 75 74 65 28 22 2f 73 75  .@app.route("/su
2a10: 67 67 65 73 74 2f 66 72 22 2c 20 6d 65 74 68 6f  ggest/fr", metho
2a20: 64 3d 22 50 4f 53 54 22 29 0a 64 65 66 20 73 75  d="POST").def su
2a30: 67 67 65 73 74 50 6f 73 74 20 28 29 3a 0a 20 20  ggestPost ():.  
2a40: 20 20 72 65 73 70 6f 6e 73 65 2e 73 65 74 5f 68    response.set_h
2a50: 65 61 64 65 72 28 22 43 6f 6e 74 65 6e 74 2d 54  eader("Content-T
2a60: 79 70 65 22 2c 20 22 61 70 70 6c 69 63 61 74 69  ype", "applicati
2a70: 6f 6e 2f 6a 73 6f 6e 3b 20 63 68 61 72 73 65 74  on/json; charset
2a80: 3d 55 54 46 2d 38 22 29 0a 20 20 20 20 74 72 79  =UTF-8").    try
2a90: 3a 0a 20 20 20 20 20 20 20 20 78 46 75 74 75 72  :.        xFutur
2aa0: 65 20 3d 20 78 50 72 6f 63 65 73 73 50 6f 6f 6c  e = xProcessPool
2ab0: 45 78 65 63 75 74 6f 72 2e 73 75 62 6d 69 74 28  Executor.submit(
2ac0: 73 75 67 67 65 73 74 2c 20 72 65 71 75 65 73 74  suggest, request
2ad0: 2e 66 6f 72 6d 73 2e 74 6f 6b 65 6e 29 0a 20 20  .forms.token).  
2ae0: 20 20 20 20 20 20 72 65 74 75 72 6e 20 78 46 75        return xFu
2af0: 74 75 72 65 2e 72 65 73 75 6c 74 28 29 0a 20 20  ture.result().  
2b00: 20 20 65 78 63 65 70 74 20 28 63 6f 6e 63 75 72    except (concur
2b10: 72 65 6e 74 2e 66 75 74 75 72 65 73 2e 54 69 6d  rent.futures.Tim
2b20: 65 6f 75 74 45 72 72 6f 72 2c 20 63 6f 6e 63 75  eoutError, concu
2b30: 72 72 65 6e 74 2e 66 75 74 75 72 65 73 2e 43 61  rrent.futures.Ca
2b40: 6e 63 65 6c 6c 65 64 45 72 72 6f 72 29 3a 0a 20  ncelledError):. 
2b50: 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 27 7b         return '{
2b60: 22 65 72 72 6f 72 22 3a 20 22 41 6e 61 6c 79 73  "error": "Analys
2b70: 69 73 20 61 62 6f 72 74 65 64 20 28 74 69 6d 65  is aborted (time
2b80: 20 6f 75 74 20 6f 72 20 63 61 6e 63 65 6c 6c 65   out or cancelle
2b90: 64 29 22 7d 27 0a 20 20 20 20 65 78 63 65 70 74  d)"}'.    except
2ba0: 20 63 6f 6e 63 75 72 72 65 6e 74 2e 66 75 74 75   concurrent.futu
2bb0: 72 65 73 2e 42 72 6f 6b 65 6e 45 78 65 63 75 74  res.BrokenExecut
2bc0: 6f 72 3a 0a 20 20 20 20 20 20 20 20 72 65 74 75  or:.        retu
2bd0: 72 6e 20 27 7b 22 65 72 72 6f 72 22 3a 20 22 45  rn '{"error": "E
2be0: 78 65 63 75 74 6f 72 20 62 72 6f 6b 65 6e 2e 20  xecutor broken. 
2bf0: 54 68 65 20 73 65 72 76 65 72 20 66 61 69 6c 65  The server faile
2c00: 64 2e 22 7d 27 0a 20 20 20 20 72 65 74 75 72 6e  d."}'.    return
2c10: 20 27 7b 22 65 72 72 6f 72 22 3a 20 22 46 61 74   '{"error": "Fat
2c20: 61 6c 20 65 72 72 6f 72 2e 20 54 68 65 20 73 65  al error. The se
2c30: 72 76 65 72 20 66 61 69 6c 65 64 2e 22 7d 27 0a  rver failed."}'.
2c40: 0a 0a 23 20 45 52 52 4f 52 0a 40 61 70 70 2e 65  ..# ERROR.@app.e
2c50: 72 72 6f 72 28 34 30 34 29 0a 64 65 66 20 65 72  rror(404).def er
2c60: 72 6f 72 34 30 34 20 28 65 72 72 6f 72 29 3a 0a  ror404 (error):.
2c70: 20 20 20 20 22 34 30 34 20 65 72 72 6f 72 20 70      "404 error p
2c80: 61 67 65 22 0a 20 20 20 20 72 65 74 75 72 6e 20  age".    return 
2c90: 27 45 72 72 6f 72 20 34 30 34 2e 3c 62 72 2f 3e  'Error 404.<br/>
2ca0: 27 20 2b 20 73 74 72 28 65 72 72 6f 72 29 0a 0a  ' + str(error)..
2cb0: 0a 23 23 20 43 6f 6d 6d 6f 6e 20 66 75 6e 63 74  .## Common funct
2cc0: 69 6f 6e 73 0a 0a 64 65 66 20 70 75 72 67 65 55  ions..def purgeU
2cd0: 73 65 72 73 20 28 29 3a 0a 20 20 20 20 22 64 65  sers ():.    "de
2ce0: 6c 65 74 65 20 75 73 65 72 20 6f 70 74 69 6f 6e  lete user option
2cf0: 73 20 6f 6c 64 65 72 20 74 68 61 6e 20 6e 20 68  s older than n h
2d00: 6f 75 72 73 22 0a 20 20 20 20 74 72 79 3a 0a 20  ours".    try:. 
2d10: 20 20 20 20 20 20 20 6e 4e 6f 77 4d 69 6e 75 73         nNowMinus
2d20: 4e 48 6f 75 72 73 20 3d 20 69 6e 74 28 74 69 6d  NHours = int(tim
2d30: 65 2e 74 69 6d 65 28 29 29 20 2d 20 28 69 6e 74  e.time()) - (int
2d40: 28 72 65 71 75 65 73 74 2e 66 6f 72 6d 73 2e 68  (request.forms.h
2d50: 6f 75 72 73 29 20 2a 20 36 30 20 2a 20 36 30 29  ours) * 60 * 60)
2d60: 0a 20 20 20 20 20 20 20 20 66 6f 72 20 6e 55 73  .        for nUs
2d70: 65 72 49 64 2c 20 64 56 61 6c 75 65 20 69 6e 20  erId, dValue in 
2d80: 64 55 73 65 72 2e 69 74 65 6d 73 28 29 3a 0a 20  dUser.items():. 
2d90: 20 20 20 20 20 20 20 20 20 20 20 69 66 20 64 56             if dV
2da0: 61 6c 75 65 5b 22 74 69 6d 65 22 5d 20 3c 20 6e  alue["time"] < n
2db0: 4e 6f 77 4d 69 6e 75 73 4e 48 6f 75 72 73 3a 0a  NowMinusNHours:.
2dc0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
2dd0: 64 65 6c 20 64 55 73 65 72 5b 6e 55 73 65 72 49  del dUser[nUserI
2de0: 64 5d 0a 20 20 20 20 20 20 20 20 72 65 74 75 72  d].        retur
2df0: 6e 20 54 72 75 65 0a 20 20 20 20 65 78 63 65 70  n True.    excep
2e00: 74 20 4b 65 79 45 72 72 6f 72 3a 0a 20 20 20 20  t KeyError:.    
2e10: 20 20 20 20 74 72 61 63 65 62 61 63 6b 2e 70 72      traceback.pr
2e20: 69 6e 74 5f 65 78 63 28 29 0a 20 20 20 20 20 20  int_exc().      
2e30: 20 20 72 65 74 75 72 6e 20 46 61 6c 73 65 0a 0a    return False..
2e40: 0a 23 23 23 23 20 53 54 41 52 54 20 23 23 23 23  .#### START ####
2e50: 0a 0a 64 65 66 20 6d 61 69 6e 20 28 73 48 6f 73  ..def main (sHos
2e60: 74 3d 22 6c 6f 63 61 6c 68 6f 73 74 22 2c 20 6e  t="localhost", n
2e70: 50 6f 72 74 3d 38 30 38 30 2c 20 64 4f 70 74 69  Port=8080, dOpti
2e80: 6f 6e 73 3d 4e 6f 6e 65 2c 20 62 54 65 73 74 50  ons=None, bTestP
2e90: 61 67 65 3d 46 61 6c 73 65 2c 20 6e 4d 75 6c 74  age=False, nMult
2ea0: 69 43 50 55 3d 4e 6f 6e 65 29 3a 0a 20 20 20 20  iCPU=None):.    
2eb0: 22 73 74 61 72 74 20 73 65 72 76 65 72 22 0a 20  "start server". 
2ec0: 20 20 20 67 6c 6f 62 61 6c 20 54 45 53 54 50 41     global TESTPA
2ed0: 47 45 0a 20 20 20 20 67 6c 6f 62 61 6c 20 48 4f  GE.    global HO
2ee0: 4d 45 50 41 47 45 0a 0a 20 20 20 20 69 66 20 62  MEPAGE..    if b
2ef0: 54 65 73 74 50 61 67 65 3a 0a 20 20 20 20 20 20  TestPage:.      
2f00: 20 20 54 45 53 54 50 41 47 45 20 3d 20 54 72 75    TESTPAGE = Tru
2f10: 65 0a 20 20 20 20 20 20 20 20 48 4f 4d 45 50 41  e.        HOMEPA
2f20: 47 45 20 3d 20 48 4f 4d 45 50 41 47 45 2e 72 65  GE = HOMEPAGE.re
2f30: 70 6c 61 63 65 28 22 7b 53 45 52 56 45 52 5f 50  place("{SERVER_P
2f40: 4f 52 54 7d 22 2c 20 73 74 72 28 6e 50 6f 72 74  ORT}", str(nPort
2f50: 29 29 0a 20 20 20 20 69 66 20 64 4f 70 74 69 6f  )).    if dOptio
2f60: 6e 73 3a 0a 20 20 20 20 20 20 20 20 6f 47 43 45  ns:.        oGCE
2f70: 2e 73 65 74 4f 70 74 69 6f 6e 73 28 64 4f 70 74  .setOptions(dOpt
2f80: 69 6f 6e 73 29 0a 0a 20 20 20 20 23 20 50 79 74  ions)..    # Pyt
2f90: 68 6f 6e 20 76 65 72 73 69 6f 6e 0a 20 20 20 20  hon version.    
2fa0: 70 72 69 6e 74 28 22 50 79 74 68 6f 6e 3a 20 22  print("Python: "
2fb0: 20 2b 20 73 79 73 2e 76 65 72 73 69 6f 6e 29 0a   + sys.version).
2fc0: 20 20 20 20 23 20 47 72 61 6d 6d 61 6c 65 63 74      # Grammalect
2fd0: 65 0a 20 20 20 20 65 63 68 6f 28 22 47 72 61 6d  e.    echo("Gram
2fe0: 6d 61 6c 65 63 74 65 20 76 7b 7d 22 2e 66 6f 72  malecte v{}".for
2ff0: 6d 61 74 28 6f 47 43 45 2e 76 65 72 73 69 6f 6e  mat(oGCE.version
3000: 29 29 0a 20 20 20 20 6f 47 43 45 2e 64 69 73 70  )).    oGCE.disp
3010: 6c 61 79 4f 70 74 69 6f 6e 73 28 29 0a 20 20 20  layOptions().   
3020: 20 23 20 50 72 6f 63 65 73 73 20 50 6f 6f 6c 20   # Process Pool 
3030: 45 78 65 63 75 74 6f 72 0a 20 20 20 20 69 6e 69  Executor.    ini
3040: 74 45 78 65 63 75 74 6f 72 28 6e 4d 75 6c 74 69  tExecutor(nMulti
3050: 43 50 55 29 0a 20 20 20 20 23 20 53 65 72 76 65  CPU).    # Serve
3060: 72 20 28 42 6f 74 74 6c 65 29 0a 20 20 20 20 72  r (Bottle).    r
3070: 75 6e 28 61 70 70 2c 20 68 6f 73 74 3d 73 48 6f  un(app, host=sHo
3080: 73 74 2c 20 70 6f 72 74 3d 6e 50 6f 72 74 29 0a  st, port=nPort).
3090: 0a 0a 69 66 20 5f 5f 6e 61 6d 65 5f 5f 20 3d 3d  ..if __name__ ==
30a0: 20 27 5f 5f 6d 61 69 6e 5f 5f 27 3a 0a 20 20 20   '__main__':.   
30b0: 20 78 50 61 72 73 65 72 20 3d 20 61 72 67 70 61   xParser = argpa
30c0: 72 73 65 2e 41 72 67 75 6d 65 6e 74 50 61 72 73  rse.ArgumentPars
30d0: 65 72 28 29 0a 20 20 20 20 23 78 50 61 72 73 65  er().    #xParse
30e0: 72 2e 61 64 64 5f 61 72 67 75 6d 65 6e 74 28 22  r.add_argument("
30f0: 6c 61 6e 67 22 2c 20 74 79 70 65 3d 73 74 72 2c  lang", type=str,
3100: 20 6e 61 72 67 73 3d 27 2b 27 2c 20 68 65 6c 70   nargs='+', help
3110: 3d 22 6c 61 6e 67 20 70 72 6f 6a 65 63 74 20 74  ="lang project t
3120: 6f 20 67 65 6e 65 72 61 74 65 20 28 6e 61 6d 65  o generate (name
3130: 20 6f 66 20 66 6f 6c 64 65 72 20 69 6e 20 2f 6c   of folder in /l
3140: 61 6e 67 29 22 29 0a 20 20 20 20 78 50 61 72 73  ang)").    xPars
3150: 65 72 2e 61 64 64 5f 61 72 67 75 6d 65 6e 74 28  er.add_argument(
3160: 22 2d 68 74 22 2c 20 22 2d 2d 68 6f 73 74 22 2c  "-ht", "--host",
3170: 20 68 65 6c 70 3d 22 68 6f 73 74 20 28 64 65 66   help="host (def
3180: 61 75 6c 74 3a 20 6c 6f 63 61 6c 68 6f 73 74 29  ault: localhost)
3190: 22 2c 20 74 79 70 65 3d 73 74 72 29 0a 20 20 20  ", type=str).   
31a0: 20 78 50 61 72 73 65 72 2e 61 64 64 5f 61 72 67   xParser.add_arg
31b0: 75 6d 65 6e 74 28 22 2d 70 22 2c 20 22 2d 2d 70  ument("-p", "--p
31c0: 6f 72 74 22 2c 20 68 65 6c 70 3d 22 70 6f 72 74  ort", help="port
31d0: 20 28 64 65 66 61 75 6c 74 3a 20 38 30 38 30 29   (default: 8080)
31e0: 22 2c 20 74 79 70 65 3d 69 6e 74 29 0a 20 20 20  ", type=int).   
31f0: 20 78 50 61 72 73 65 72 2e 61 64 64 5f 61 72 67   xParser.add_arg
3200: 75 6d 65 6e 74 28 22 2d 6d 70 22 2c 20 22 2d 2d  ument("-mp", "--
3210: 6d 75 6c 74 69 70 72 6f 63 65 73 73 6f 72 22 2c  multiprocessor",
3220: 20 68 65 6c 70 3d 22 64 65 66 69 6e 65 20 68 6f   help="define ho
3230: 77 20 6d 61 6e 79 20 70 72 6f 63 65 73 73 65 73  w many processes
3240: 20 66 6f 72 20 74 68 65 20 67 72 61 6d 6d 61 72   for the grammar
3250: 20 63 68 65 63 6b 65 72 22 2c 20 74 79 70 65 3d   checker", type=
3260: 69 6e 74 29 0a 20 20 20 20 78 50 61 72 73 65 72  int).    xParser
3270: 2e 61 64 64 5f 61 72 67 75 6d 65 6e 74 28 22 2d  .add_argument("-
3280: 74 22 2c 20 22 2d 2d 74 65 73 74 5f 70 61 67 65  t", "--test_page
3290: 22 2c 20 68 65 6c 70 3d 22 70 61 67 65 20 74 6f  ", help="page to
32a0: 20 74 65 73 74 20 74 68 65 20 73 65 72 76 65 72   test the server
32b0: 20 6f 6e 20 2f 22 2c 20 61 63 74 69 6f 6e 3d 22   on /", action="
32c0: 73 74 6f 72 65 5f 74 72 75 65 22 29 0a 20 20 20  store_true").   
32d0: 20 78 50 61 72 73 65 72 2e 61 64 64 5f 61 72 67   xParser.add_arg
32e0: 75 6d 65 6e 74 28 22 2d 6f 6e 22 2c 20 22 2d 2d  ument("-on", "--
32f0: 6f 70 74 5f 6f 6e 22 2c 20 6e 61 72 67 73 3d 22  opt_on", nargs="
3300: 2b 22 2c 20 68 65 6c 70 3d 22 61 63 74 69 76 61  +", help="activa
3310: 74 65 20 6f 70 74 69 6f 6e 73 22 29 0a 20 20 20  te options").   
3320: 20 78 50 61 72 73 65 72 2e 61 64 64 5f 61 72 67   xParser.add_arg
3330: 75 6d 65 6e 74 28 22 2d 6f 66 66 22 2c 20 22 2d  ument("-off", "-
3340: 2d 6f 70 74 5f 6f 66 66 22 2c 20 6e 61 72 67 73  -opt_off", nargs
3350: 3d 22 2b 22 2c 20 68 65 6c 70 3d 22 64 65 61 63  ="+", help="deac
3360: 74 69 76 61 74 65 20 6f 70 74 69 6f 6e 73 22 29  tivate options")
3370: 0a 20 20 20 20 78 41 72 67 73 20 3d 20 78 50 61  .    xArgs = xPa
3380: 72 73 65 72 2e 70 61 72 73 65 5f 61 72 67 73 28  rser.parse_args(
3390: 29 0a 0a 20 20 20 20 64 4f 70 74 20 3d 20 4e 6f  )..    dOpt = No
33a0: 6e 65 0a 20 20 20 20 69 66 20 78 41 72 67 73 2e  ne.    if xArgs.
33b0: 6f 70 74 5f 6f 6e 20 20 6f 72 20 20 78 41 72 67  opt_on  or  xArg
33c0: 73 2e 6f 70 74 5f 6f 66 66 3a 0a 20 20 20 20 20  s.opt_off:.     
33d0: 20 20 20 64 4f 70 74 20 3d 20 7b 7d 0a 20 20 20     dOpt = {}.   
33e0: 20 20 20 20 20 69 66 20 78 41 72 67 73 2e 6f 70       if xArgs.op
33f0: 74 5f 6f 6e 3a 0a 20 20 20 20 20 20 20 20 20 20  t_on:.          
3400: 20 20 64 4f 70 74 20 3d 20 7b 20 6f 70 74 3a 54    dOpt = { opt:T
3410: 72 75 65 20 20 66 6f 72 20 6f 70 74 20 69 6e 20  rue  for opt in 
3420: 78 41 72 67 73 2e 6f 70 74 5f 6f 6e 20 7d 0a 20  xArgs.opt_on }. 
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 66 66 3a 0a 20 20 20 20 20 20 20  opt_off:.       
3450: 20 20 20 20 20 64 4f 70 74 2e 75 70 64 61 74 65       dOpt.update
3460: 28 7b 20 6f 70 74 3a 46 61 6c 73 65 20 20 66 6f  ({ opt:False  fo
3470: 72 20 6f 70 74 20 69 6e 20 78 41 72 67 73 2e 6f  r opt in xArgs.o
3480: 70 74 5f 6f 66 66 20 7d 29 0a 0a 20 20 20 20 6d  pt_off })..    m
3490: 61 69 6e 28 78 41 72 67 73 2e 68 6f 73 74 20 6f  ain(xArgs.host o
34a0: 72 20 22 6c 6f 63 61 6c 68 6f 73 74 22 2c 20 5c  r "localhost", \
34b0: 0a 20 20 20 20 20 20 20 20 20 78 41 72 67 73 2e  .         xArgs.
34c0: 70 6f 72 74 20 6f 72 20 38 30 38 30 2c 20 5c 0a  port or 8080, \.
34d0: 20 20 20 20 20 20 20 20 20 64 4f 70 74 2c 0a 20           dOpt,. 
34e0: 20 20 20 20 20 20 20 20 78 41 72 67 73 2e 74 65          xArgs.te
34f0: 73 74 5f 70 61 67 65 2c 0a 20 20 20 20 20 20 20  st_page,.       
3500: 20 20 78 41 72 67 73 2e 6d 75 6c 74 69 70 72 6f    xArgs.multipro
3510: 63 65 73 73 6f 72 29 0a 65 6c 73 65 3a 0a 20 20  cessor).else:.  
3520: 20 20 23 20 4d 75 73 74 20 62 65 20 6c 61 75 6e    # Must be laun
3530: 63 68 65 64 20 61 74 20 73 74 61 72 74 2c 20 66  ched at start, f
3540: 6f 72 20 57 53 47 49 20 73 65 72 76 65 72 20 28  or WSGI server (
3550: 77 68 69 63 68 20 64 6f 65 73 6e e2 80 99 74 20  which doesn...t 
3560: 63 61 6c 6c 20 6d 61 69 6e 28 29 29 0a 20 20 20  call main()).   
3570: 20 23 20 57 53 47 49 20 73 65 72 76 65 72 73 20   # WSGI servers 
3580: 6a 75 73 74 20 69 6d 70 6f 72 74 20 74 68 65 20  just import the 
3590: 67 69 76 65 6e 20 66 69 6c 65 20 61 73 20 61 20  given file as a 
35a0: 6d 6f 64 75 6c 65 20 61 6e 64 20 75 73 65 20 61  module and use a
35b0: 6e 20 6f 62 6a 65 63 74 20 65 78 70 6f 72 74 65  n object exporte
35c0: 64 20 66 72 6f 6d 20 69 74 20 28 3c 61 70 70 3e  d from it (<app>
35d0: 20 69 6e 20 74 68 69 73 20 63 61 73 65 29 20 74   in this case) t
35e0: 6f 20 72 75 6e 20 74 68 65 20 73 65 72 76 65 72  o run the server
35f0: 2e 0a 20 20 20 20 69 6e 69 74 45 78 65 63 75 74  ..    initExecut
3600: 6f 72 28 29 0a                                   or().