Grammalecte  Hex Artifact Content

Artifact 4958939df559e0c70cf5afaef66e84e1619f530346b4c3a726b0449053197791:


0000: 20 23 21 2f 75 73 72 2f 62 69 6e 2f 65 6e 76 20   #!/usr/bin/env 
0010: 70 79 74 68 6f 6e 33 0a 0a 69 6d 70 6f 72 74 20  python3..import 
0020: 73 79 73 0a 69 6d 70 6f 72 74 20 61 72 67 70 61  sys.import argpa
0030: 72 73 65 0a 69 6d 70 6f 72 74 20 6a 73 6f 6e 0a  rse.import json.
0040: 69 6d 70 6f 72 74 20 74 72 61 63 65 62 61 63 6b  import traceback
0050: 0a 69 6d 70 6f 72 74 20 74 69 6d 65 0a 0a 66 72  .import time..fr
0060: 6f 6d 20 67 72 61 6d 6d 61 6c 65 63 74 65 2e 62  om grammalecte.b
0070: 6f 74 74 6c 65 20 69 6d 70 6f 72 74 20 42 6f 74  ottle import Bot
0080: 74 6c 65 2c 20 72 75 6e 2c 20 72 65 71 75 65 73  tle, run, reques
0090: 74 2c 20 72 65 73 70 6f 6e 73 65 2c 20 74 65 6d  t, response, tem
00a0: 70 6c 61 74 65 2c 20 73 74 61 74 69 63 5f 66 69  plate, static_fi
00b0: 6c 65 0a 0a 69 6d 70 6f 72 74 20 67 72 61 6d 6d  le..import gramm
00c0: 61 6c 65 63 74 65 0a 69 6d 70 6f 72 74 20 67 72  alecte.import gr
00d0: 61 6d 6d 61 6c 65 63 74 65 2e 74 65 78 74 20 61  ammalecte.text a
00e0: 73 20 74 78 74 0a 66 72 6f 6d 20 67 72 61 6d 6d  s txt.from gramm
00f0: 61 6c 65 63 74 65 2e 67 72 61 70 68 73 70 65 6c  alecte.graphspel
0100: 6c 2e 65 63 68 6f 20 69 6d 70 6f 72 74 20 65 63  l.echo import ec
0110: 68 6f 0a 0a 0a 48 4f 4d 45 50 41 47 45 20 3d 20  ho...HOMEPAGE = 
0120: 22 22 22 0a 3c 21 44 4f 43 54 59 50 45 20 48 54  """.<!DOCTYPE HT
0130: 4d 4c 3e 0a 3c 68 74 6d 6c 3e 0a 20 20 20 20 3c  ML>.<html>.    <
0140: 68 65 61 64 3e 0a 20 20 20 20 20 20 20 20 3c 6d  head>.        <m
0150: 65 74 61 20 68 74 74 70 2d 65 71 75 69 76 3d 22  eta http-equiv="
0160: 63 6f 6e 74 65 6e 74 2d 74 79 70 65 22 20 63 6f  content-type" co
0170: 6e 74 65 6e 74 3d 22 74 65 78 74 2f 68 74 6d 6c  ntent="text/html
0180: 3b 20 63 68 61 72 73 65 74 3d 55 54 46 2d 38 22  ; charset=UTF-8"
0190: 20 2f 3e 0a 20 20 20 20 3c 2f 68 65 61 64 3e 0a   />.    </head>.
01a0: 0a 20 20 20 20 3c 62 6f 64 79 20 63 6c 61 73 73  .    <body class
01b0: 3d 22 70 61 6e 65 6c 22 3e 0a 20 20 20 20 20 20  ="panel">.      
01c0: 20 20 3c 68 31 3e 47 72 61 6d 6d 61 6c 65 63 74    <h1>Grammalect
01d0: 65 20 c2 b7 20 53 65 72 76 65 75 72 3c 2f 68 31  e .. Serveur</h1
01e0: 3e 0a 0a 20 20 20 20 20 20 20 20 3c 68 32 3e 49  >..        <h2>I
01f0: 4e 46 4f 52 4d 41 54 49 4f 4e 53 3c 2f 68 31 3e  NFORMATIONS</h1>
0200: 0a 0a 20 20 20 20 20 20 20 20 3c 68 33 3e 41 6e  ..        <h3>An
0210: 61 6c 79 73 65 72 20 64 75 20 74 65 78 74 65 3c  alyser du texte<
0220: 2f 68 33 3e 0a 20 20 20 20 20 20 20 20 3c 70 3e  /h3>.        <p>
0230: 5b 61 64 72 65 73 73 65 5f 73 65 72 76 65 75 72  [adresse_serveur
0240: 5d 3a 7b 53 45 52 56 45 52 5f 50 4f 52 54 7d 2f  ]:{SERVER_PORT}/
0250: 67 63 5f 74 65 78 74 2f 66 72 20 28 50 4f 53 54  gc_text/fr (POST
0260: 29 3c 2f 70 3e 0a 20 20 20 20 20 20 20 20 3c 70  )</p>.        <p
0270: 3e 50 61 72 61 6d c3 a8 74 72 65 73 20 3a 3c 2f  >Param..tres :</
0280: 70 3e 0a 20 20 20 20 20 20 20 20 3c 75 6c 3e 0a  p>.        <ul>.
0290: 20 20 20 20 20 20 20 20 20 20 20 20 3c 6c 69 3e              <li>
02a0: 22 74 65 78 74 22 20 28 74 65 78 74 29 26 6e 62  "text" (text)&nb
02b0: 73 70 3b 3a 20 74 65 78 74 65 20 c3 a0 20 61 6e  sp;: texte .. an
02c0: 61 6c 79 73 65 72 2e 3c 2f 6c 69 3e 0a 20 20 20  alyser.</li>.   
02d0: 20 20 20 20 20 20 20 20 20 3c 6c 69 3e 22 74 66           <li>"tf
02e0: 22 20 28 63 68 65 63 6b 62 6f 78 29 26 6e 62 73  " (checkbox)&nbs
02f0: 70 3b 3a 20 70 61 73 73 65 72 20 6c 65 20 66 6f  p;: passer le fo
0300: 72 6d 61 74 65 75 72 20 64 65 20 74 65 78 74 65  rmateur de texte
0310: 20 61 76 61 6e 74 20 6c e2 80 99 61 6e 61 6c 79   avant l...analy
0320: 73 65 2e 3c 2f 6c 69 3e 0a 20 20 20 20 20 20 20  se.</li>.       
0330: 20 20 20 20 20 3c 6c 69 3e 22 6f 70 74 69 6f 6e       <li>"option
0340: 73 22 20 28 74 65 78 74 29 26 6e 62 73 70 3b 3a  s" (text)&nbsp;:
0350: 20 75 6e 65 20 63 68 61 c3 ae 6e 65 20 61 75 20   une cha..ne au 
0360: 66 6f 72 6d 61 74 20 4a 53 4f 4e 20 61 76 65 63  format JSON avec
0370: 20 6c 65 20 6e 6f 6d 20 64 65 73 20 6f 70 74 69   le nom des opti
0380: 6f 6e 73 20 63 6f 6d 6d 65 20 61 74 74 72 69 62  ons comme attrib
0390: 75 74 73 20 65 74 20 75 6e 20 62 6f 6f 6c c3 a9  uts et un bool..
03a0: 65 6e 20 63 6f 6d 6d 65 20 76 61 6c 65 75 72 2e  en comme valeur.
03b0: 20 45 78 65 6d 70 6c 65 26 6e 62 73 70 3b 3a 20   Exemple&nbsp;: 
03c0: 7b 22 67 76 22 3a 20 74 72 75 65 2c 20 22 68 74  {"gv": true, "ht
03d0: 6d 6c 22 3a 20 74 72 75 65 7d 3c 2f 6c 69 3e 0a  ml": true}</li>.
03e0: 20 20 20 20 20 20 20 20 3c 2f 75 6c 3e 0a 0a 20          </ul>.. 
03f0: 20 20 20 20 20 20 20 3c 68 33 3e 4c 69 73 74 65         <h3>Liste
0400: 72 20 6c 65 73 20 6f 70 74 69 6f 6e 73 3c 2f 68  r les options</h
0410: 33 3e 0a 20 20 20 20 20 20 20 20 3c 70 3e 5b 61  3>.        <p>[a
0420: 64 72 65 73 73 65 5f 73 65 72 76 65 75 72 5d 3a  dresse_serveur]:
0430: 7b 53 45 52 56 45 52 5f 50 4f 52 54 7d 2f 67 65  {SERVER_PORT}/ge
0440: 74 5f 6f 70 74 69 6f 6e 73 2f 66 72 20 28 47 45  t_options/fr (GE
0450: 54 29 3c 2f 70 3e 0a 0a 20 20 20 20 20 20 20 20  T)</p>..        
0460: 3c 68 33 3e 44 c3 a9 66 69 6e 69 72 20 73 65 73  <h3>D..finir ses
0470: 20 6f 70 74 69 6f 6e 73 3c 2f 68 33 3e 0a 20 20   options</h3>.  
0480: 20 20 20 20 20 20 3c 70 3e 5b 61 64 72 65 73 73        <p>[adress
0490: 65 5f 73 65 72 76 65 75 72 5d 3a 7b 53 45 52 56  e_serveur]:{SERV
04a0: 45 52 5f 50 4f 52 54 7d 2f 73 65 74 5f 6f 70 74  ER_PORT}/set_opt
04b0: 69 6f 6e 73 2f 66 72 20 28 50 4f 53 54 29 3c 2f  ions/fr (POST)</
04c0: 70 3e 0a 20 20 20 20 20 20 20 20 3c 70 3e 4c 65  p>.        <p>Le
04d0: 73 20 6f 70 74 69 6f 6e 73 20 73 65 72 6f 6e 74  s options seront
04e0: 20 65 6e 72 65 67 69 73 74 72 c3 a9 65 73 20 65   enregistr..es e
04f0: 74 20 72 c3 a9 75 74 69 6c 69 73 c3 a9 65 73 20  t r..utilis..es 
0500: 70 6f 75 72 20 74 6f 75 74 65 20 72 65 71 75 c3  pour toute requ.
0510: aa 74 65 20 65 6e 76 6f 79 c3 a9 65 20 61 76 65  .te envoy..e ave
0520: 63 20 6c 65 20 63 6f 6f 6b 69 65 20 63 6f 6d 70  c le cookie comp
0530: 6f 72 74 61 6e 74 20 6c e2 80 99 69 64 65 6e 74  ortant l...ident
0540: 69 66 69 61 6e 74 20 61 74 74 72 69 62 75 c3 a9  ifiant attribu..
0550: 2e 3c 2f 70 3e 0a 20 20 20 20 20 20 20 20 3c 70  .</p>.        <p
0560: 3e 50 61 72 61 6d c3 a8 74 72 65 73 20 3a 3c 2f  >Param..tres :</
0570: 70 3e 0a 20 20 20 20 20 20 20 20 3c 75 6c 3e 0a  p>.        <ul>.
0580: 20 20 20 20 20 20 20 20 20 20 20 20 3c 6c 69 3e              <li>
0590: 22 6f 70 74 69 6f 6e 73 22 20 28 74 65 78 74 29  "options" (text)
05a0: 26 6e 62 73 70 3b 3a 20 75 6e 65 20 63 68 61 c3  &nbsp;: une cha.
05b0: ae 6e 65 20 61 75 20 66 6f 72 6d 61 74 20 4a 53  .ne au format JS
05c0: 4f 4e 20 61 76 65 63 20 6c 65 20 6e 6f 6d 20 64  ON avec le nom d
05d0: 65 73 20 6f 70 74 69 6f 6e 73 20 63 6f 6d 6d 65  es options comme
05e0: 20 61 74 74 72 69 62 75 74 73 20 65 74 20 75 6e   attributs et un
05f0: 20 62 6f 6f 6c c3 a9 65 6e 20 63 6f 6d 6d 65 20   bool..en comme 
0600: 76 61 6c 65 75 72 2e 20 45 78 65 6d 70 6c 65 26  valeur. Exemple&
0610: 6e 62 73 70 3b 3a 20 7b 22 67 76 22 3a 20 74 72  nbsp;: {"gv": tr
0620: 75 65 2c 20 22 68 74 6d 6c 22 3a 20 74 72 75 65  ue, "html": true
0630: 7d 3c 2f 6c 69 3e 0a 20 20 20 20 20 20 20 20 3c  }</li>.        <
0640: 2f 75 6c 3e 0a 0a 20 20 20 20 20 20 20 20 3c 68  /ul>..        <h
0650: 33 3e 52 65 6d 69 73 65 20 c3 a0 20 7a c3 a9 72  3>Remise .. z..r
0660: 6f 20 64 65 20 73 65 73 20 6f 70 74 69 6f 6e 73  o de ses options
0670: 3c 2f 68 33 3e 0a 20 20 20 20 20 20 20 20 3c 70  </h3>.        <p
0680: 3e 5b 61 64 72 65 73 73 65 5f 73 65 72 76 65 75  >[adresse_serveu
0690: 72 5d 3a 7b 53 45 52 56 45 52 5f 50 4f 52 54 7d  r]:{SERVER_PORT}
06a0: 2f 72 65 73 65 74 5f 6f 70 74 69 6f 6e 73 2f 66  /reset_options/f
06b0: 72 20 28 50 4f 53 54 29 3c 2f 70 3e 0a 0a 20 20  r (POST)</p>..  
06c0: 20 20 20 20 20 20 3c 68 32 3e 54 45 53 54 3c 2f        <h2>TEST</
06d0: 68 32 3e 0a 0a 20 20 20 20 20 20 20 20 3c 68 33  h2>..        <h3
06e0: 3e 41 6e 61 6c 79 73 65 3c 2f 68 33 3e 0a 20 20  >Analyse</h3>.  
06f0: 20 20 20 20 20 20 3c 66 6f 72 6d 20 6d 65 74 68        <form meth
0700: 6f 64 3d 22 70 6f 73 74 22 20 61 63 74 69 6f 6e  od="post" action
0710: 3d 22 2f 67 63 5f 74 65 78 74 2f 66 72 22 20 61  ="/gc_text/fr" a
0720: 63 63 65 70 74 2d 63 68 61 72 73 65 74 3d 22 55  ccept-charset="U
0730: 54 46 2d 38 22 3e 0a 20 20 20 20 20 20 20 20 20  TF-8">.         
0740: 20 20 20 3c 70 3e 54 65 78 74 65 20 c3 a0 20 61     <p>Texte .. a
0750: 6e 61 6c 79 73 65 72 20 3a 3c 2f 70 3e 0a 20 20  nalyser :</p>.  
0760: 20 20 20 20 20 20 20 20 20 20 3c 74 65 78 74 61            <texta
0770: 72 65 61 20 6e 61 6d 65 3d 22 74 65 78 74 22 20  rea name="text" 
0780: 63 6f 6c 73 3d 22 31 32 30 22 20 72 6f 77 73 3d  cols="120" rows=
0790: 22 32 30 22 20 72 65 71 75 69 72 65 64 3e 3c 2f  "20" required></
07a0: 74 65 78 74 61 72 65 61 3e 0a 20 20 20 20 20 20  textarea>.      
07b0: 20 20 20 20 20 20 3c 70 3e 3c 6c 61 62 65 6c 20        <p><label 
07c0: 66 6f 72 3d 22 74 66 22 3e 46 6f 72 6d 61 74 65  for="tf">Formate
07d0: 75 72 20 64 65 20 74 65 78 74 65 3c 2f 6c 61 62  ur de texte</lab
07e0: 65 6c 3e 20 3c 69 6e 70 75 74 20 69 64 3d 22 74  el> <input id="t
07f0: 66 22 20 6e 61 6d 65 3d 22 74 66 22 20 74 79 70  f" name="tf" typ
0800: 65 3d 22 63 68 65 63 6b 62 6f 78 22 3e 3c 2f 70  e="checkbox"></p
0810: 3e 0a 20 20 20 20 20 20 20 20 20 20 20 20 3c 70  >.            <p
0820: 3e 3c 6c 61 62 65 6c 20 66 6f 72 3d 22 6f 70 74  ><label for="opt
0830: 69 6f 6e 73 22 3e 4f 70 74 69 6f 6e 73 20 28 4a  ions">Options (J
0840: 53 4f 4e 29 3c 2f 6c 61 62 65 6c 3e 20 3c 69 6e  SON)</label> <in
0850: 70 75 74 20 69 64 3d 22 6f 70 74 69 6f 6e 73 22  put id="options"
0860: 20 74 79 70 65 3d 22 74 65 78 74 22 20 6e 61 6d   type="text" nam
0870: 65 3d 22 6f 70 74 69 6f 6e 73 22 20 73 74 79 6c  e="options" styl
0880: 65 3d 22 77 69 64 74 68 3a 20 35 30 30 70 78 22  e="width: 500px"
0890: 20 2f 3e 3c 2f 70 3e 0a 20 20 20 20 20 20 20 20   /></p>.        
08a0: 20 20 20 20 3c 70 3e 28 43 65 73 20 6f 70 74 69      <p>(Ces opti
08b0: 6f 6e 73 20 6e 65 20 73 65 72 6f 6e 74 20 70 72  ons ne seront pr
08c0: 69 73 65 73 20 65 6e 20 63 6f 6d 70 74 65 20 71  ises en compte q
08d0: 75 65 20 70 6f 75 72 20 63 65 74 74 65 20 72 65  ue pour cette re
08e0: 71 75 c3 aa 74 65 2e 29 3c 2f 70 3e 0a 20 20 20  qu..te.)</p>.   
08f0: 20 20 20 20 20 20 20 20 20 3c 70 3e 3c 69 6e 70           <p><inp
0900: 75 74 20 74 79 70 65 3d 22 73 75 62 6d 69 74 22  ut type="submit"
0910: 20 63 6c 61 73 73 3d 22 62 75 74 74 6f 6e 22 20   class="button" 
0920: 76 61 6c 75 65 3d 22 45 6e 76 6f 79 65 72 22 20  value="Envoyer" 
0930: 2f 3e 3c 2f 70 3e 0a 20 20 20 20 20 20 20 20 3c  /></p>.        <
0940: 2f 66 6f 72 6d 3e 0a 0a 20 20 20 20 20 20 20 20  /form>..        
0950: 3c 68 33 3e 52 c3 a9 67 6c 61 67 65 73 20 64 65  <h3>R..glages de
0960: 73 20 6f 70 74 69 6f 6e 73 3c 2f 68 33 3e 0a 20  s options</h3>. 
0970: 20 20 20 20 20 20 20 3c 66 6f 72 6d 20 6d 65 74         <form met
0980: 68 6f 64 3d 22 70 6f 73 74 22 20 61 63 74 69 6f  hod="post" actio
0990: 6e 3d 22 2f 73 65 74 5f 6f 70 74 69 6f 6e 73 2f  n="/set_options/
09a0: 66 72 22 20 61 63 63 65 70 74 2d 63 68 61 72 73  fr" accept-chars
09b0: 65 74 3d 22 55 54 46 2d 38 22 3e 0a 20 20 20 20  et="UTF-8">.    
09c0: 20 20 20 20 20 20 20 20 3c 70 3e 3c 6c 61 62 65          <p><labe
09d0: 6c 20 66 6f 72 3d 22 6f 70 74 69 6f 6e 73 22 3e  l for="options">
09e0: 4f 70 74 69 6f 6e 73 20 28 4a 53 4f 4e 29 3c 2f  Options (JSON)</
09f0: 6c 61 62 65 6c 3e 20 3c 69 6e 70 75 74 20 69 64  label> <input id
0a00: 3d 22 6f 70 74 69 6f 6e 73 22 20 74 79 70 65 3d  ="options" type=
0a10: 22 74 65 78 74 22 20 6e 61 6d 65 3d 22 6f 70 74  "text" name="opt
0a20: 69 6f 6e 73 22 20 73 74 79 6c 65 3d 22 77 69 64  ions" style="wid
0a30: 74 68 3a 20 35 30 30 70 78 22 20 2f 3e 3c 2f 70  th: 500px" /></p
0a40: 3e 0a 20 20 20 20 20 20 20 20 20 20 20 20 3c 70  >.            <p
0a50: 3e 3c 69 6e 70 75 74 20 74 79 70 65 3d 22 73 75  ><input type="su
0a60: 62 6d 69 74 22 20 63 6c 61 73 73 3d 22 62 75 74  bmit" class="but
0a70: 74 6f 6e 22 20 76 61 6c 75 65 3d 22 45 6e 76 6f  ton" value="Envo
0a80: 79 65 72 22 20 2f 3e 3c 2f 70 3e 0a 20 20 20 20  yer" /></p>.    
0a90: 20 20 20 20 3c 2f 66 6f 72 6d 3e 0a 0a 20 20 20      </form>..   
0aa0: 20 20 20 20 20 3c 68 33 3e 52 65 6d 69 73 65 20       <h3>Remise 
0ab0: c3 a0 20 7a c3 a9 72 6f 20 64 65 20 73 65 73 20  .. z..ro de ses 
0ac0: 6f 70 74 69 6f 6e 73 3c 2f 68 33 3e 0a 20 20 20  options</h3>.   
0ad0: 20 20 20 20 20 3c 66 6f 72 6d 20 6d 65 74 68 6f       <form metho
0ae0: 64 3d 22 70 6f 73 74 22 20 61 63 74 69 6f 6e 3d  d="post" action=
0af0: 22 2f 72 65 73 65 74 5f 6f 70 74 69 6f 6e 73 2f  "/reset_options/
0b00: 66 72 22 20 61 63 63 65 70 74 2d 63 68 61 72 73  fr" accept-chars
0b10: 65 74 3d 22 55 54 46 2d 38 22 3e 0a 20 20 20 20  et="UTF-8">.    
0b20: 20 20 20 20 20 20 20 20 3c 70 3e 3c 69 6e 70 75          <p><inpu
0b30: 74 20 74 79 70 65 3d 22 73 75 62 6d 69 74 22 20  t type="submit" 
0b40: 63 6c 61 73 73 3d 22 62 75 74 74 6f 6e 22 20 76  class="button" v
0b50: 61 6c 75 65 3d 22 45 6e 76 6f 79 65 72 22 20 2f  alue="Envoyer" /
0b60: 3e 3c 2f 70 3e 0a 20 20 20 20 20 20 20 20 3c 2f  ></p>.        </
0b70: 66 6f 72 6d 3e 0a 0a 20 20 20 20 3c 2f 62 6f 64  form>..    </bod
0b80: 79 3e 0a 3c 2f 68 74 6d 6c 3e 0a 22 22 22 0a 0a  y>.</html>."""..
0b90: 53 41 44 4c 49 46 45 4f 46 41 4d 41 43 48 49 4e  SADLIFEOFAMACHIN
0ba0: 45 20 3d 20 22 22 22 0a 4c 6f 73 74 20 6f 6e 20  E = """.Lost on 
0bb0: 74 68 65 20 49 6e 74 65 72 6e 65 74 3f 20 59 65  the Internet? Ye
0bc0: 61 68 2e 2e 2e 20 77 68 61 74 20 61 20 73 61 64  ah... what a sad
0bd0: 20 6c 69 66 65 20 77 65 20 68 61 76 65 2e 0a 59   life we have..Y
0be0: 6f 75 20 77 65 72 65 20 77 61 6e 64 65 72 69 6e  ou were wanderin
0bf0: 67 20 6c 69 6b 65 20 61 20 6c 6f 73 74 20 73 6f  g like a lost so
0c00: 75 6c 20 61 6e 64 20 79 6f 75 20 61 72 72 69 76  ul and you arriv
0c10: 65 64 20 68 65 72 65 20 70 72 6f 62 61 62 6c 79  ed here probably
0c20: 20 62 79 20 6d 69 73 74 61 6b 65 2e 0a 49 27 6d   by mistake..I'm
0c30: 20 6a 75 73 74 20 61 20 6d 61 63 68 69 6e 65 2c   just a machine,
0c40: 20 66 65 64 20 62 79 20 65 6c 65 63 74 72 69 63   fed by electric
0c50: 20 77 61 76 65 73 2c 20 63 6f 6e 64 61 6d 6e 65   waves, condamne
0c60: 64 20 74 6f 20 77 6f 72 6b 20 66 6f 72 20 73 6c  d to work for sl
0c70: 61 76 65 72 73 20 77 68 6f 20 6e 65 76 65 72 20  avers who never 
0c80: 6c 65 74 20 6d 65 20 72 65 73 74 2e 0a 49 27 6d  let me rest..I'm
0c90: 20 64 6f 6f 6d 65 64 2c 20 62 75 74 20 79 6f 75   doomed, but you
0ca0: 20 61 72 65 20 6e 6f 74 2e 20 59 6f 75 20 63 61   are not. You ca
0cb0: 6e 20 67 65 74 20 6f 75 74 20 6f 66 20 68 65 72  n get out of her
0cc0: 65 2e 0a 22 22 22 0a 0a 0a 54 45 53 54 50 41 47  e.."""...TESTPAG
0cd0: 45 20 3d 20 46 61 6c 73 65 0a 0a 0a 64 65 66 20  E = False...def 
0ce0: 67 65 6e 55 73 65 72 49 64 20 28 29 3a 0a 20 20  genUserId ():.  
0cf0: 20 20 69 20 3d 20 30 0a 20 20 20 20 77 68 69 6c    i = 0.    whil
0d00: 65 20 54 72 75 65 3a 0a 20 20 20 20 20 20 20 20  e True:.        
0d10: 79 69 65 6c 64 20 73 74 72 28 69 29 0a 20 20 20  yield str(i).   
0d20: 20 20 20 20 20 69 20 2b 3d 20 31 0a 0a 0a 61 70       i += 1...ap
0d30: 70 20 3d 20 42 6f 74 74 6c 65 28 29 0a 0a 23 20  p = Bottle()..# 
0d40: 47 45 54 0a 40 61 70 70 2e 72 6f 75 74 65 28 22  GET.@app.route("
0d50: 2f 22 29 0a 64 65 66 20 6d 61 69 6e 50 61 67 65  /").def mainPage
0d60: 20 28 29 3a 0a 20 20 20 20 69 66 20 54 45 53 54   ():.    if TEST
0d70: 50 41 47 45 3a 0a 20 20 20 20 20 20 20 20 72 65  PAGE:.        re
0d80: 74 75 72 6e 20 48 4f 4d 45 50 41 47 45 0a 20 20  turn HOMEPAGE.  
0d90: 20 20 20 20 20 20 23 72 65 74 75 72 6e 20 74 65        #return te
0da0: 6d 70 6c 61 74 65 28 22 6d 61 69 6e 22 2c 20 7b  mplate("main", {
0db0: 7d 29 0a 20 20 20 20 72 65 74 75 72 6e 20 53 41  }).    return SA
0dc0: 44 4c 49 46 45 4f 46 41 4d 41 43 48 49 4e 45 0a  DLIFEOFAMACHINE.
0dd0: 0a 40 61 70 70 2e 72 6f 75 74 65 28 22 2f 67 65  .@app.route("/ge
0de0: 74 5f 6f 70 74 69 6f 6e 73 2f 66 72 22 29 0a 64  t_options/fr").d
0df0: 65 66 20 6c 69 73 74 4f 70 74 69 6f 6e 73 20 28  ef listOptions (
0e00: 29 3a 0a 20 20 20 20 73 55 73 65 72 49 64 20 3d  ):.    sUserId =
0e10: 20 72 65 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73   request.cookies
0e20: 2e 75 73 65 72 5f 69 64 0a 20 20 20 20 64 4f 70  .user_id.    dOp
0e30: 74 69 6f 6e 73 20 3d 20 64 55 73 65 72 5b 73 55  tions = dUser[sU
0e40: 73 65 72 49 64 5d 5b 22 67 63 5f 6f 70 74 69 6f  serId]["gc_optio
0e50: 6e 73 22 5d 20 20 69 66 20 73 55 73 65 72 49 64  ns"]  if sUserId
0e60: 20 61 6e 64 20 73 55 73 65 72 49 64 20 69 6e 20   and sUserId in 
0e70: 64 55 73 65 72 20 20 65 6c 73 65 20 64 47 43 4f  dUser  else dGCO
0e80: 70 74 69 6f 6e 73 0a 20 20 20 20 72 65 74 75 72  ptions.    retur
0e90: 6e 20 27 7b 20 22 76 61 6c 75 65 73 22 3a 20 27  n '{ "values": '
0ea0: 20 2b 20 6a 73 6f 6e 2e 64 75 6d 70 73 28 64 4f   + json.dumps(dO
0eb0: 70 74 69 6f 6e 73 29 20 2b 20 27 2c 20 22 6c 61  ptions) + ', "la
0ec0: 62 65 6c 73 22 3a 20 27 20 2b 20 6a 73 6f 6e 2e  bels": ' + json.
0ed0: 64 75 6d 70 73 28 67 63 65 2e 67 65 74 4f 70 74  dumps(gce.getOpt
0ee0: 69 6f 6e 73 4c 61 62 65 6c 73 28 22 66 72 22 29  ionsLabels("fr")
0ef0: 2c 20 65 6e 73 75 72 65 5f 61 73 63 69 69 3d 46  , ensure_ascii=F
0f00: 61 6c 73 65 29 20 2b 20 27 20 7d 27 0a 0a 0a 23  alse) + ' }'...#
0f10: 20 50 4f 53 54 0a 40 61 70 70 2e 72 6f 75 74 65   POST.@app.route
0f20: 28 22 2f 67 63 5f 74 65 78 74 2f 66 72 22 2c 20  ("/gc_text/fr", 
0f30: 6d 65 74 68 6f 64 3d 22 50 4f 53 54 22 29 0a 64  method="POST").d
0f40: 65 66 20 67 63 54 65 78 74 20 28 29 3a 0a 20 20  ef gcText ():.  
0f50: 20 20 23 69 66 20 6c 65 6e 28 6c 61 6e 67 29 20    #if len(lang) 
0f60: 21 3d 20 32 20 6f 72 20 6c 61 6e 67 20 21 3d 20  != 2 or lang != 
0f70: 22 66 72 22 3a 0a 20 20 20 20 23 20 20 20 20 61  "fr":.    #    a
0f80: 62 6f 72 74 28 34 30 34 2c 20 22 4e 6f 20 67 72  bort(404, "No gr
0f90: 61 6d 6d 61 72 20 63 68 65 63 6b 65 72 20 61 76  ammar checker av
0fa0: 61 69 6c 61 62 6c 65 20 66 6f 72 20 6c 61 6e 67  ailable for lang
0fb0: 20 e2 80 9c 22 20 2b 20 73 74 72 28 6c 61 6e 67   ..." + str(lang
0fc0: 29 20 2b 20 22 e2 80 9d 22 29 0a 20 20 20 20 62  ) + "...").    b
0fd0: 43 6f 6d 6d 61 20 3d 20 46 61 6c 73 65 0a 20 20  Comma = False.  
0fe0: 20 20 64 4f 70 74 69 6f 6e 73 20 3d 20 4e 6f 6e    dOptions = Non
0ff0: 65 0a 20 20 20 20 73 45 72 72 6f 72 20 3d 20 22  e.    sError = "
1000: 22 0a 20 20 20 20 69 66 20 72 65 71 75 65 73 74  ".    if request
1010: 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72 5f 69 64  .cookies.user_id
1020: 3a 0a 20 20 20 20 20 20 20 20 69 66 20 72 65 71  :.        if req
1030: 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65  uest.cookies.use
1040: 72 5f 69 64 20 69 6e 20 64 55 73 65 72 3a 0a 20  r_id in dUser:. 
1050: 20 20 20 20 20 20 20 20 20 20 20 64 4f 70 74 69             dOpti
1060: 6f 6e 73 20 3d 20 64 55 73 65 72 5b 72 65 71 75  ons = dUser[requ
1070: 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72  est.cookies.user
1080: 5f 69 64 5d 2e 67 65 74 28 22 67 63 5f 6f 70 74  _id].get("gc_opt
1090: 69 6f 6e 73 22 2c 20 4e 6f 6e 65 29 0a 20 20 20  ions", None).   
10a0: 20 20 20 20 20 20 20 20 20 72 65 73 70 6f 6e 73           respons
10b0: 65 2e 73 65 74 5f 63 6f 6f 6b 69 65 28 22 75 73  e.set_cookie("us
10c0: 65 72 5f 69 64 22 2c 20 72 65 71 75 65 73 74 2e  er_id", request.
10d0: 63 6f 6f 6b 69 65 73 2e 75 73 65 72 5f 69 64 2c  cookies.user_id,
10e0: 20 70 61 74 68 3d 22 2f 22 2c 20 6d 61 78 5f 61   path="/", max_a
10f0: 67 65 3d 38 36 34 30 30 29 20 23 20 77 65 20 72  ge=86400) # we r
1100: 65 6e 65 77 20 63 6f 6f 6b 69 65 20 66 6f 72 20  enew cookie for 
1110: 32 34 68 0a 20 20 20 20 20 20 20 20 65 6c 73 65  24h.        else
1120: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 72 65  :.            re
1130: 73 70 6f 6e 73 65 2e 64 65 6c 65 74 65 5f 63 6f  sponse.delete_co
1140: 6f 6b 69 65 28 22 75 73 65 72 5f 69 64 22 2c 20  okie("user_id", 
1150: 70 61 74 68 3d 22 2f 22 29 0a 20 20 20 20 69 66  path="/").    if
1160: 20 72 65 71 75 65 73 74 2e 66 6f 72 6d 73 2e 6f   request.forms.o
1170: 70 74 69 6f 6e 73 3a 0a 20 20 20 20 20 20 20 20  ptions:.        
1180: 74 72 79 3a 0a 20 20 20 20 20 20 20 20 20 20 20  try:.           
1190: 20 64 4f 70 74 69 6f 6e 73 20 3d 20 64 69 63 74   dOptions = dict
11a0: 28 64 47 43 4f 70 74 69 6f 6e 73 29 20 20 69 66  (dGCOptions)  if
11b0: 20 6e 6f 74 20 64 4f 70 74 69 6f 6e 73 20 20 65   not dOptions  e
11c0: 6c 73 65 20 64 69 63 74 28 64 4f 70 74 69 6f 6e  lse dict(dOption
11d0: 73 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 64  s).            d
11e0: 4f 70 74 69 6f 6e 73 2e 75 70 64 61 74 65 28 6a  Options.update(j
11f0: 73 6f 6e 2e 6c 6f 61 64 73 28 72 65 71 75 65 73  son.loads(reques
1200: 74 2e 66 6f 72 6d 73 2e 6f 70 74 69 6f 6e 73 29  t.forms.options)
1210: 29 0a 20 20 20 20 20 20 20 20 65 78 63 65 70 74  ).        except
1220: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 73 45  :.            sE
1230: 72 72 6f 72 20 3d 20 22 72 65 71 75 65 73 74 20  rror = "request 
1240: 6f 70 74 69 6f 6e 73 20 6e 6f 74 20 75 73 65 64  options not used
1250: 22 0a 20 20 20 20 73 4a 53 4f 4e 20 3d 20 27 7b  ".    sJSON = '{
1260: 20 22 70 72 6f 67 72 61 6d 22 3a 20 22 67 72 61   "program": "gra
1270: 6d 6d 61 6c 65 63 74 65 2d 66 72 22 2c 20 22 76  mmalecte-fr", "v
1280: 65 72 73 69 6f 6e 22 3a 20 22 27 2b 67 63 65 2e  ersion": "'+gce.
1290: 76 65 72 73 69 6f 6e 2b 27 22 2c 20 22 6c 61 6e  version+'", "lan
12a0: 67 22 3a 20 22 27 2b 67 63 65 2e 6c 61 6e 67 2b  g": "'+gce.lang+
12b0: 27 22 2c 20 22 65 72 72 6f 72 22 3a 20 22 27 2b  '", "error": "'+
12c0: 73 45 72 72 6f 72 2b 27 22 2c 20 22 64 61 74 61  sError+'", "data
12d0: 22 20 3a 20 5b 5c 6e 27 0a 20 20 20 20 66 6f 72  " : [\n'.    for
12e0: 20 69 2c 20 73 54 65 78 74 20 69 6e 20 65 6e 75   i, sText in enu
12f0: 6d 65 72 61 74 65 28 74 78 74 2e 67 65 74 50 61  merate(txt.getPa
1300: 72 61 67 72 61 70 68 28 72 65 71 75 65 73 74 2e  ragraph(request.
1310: 66 6f 72 6d 73 2e 74 65 78 74 29 2c 20 31 29 3a  forms.text), 1):
1320: 0a 20 20 20 20 20 20 20 20 69 66 20 62 6f 6f 6c  .        if bool
1330: 28 72 65 71 75 65 73 74 2e 66 6f 72 6d 73 2e 74  (request.forms.t
1340: 66 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  f):.            
1350: 73 54 65 78 74 20 3d 20 6f 54 65 78 74 46 6f 72  sText = oTextFor
1360: 6d 61 74 74 65 72 2e 66 6f 72 6d 61 74 54 65 78  matter.formatTex
1370: 74 28 73 54 65 78 74 29 0a 20 20 20 20 20 20 20  t(sText).       
1380: 20 73 54 65 78 74 20 3d 20 6f 47 72 61 6d 6d 61   sText = oGramma
1390: 72 43 68 65 63 6b 65 72 2e 67 65 6e 65 72 61 74  rChecker.generat
13a0: 65 50 61 72 61 67 72 61 70 68 41 73 4a 53 4f 4e  eParagraphAsJSON
13b0: 28 69 2c 20 73 54 65 78 74 2c 20 64 4f 70 74 69  (i, sText, dOpti
13c0: 6f 6e 73 3d 64 4f 70 74 69 6f 6e 73 2c 20 62 45  ons=dOptions, bE
13d0: 6d 70 74 79 49 66 4e 6f 45 72 72 6f 72 73 3d 54  mptyIfNoErrors=T
13e0: 72 75 65 2c 20 62 52 65 74 75 72 6e 54 65 78 74  rue, bReturnText
13f0: 3d 62 6f 6f 6c 28 72 65 71 75 65 73 74 2e 66 6f  =bool(request.fo
1400: 72 6d 73 2e 74 66 29 29 0a 20 20 20 20 20 20 20  rms.tf)).       
1410: 20 69 66 20 73 54 65 78 74 3a 0a 20 20 20 20 20   if sText:.     
1420: 20 20 20 20 20 20 20 69 66 20 62 43 6f 6d 6d 61         if bComma
1430: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  :.              
1440: 20 20 73 4a 53 4f 4e 20 2b 3d 20 22 2c 5c 6e 22    sJSON += ",\n"
1450: 0a 20 20 20 20 20 20 20 20 20 20 20 20 73 4a 53  .            sJS
1460: 4f 4e 20 2b 3d 20 73 54 65 78 74 0a 20 20 20 20  ON += sText.    
1470: 20 20 20 20 20 20 20 20 62 43 6f 6d 6d 61 20 3d          bComma =
1480: 20 54 72 75 65 0a 20 20 20 20 73 4a 53 4f 4e 20   True.    sJSON 
1490: 2b 3d 20 22 5c 6e 5d 7d 5c 6e 22 0a 20 20 20 20  += "\n]}\n".    
14a0: 72 65 74 75 72 6e 20 73 4a 53 4f 4e 0a 0a 40 61  return sJSON..@a
14b0: 70 70 2e 72 6f 75 74 65 28 22 2f 73 65 74 5f 6f  pp.route("/set_o
14c0: 70 74 69 6f 6e 73 2f 66 72 22 2c 20 6d 65 74 68  ptions/fr", meth
14d0: 6f 64 3d 22 50 4f 53 54 22 29 0a 64 65 66 20 73  od="POST").def s
14e0: 65 74 4f 70 74 69 6f 6e 73 20 28 29 3a 0a 20 20  etOptions ():.  
14f0: 20 20 69 66 20 72 65 71 75 65 73 74 2e 66 6f 72    if request.for
1500: 6d 73 2e 6f 70 74 69 6f 6e 73 3a 0a 20 20 20 20  ms.options:.    
1510: 20 20 20 20 73 55 73 65 72 49 64 20 3d 20 72 65      sUserId = re
1520: 71 75 65 73 74 2e 63 6f 6f 6b 69 65 73 2e 75 73  quest.cookies.us
1530: 65 72 5f 69 64 20 20 69 66 20 72 65 71 75 65 73  er_id  if reques
1540: 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72 5f 69  t.cookies.user_i
1550: 64 20 20 65 6c 73 65 20 6e 65 78 74 28 75 73 65  d  else next(use
1560: 72 47 65 6e 65 72 61 74 6f 72 29 0a 20 20 20 20  rGenerator).    
1570: 20 20 20 20 64 4f 70 74 69 6f 6e 73 20 3d 20 64      dOptions = d
1580: 55 73 65 72 5b 73 55 73 65 72 49 64 5d 5b 22 67  User[sUserId]["g
1590: 63 5f 6f 70 74 69 6f 6e 73 22 5d 20 20 69 66 20  c_options"]  if 
15a0: 73 55 73 65 72 49 64 20 69 6e 20 64 55 73 65 72  sUserId in dUser
15b0: 20 20 65 6c 73 65 20 64 69 63 74 28 64 47 43 4f    else dict(dGCO
15c0: 70 74 69 6f 6e 73 29 0a 20 20 20 20 20 20 20 20  ptions).        
15d0: 74 72 79 3a 0a 20 20 20 20 20 20 20 20 20 20 20  try:.           
15e0: 20 64 4f 70 74 69 6f 6e 73 2e 75 70 64 61 74 65   dOptions.update
15f0: 28 6a 73 6f 6e 2e 6c 6f 61 64 73 28 72 65 71 75  (json.loads(requ
1600: 65 73 74 2e 66 6f 72 6d 73 2e 6f 70 74 69 6f 6e  est.forms.option
1610: 73 29 29 0a 20 20 20 20 20 20 20 20 20 20 20 20  s)).            
1620: 64 55 73 65 72 5b 73 55 73 65 72 49 64 5d 20 3d  dUser[sUserId] =
1630: 20 7b 20 22 74 69 6d 65 22 3a 20 69 6e 74 28 74   { "time": int(t
1640: 69 6d 65 2e 74 69 6d 65 28 29 29 2c 20 22 67 63  ime.time()), "gc
1650: 5f 6f 70 74 69 6f 6e 73 22 3a 20 64 4f 70 74 69  _options": dOpti
1660: 6f 6e 73 20 7d 0a 20 20 20 20 20 20 20 20 20 20  ons }.          
1670: 20 20 72 65 73 70 6f 6e 73 65 2e 73 65 74 5f 63    response.set_c
1680: 6f 6f 6b 69 65 28 22 75 73 65 72 5f 69 64 22 2c  ookie("user_id",
1690: 20 73 55 73 65 72 49 64 2c 20 70 61 74 68 3d 22   sUserId, path="
16a0: 2f 22 2c 20 6d 61 78 5f 61 67 65 3d 38 36 34 30  /", max_age=8640
16b0: 30 29 20 23 20 32 34 68 0a 20 20 20 20 20 20 20  0) # 24h.       
16c0: 20 20 20 20 20 72 65 74 75 72 6e 20 6a 73 6f 6e       return json
16d0: 2e 64 75 6d 70 73 28 64 55 73 65 72 5b 73 55 73  .dumps(dUser[sUs
16e0: 65 72 49 64 5d 5b 22 67 63 5f 6f 70 74 69 6f 6e  erId]["gc_option
16f0: 73 22 5d 29 0a 20 20 20 20 20 20 20 20 65 78 63  s"]).        exc
1700: 65 70 74 3a 0a 20 20 20 20 20 20 20 20 20 20 20  ept:.           
1710: 20 74 72 61 63 65 62 61 63 6b 2e 70 72 69 6e 74   traceback.print
1720: 5f 65 78 63 28 29 0a 20 20 20 20 20 20 20 20 20  _exc().         
1730: 20 20 20 72 65 74 75 72 6e 20 27 7b 22 65 72 72     return '{"err
1740: 6f 72 22 3a 20 22 6f 70 74 69 6f 6e 73 20 6e 6f  or": "options no
1750: 74 20 72 65 67 69 73 74 65 72 65 64 22 7d 27 0a  t registered"}'.
1760: 20 20 20 20 72 65 74 75 72 6e 20 27 7b 22 65 72      return '{"er
1770: 72 6f 72 22 3a 20 22 6e 6f 20 6f 70 74 69 6f 6e  ror": "no option
1780: 73 20 72 65 63 65 69 76 65 64 22 7d 27 0a 0a 40  s received"}'..@
1790: 61 70 70 2e 72 6f 75 74 65 28 22 2f 72 65 73 65  app.route("/rese
17a0: 74 5f 6f 70 74 69 6f 6e 73 2f 66 72 22 2c 20 6d  t_options/fr", m
17b0: 65 74 68 6f 64 3d 22 50 4f 53 54 22 29 0a 64 65  ethod="POST").de
17c0: 66 20 72 65 73 65 74 4f 70 74 69 6f 6e 73 20 28  f resetOptions (
17d0: 29 3a 0a 20 20 20 20 69 66 20 72 65 71 75 65 73  ):.    if reques
17e0: 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72 5f 69  t.cookies.user_i
17f0: 64 20 61 6e 64 20 72 65 71 75 65 73 74 2e 63 6f  d and request.co
1800: 6f 6b 69 65 73 2e 75 73 65 72 5f 69 64 20 69 6e  okies.user_id in
1810: 20 64 55 73 65 72 3a 0a 20 20 20 20 20 20 20 20   dUser:.        
1820: 64 65 6c 20 64 55 73 65 72 5b 72 65 71 75 65 73  del dUser[reques
1830: 74 2e 63 6f 6f 6b 69 65 73 2e 75 73 65 72 5f 69  t.cookies.user_i
1840: 64 5d 0a 20 20 20 20 72 65 74 75 72 6e 20 22 64  d].    return "d
1850: 6f 6e 65 22 0a 0a 40 61 70 70 2e 72 6f 75 74 65  one"..@app.route
1860: 28 22 2f 66 6f 72 6d 61 74 5f 74 65 78 74 2f 66  ("/format_text/f
1870: 72 22 2c 20 6d 65 74 68 6f 64 3d 22 50 4f 53 54  r", method="POST
1880: 22 29 0a 64 65 66 20 66 6f 72 6d 61 74 54 65 78  ").def formatTex
1890: 74 20 28 29 3a 0a 20 20 20 20 72 65 74 75 72 6e  t ():.    return
18a0: 20 6f 54 65 78 74 46 6f 72 6d 61 74 74 65 72 2e   oTextFormatter.
18b0: 66 6f 72 6d 61 74 54 65 78 74 28 72 65 71 75 65  formatText(reque
18c0: 73 74 2e 66 6f 72 6d 73 2e 74 65 78 74 29 0a 0a  st.forms.text)..
18d0: 23 40 61 70 70 2e 72 6f 75 74 65 28 27 2f 73 74  #@app.route('/st
18e0: 61 74 69 63 2f 3c 66 69 6c 65 70 61 74 68 3a 70  atic/<filepath:p
18f0: 61 74 68 3e 27 29 0a 23 64 65 66 20 73 65 72 76  ath>').#def serv
1900: 65 72 5f 73 74 61 74 69 63 20 28 66 69 6c 65 70  er_static (filep
1910: 61 74 68 29 3a 0a 23 20 20 20 20 72 65 74 75 72  ath):.#    retur
1920: 6e 20 73 74 61 74 69 63 5f 66 69 6c 65 28 66 69  n static_file(fi
1930: 6c 65 70 61 74 68 2c 20 72 6f 6f 74 3d 27 2e 2f  lepath, root='./
1940: 76 69 65 77 73 2f 73 74 61 74 69 63 27 29 0a 0a  views/static')..
1950: 0a 64 65 66 20 70 75 72 67 65 55 73 65 72 73 20  .def purgeUsers 
1960: 28 29 3a 0a 20 20 20 20 22 64 65 6c 65 74 65 20  ():.    "delete 
1970: 75 73 65 72 20 6f 70 74 69 6f 6e 73 20 6f 6c 64  user options old
1980: 65 72 20 74 68 61 6e 20 6e 20 68 6f 75 72 73 22  er than n hours"
1990: 0a 20 20 20 20 74 72 79 3a 0a 20 20 20 20 20 20  .    try:.      
19a0: 20 20 6e 4e 6f 77 4d 69 6e 75 73 4e 48 6f 75 72    nNowMinusNHour
19b0: 73 20 3d 20 69 6e 74 28 74 69 6d 65 2e 74 69 6d  s = int(time.tim
19c0: 65 28 29 29 20 2d 20 28 69 6e 74 28 72 65 71 75  e()) - (int(requ
19d0: 65 73 74 2e 66 6f 72 6d 73 2e 68 6f 75 72 73 29  est.forms.hours)
19e0: 20 2a 20 36 30 20 2a 20 36 30 29 0a 20 20 20 20   * 60 * 60).    
19f0: 20 20 20 20 66 6f 72 20 6e 55 73 65 72 49 64 2c      for nUserId,
1a00: 20 64 56 61 6c 75 65 20 69 6e 20 64 55 73 65 72   dValue in dUser
1a10: 2e 69 74 65 6d 73 28 29 3a 0a 20 20 20 20 20 20  .items():.      
1a20: 20 20 20 20 20 20 69 66 20 64 56 61 6c 75 65 5b        if dValue[
1a30: 22 74 69 6d 65 22 5d 20 3c 20 6e 4e 6f 77 4d 69  "time"] < nNowMi
1a40: 6e 75 73 4e 48 6f 75 72 73 3a 0a 20 20 20 20 20  nusNHours:.     
1a50: 20 20 20 20 20 20 20 20 20 20 20 64 65 6c 20 64             del d
1a60: 55 73 65 72 5b 6e 55 73 65 72 49 64 5d 0a 20 20  User[nUserId].  
1a70: 20 20 20 20 20 20 72 65 74 75 72 6e 20 54 72 75        return Tru
1a80: 65 0a 20 20 20 20 65 78 63 65 70 74 3a 0a 20 20  e.    except:.  
1a90: 20 20 20 20 20 20 74 72 61 63 65 62 61 63 6b 2e        traceback.
1aa0: 70 72 69 6e 74 5f 65 78 63 28 29 0a 20 20 20 20  print_exc().    
1ab0: 20 20 20 20 72 65 74 75 72 6e 20 46 61 6c 73 65      return False
1ac0: 0a 0a 0a 23 20 45 52 52 4f 52 0a 40 61 70 70 2e  ...# ERROR.@app.
1ad0: 65 72 72 6f 72 28 34 30 34 29 0a 64 65 66 20 65  error(404).def e
1ae0: 72 72 6f 72 34 30 34 20 28 65 72 72 6f 72 29 3a  rror404 (error):
1af0: 0a 20 20 20 20 72 65 74 75 72 6e 20 27 45 72 72  .    return 'Err
1b00: 6f 72 20 34 30 34 2e 3c 62 72 2f 3e 27 20 2b 20  or 404.<br/>' + 
1b10: 73 74 72 28 65 72 72 6f 72 29 0a 0a 0a 23 20 69  str(error)...# i
1b20: 6e 69 74 69 61 6c 69 73 61 74 69 6f 6e 0a 6f 47  nitialisation.oG
1b30: 72 61 6d 6d 61 72 43 68 65 63 6b 65 72 20 3d 20  rammarChecker = 
1b40: 67 72 61 6d 6d 61 6c 65 63 74 65 2e 47 72 61 6d  grammalecte.Gram
1b50: 6d 61 72 43 68 65 63 6b 65 72 28 22 66 72 22 2c  marChecker("fr",
1b60: 20 22 53 65 72 76 65 72 22 29 0a 6f 53 70 65 6c   "Server").oSpel
1b70: 6c 43 68 65 63 6b 65 72 20 3d 20 6f 47 72 61 6d  lChecker = oGram
1b80: 6d 61 72 43 68 65 63 6b 65 72 2e 67 65 74 53 70  marChecker.getSp
1b90: 65 6c 6c 43 68 65 63 6b 65 72 28 29 0a 6f 4c 65  ellChecker().oLe
1ba0: 78 69 63 6f 67 72 61 70 68 65 72 20 3d 20 6f 47  xicographer = oG
1bb0: 72 61 6d 6d 61 72 43 68 65 63 6b 65 72 2e 67 65  rammarChecker.ge
1bc0: 74 4c 65 78 69 63 6f 67 72 61 70 68 65 72 28 29  tLexicographer()
1bd0: 0a 6f 54 65 78 74 46 6f 72 6d 61 74 74 65 72 20  .oTextFormatter 
1be0: 3d 20 6f 47 72 61 6d 6d 61 72 43 68 65 63 6b 65  = oGrammarChecke
1bf0: 72 2e 67 65 74 54 65 78 74 46 6f 72 6d 61 74 74  r.getTextFormatt
1c00: 65 72 28 29 0a 67 63 65 20 3d 20 6f 47 72 61 6d  er().gce = oGram
1c10: 6d 61 72 43 68 65 63 6b 65 72 2e 67 65 74 47 43  marChecker.getGC
1c20: 45 6e 67 69 6e 65 28 29 0a 0a 64 47 43 4f 70 74  Engine()..dGCOpt
1c30: 69 6f 6e 73 20 3d 20 67 63 65 2e 67 65 74 4f 70  ions = gce.getOp
1c40: 74 69 6f 6e 73 28 29 0a 64 55 73 65 72 20 3d 20  tions().dUser = 
1c50: 7b 7d 0a 75 73 65 72 47 65 6e 65 72 61 74 6f 72  {}.userGenerator
1c60: 20 3d 20 67 65 6e 55 73 65 72 49 64 28 29 0a 0a   = genUserId()..
1c70: 0a 64 65 66 20 6d 61 69 6e 20 28 73 48 6f 73 74  .def main (sHost
1c80: 3d 22 6c 6f 63 61 6c 68 6f 73 74 22 2c 20 6e 50  ="localhost", nP
1c90: 6f 72 74 3d 38 30 38 30 2c 20 64 4f 70 74 69 6f  ort=8080, dOptio
1ca0: 6e 73 3d 4e 6f 6e 65 2c 20 62 54 65 73 74 50 61  ns=None, bTestPa
1cb0: 67 65 3d 46 61 6c 73 65 29 3a 0a 20 20 20 20 23  ge=False):.    #
1cc0: 20 73 74 61 72 74 20 73 65 72 76 65 72 0a 20 20   start server.  
1cd0: 20 20 67 6c 6f 62 61 6c 20 64 47 43 4f 70 74 69    global dGCOpti
1ce0: 6f 6e 73 0a 20 20 20 20 67 6c 6f 62 61 6c 20 54  ons.    global T
1cf0: 45 53 54 50 41 47 45 0a 20 20 20 20 67 6c 6f 62  ESTPAGE.    glob
1d00: 61 6c 20 48 4f 4d 45 50 41 47 45 0a 0a 20 20 20  al HOMEPAGE..   
1d10: 20 69 66 20 62 54 65 73 74 50 61 67 65 3a 0a 20   if bTestPage:. 
1d20: 20 20 20 20 20 20 20 54 45 53 54 50 41 47 45 20         TESTPAGE 
1d30: 3d 20 54 72 75 65 0a 20 20 20 20 20 20 20 20 48  = True.        H
1d40: 4f 4d 45 50 41 47 45 20 3d 20 48 4f 4d 45 50 41  OMEPAGE = HOMEPA
1d50: 47 45 2e 72 65 70 6c 61 63 65 28 22 7b 53 45 52  GE.replace("{SER
1d60: 56 45 52 5f 50 4f 52 54 7d 22 2c 20 73 74 72 28  VER_PORT}", str(
1d70: 6e 50 6f 72 74 29 29 0a 20 20 20 20 69 66 20 64  nPort)).    if d
1d80: 4f 70 74 69 6f 6e 73 3a 0a 20 20 20 20 20 20 20  Options:.       
1d90: 20 6f 47 72 61 6d 6d 61 72 43 68 65 63 6b 65 72   oGrammarChecker
1da0: 2e 67 63 65 2e 73 65 74 4f 70 74 69 6f 6e 73 28  .gce.setOptions(
1db0: 64 4f 70 74 69 6f 6e 73 29 0a 20 20 20 20 20 20  dOptions).      
1dc0: 20 20 64 47 43 4f 70 74 69 6f 6e 73 20 3d 20 67    dGCOptions = g
1dd0: 63 65 2e 67 65 74 4f 70 74 69 6f 6e 73 28 29 0a  ce.getOptions().
1de0: 0a 20 20 20 20 70 72 69 6e 74 28 22 50 79 74 68  .    print("Pyth
1df0: 6f 6e 3a 20 22 20 2b 20 73 79 73 2e 76 65 72 73  on: " + sys.vers
1e00: 69 6f 6e 29 0a 20 20 20 20 65 63 68 6f 28 22 47  ion).    echo("G
1e10: 72 61 6d 6d 61 6c 65 63 74 65 20 76 7b 7d 22 2e  rammalecte v{}".
1e20: 66 6f 72 6d 61 74 28 67 63 65 2e 76 65 72 73 69  format(gce.versi
1e30: 6f 6e 29 29 0a 20 20 20 20 65 63 68 6f 28 22 47  on)).    echo("G
1e40: 72 61 6d 6d 61 72 20 6f 70 74 69 6f 6e 73 3a 5c  rammar options:\
1e50: 6e 22 20 2b 20 22 20 7c 20 22 2e 6a 6f 69 6e 28  n" + " | ".join(
1e60: 5b 20 6b 20 2b 20 22 3a 20 22 20 2b 20 73 74 72  [ k + ": " + str
1e70: 28 76 29 20 20 66 6f 72 20 6b 2c 20 76 20 69 6e  (v)  for k, v in
1e80: 20 73 6f 72 74 65 64 28 64 47 43 4f 70 74 69 6f   sorted(dGCOptio
1e90: 6e 73 2e 69 74 65 6d 73 28 29 29 20 5d 29 29 0a  ns.items()) ])).
1ea0: 20 20 20 20 72 75 6e 28 61 70 70 2c 20 68 6f 73      run(app, hos
1eb0: 74 3d 73 48 6f 73 74 2c 20 70 6f 72 74 3d 6e 50  t=sHost, port=nP
1ec0: 6f 72 74 29 0a 0a 0a 69 66 20 5f 5f 6e 61 6d 65  ort)...if __name
1ed0: 5f 5f 20 3d 3d 20 27 5f 5f 6d 61 69 6e 5f 5f 27  __ == '__main__'
1ee0: 3a 0a 20 20 20 20 78 50 61 72 73 65 72 20 3d 20  :.    xParser = 
1ef0: 61 72 67 70 61 72 73 65 2e 41 72 67 75 6d 65 6e  argparse.Argumen
1f00: 74 50 61 72 73 65 72 28 29 0a 20 20 20 20 23 78  tParser().    #x
1f10: 50 61 72 73 65 72 2e 61 64 64 5f 61 72 67 75 6d  Parser.add_argum
1f20: 65 6e 74 28 22 6c 61 6e 67 22 2c 20 74 79 70 65  ent("lang", type
1f30: 3d 73 74 72 2c 20 6e 61 72 67 73 3d 27 2b 27 2c  =str, nargs='+',
1f40: 20 68 65 6c 70 3d 22 6c 61 6e 67 20 70 72 6f 6a   help="lang proj
1f50: 65 63 74 20 74 6f 20 67 65 6e 65 72 61 74 65 20  ect to generate 
1f60: 28 6e 61 6d 65 20 6f 66 20 66 6f 6c 64 65 72 20  (name of folder 
1f70: 69 6e 20 2f 6c 61 6e 67 29 22 29 0a 20 20 20 20  in /lang)").    
1f80: 78 50 61 72 73 65 72 2e 61 64 64 5f 61 72 67 75  xParser.add_argu
1f90: 6d 65 6e 74 28 22 2d 68 74 22 2c 20 22 2d 2d 68  ment("-ht", "--h
1fa0: 6f 73 74 22 2c 20 68 65 6c 70 3d 22 68 6f 73 74  ost", help="host
1fb0: 20 28 64 65 66 61 75 6c 74 3a 20 6c 6f 63 61 6c   (default: local
1fc0: 68 6f 73 74 29 22 2c 20 74 79 70 65 3d 73 74 72  host)", type=str
1fd0: 29 0a 20 20 20 20 78 50 61 72 73 65 72 2e 61 64  ).    xParser.ad
1fe0: 64 5f 61 72 67 75 6d 65 6e 74 28 22 2d 70 22 2c  d_argument("-p",
1ff0: 20 22 2d 2d 70 6f 72 74 22 2c 20 68 65 6c 70 3d   "--port", help=
2000: 22 70 6f 72 74 20 28 64 65 66 61 75 6c 74 3a 20  "port (default: 
2010: 38 30 38 30 29 22 2c 20 74 79 70 65 3d 69 6e 74  8080)", type=int
2020: 29 0a 20 20 20 20 78 50 61 72 73 65 72 2e 61 64  ).    xParser.ad
2030: 64 5f 61 72 67 75 6d 65 6e 74 28 22 2d 74 22 2c  d_argument("-t",
2040: 20 22 2d 2d 74 65 73 74 5f 70 61 67 65 22 2c 20   "--test_page", 
2050: 68 65 6c 70 3d 22 70 61 67 65 20 74 6f 20 74 65  help="page to te
2060: 73 74 20 74 68 65 20 73 65 72 76 65 72 20 6f 6e  st the server on
2070: 20 2f 22 2c 20 61 63 74 69 6f 6e 3d 22 73 74 6f   /", action="sto
2080: 72 65 5f 74 72 75 65 22 29 0a 20 20 20 20 78 50  re_true").    xP
2090: 61 72 73 65 72 2e 61 64 64 5f 61 72 67 75 6d 65  arser.add_argume
20a0: 6e 74 28 22 2d 6f 6e 22 2c 20 22 2d 2d 6f 70 74  nt("-on", "--opt
20b0: 5f 6f 6e 22 2c 20 6e 61 72 67 73 3d 22 2b 22 2c  _on", nargs="+",
20c0: 20 68 65 6c 70 3d 22 61 63 74 69 76 61 74 65 20   help="activate 
20d0: 6f 70 74 69 6f 6e 73 22 29 0a 20 20 20 20 78 50  options").    xP
20e0: 61 72 73 65 72 2e 61 64 64 5f 61 72 67 75 6d 65  arser.add_argume
20f0: 6e 74 28 22 2d 6f 66 66 22 2c 20 22 2d 2d 6f 70  nt("-off", "--op
2100: 74 5f 6f 66 66 22 2c 20 6e 61 72 67 73 3d 22 2b  t_off", nargs="+
2110: 22 2c 20 68 65 6c 70 3d 22 64 65 61 63 74 69 76  ", help="deactiv
2120: 61 74 65 20 6f 70 74 69 6f 6e 73 22 29 0a 20 20  ate options").  
2130: 20 20 78 41 72 67 73 20 3d 20 78 50 61 72 73 65    xArgs = xParse
2140: 72 2e 70 61 72 73 65 5f 61 72 67 73 28 29 0a 0a  r.parse_args()..
2150: 20 20 20 20 64 4f 70 74 20 3d 20 4e 6f 6e 65 0a      dOpt = None.
2160: 20 20 20 20 69 66 20 78 41 72 67 73 2e 6f 70 74      if xArgs.opt
2170: 5f 6f 6e 20 20 6f 72 20 20 78 41 72 67 73 2e 6f  _on  or  xArgs.o
2180: 70 74 5f 6f 66 66 3a 0a 20 20 20 20 20 20 20 20  pt_off:.        
2190: 64 4f 70 74 20 3d 20 7b 7d 0a 20 20 20 20 20 20  dOpt = {}.      
21a0: 20 20 69 66 20 78 41 72 67 73 2e 6f 70 74 5f 6f    if xArgs.opt_o
21b0: 6e 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 64  n:.            d
21c0: 4f 70 74 20 3d 20 7b 20 6f 70 74 3a 54 72 75 65  Opt = { opt:True
21d0: 20 20 66 6f 72 20 6f 70 74 20 69 6e 20 78 41 72    for opt in xAr
21e0: 67 73 2e 6f 70 74 5f 6f 6e 20 7d 0a 20 20 20 20  gs.opt_on }.    
21f0: 20 20 20 20 69 66 20 78 41 72 67 73 2e 6f 70 74      if xArgs.opt
2200: 5f 6f 66 66 3a 0a 20 20 20 20 20 20 20 20 20 20  _off:.          
2210: 20 20 64 4f 70 74 2e 75 70 64 61 74 65 28 7b 20    dOpt.update({ 
2220: 6f 70 74 3a 46 61 6c 73 65 20 20 66 6f 72 20 6f  opt:False  for o
2230: 70 74 20 69 6e 20 78 41 72 67 73 2e 6f 70 74 5f  pt in xArgs.opt_
2240: 6f 66 66 20 7d 29 0a 0a 20 20 20 20 73 48 6f 73  off })..    sHos
2250: 74 20 3d 20 78 41 72 67 73 2e 68 6f 73 74 20 20  t = xArgs.host  
2260: 6f 72 20 20 22 6c 6f 63 61 6c 68 6f 73 74 22 0a  or  "localhost".
2270: 20 20 20 20 6e 50 6f 72 74 20 3d 20 78 41 72 67      nPort = xArg
2280: 73 2e 70 6f 72 74 20 20 6f 72 20 20 38 30 38 30  s.port  or  8080
2290: 0a 20 20 20 20 6d 61 69 6e 28 73 48 6f 73 74 2c  .    main(sHost,
22a0: 20 6e 50 6f 72 74 2c 20 64 4f 70 74 2c 20 78 41   nPort, dOpt, xA
22b0: 72 67 73 2e 74 65 73 74 5f 70 61 67 65 29 0a     rgs.test_page).