Grammalecte  Hex Artifact Content

Artifact 7ee8916cfbacb8c38a40145d3dd8a6ead6ce78be2cba4a6fc24eee221c4acc2d:


0000: 22 22 22 0a 47 72 61 6d 6d 61 6c 65 63 74 65 3a  """.Grammalecte:
0010: 20 63 6f 6d 70 69 6c 65 20 72 75 6c 65 73 0a 22   compile rules."
0020: 22 22 0a 0a 69 6d 70 6f 72 74 20 72 65 0a 69 6d  ""..import re.im
0030: 70 6f 72 74 20 6f 73 0a 69 6d 70 6f 72 74 20 74  port os.import t
0040: 72 61 63 65 62 61 63 6b 0a 69 6d 70 6f 72 74 20  raceback.import 
0050: 6a 73 6f 6e 0a 69 6d 70 6f 72 74 20 63 6f 6c 6f  json.import colo
0060: 72 73 79 73 0a 69 6d 70 6f 72 74 20 74 69 6d 65  rsys.import time
0070: 0a 69 6d 70 6f 72 74 20 68 61 73 68 6c 69 62 0a  .import hashlib.
0080: 0a 69 6d 70 6f 72 74 20 63 6f 6d 70 69 6c 65 5f  .import compile_
0090: 72 75 6c 65 73 5f 6a 73 5f 63 6f 6e 76 65 72 74  rules_js_convert
00a0: 20 61 73 20 6a 73 63 6f 6e 76 0a 69 6d 70 6f 72   as jsconv.impor
00b0: 74 20 63 6f 6d 70 69 6c 65 5f 72 75 6c 65 73 5f  t compile_rules_
00c0: 67 72 61 70 68 20 61 73 20 63 72 67 0a 0a 0a 64  graph as crg...d
00d0: 44 45 46 49 4e 49 54 49 4f 4e 53 20 3d 20 7b 7d  DEFINITIONS = {}
00e0: 0a 64 44 45 43 4c 45 4e 53 49 4f 4e 53 20 3d 20  .dDECLENSIONS = 
00f0: 7b 7d 0a 6c 46 55 4e 43 54 49 4f 4e 53 20 3d 20  {}.lFUNCTIONS = 
0100: 5b 5d 0a 0a 61 52 55 4c 45 53 45 54 20 3d 20 73  []..aRULESET = s
0110: 65 74 28 29 20 20 20 20 20 23 20 73 65 74 20 6f  et()     # set o
0120: 66 20 72 75 6c 65 2d 69 64 73 20 74 6f 20 63 68  f rule-ids to ch
0130: 65 63 6b 20 69 66 20 74 68 65 72 65 20 69 73 20  eck if there is 
0140: 73 65 76 65 72 61 6c 20 72 75 6c 65 73 20 77 69  several rules wi
0150: 74 68 20 74 68 65 20 73 61 6d 65 20 69 64 0a 0a  th the same id..
0160: 64 4a 53 52 45 47 45 58 45 53 20 3d 20 7b 7d 0a  dJSREGEXES = {}.
0170: 0a 73 57 4f 52 44 4c 49 4d 49 54 4c 45 46 54 20  .sWORDLIMITLEFT 
0180: 20 3d 20 72 22 28 3f 3c 21 5b 5c 77 2e 2c e2 80   = r"(?<![\w.,..
0190: 93 2d 5d 29 22 20 20 20 23 20 72 22 28 3f 3c 21  .-])"   # r"(?<!
01a0: 5b 2d 2e 2c e2 80 94 5d 29 5c 62 22 20 20 73 65  [-.,...])\b"  se
01b0: 65 6d 73 20 73 6c 6f 77 65 72 0a 73 57 4f 52 44  ems slower.sWORD
01c0: 4c 49 4d 49 54 52 49 47 48 54 20 3d 20 72 22 28  LIMITRIGHT = r"(
01d0: 3f 21 5b 5c 77 e2 80 93 2d 5d 29 22 20 20 20 20  ?![\w...-])"    
01e0: 20 20 23 20 72 22 5c 62 28 3f 21 2d e2 80 94 29    # r"\b(?!-...)
01f0: 22 20 20 20 20 20 20 20 73 65 65 6d 73 20 73 6c  "       seems sl
0200: 6f 77 65 72 0a 0a 0a 64 65 66 20 63 6f 6e 76 65  ower...def conve
0210: 72 74 52 47 42 54 6f 49 6e 74 65 67 65 72 20 28  rtRGBToInteger (
0220: 72 2c 20 67 2c 20 62 29 3a 0a 20 20 20 20 22 72  r, g, b):.    "r
0230: 62 67 20 28 69 6e 74 2c 20 69 6e 74 2c 20 69 6e  bg (int, int, in
0240: 74 29 20 2d 3e 20 69 6e 74 22 0a 20 20 20 20 72  t) -> int".    r
0250: 65 74 75 72 6e 20 28 72 20 26 20 32 35 35 29 20  eturn (r & 255) 
0260: 3c 3c 20 31 36 20 7c 20 28 67 20 26 20 32 35 35  << 16 | (g & 255
0270: 29 20 3c 3c 20 38 20 7c 20 28 62 20 26 20 32 35  ) << 8 | (b & 25
0280: 35 29 0a 0a 0a 64 65 66 20 63 6f 6e 76 65 72 74  5)...def convert
0290: 48 53 4c 54 6f 52 42 47 20 28 68 2c 20 73 2c 20  HSLToRBG (h, s, 
02a0: 6c 29 3a 0a 20 20 20 20 22 68 73 6c 20 28 69 6e  l):.    "hsl (in
02b0: 74 2c 20 69 6e 74 2c 20 69 6e 74 29 20 2d 3e 20  t, int, int) -> 
02c0: 5b 69 6e 74 2c 20 69 6e 74 2c 20 69 6e 74 5d 22  [int, int, int]"
02d0: 0a 20 20 20 20 72 2c 20 67 2c 20 62 20 3d 20 63  .    r, g, b = c
02e0: 6f 6c 6f 72 73 79 73 2e 68 6c 73 5f 74 6f 5f 72  olorsys.hls_to_r
02f0: 67 62 28 68 2f 33 36 30 2c 20 6c 2f 31 30 30 2c  gb(h/360, l/100,
0300: 20 73 2f 31 30 30 29 0a 20 20 20 20 72 65 74 75   s/100).    retu
0310: 72 6e 20 5b 72 6f 75 6e 64 28 72 2a 32 35 35 29  rn [round(r*255)
0320: 2c 20 72 6f 75 6e 64 28 67 2a 32 35 35 29 2c 20  , round(g*255), 
0330: 72 6f 75 6e 64 28 62 2a 32 35 35 29 5d 0a 0a 0a  round(b*255)]...
0340: 64 65 66 20 63 72 65 61 74 65 43 6f 6c 6f 72 73  def createColors
0350: 20 28 64 43 6f 6c 6f 72 29 3a 0a 20 20 20 20 22   (dColor):.    "
0360: 64 69 63 74 69 6f 6e 61 72 79 20 6f 66 20 63 6f  dictionary of co
0370: 6c 6f 72 73 20 7b 63 6f 6c 6f 72 5f 6e 61 6d 65  lors {color_name
0380: 3a 20 5b 68 2c 20 73 2c 20 6c 5d 7d 20 2d 3e 20  : [h, s, l]} -> 
0390: 72 65 74 75 72 6e 73 20 64 69 63 74 69 6f 6e 61  returns dictiona
03a0: 72 79 20 6f 66 20 63 6f 6c 6f 72 73 20 61 73 20  ry of colors as 
03b0: 64 69 63 74 69 6f 6e 61 72 69 65 73 20 6f 66 20  dictionaries of 
03c0: 63 6f 6c 6f 72 20 74 79 70 65 73 22 0a 20 20 20  color types".   
03d0: 20 64 43 6f 6c 6f 72 54 79 70 65 20 3d 20 7b 0a   dColorType = {.
03e0: 20 20 20 20 20 20 20 20 22 61 48 53 4c 22 3a 20          "aHSL": 
03f0: 7b 7d 2c 20 20 20 20 20 23 20 64 69 63 74 69 6f  {},     # dictio
0400: 6e 61 72 79 20 6f 66 20 63 6f 6c 6f 72 73 20 61  nary of colors a
0410: 73 20 48 53 4c 20 6c 69 73 74 0a 20 20 20 20 20  s HSL list.     
0420: 20 20 20 22 73 43 53 53 22 3a 20 7b 7d 2c 20 20     "sCSS": {},  
0430: 20 20 20 23 20 64 69 63 74 69 6f 6e 61 72 79 20     # dictionary 
0440: 6f 66 20 63 6f 6c 6f 72 73 20 61 73 20 73 74 72  of colors as str
0450: 69 6e 67 73 20 66 6f 72 20 48 54 4d 4c 2f 43 53  ings for HTML/CS
0460: 53 20 28 65 78 61 6d 70 6c 65 3a 20 68 73 6c 28  S (example: hsl(
0470: 30 2c 20 35 30 25 2c 20 35 30 25 29 29 0a 20 20  0, 50%, 50%)).  
0480: 20 20 20 20 20 20 22 61 52 47 42 22 3a 20 7b 7d        "aRGB": {}
0490: 2c 20 20 20 20 20 23 20 64 69 63 74 69 6f 6e 61  ,     # dictiona
04a0: 72 79 20 6f 66 20 63 6f 6c 6f 72 73 20 61 73 20  ry of colors as 
04b0: 52 47 42 20 6c 69 73 74 0a 20 20 20 20 20 20 20  RGB list.       
04c0: 20 22 6e 49 6e 74 22 3a 20 7b 7d 20 20 20 20 20   "nInt": {}     
04d0: 20 23 20 64 69 63 74 69 6f 6e 61 72 79 20 6f 66   # dictionary of
04e0: 20 63 6f 6c 6f 72 73 20 61 73 20 69 6e 74 65 67   colors as integ
04f0: 65 72 20 76 61 6c 75 65 73 20 28 66 6f 72 20 57  er values (for W
0500: 72 69 74 65 72 29 0a 20 20 20 20 7d 0a 20 20 20  riter).    }.   
0510: 20 66 6f 72 20 73 4b 65 79 2c 20 61 48 53 4c 20   for sKey, aHSL 
0520: 69 6e 20 64 43 6f 6c 6f 72 2e 69 74 65 6d 73 28  in dColor.items(
0530: 29 3a 0a 20 20 20 20 20 20 20 20 64 43 6f 6c 6f  ):.        dColo
0540: 72 54 79 70 65 5b 22 61 48 53 4c 22 5d 5b 73 4b  rType["aHSL"][sK
0550: 65 79 5d 20 3d 20 61 48 53 4c 0a 20 20 20 20 20  ey] = aHSL.     
0560: 20 20 20 64 43 6f 6c 6f 72 54 79 70 65 5b 22 73     dColorType["s
0570: 43 53 53 22 5d 5b 73 4b 65 79 5d 20 3d 20 22 68  CSS"][sKey] = "h
0580: 73 6c 28 7b 7d 2c 20 7b 7d 25 2c 20 7b 7d 25 29  sl({}, {}%, {}%)
0590: 22 2e 66 6f 72 6d 61 74 28 2a 61 48 53 4c 29 0a  ".format(*aHSL).
05a0: 20 20 20 20 20 20 20 20 64 43 6f 6c 6f 72 54 79          dColorTy
05b0: 70 65 5b 22 61 52 47 42 22 5d 5b 73 4b 65 79 5d  pe["aRGB"][sKey]
05c0: 20 3d 20 63 6f 6e 76 65 72 74 48 53 4c 54 6f 52   = convertHSLToR
05d0: 42 47 28 2a 61 48 53 4c 29 0a 20 20 20 20 20 20  BG(*aHSL).      
05e0: 20 20 64 43 6f 6c 6f 72 54 79 70 65 5b 22 6e 49    dColorType["nI
05f0: 6e 74 22 5d 5b 73 4b 65 79 5d 20 3d 20 63 6f 6e  nt"][sKey] = con
0600: 76 65 72 74 52 47 42 54 6f 49 6e 74 65 67 65 72  vertRGBToInteger
0610: 28 2a 64 43 6f 6c 6f 72 54 79 70 65 5b 22 61 52  (*dColorType["aR
0620: 47 42 22 5d 5b 73 4b 65 79 5d 29 0a 20 20 20 20  GB"][sKey]).    
0630: 72 65 74 75 72 6e 20 64 43 6f 6c 6f 72 54 79 70  return dColorTyp
0640: 65 0a 0a 0a 64 65 66 20 70 72 65 70 61 72 65 46  e...def prepareF
0650: 75 6e 63 74 69 6f 6e 20 28 73 29 3a 0a 20 20 20  unction (s):.   
0660: 20 22 63 6f 6e 76 65 72 74 20 73 69 6d 70 6c 65   "convert simple
0670: 20 72 75 6c 65 20 73 79 6e 74 61 78 20 74 6f 20   rule syntax to 
0680: 61 20 73 74 72 69 6e 67 20 6f 66 20 50 79 74 68  a string of Pyth
0690: 6f 6e 20 63 6f 64 65 22 0a 20 20 20 20 73 20 3d  on code".    s =
06a0: 20 73 2e 72 65 70 6c 61 63 65 28 22 5f 5f 61 6c   s.replace("__al
06b0: 73 6f 5f 5f 22 2c 20 22 62 43 6f 6e 64 4d 65 6d  so__", "bCondMem
06c0: 6f 22 29 0a 20 20 20 20 73 20 3d 20 73 2e 72 65  o").    s = s.re
06d0: 70 6c 61 63 65 28 22 5f 5f 65 6c 73 65 5f 5f 22  place("__else__"
06e0: 2c 20 22 6e 6f 74 20 62 43 6f 6e 64 4d 65 6d 6f  , "not bCondMemo
06f0: 22 29 0a 20 20 20 20 73 20 3d 20 73 2e 72 65 70  ").    s = s.rep
0700: 6c 61 63 65 28 22 73 43 6f 6e 74 65 78 74 22 2c  lace("sContext",
0710: 20 22 5f 73 41 70 70 43 6f 6e 74 65 78 74 22 29   "_sAppContext")
0720: 0a 20 20 20 20 73 20 3d 20 72 65 2e 73 75 62 28  .    s = re.sub(
0730: 72 22 69 73 53 74 61 72 74 20 2a 5c 28 5c 29 22  r"isStart *\(\)"
0740: 2c 20 27 62 65 66 6f 72 65 28 22 5e 20 2a 24 7c  , 'before("^ *$|
0750: 2c 20 2a 24 22 29 27 2c 20 73 29 0a 20 20 20 20  , *$")', s).    
0760: 73 20 3d 20 72 65 2e 73 75 62 28 72 22 69 73 52  s = re.sub(r"isR
0770: 65 61 6c 53 74 61 72 74 20 2a 5c 28 5c 29 22 2c  ealStart *\(\)",
0780: 20 27 62 65 66 6f 72 65 28 22 5e 20 2a 24 22 29   'before("^ *$")
0790: 27 2c 20 73 29 0a 20 20 20 20 73 20 3d 20 72 65  ', s).    s = re
07a0: 2e 73 75 62 28 72 22 69 73 53 74 61 72 74 30 20  .sub(r"isStart0 
07b0: 2a 5c 28 5c 29 22 2c 20 27 62 65 66 6f 72 65 30  *\(\)", 'before0
07c0: 28 22 5e 20 2a 24 7c 2c 20 2a 24 22 29 27 2c 20  ("^ *$|, *$")', 
07d0: 73 29 0a 20 20 20 20 73 20 3d 20 72 65 2e 73 75  s).    s = re.su
07e0: 62 28 72 22 69 73 52 65 61 6c 53 74 61 72 74 30  b(r"isRealStart0
07f0: 20 2a 5c 28 5c 29 22 2c 20 27 62 65 66 6f 72 65   *\(\)", 'before
0800: 30 28 22 5e 20 2a 24 22 29 27 2c 20 73 29 0a 20  0("^ *$")', s). 
0810: 20 20 20 73 20 3d 20 72 65 2e 73 75 62 28 72 22     s = re.sub(r"
0820: 69 73 45 6e 64 20 2a 5c 28 5c 29 22 2c 20 27 61  isEnd *\(\)", 'a
0830: 66 74 65 72 28 22 5e 20 2a 24 7c 5e 2c 22 29 27  fter("^ *$|^,")'
0840: 2c 20 73 29 0a 20 20 20 20 73 20 3d 20 72 65 2e  , s).    s = re.
0850: 73 75 62 28 72 22 69 73 52 65 61 6c 45 6e 64 20  sub(r"isRealEnd 
0860: 2a 5c 28 5c 29 22 2c 20 27 61 66 74 65 72 28 22  *\(\)", 'after("
0870: 5e 20 2a 24 22 29 27 2c 20 73 29 0a 20 20 20 20  ^ *$")', s).    
0880: 73 20 3d 20 72 65 2e 73 75 62 28 72 22 69 73 45  s = re.sub(r"isE
0890: 6e 64 30 20 2a 5c 28 5c 29 22 2c 20 27 61 66 74  nd0 *\(\)", 'aft
08a0: 65 72 30 28 22 5e 20 2a 24 7c 5e 2c 22 29 27 2c  er0("^ *$|^,")',
08b0: 20 73 29 0a 20 20 20 20 73 20 3d 20 72 65 2e 73   s).    s = re.s
08c0: 75 62 28 72 22 69 73 52 65 61 6c 45 6e 64 30 20  ub(r"isRealEnd0 
08d0: 2a 5c 28 5c 29 22 2c 20 27 61 66 74 65 72 30 28  *\(\)", 'after0(
08e0: 22 5e 20 2a 24 22 29 27 2c 20 73 29 0a 20 20 20  "^ *$")', s).   
08f0: 20 73 20 3d 20 72 65 2e 73 75 62 28 72 22 28 73   s = re.sub(r"(s
0900: 65 6c 65 63 74 7c 65 78 63 6c 75 64 65 29 5b 28  elect|exclude)[(
0910: 5d 5b 5c 5c 5d 28 5c 64 2b 29 22 2c 20 27 5c 5c  ][\\](\d+)", '\\
0920: 31 28 64 54 6f 6b 65 6e 50 6f 73 2c 20 6d 2e 73  1(dTokenPos, m.s
0930: 74 61 72 74 28 5c 5c 32 29 2c 20 6d 2e 67 72 6f  tart(\\2), m.gro
0940: 75 70 28 5c 5c 32 29 27 2c 20 73 29 0a 20 20 20  up(\\2)', s).   
0950: 20 73 20 3d 20 72 65 2e 73 75 62 28 72 22 64 65   s = re.sub(r"de
0960: 66 69 6e 65 5b 28 5d 5b 5c 5c 5d 28 5c 64 2b 29  fine[(][\\](\d+)
0970: 22 2c 20 27 64 65 66 69 6e 65 28 64 54 6f 6b 65  ", 'define(dToke
0980: 6e 50 6f 73 2c 20 6d 2e 73 74 61 72 74 28 5c 5c  nPos, m.start(\\
0990: 31 29 27 2c 20 73 29 0a 20 20 20 20 73 20 3d 20  1)', s).    s = 
09a0: 72 65 2e 73 75 62 28 72 22 28 6d 6f 72 70 68 7c  re.sub(r"(morph|
09b0: 64 69 73 70 6c 61 79 49 6e 66 6f 29 5b 28 5d 5b  displayInfo)[(][
09c0: 5c 5c 5d 28 5c 64 2b 29 22 2c 20 27 5c 5c 31 28  \\](\d+)", '\\1(
09d0: 28 6d 2e 73 74 61 72 74 28 5c 5c 32 29 2c 20 6d  (m.start(\\2), m
09e0: 2e 67 72 6f 75 70 28 5c 5c 32 29 29 27 2c 20 73  .group(\\2))', s
09f0: 29 0a 20 20 20 20 73 20 3d 20 72 65 2e 73 75 62  ).    s = re.sub
0a00: 28 72 22 28 6d 6f 72 70 68 7c 64 69 73 70 6c 61  (r"(morph|displa
0a10: 79 49 6e 66 6f 29 5b 28 5d 22 2c 20 27 5c 5c 31  yInfo)[(]", '\\1
0a20: 28 64 54 6f 6b 65 6e 50 6f 73 2c 20 27 2c 20 73  (dTokenPos, ', s
0a30: 29 0a 20 20 20 20 73 20 3d 20 72 65 2e 73 75 62  ).    s = re.sub
0a40: 28 72 22 28 73 75 67 67 5c 77 2b 7c 73 77 69 74  (r"(sugg\w+|swit
0a50: 63 68 5c 77 2b 29 5c 28 40 22 2c 20 27 5c 5c 31  ch\w+)\(@", '\\1
0a60: 28 6d 2e 67 72 6f 75 70 28 69 5b 34 5d 29 27 2c  (m.group(i[4])',
0a70: 20 73 29 0a 20 20 20 20 73 20 3d 20 72 65 2e 73   s).    s = re.s
0a80: 75 62 28 72 22 77 6f 72 64 5c 28 5c 73 2a 31 5c  ub(r"word\(\s*1\
0a90: 62 22 2c 20 27 6e 65 78 74 77 6f 72 64 31 28 73  b", 'nextword1(s
0aa0: 53 65 6e 74 65 6e 63 65 2c 20 6d 2e 65 6e 64 28  Sentence, m.end(
0ab0: 29 27 2c 20 73 29 20 20 20 20 20 20 20 20 20 20  )', s)          
0ac0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0ad0: 20 20 20 20 20 20 20 20 23 20 77 6f 72 64 28 31          # word(1
0ae0: 29 0a 20 20 20 20 73 20 3d 20 72 65 2e 73 75 62  ).    s = re.sub
0af0: 28 72 22 77 6f 72 64 5c 28 5c 73 2a 2d 31 5c 62  (r"word\(\s*-1\b
0b00: 22 2c 20 27 70 72 65 76 77 6f 72 64 31 28 73 53  ", 'prevword1(sS
0b10: 65 6e 74 65 6e 63 65 2c 20 6d 2e 73 74 61 72 74  entence, m.start
0b20: 28 29 27 2c 20 73 29 20 20 20 20 20 20 20 20 20  ()', s)         
0b30: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0b40: 20 20 20 20 20 20 23 20 77 6f 72 64 28 2d 31 29        # word(-1)
0b50: 0a 20 20 20 20 73 20 3d 20 72 65 2e 73 75 62 28  .    s = re.sub(
0b60: 72 22 77 6f 72 64 5c 28 5c 73 2a 28 5c 64 29 22  r"word\(\s*(\d)"
0b70: 2c 20 27 6e 65 78 74 77 6f 72 64 28 73 53 65 6e  , 'nextword(sSen
0b80: 74 65 6e 63 65 2c 20 6d 2e 65 6e 64 28 29 2c 20  tence, m.end(), 
0b90: 5c 5c 31 27 2c 20 73 29 20 20 20 20 20 20 20 20  \\1', s)        
0ba0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0bb0: 20 20 20 20 20 23 20 77 6f 72 64 28 6e 29 0a 20       # word(n). 
0bc0: 20 20 20 73 20 3d 20 72 65 2e 73 75 62 28 72 22     s = re.sub(r"
0bd0: 77 6f 72 64 5c 28 5c 73 2a 2d 28 5c 64 29 22 2c  word\(\s*-(\d)",
0be0: 20 27 70 72 65 76 77 6f 72 64 28 73 53 65 6e 74   'prevword(sSent
0bf0: 65 6e 63 65 2c 20 6d 2e 73 74 61 72 74 28 29 2c  ence, m.start(),
0c00: 20 5c 5c 31 27 2c 20 73 29 20 20 20 20 20 20 20   \\1', s)       
0c10: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0c20: 20 20 20 23 20 77 6f 72 64 28 2d 6e 29 0a 20 20     # word(-n).  
0c30: 20 20 73 20 3d 20 72 65 2e 73 75 62 28 72 22 62    s = re.sub(r"b
0c40: 65 66 6f 72 65 5c 28 5c 73 2a 22 2c 20 27 6c 6f  efore\(\s*", 'lo
0c50: 6f 6b 28 73 53 65 6e 74 65 6e 63 65 5b 3a 6d 2e  ok(sSentence[:m.
0c60: 73 74 61 72 74 28 29 5d 2c 20 27 2c 20 73 29 20  start()], ', s) 
0c70: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0c80: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0c90: 20 20 23 20 62 65 66 6f 72 65 28 73 53 65 6e 74    # before(sSent
0ca0: 65 6e 63 65 29 0a 20 20 20 20 73 20 3d 20 72 65  ence).    s = re
0cb0: 2e 73 75 62 28 72 22 61 66 74 65 72 5c 28 5c 73  .sub(r"after\(\s
0cc0: 2a 22 2c 20 27 6c 6f 6f 6b 28 73 53 65 6e 74 65  *", 'look(sSente
0cd0: 6e 63 65 5b 6d 2e 65 6e 64 28 29 3a 5d 2c 20 27  nce[m.end():], '
0ce0: 2c 20 73 29 20 20 20 20 20 20 20 20 20 20 20 20  , s)            
0cf0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0d00: 20 20 20 20 20 20 20 20 20 20 23 20 61 66 74 65            # afte
0d10: 72 28 73 53 65 6e 74 65 6e 63 65 29 0a 20 20 20  r(sSentence).   
0d20: 20 73 20 3d 20 72 65 2e 73 75 62 28 72 22 74 65   s = re.sub(r"te
0d30: 78 74 61 72 65 61 5c 28 5c 73 2a 22 2c 20 27 6c  xtarea\(\s*", 'l
0d40: 6f 6f 6b 28 73 53 65 6e 74 65 6e 63 65 2c 20 27  ook(sSentence, '
0d50: 2c 20 73 29 20 20 20 20 20 20 20 20 20 20 20 20  , s)            
0d60: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0d70: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0d80: 20 23 20 74 65 78 74 61 72 65 61 28 73 53 65 6e   # textarea(sSen
0d90: 74 65 6e 63 65 29 0a 20 20 20 20 73 20 3d 20 72  tence).    s = r
0da0: 65 2e 73 75 62 28 72 22 2f 30 22 2c 20 27 73 53  e.sub(r"/0", 'sS
0db0: 65 6e 74 65 6e 63 65 30 5b 6d 2e 73 74 61 72 74  entence0[m.start
0dc0: 28 29 3a 6d 2e 65 6e 64 28 29 5d 27 2c 20 73 29  ():m.end()]', s)
0dd0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0de0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0df0: 20 20 20 20 20 20 20 20 20 20 20 23 20 2f 30 0a             # /0.
0e00: 20 20 20 20 73 20 3d 20 72 65 2e 73 75 62 28 72      s = re.sub(r
0e10: 22 62 65 66 6f 72 65 30 5c 28 5c 73 2a 22 2c 20  "before0\(\s*", 
0e20: 27 6c 6f 6f 6b 28 73 53 65 6e 74 65 6e 63 65 30  'look(sSentence0
0e30: 5b 3a 6d 2e 73 74 61 72 74 28 29 5d 2c 20 27 2c  [:m.start()], ',
0e40: 20 73 29 20 20 20 20 20 20 20 20 20 20 20 20 20   s)             
0e50: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0e60: 20 20 20 20 23 20 62 65 66 6f 72 65 30 28 73 53      # before0(sS
0e70: 65 6e 74 65 6e 63 65 29 0a 20 20 20 20 73 20 3d  entence).    s =
0e80: 20 72 65 2e 73 75 62 28 72 22 61 66 74 65 72 30   re.sub(r"after0
0e90: 5c 28 5c 73 2a 22 2c 20 27 6c 6f 6f 6b 28 73 53  \(\s*", 'look(sS
0ea0: 65 6e 74 65 6e 63 65 30 5b 6d 2e 65 6e 64 28 29  entence0[m.end()
0eb0: 3a 5d 2c 20 27 2c 20 73 29 20 20 20 20 20 20 20  :], ', s)       
0ec0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0ed0: 20 20 20 20 20 20 20 20 20 20 20 20 20 23 20 61               # a
0ee0: 66 74 65 72 30 28 73 53 65 6e 74 65 6e 63 65 29  fter0(sSentence)
0ef0: 0a 20 20 20 20 73 20 3d 20 72 65 2e 73 75 62 28  .    s = re.sub(
0f00: 72 22 74 65 78 74 61 72 65 61 30 5c 28 5c 73 2a  r"textarea0\(\s*
0f10: 22 2c 20 27 6c 6f 6f 6b 28 73 53 65 6e 74 65 6e  ", 'look(sSenten
0f20: 63 65 30 2c 20 27 2c 20 73 29 20 20 20 20 20 20  ce0, ', s)      
0f30: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0f40: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0f50: 20 20 20 20 20 23 20 74 65 78 74 61 72 65 61 30       # textarea0
0f60: 28 73 53 65 6e 74 65 6e 63 65 29 0a 20 20 20 20  (sSentence).    
0f70: 73 20 3d 20 72 65 2e 73 75 62 28 72 22 5c 62 73  s = re.sub(r"\bs
0f80: 70 65 6c 6c 20 2a 5b 28 5d 22 2c 20 27 5f 6f 53  pell *[(]", '_oS
0f90: 70 65 6c 6c 43 68 65 63 6b 65 72 2e 69 73 56 61  pellChecker.isVa
0fa0: 6c 69 64 28 27 2c 20 73 29 0a 20 20 20 20 73 20  lid(', s).    s 
0fb0: 3d 20 72 65 2e 73 75 62 28 72 22 5b 5c 5c 5d 28  = re.sub(r"[\\](
0fc0: 5c 64 2b 29 22 2c 20 27 6d 2e 67 72 6f 75 70 28  \d+)", 'm.group(
0fd0: 5c 5c 31 29 27 2c 20 73 29 0a 20 20 20 20 72 65  \\1)', s).    re
0fe0: 74 75 72 6e 20 73 0a 0a 0a 64 65 66 20 75 70 70  turn s...def upp
0ff0: 65 72 63 61 73 65 20 28 73 54 65 78 74 2c 20 73  ercase (sText, s
1000: 4c 61 6e 67 29 3a 0a 20 20 20 20 22 28 66 6c 61  Lang):.    "(fla
1010: 67 20 69 20 69 73 20 6e 6f 74 20 65 6e 6f 75 67  g i is not enoug
1020: 68 29 3a 20 63 6f 6e 76 65 72 74 73 20 72 65 67  h): converts reg
1030: 65 78 20 74 6f 20 75 70 70 65 72 63 61 73 65 20  ex to uppercase 
1040: 72 65 67 65 78 3a 20 27 66 6f 6f 27 20 62 65 63  regex: 'foo' bec
1050: 6f 6d 65 73 20 27 5b 46 66 5d 5b 4f 6f 5d 5b 4f  omes '[Ff][Oo][O
1060: 6f 5d 27 2c 20 62 75 74 20 27 42 61 72 27 20 62  o]', but 'Bar' b
1070: 65 63 6f 6d 65 73 20 27 42 5b 41 61 5d 5b 52 72  ecomes 'B[Aa][Rr
1080: 5d 27 2e 22 0a 20 20 20 20 73 55 70 20 3d 20 22  ]'.".    sUp = "
1090: 22 0a 20 20 20 20 6e 53 74 61 74 65 20 3d 20 30  ".    nState = 0
10a0: 0a 20 20 20 20 66 6f 72 20 69 2c 20 63 20 69 6e  .    for i, c in
10b0: 20 65 6e 75 6d 65 72 61 74 65 28 73 54 65 78 74   enumerate(sText
10c0: 29 3a 0a 20 20 20 20 20 20 20 20 69 66 20 63 20  ):.        if c 
10d0: 3d 3d 20 22 5b 22 3a 0a 20 20 20 20 20 20 20 20  == "[":.        
10e0: 20 20 20 20 6e 53 74 61 74 65 20 3d 20 31 0a 20      nState = 1. 
10f0: 20 20 20 20 20 20 20 69 66 20 6e 53 74 61 74 65         if nState
1100: 20 3d 3d 20 31 20 61 6e 64 20 63 20 3d 3d 20 22   == 1 and c == "
1110: 5d 22 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  ]":.            
1120: 6e 53 74 61 74 65 20 3d 20 30 0a 20 20 20 20 20  nState = 0.     
1130: 20 20 20 69 66 20 63 20 3d 3d 20 22 3c 22 20 61     if c == "<" a
1140: 6e 64 20 69 20 3e 20 33 20 61 6e 64 20 73 54 65  nd i > 3 and sTe
1150: 78 74 5b 69 2d 33 3a 69 5d 20 3d 3d 20 22 28 3f  xt[i-3:i] == "(?
1160: 50 22 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  P":.            
1170: 6e 53 74 61 74 65 20 3d 20 32 0a 20 20 20 20 20  nState = 2.     
1180: 20 20 20 69 66 20 6e 53 74 61 74 65 20 3d 3d 20     if nState == 
1190: 32 20 61 6e 64 20 63 20 3d 3d 20 22 3e 22 3a 0a  2 and c == ">":.
11a0: 20 20 20 20 20 20 20 20 20 20 20 20 6e 53 74 61              nSta
11b0: 74 65 20 3d 20 30 0a 20 20 20 20 20 20 20 20 69  te = 0.        i
11c0: 66 20 63 20 3d 3d 20 22 3f 22 20 61 6e 64 20 69  f c == "?" and i
11d0: 20 3e 20 30 20 61 6e 64 20 73 54 65 78 74 5b 69   > 0 and sText[i
11e0: 2d 31 3a 69 5d 20 3d 3d 20 22 28 22 20 61 6e 64  -1:i] == "(" and
11f0: 20 73 54 65 78 74 5b 69 2b 31 3a 69 2b 32 5d 20   sText[i+1:i+2] 
1200: 21 3d 20 22 3a 22 3a 0a 20 20 20 20 20 20 20 20  != ":":.        
1210: 20 20 20 20 6e 53 74 61 74 65 20 3d 20 35 0a 20      nState = 5. 
1220: 20 20 20 20 20 20 20 69 66 20 6e 53 74 61 74 65         if nState
1230: 20 3d 3d 20 35 20 61 6e 64 20 63 20 3d 3d 20 22   == 5 and c == "
1240: 29 22 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  )":.            
1250: 6e 53 74 61 74 65 20 3d 20 30 0a 20 20 20 20 20  nState = 0.     
1260: 20 20 20 69 66 20 63 2e 69 73 61 6c 70 68 61 28     if c.isalpha(
1270: 29 20 61 6e 64 20 63 2e 69 73 6c 6f 77 65 72 28  ) and c.islower(
1280: 29 20 61 6e 64 20 6e 53 74 61 74 65 20 3d 3d 20  ) and nState == 
1290: 30 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 69  0:.            i
12a0: 66 20 63 20 3d 3d 20 22 69 22 20 61 6e 64 20 73  f c == "i" and s
12b0: 4c 61 6e 67 20 69 6e 20 28 22 74 72 22 2c 20 22  Lang in ("tr", "
12c0: 61 7a 22 29 3a 0a 20 20 20 20 20 20 20 20 20 20  az"):.          
12d0: 20 20 20 20 20 20 73 55 70 20 2b 3d 20 22 5b c4        sUp += "[.
12e0: b0 22 20 2b 20 63 20 2b 20 22 5d 22 0a 20 20 20  ." + c + "]".   
12f0: 20 20 20 20 20 20 20 20 20 65 6c 73 65 3a 0a 20           else:. 
1300: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 73                 s
1310: 55 70 20 2b 3d 20 22 5b 22 20 2b 20 63 2e 75 70  Up += "[" + c.up
1320: 70 65 72 28 29 20 2b 20 63 20 2b 20 22 5d 22 0a  per() + c + "]".
1330: 20 20 20 20 20 20 20 20 65 6c 69 66 20 63 2e 69          elif c.i
1340: 73 61 6c 70 68 61 28 29 20 61 6e 64 20 63 2e 69  salpha() and c.i
1350: 73 6c 6f 77 65 72 28 29 20 61 6e 64 20 6e 53 74  slower() and nSt
1360: 61 74 65 20 3d 3d 20 31 20 61 6e 64 20 73 54 65  ate == 1 and sTe
1370: 78 74 5b 69 2b 31 3a 69 2b 32 5d 20 21 3d 20 22  xt[i+1:i+2] != "
1380: 2d 22 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  -":.            
1390: 69 66 20 73 54 65 78 74 5b 69 2d 31 3a 69 5d 20  if sText[i-1:i] 
13a0: 3d 3d 20 22 2d 22 20 61 6e 64 20 73 54 65 78 74  == "-" and sText
13b0: 5b 69 2d 32 3a 69 2d 31 5d 2e 69 73 6c 6f 77 65  [i-2:i-1].islowe
13c0: 72 28 29 3a 20 20 23 20 5b 61 2d 7a 5d 20 2d 3e  r():  # [a-z] ->
13d0: 20 5b 61 2d 7a 41 2d 5a 5d 0a 20 20 20 20 20 20   [a-zA-Z].      
13e0: 20 20 20 20 20 20 20 20 20 20 73 55 70 20 2b 3d            sUp +=
13f0: 20 63 20 2b 20 73 54 65 78 74 5b 69 2d 32 3a 69   c + sText[i-2:i
1400: 2d 31 5d 2e 75 70 70 65 72 28 29 20 2b 20 22 2d  -1].upper() + "-
1410: 22 20 2b 20 63 2e 75 70 70 65 72 28 29 0a 20 20  " + c.upper().  
1420: 20 20 20 20 20 20 20 20 20 20 65 6c 69 66 20 63            elif c
1430: 20 3d 3d 20 22 69 22 20 61 6e 64 20 73 4c 61 6e   == "i" and sLan
1440: 67 20 69 6e 20 28 22 74 72 22 2c 20 22 61 7a 22  g in ("tr", "az"
1450: 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 20  ):.             
1460: 20 20 20 73 55 70 20 2b 3d 20 22 c4 b0 22 20 2b     sUp += ".." +
1470: 20 63 0a 20 20 20 20 20 20 20 20 20 20 20 20 65   c.            e
1480: 6c 73 65 3a 0a 20 20 20 20 20 20 20 20 20 20 20  lse:.           
1490: 20 20 20 20 20 73 55 70 20 2b 3d 20 63 2e 75 70       sUp += c.up
14a0: 70 65 72 28 29 20 2b 20 63 0a 20 20 20 20 20 20  per() + c.      
14b0: 20 20 65 6c 73 65 3a 0a 20 20 20 20 20 20 20 20    else:.        
14c0: 20 20 20 20 73 55 70 20 2b 3d 20 63 0a 20 20 20      sUp += c.   
14d0: 20 20 20 20 20 69 66 20 63 20 3d 3d 20 22 5c 5c       if c == "\\
14e0: 22 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 6e  ":.            n
14f0: 53 74 61 74 65 20 3d 20 34 0a 20 20 20 20 20 20  State = 4.      
1500: 20 20 65 6c 69 66 20 6e 53 74 61 74 65 20 3d 3d    elif nState ==
1510: 20 34 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20   4:.            
1520: 6e 53 74 61 74 65 20 3d 20 30 0a 20 20 20 20 72  nState = 0.    r
1530: 65 74 75 72 6e 20 73 55 70 0a 0a 0a 64 65 66 20  eturn sUp...def 
1540: 63 6f 75 6e 74 47 72 6f 75 70 49 6e 52 65 67 65  countGroupInRege
1550: 78 20 28 73 52 65 67 65 78 29 3a 0a 20 20 20 20  x (sRegex):.    
1560: 22 72 65 74 75 72 6e 73 20 74 68 65 20 6e 75 6d  "returns the num
1570: 62 65 72 20 6f 66 20 67 72 6f 75 70 73 20 69 6e  ber of groups in
1580: 20 3c 73 52 65 67 65 78 3e 22 0a 20 20 20 20 74   <sRegex>".    t
1590: 72 79 3a 0a 20 20 20 20 20 20 20 20 72 65 74 75  ry:.        retu
15a0: 72 6e 20 72 65 2e 63 6f 6d 70 69 6c 65 28 73 52  rn re.compile(sR
15b0: 65 67 65 78 29 2e 67 72 6f 75 70 73 0a 20 20 20  egex).groups.   
15c0: 20 65 78 63 65 70 74 20 72 65 2e 65 72 72 6f 72   except re.error
15d0: 3a 0a 20 20 20 20 20 20 20 20 74 72 61 63 65 62  :.        traceb
15e0: 61 63 6b 2e 70 72 69 6e 74 5f 65 78 63 28 29 0a  ack.print_exc().
15f0: 20 20 20 20 20 20 20 20 70 72 69 6e 74 28 73 52          print(sR
1600: 65 67 65 78 29 0a 20 20 20 20 72 65 74 75 72 6e  egex).    return
1610: 20 30 0a 0a 0a 64 65 66 20 63 72 65 61 74 65 52   0...def createR
1620: 75 6c 65 20 28 73 2c 20 6e 4c 69 6e 65 49 64 2c  ule (s, nLineId,
1630: 20 73 4c 61 6e 67 2c 20 62 50 61 72 61 67 72 61   sLang, bParagra
1640: 70 68 2c 20 64 4f 70 74 50 72 69 6f 72 69 74 79  ph, dOptPriority
1650: 29 3a 0a 20 20 20 20 22 72 65 74 75 72 6e 73 20  ):.    "returns 
1660: 72 75 6c 65 20 61 73 20 6c 69 73 74 20 5b 6f 70  rule as list [op
1670: 74 69 6f 6e 20 6e 61 6d 65 2c 20 72 65 67 65 78  tion name, regex
1680: 2c 20 62 43 61 73 65 49 6e 73 65 6e 73 69 74 69  , bCaseInsensiti
1690: 76 65 2c 20 69 64 65 6e 74 69 66 69 65 72 2c 20  ve, identifier, 
16a0: 6c 69 73 74 20 6f 66 20 61 63 74 69 6f 6e 73 5d  list of actions]
16b0: 22 0a 20 20 20 20 67 6c 6f 62 61 6c 20 64 4a 53  ".    global dJS
16c0: 52 45 47 45 58 45 53 0a 0a 20 20 20 20 73 4c 69  REGEXES..    sLi
16d0: 6e 65 49 64 20 3d 20 66 22 23 7b 6e 4c 69 6e 65  neId = f"#{nLine
16e0: 49 64 7d 22 20 2b 20 28 22 70 22 20 69 66 20 62  Id}" + ("p" if b
16f0: 50 61 72 61 67 72 61 70 68 20 65 6c 73 65 20 22  Paragraph else "
1700: 73 22 29 0a 20 20 20 20 73 52 75 6c 65 49 64 20  s").    sRuleId 
1710: 3d 20 73 4c 69 6e 65 49 64 0a 0a 20 20 20 20 23  = sLineId..    #
1720: 23 23 23 20 47 52 41 50 48 20 43 41 4c 4c 0a 20  ### GRAPH CALL. 
1730: 20 20 20 69 66 20 73 2e 73 74 61 72 74 73 77 69     if s.startswi
1740: 74 68 28 22 40 40 40 40 22 29 3a 0a 20 20 20 20  th("@@@@"):.    
1750: 20 20 20 20 69 66 20 62 50 61 72 61 67 72 61 70      if bParagrap
1760: 68 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 70  h:.            p
1770: 72 69 6e 74 28 22 45 72 72 6f 72 2e 20 47 72 61  rint("Error. Gra
1780: 70 68 20 63 61 6c 6c 20 63 61 6e 20 62 65 20 6d  ph call can be m
1790: 61 64 65 20 6f 6e 6c 79 20 61 66 74 65 72 20 74  ade only after t
17a0: 68 65 20 66 69 72 73 74 20 70 61 73 73 20 28 73  he first pass (s
17b0: 65 6e 74 65 6e 63 65 20 62 79 20 73 65 6e 74 65  entence by sente
17c0: 6e 63 65 29 22 29 0a 20 20 20 20 20 20 20 20 20  nce)").         
17d0: 20 20 20 65 78 69 74 28 29 0a 20 20 20 20 20 20     exit().      
17e0: 20 20 72 65 74 75 72 6e 20 5b 22 40 40 40 40 22    return ["@@@@"
17f0: 2c 20 73 5b 34 3a 5d 2c 20 73 4c 69 6e 65 49 64  , s[4:], sLineId
1800: 5d 0a 0a 20 20 20 20 23 23 23 23 20 4f 50 54 49  ]..    #### OPTI
1810: 4f 4e 53 0a 20 20 20 20 73 4f 70 74 69 6f 6e 20  ONS.    sOption 
1820: 3d 20 22 22 20 20 20 20 20 20 20 20 20 20 20 20  = ""            
1830: 23 20 65 6d 70 74 79 20 73 74 72 69 6e 67 20 6f  # empty string o
1840: 72 20 5b 61 2d 7a 30 2d 39 5d 2b 20 6e 61 6d 65  r [a-z0-9]+ name
1850: 0a 20 20 20 20 6e 50 72 69 6f 72 69 74 79 20 3d  .    nPriority =
1860: 20 34 20 20 20 20 20 20 20 20 20 20 20 23 20 44   4           # D
1870: 65 66 61 75 6c 74 20 69 73 20 34 2c 20 76 61 6c  efault is 4, val
1880: 75 65 20 6d 75 73 74 20 62 65 20 62 65 74 77 65  ue must be betwe
1890: 65 6e 20 30 20 61 6e 64 20 39 0a 20 20 20 20 74  en 0 and 9.    t
18a0: 47 72 6f 75 70 73 20 3d 20 4e 6f 6e 65 20 20 20  Groups = None   
18b0: 20 20 20 20 20 20 20 23 20 63 6f 64 65 20 66 6f         # code fo
18c0: 72 20 67 72 6f 75 70 73 20 70 6f 73 69 74 69 6f  r groups positio
18d0: 6e 69 6e 67 20 28 6f 6e 6c 79 20 75 73 65 66 75  ning (only usefu
18e0: 6c 20 66 6f 72 20 4a 61 76 61 53 63 72 69 70 74  l for JavaScript
18f0: 29 0a 20 20 20 20 63 43 61 73 65 4d 6f 64 65 20  ).    cCaseMode 
1900: 3d 20 27 69 27 20 20 20 20 20 20 20 20 20 23 20  = 'i'         # 
1910: 69 3a 20 63 61 73 65 20 69 6e 73 65 6e 73 69 74  i: case insensit
1920: 69 76 65 2c 20 20 73 3a 20 63 61 73 65 20 73 65  ive,  s: case se
1930: 6e 73 69 74 69 76 65 2c 20 20 75 3a 20 75 70 70  nsitive,  u: upp
1940: 65 72 63 61 73 69 6e 67 20 61 6c 6c 6f 77 65 64  ercasing allowed
1950: 0a 20 20 20 20 63 57 6f 72 64 4c 69 6d 69 74 4c  .    cWordLimitL
1960: 65 66 74 20 3d 20 27 5b 27 20 20 20 20 23 20 5b  eft = '['    # [
1970: 3a 20 77 6f 72 64 20 6c 69 6d 69 74 2c 20 3c 3a  : word limit, <:
1980: 20 6e 6f 20 73 70 65 63 69 66 69 63 20 6c 69 6d   no specific lim
1990: 69 74 0a 20 20 20 20 63 57 6f 72 64 4c 69 6d 69  it.    cWordLimi
19a0: 74 52 69 67 68 74 20 3d 20 27 5d 27 20 20 20 23  tRight = ']'   #
19b0: 20 5d 3a 20 77 6f 72 64 20 6c 69 6d 69 74 2c 20   ]: word limit, 
19c0: 3e 3a 20 6e 6f 20 73 70 65 63 69 66 69 63 20 6c  >: no specific l
19d0: 69 6d 69 74 0a 20 20 20 20 6d 20 3d 20 72 65 2e  imit.    m = re.
19e0: 6d 61 74 63 68 28 22 5e 5f 5f 28 3f 50 3c 62 6f  match("^__(?P<bo
19f0: 72 64 65 72 73 5f 61 6e 64 5f 63 61 73 65 3e 5b  rders_and_case>[
1a00: 5c 5c 5b 3c 5d 5c 5c 77 5b 5c 5c 5d 3e 5d 29 28  \\[<]\\w[\\]>])(
1a10: 3f 50 3c 6f 70 74 69 6f 6e 3e 2f 5b 61 2d 7a 41  ?P<option>/[a-zA
1a20: 2d 5a 30 2d 39 5d 2b 7c 29 28 3f 50 3c 72 75 6c  -Z0-9]+|)(?P<rul
1a30: 65 69 64 3e 5c 5c 28 5c 5c 77 2b 5c 5c 29 29 28  eid>\\(\\w+\\))(
1a40: 3f 50 3c 70 72 69 6f 72 69 74 79 3e 21 5b 30 2d  ?P<priority>![0-
1a50: 39 5d 7c 29 5f 5f 20 2a 22 2c 20 73 29 0a 20 20  9]|)__ *", s).  
1a60: 20 20 69 66 20 6d 3a 0a 20 20 20 20 20 20 20 20    if m:.        
1a70: 63 57 6f 72 64 4c 69 6d 69 74 4c 65 66 74 20 3d  cWordLimitLeft =
1a80: 20 6d 2e 67 72 6f 75 70 28 27 62 6f 72 64 65 72   m.group('border
1a90: 73 5f 61 6e 64 5f 63 61 73 65 27 29 5b 30 5d 0a  s_and_case')[0].
1aa0: 20 20 20 20 20 20 20 20 63 43 61 73 65 4d 6f 64          cCaseMod
1ab0: 65 20 3d 20 6d 2e 67 72 6f 75 70 28 27 62 6f 72  e = m.group('bor
1ac0: 64 65 72 73 5f 61 6e 64 5f 63 61 73 65 27 29 5b  ders_and_case')[
1ad0: 31 5d 0a 20 20 20 20 20 20 20 20 63 57 6f 72 64  1].        cWord
1ae0: 4c 69 6d 69 74 52 69 67 68 74 20 3d 20 6d 2e 67  LimitRight = m.g
1af0: 72 6f 75 70 28 27 62 6f 72 64 65 72 73 5f 61 6e  roup('borders_an
1b00: 64 5f 63 61 73 65 27 29 5b 32 5d 0a 20 20 20 20  d_case')[2].    
1b10: 20 20 20 20 73 4f 70 74 69 6f 6e 20 3d 20 6d 2e      sOption = m.
1b20: 67 72 6f 75 70 28 27 6f 70 74 69 6f 6e 27 29 5b  group('option')[
1b30: 31 3a 5d 20 20 69 66 20 6d 2e 67 72 6f 75 70 28  1:]  if m.group(
1b40: 27 6f 70 74 69 6f 6e 27 29 20 20 65 6c 73 65 20  'option')  else 
1b50: 22 22 0a 20 20 20 20 20 20 20 20 73 52 75 6c 65  "".        sRule
1b60: 49 64 20 3d 20 20 6d 2e 67 72 6f 75 70 28 27 72  Id =  m.group('r
1b70: 75 6c 65 69 64 27 29 5b 31 3a 2d 31 5d 0a 20 20  uleid')[1:-1].  
1b80: 20 20 20 20 20 20 69 66 20 73 52 75 6c 65 49 64        if sRuleId
1b90: 20 69 6e 20 61 52 55 4c 45 53 45 54 3a 0a 20 20   in aRULESET:.  
1ba0: 20 20 20 20 20 20 20 20 20 20 70 72 69 6e 74 28            print(
1bb0: 66 22 23 20 45 72 72 6f 72 2e 20 53 65 76 65 72  f"# Error. Sever
1bc0: 61 6c 20 72 75 6c 65 73 20 68 61 76 65 20 74 68  al rules have th
1bd0: 65 20 73 61 6d 65 20 69 64 3a 20 7b 73 52 75 6c  e same id: {sRul
1be0: 65 49 64 7d 22 29 0a 20 20 20 20 20 20 20 20 20  eId}").         
1bf0: 20 20 20 65 78 69 74 28 29 0a 20 20 20 20 20 20     exit().      
1c00: 20 20 61 52 55 4c 45 53 45 54 2e 61 64 64 28 73    aRULESET.add(s
1c10: 52 75 6c 65 49 64 29 0a 20 20 20 20 20 20 20 20  RuleId).        
1c20: 6e 50 72 69 6f 72 69 74 79 20 3d 20 64 4f 70 74  nPriority = dOpt
1c30: 50 72 69 6f 72 69 74 79 2e 67 65 74 28 73 4f 70  Priority.get(sOp
1c40: 74 69 6f 6e 2c 20 34 29 0a 20 20 20 20 20 20 20  tion, 4).       
1c50: 20 69 66 20 6d 2e 67 72 6f 75 70 28 27 70 72 69   if m.group('pri
1c60: 6f 72 69 74 79 27 29 3a 0a 20 20 20 20 20 20 20  ority'):.       
1c70: 20 20 20 20 20 6e 50 72 69 6f 72 69 74 79 20 3d       nPriority =
1c80: 20 69 6e 74 28 6d 2e 67 72 6f 75 70 28 27 70 72   int(m.group('pr
1c90: 69 6f 72 69 74 79 27 29 5b 31 3a 5d 29 0a 20 20  iority')[1:]).  
1ca0: 20 20 20 20 20 20 73 20 3d 20 73 5b 6d 2e 65 6e        s = s[m.en
1cb0: 64 28 30 29 3a 5d 0a 20 20 20 20 65 6c 73 65 3a  d(0):].    else:
1cc0: 0a 20 20 20 20 20 20 20 20 70 72 69 6e 74 28 66  .        print(f
1cd0: 22 23 20 57 61 72 6e 69 6e 67 2e 20 52 75 6c 65  "# Warning. Rule
1ce0: 20 77 72 6f 6e 67 6c 79 20 73 68 61 70 65 64 20   wrongly shaped 
1cf0: 61 74 20 6c 69 6e 65 3a 20 7b 73 4c 69 6e 65 49  at line: {sLineI
1d00: 64 7d 22 29 0a 20 20 20 20 20 20 20 20 65 78 69  d}").        exi
1d10: 74 28 29 0a 0a 20 20 20 20 23 23 23 23 20 52 45  t()..    #### RE
1d20: 47 45 58 20 54 52 49 47 47 45 52 0a 20 20 20 20  GEX TRIGGER.    
1d30: 69 20 3d 20 73 2e 66 69 6e 64 28 22 20 3c 3c 2d  i = s.find(" <<-
1d40: 22 29 0a 20 20 20 20 69 66 20 69 20 3d 3d 20 2d  ").    if i == -
1d50: 31 3a 0a 20 20 20 20 20 20 20 20 70 72 69 6e 74  1:.        print
1d60: 28 66 22 23 20 45 72 72 6f 72 3a 20 6e 6f 20 63  (f"# Error: no c
1d70: 6f 6e 64 69 74 69 6f 6e 20 61 74 20 6c 69 6e 65  ondition at line
1d80: 20 7b 73 4c 69 6e 65 49 64 7d 22 29 0a 20 20 20   {sLineId}").   
1d90: 20 20 20 20 20 72 65 74 75 72 6e 20 4e 6f 6e 65       return None
1da0: 0a 20 20 20 20 73 52 65 67 65 78 20 3d 20 73 5b  .    sRegex = s[
1db0: 3a 69 5d 2e 73 74 72 69 70 28 29 0a 20 20 20 20  :i].strip().    
1dc0: 73 20 3d 20 73 5b 69 2b 34 3a 5d 0a 0a 20 20 20  s = s[i+4:]..   
1dd0: 20 23 20 4a 53 20 67 72 6f 75 70 73 20 70 6f 73   # JS groups pos
1de0: 69 74 69 6f 6e 69 6e 67 20 63 6f 64 65 73 0a 20  itioning codes. 
1df0: 20 20 20 6d 20 3d 20 72 65 2e 73 65 61 72 63 68     m = re.search
1e00: 28 22 40 40 5c 5c 53 2b 22 2c 20 73 52 65 67 65  ("@@\\S+", sRege
1e10: 78 29 0a 20 20 20 20 69 66 20 6d 3a 0a 20 20 20  x).    if m:.   
1e20: 20 20 20 20 20 74 47 72 6f 75 70 73 20 3d 20 6a       tGroups = j
1e30: 73 63 6f 6e 76 2e 67 72 6f 75 70 73 50 6f 73 69  sconv.groupsPosi
1e40: 74 69 6f 6e 69 6e 67 43 6f 64 65 54 6f 4c 69 73  tioningCodeToLis
1e50: 74 28 73 52 65 67 65 78 5b 6d 2e 73 74 61 72 74  t(sRegex[m.start
1e60: 28 29 2b 32 3a 5d 29 0a 20 20 20 20 20 20 20 20  ()+2:]).        
1e70: 73 52 65 67 65 78 20 3d 20 73 52 65 67 65 78 5b  sRegex = sRegex[
1e80: 3a 6d 2e 73 74 61 72 74 28 29 5d 2e 73 74 72 69  :m.start()].stri
1e90: 70 28 29 0a 20 20 20 20 23 20 4a 53 20 72 65 67  p().    # JS reg
1ea0: 65 78 0a 20 20 20 20 6d 20 3d 20 72 65 2e 73 65  ex.    m = re.se
1eb0: 61 72 63 68 28 22 3c 6a 73 3e 2e 2b 3c 2f 6a 73  arch("<js>.+</js
1ec0: 3e 69 3f 22 2c 20 73 52 65 67 65 78 29 0a 20 20  >i?", sRegex).  
1ed0: 20 20 69 66 20 6d 3a 0a 20 20 20 20 20 20 20 20    if m:.        
1ee0: 64 4a 53 52 45 47 45 58 45 53 5b 73 4c 69 6e 65  dJSREGEXES[sLine
1ef0: 49 64 5d 20 3d 20 6d 2e 67 72 6f 75 70 28 30 29  Id] = m.group(0)
1f00: 0a 20 20 20 20 20 20 20 20 73 52 65 67 65 78 20  .        sRegex 
1f10: 3d 20 73 52 65 67 65 78 5b 3a 6d 2e 73 74 61 72  = sRegex[:m.star
1f20: 74 28 29 5d 2e 73 74 72 69 70 28 29 0a 20 20 20  t()].strip().   
1f30: 20 69 66 20 22 3c 6a 73 3e 22 20 69 6e 20 73 52   if "<js>" in sR
1f40: 65 67 65 78 20 6f 72 20 22 3c 2f 6a 73 3e 22 20  egex or "</js>" 
1f50: 69 6e 20 73 52 65 67 65 78 3a 0a 20 20 20 20 20  in sRegex:.     
1f60: 20 20 20 70 72 69 6e 74 28 66 22 23 20 45 72 72     print(f"# Err
1f70: 6f 72 3a 20 4a 61 76 61 53 63 72 69 70 74 20 72  or: JavaScript r
1f80: 65 67 65 78 20 6e 6f 74 20 64 65 6c 69 6d 69 74  egex not delimit
1f90: 65 64 20 61 74 20 6c 69 6e 65 20 7b 73 4c 69 6e  ed at line {sLin
1fa0: 65 49 64 7d 22 29 0a 20 20 20 20 20 20 20 20 72  eId}").        r
1fb0: 65 74 75 72 6e 20 4e 6f 6e 65 0a 0a 20 20 20 20  eturn None..    
1fc0: 23 20 71 75 6f 74 65 73 20 3f 0a 20 20 20 20 69  # quotes ?.    i
1fd0: 66 20 73 52 65 67 65 78 2e 73 74 61 72 74 73 77  f sRegex.startsw
1fe0: 69 74 68 28 27 22 27 29 20 61 6e 64 20 73 52 65  ith('"') and sRe
1ff0: 67 65 78 2e 65 6e 64 73 77 69 74 68 28 27 22 27  gex.endswith('"'
2000: 29 3a 0a 20 20 20 20 20 20 20 20 73 52 65 67 65  ):.        sRege
2010: 78 20 3d 20 73 52 65 67 65 78 5b 31 3a 2d 31 5d  x = sRegex[1:-1]
2020: 0a 0a 20 20 20 20 23 23 20 64 65 66 69 6e 69 74  ..    ## definit
2030: 69 6f 6e 73 0a 20 20 20 20 66 6f 72 20 73 44 65  ions.    for sDe
2040: 66 2c 20 73 52 65 70 6c 20 69 6e 20 64 44 45 46  f, sRepl in dDEF
2050: 49 4e 49 54 49 4f 4e 53 2e 69 74 65 6d 73 28 29  INITIONS.items()
2060: 3a 0a 20 20 20 20 20 20 20 20 73 52 65 67 65 78  :.        sRegex
2070: 20 3d 20 73 52 65 67 65 78 2e 72 65 70 6c 61 63   = sRegex.replac
2080: 65 28 73 44 65 66 2c 20 73 52 65 70 6c 29 0a 0a  e(sDef, sRepl)..
2090: 20 20 20 20 23 23 20 63 6f 75 6e 74 20 6e 75 6d      ## count num
20a0: 62 65 72 20 6f 66 20 67 72 6f 75 70 73 20 28 6d  ber of groups (m
20b0: 75 73 74 20 62 65 20 64 6f 6e 65 20 62 65 66 6f  ust be done befo
20c0: 72 65 20 6d 6f 64 69 66 79 69 6e 67 20 74 68 65  re modifying the
20d0: 20 72 65 67 65 78 29 0a 20 20 20 20 6e 47 72 6f   regex).    nGro
20e0: 75 70 20 3d 20 63 6f 75 6e 74 47 72 6f 75 70 49  up = countGroupI
20f0: 6e 52 65 67 65 78 28 73 52 65 67 65 78 29 0a 20  nRegex(sRegex). 
2100: 20 20 20 69 66 20 6e 47 72 6f 75 70 20 3e 20 30     if nGroup > 0
2110: 3a 0a 20 20 20 20 20 20 20 20 69 66 20 6e 6f 74  :.        if not
2120: 20 74 47 72 6f 75 70 73 3a 0a 20 20 20 20 20 20   tGroups:.      
2130: 20 20 20 20 20 20 70 72 69 6e 74 28 66 22 23 20        print(f"# 
2140: 57 61 72 6e 69 6e 67 3a 20 67 72 6f 75 70 73 20  Warning: groups 
2150: 70 6f 73 69 74 69 6f 6e 69 6e 67 20 63 6f 64 65  positioning code
2160: 20 66 6f 72 20 4a 61 76 61 53 63 72 69 70 74 20   for JavaScript 
2170: 73 68 6f 75 6c 64 20 62 65 20 64 65 66 69 6e 65  should be define
2180: 64 20 61 74 20 6c 69 6e 65 20 7b 73 4c 69 6e 65  d at line {sLine
2190: 49 64 7d 22 29 0a 20 20 20 20 20 20 20 20 65 6c  Id}").        el
21a0: 73 65 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  se:.            
21b0: 69 66 20 6e 47 72 6f 75 70 20 21 3d 20 6c 65 6e  if nGroup != len
21c0: 28 74 47 72 6f 75 70 73 29 3a 0a 20 20 20 20 20  (tGroups):.     
21d0: 20 20 20 20 20 20 20 20 20 20 20 70 72 69 6e 74             print
21e0: 28 66 22 23 20 45 72 72 6f 72 3a 20 67 72 6f 75  (f"# Error: grou
21f0: 70 73 20 70 6f 73 69 74 69 6f 6e 69 6e 67 20 63  ps positioning c
2200: 6f 64 65 20 69 72 72 65 6c 65 76 61 6e 74 20 61  ode irrelevant a
2210: 74 20 6c 69 6e 65 20 7b 73 4c 69 6e 65 49 64 7d  t line {sLineId}
2220: 22 29 0a 0a 20 20 20 20 23 23 20 77 6f 72 64 20  ")..    ## word 
2230: 6c 69 6d 69 74 0a 20 20 20 20 69 66 20 63 57 6f  limit.    if cWo
2240: 72 64 4c 69 6d 69 74 4c 65 66 74 20 3d 3d 20 27  rdLimitLeft == '
2250: 5b 27 20 61 6e 64 20 6e 6f 74 20 73 52 65 67 65  [' and not sRege
2260: 78 2e 73 74 61 72 74 73 77 69 74 68 28 28 22 5e  x.startswith(("^
2270: 22 2c 20 27 e2 80 99 27 2c 20 22 27 22 2c 20 22  ", '...', "'", "
2280: 2c 22 29 29 3a 0a 20 20 20 20 20 20 20 20 73 52  ,")):.        sR
2290: 65 67 65 78 20 3d 20 73 57 4f 52 44 4c 49 4d 49  egex = sWORDLIMI
22a0: 54 4c 45 46 54 20 2b 20 73 52 65 67 65 78 0a 20  TLEFT + sRegex. 
22b0: 20 20 20 69 66 20 63 57 6f 72 64 4c 69 6d 69 74     if cWordLimit
22c0: 52 69 67 68 74 20 3d 3d 20 27 5d 27 20 61 6e 64  Right == ']' and
22d0: 20 6e 6f 74 20 73 52 65 67 65 78 2e 65 6e 64 73   not sRegex.ends
22e0: 77 69 74 68 28 28 22 24 22 2c 20 27 e2 80 99 27  with(("$", '...'
22f0: 2c 20 22 27 22 2c 20 22 2c 22 29 29 3a 0a 20 20  , "'", ",")):.  
2300: 20 20 20 20 20 20 73 52 65 67 65 78 20 3d 20 73        sRegex = s
2310: 52 65 67 65 78 20 2b 20 73 57 4f 52 44 4c 49 4d  Regex + sWORDLIM
2320: 49 54 52 49 47 48 54 0a 0a 20 20 20 20 23 23 20  ITRIGHT..    ## 
2330: 63 61 73 69 6e 67 20 6d 6f 64 65 0a 20 20 20 20  casing mode.    
2340: 69 66 20 63 43 61 73 65 4d 6f 64 65 20 3d 3d 20  if cCaseMode == 
2350: 22 69 22 3a 0a 20 20 20 20 20 20 20 20 62 43 61  "i":.        bCa
2360: 73 65 49 6e 73 65 6e 73 69 74 69 76 65 20 3d 20  seInsensitive = 
2370: 54 72 75 65 0a 20 20 20 20 20 20 20 20 69 66 20  True.        if 
2380: 6e 6f 74 20 73 52 65 67 65 78 2e 73 74 61 72 74  not sRegex.start
2390: 73 77 69 74 68 28 22 28 3f 69 29 22 29 3a 0a 20  swith("(?i)"):. 
23a0: 20 20 20 20 20 20 20 20 20 20 20 73 52 65 67 65             sRege
23b0: 78 20 3d 20 22 28 3f 69 29 22 20 2b 20 73 52 65  x = "(?i)" + sRe
23c0: 67 65 78 0a 20 20 20 20 65 6c 69 66 20 63 43 61  gex.    elif cCa
23d0: 73 65 4d 6f 64 65 20 3d 3d 20 22 73 22 3a 0a 20  seMode == "s":. 
23e0: 20 20 20 20 20 20 20 62 43 61 73 65 49 6e 73 65         bCaseInse
23f0: 6e 73 69 74 69 76 65 20 3d 20 46 61 6c 73 65 0a  nsitive = False.
2400: 20 20 20 20 20 20 20 20 73 52 65 67 65 78 20 3d          sRegex =
2410: 20 73 52 65 67 65 78 2e 72 65 70 6c 61 63 65 28   sRegex.replace(
2420: 22 28 3f 69 29 22 2c 20 22 22 29 0a 20 20 20 20  "(?i)", "").    
2430: 65 6c 69 66 20 63 43 61 73 65 4d 6f 64 65 20 3d  elif cCaseMode =
2440: 3d 20 22 75 22 3a 0a 20 20 20 20 20 20 20 20 62  = "u":.        b
2450: 43 61 73 65 49 6e 73 65 6e 73 69 74 69 76 65 20  CaseInsensitive 
2460: 3d 20 46 61 6c 73 65 0a 20 20 20 20 20 20 20 20  = False.        
2470: 73 52 65 67 65 78 20 3d 20 73 52 65 67 65 78 2e  sRegex = sRegex.
2480: 72 65 70 6c 61 63 65 28 22 28 3f 69 29 22 2c 20  replace("(?i)", 
2490: 22 22 29 0a 20 20 20 20 20 20 20 20 73 52 65 67  "").        sReg
24a0: 65 78 20 3d 20 75 70 70 65 72 63 61 73 65 28 73  ex = uppercase(s
24b0: 52 65 67 65 78 2c 20 73 4c 61 6e 67 29 0a 20 20  Regex, sLang).  
24c0: 20 20 65 6c 73 65 3a 0a 20 20 20 20 20 20 20 20    else:.        
24d0: 70 72 69 6e 74 28 66 22 23 20 55 6e 6b 6e 6f 77  print(f"# Unknow
24e0: 6e 20 63 61 73 65 20 6d 6f 64 65 20 5b 7b 63 43  n case mode [{cC
24f0: 61 73 65 4d 6f 64 65 7d 5d 20 61 74 20 6c 69 6e  aseMode}] at lin
2500: 65 20 7b 73 4c 69 6e 65 49 64 7d 22 29 0a 0a 20  e {sLineId}").. 
2510: 20 20 20 23 23 20 63 68 65 63 6b 20 72 65 67 65     ## check rege
2520: 78 0a 20 20 20 20 74 72 79 3a 0a 20 20 20 20 20  x.    try:.     
2530: 20 20 20 72 65 2e 63 6f 6d 70 69 6c 65 28 73 52     re.compile(sR
2540: 65 67 65 78 29 0a 20 20 20 20 65 78 63 65 70 74  egex).    except
2550: 20 72 65 2e 65 72 72 6f 72 3a 0a 20 20 20 20 20   re.error:.     
2560: 20 20 20 70 72 69 6e 74 28 66 22 23 20 52 65 67     print(f"# Reg
2570: 65 78 20 65 72 72 6f 72 20 61 74 20 6c 69 6e 65  ex error at line
2580: 20 7b 73 4c 69 6e 65 49 64 7d 22 29 0a 20 20 20   {sLineId}").   
2590: 20 20 20 20 20 70 72 69 6e 74 28 73 52 65 67 65       print(sRege
25a0: 78 29 0a 20 20 20 20 20 20 20 20 72 65 74 75 72  x).        retur
25b0: 6e 20 4e 6f 6e 65 0a 20 20 20 20 23 23 20 67 72  n None.    ## gr
25c0: 6f 75 70 73 20 69 6e 20 6e 6f 6e 20 67 72 6f 75  oups in non grou
25d0: 70 69 6e 67 20 70 61 72 65 6e 74 68 65 73 69 73  ping parenthesis
25e0: 0a 20 20 20 20 66 6f 72 20 5f 20 69 6e 20 72 65  .    for _ in re
25f0: 2e 66 69 6e 64 69 74 65 72 28 72 22 5c 28 5c 3f  .finditer(r"\(\?
2600: 3a 5b 5e 29 5d 2a 5c 28 5b 5c 5b 5c 77 20 2d 5d  :[^)]*\([\[\w -]
2610: 22 2c 20 73 52 65 67 65 78 29 3a 0a 20 20 20 20  ", sRegex):.    
2620: 20 20 20 20 70 72 69 6e 74 28 66 22 23 20 57 61      print(f"# Wa
2630: 72 6e 69 6e 67 3a 20 67 72 6f 75 70 73 20 69 6e  rning: groups in
2640: 73 69 64 65 20 6e 6f 6e 20 67 72 6f 75 70 69 6e  side non groupin
2650: 67 20 70 61 72 65 6e 74 68 65 73 69 73 20 69 6e  g parenthesis in
2660: 20 72 65 67 65 78 20 61 74 20 6c 69 6e 65 20 7b   regex at line {
2670: 73 4c 69 6e 65 49 64 7d 22 29 0a 0a 20 20 20 20  sLineId}")..    
2680: 23 23 23 23 20 50 41 52 53 45 20 41 43 54 49 4f  #### PARSE ACTIO
2690: 4e 53 0a 20 20 20 20 6c 41 63 74 69 6f 6e 73 20  NS.    lActions 
26a0: 3d 20 5b 5d 0a 20 20 20 20 6e 41 63 74 69 6f 6e  = [].    nAction
26b0: 20 3d 20 31 0a 20 20 20 20 66 6f 72 20 73 41 63   = 1.    for sAc
26c0: 74 69 6f 6e 20 69 6e 20 73 2e 73 70 6c 69 74 28  tion in s.split(
26d0: 22 20 3c 3c 2d 20 22 29 3a 0a 20 20 20 20 20 20  " <<- "):.      
26e0: 20 20 74 20 3d 20 63 72 65 61 74 65 41 63 74 69    t = createActi
26f0: 6f 6e 28 73 4c 69 6e 65 49 64 2c 20 73 52 75 6c  on(sLineId, sRul
2700: 65 49 64 20 2b 20 22 5f 22 20 2b 20 73 74 72 28  eId + "_" + str(
2710: 6e 41 63 74 69 6f 6e 29 2c 20 73 41 63 74 69 6f  nAction), sActio
2720: 6e 2c 20 6e 47 72 6f 75 70 29 0a 20 20 20 20 20  n, nGroup).     
2730: 20 20 20 6e 41 63 74 69 6f 6e 20 2b 3d 20 31 0a     nAction += 1.
2740: 20 20 20 20 20 20 20 20 69 66 20 74 3a 0a 20 20          if t:.  
2750: 20 20 20 20 20 20 20 20 20 20 6c 41 63 74 69 6f            lActio
2760: 6e 73 2e 61 70 70 65 6e 64 28 74 29 0a 20 20 20  ns.append(t).   
2770: 20 69 66 20 6e 6f 74 20 6c 41 63 74 69 6f 6e 73   if not lActions
2780: 3a 0a 20 20 20 20 20 20 20 20 72 65 74 75 72 6e  :.        return
2790: 20 4e 6f 6e 65 0a 0a 20 20 20 20 72 65 74 75 72   None..    retur
27a0: 6e 20 5b 73 4f 70 74 69 6f 6e 2c 20 73 52 65 67  n [sOption, sReg
27b0: 65 78 2c 20 62 43 61 73 65 49 6e 73 65 6e 73 69  ex, bCaseInsensi
27c0: 74 69 76 65 2c 20 73 4c 69 6e 65 49 64 2c 20 73  tive, sLineId, s
27d0: 52 75 6c 65 49 64 2c 20 6e 50 72 69 6f 72 69 74  RuleId, nPriorit
27e0: 79 2c 20 6c 41 63 74 69 6f 6e 73 2c 20 74 47 72  y, lActions, tGr
27f0: 6f 75 70 73 5d 0a 0a 0a 64 65 66 20 63 68 65 63  oups]...def chec
2800: 6b 52 65 66 65 72 65 6e 63 65 4e 75 6d 62 65 72  kReferenceNumber
2810: 73 20 28 73 54 65 78 74 2c 20 73 41 63 74 69 6f  s (sText, sActio
2820: 6e 49 64 2c 20 6e 54 6f 6b 65 6e 29 3a 0a 20 20  nId, nToken):.  
2830: 20 20 22 63 68 65 63 6b 20 69 66 20 74 6f 6b 65    "check if toke
2840: 6e 20 72 65 66 65 72 65 6e 63 65 73 20 69 6e 20  n references in 
2850: 3c 73 54 65 78 74 3e 20 67 72 65 61 74 65 72 20  <sText> greater 
2860: 74 68 61 6e 20 3c 6e 54 6f 6b 65 6e 3e 20 28 64  than <nToken> (d
2870: 65 62 75 67 67 69 6e 67 29 22 0a 20 20 20 20 66  ebugging)".    f
2880: 6f 72 20 78 20 69 6e 20 72 65 2e 66 69 6e 64 69  or x in re.findi
2890: 74 65 72 28 72 22 5c 5c 28 5c 64 2b 29 22 2c 20  ter(r"\\(\d+)", 
28a0: 73 54 65 78 74 29 3a 0a 20 20 20 20 20 20 20 20  sText):.        
28b0: 69 66 20 69 6e 74 28 78 2e 67 72 6f 75 70 28 31  if int(x.group(1
28c0: 29 29 20 3e 20 6e 54 6f 6b 65 6e 3a 0a 20 20 20  )) > nToken:.   
28d0: 20 20 20 20 20 20 20 20 20 70 72 69 6e 74 28 66           print(f
28e0: 22 23 20 45 72 72 6f 72 20 69 6e 20 74 6f 6b 65  "# Error in toke
28f0: 6e 20 69 6e 64 65 78 20 61 74 20 6c 69 6e 65 20  n index at line 
2900: 7b 73 4c 69 6e 65 49 64 7d 20 2f 20 7b 73 41 63  {sLineId} / {sAc
2910: 74 69 6f 6e 49 64 7d 20 28 7b 6e 54 6f 6b 65 6e  tionId} ({nToken
2920: 7d 20 74 6f 6b 65 6e 73 20 6f 6e 6c 79 29 22 29  } tokens only)")
2930: 0a 20 20 20 20 20 20 20 20 20 20 20 20 70 72 69  .            pri
2940: 6e 74 28 73 54 65 78 74 29 0a 0a 0a 64 65 66 20  nt(sText)...def 
2950: 63 68 65 63 6b 49 66 54 68 65 72 65 49 73 43 6f  checkIfThereIsCo
2960: 64 65 20 28 73 54 65 78 74 2c 20 73 4c 69 6e 65  de (sText, sLine
2970: 49 64 2c 20 73 41 63 74 69 6f 6e 49 64 29 3a 0a  Id, sActionId):.
2980: 20 20 20 20 22 63 68 65 63 6b 20 69 66 20 74 68      "check if th
2990: 65 72 65 20 69 73 20 63 6f 64 65 20 69 6e 20 3c  ere is code in <
29a0: 73 54 65 78 74 3e 20 28 64 65 62 75 67 67 69 6e  sText> (debuggin
29b0: 67 29 22 0a 20 20 20 20 69 66 20 72 65 2e 73 65  g)".    if re.se
29c0: 61 72 63 68 28 72 22 5b 2e 5d 5c 77 2b 5b 28 5d  arch(r"[.]\w+[(]
29d0: 7c 73 75 67 67 5c 77 2b 5b 28 5d 7c 5c 28 5c 5c  |sugg\w+[(]|\(\\
29e0: 5b 30 2d 39 5d 7c 5c 5b 28 3f 3a 5b 30 2d 39 5d  [0-9]|\[(?:[0-9]
29f0: 3a 7c 3a 29 22 2c 20 73 54 65 78 74 29 3a 0a 20  :|:)", sText):. 
2a00: 20 20 20 20 20 20 20 70 72 69 6e 74 28 66 22 23         print(f"#
2a10: 20 57 61 72 6e 69 6e 67 20 61 74 20 6c 69 6e 65   Warning at line
2a20: 20 7b 73 4c 69 6e 65 49 64 7d 20 2f 20 7b 73 41   {sLineId} / {sA
2a30: 63 74 69 6f 6e 49 64 7d 3a 20 20 54 68 69 73 20  ctionId}:  This 
2a40: 6d 65 73 73 61 67 65 20 6c 6f 6f 6b 73 20 6c 69  message looks li
2a50: 6b 65 20 63 6f 64 65 2e 20 4c 69 6e 65 20 73 68  ke code. Line sh
2a60: 6f 75 6c 64 20 70 72 6f 62 61 62 6c 79 20 62 65  ould probably be
2a70: 67 69 6e 20 77 69 74 68 20 3d 22 29 0a 20 20 20  gin with =").   
2a80: 20 20 20 20 20 70 72 69 6e 74 28 73 54 65 78 74       print(sText
2a90: 29 0a 0a 0a 64 65 66 20 63 72 65 61 74 65 41 63  )...def createAc
2aa0: 74 69 6f 6e 20 28 73 4c 69 6e 65 49 64 2c 20 73  tion (sLineId, s
2ab0: 41 63 74 69 6f 6e 49 64 2c 20 73 41 63 74 69 6f  ActionId, sActio
2ac0: 6e 2c 20 6e 47 72 6f 75 70 29 3a 0a 20 20 20 20  n, nGroup):.    
2ad0: 22 72 65 74 75 72 6e 73 20 61 6e 20 61 63 74 69  "returns an acti
2ae0: 6f 6e 20 74 6f 20 70 65 72 66 6f 72 6d 20 61 73  on to perform as
2af0: 20 61 20 74 75 70 6c 65 20 28 63 6f 6e 64 69 74   a tuple (condit
2b00: 69 6f 6e 2c 20 61 63 74 69 6f 6e 20 74 79 70 65  ion, action type
2b10: 2c 20 61 63 74 69 6f 6e 5b 2c 20 69 47 72 6f 75  , action[, iGrou
2b20: 70 20 5b 2c 20 6d 65 73 73 61 67 65 2c 20 55 52  p [, message, UR
2b30: 4c 20 5d 5d 29 22 0a 20 20 20 20 6d 20 3d 20 72  L ]])".    m = r
2b40: 65 2e 73 65 61 72 63 68 28 72 22 28 5b 2d 7e 3d  e.search(r"([-~=
2b50: 3e 5d 29 28 5c 64 2a 7c 29 3e 3e 22 2c 20 73 41  >])(\d*|)>>", sA
2b60: 63 74 69 6f 6e 29 0a 20 20 20 20 69 66 20 6e 6f  ction).    if no
2b70: 74 20 6d 3a 0a 20 20 20 20 20 20 20 20 70 72 69  t m:.        pri
2b80: 6e 74 28 66 22 23 20 4e 6f 20 61 63 74 69 6f 6e  nt(f"# No action
2b90: 20 61 74 20 6c 69 6e 65 20 7b 73 4c 69 6e 65 49   at line {sLineI
2ba0: 64 7d 20 2f 20 7b 73 41 63 74 69 6f 6e 49 64 7d  d} / {sActionId}
2bb0: 22 29 0a 20 20 20 20 20 20 20 20 72 65 74 75 72  ").        retur
2bc0: 6e 20 4e 6f 6e 65 0a 0a 20 20 20 20 23 23 23 23  n None..    ####
2bd0: 20 43 4f 4e 44 49 54 49 4f 4e 0a 20 20 20 20 73   CONDITION.    s
2be0: 43 6f 6e 64 69 74 69 6f 6e 20 3d 20 73 41 63 74  Condition = sAct
2bf0: 69 6f 6e 5b 3a 6d 2e 73 74 61 72 74 28 29 5d 2e  ion[:m.start()].
2c00: 73 74 72 69 70 28 29 0a 20 20 20 20 69 66 20 73  strip().    if s
2c10: 43 6f 6e 64 69 74 69 6f 6e 3a 0a 20 20 20 20 20  Condition:.     
2c20: 20 20 20 73 43 6f 6e 64 69 74 69 6f 6e 20 3d 20     sCondition = 
2c30: 70 72 65 70 61 72 65 46 75 6e 63 74 69 6f 6e 28  prepareFunction(
2c40: 73 43 6f 6e 64 69 74 69 6f 6e 29 0a 20 20 20 20  sCondition).    
2c50: 20 20 20 20 6c 46 55 4e 43 54 49 4f 4e 53 2e 61      lFUNCTIONS.a
2c60: 70 70 65 6e 64 28 28 22 5f 63 5f 22 2b 73 41 63  ppend(("_c_"+sAc
2c70: 74 69 6f 6e 49 64 2c 20 73 43 6f 6e 64 69 74 69  tionId, sConditi
2c80: 6f 6e 29 29 0a 20 20 20 20 20 20 20 20 63 68 65  on)).        che
2c90: 63 6b 52 65 66 65 72 65 6e 63 65 4e 75 6d 62 65  ckReferenceNumbe
2ca0: 72 73 28 73 43 6f 6e 64 69 74 69 6f 6e 2c 20 73  rs(sCondition, s
2cb0: 41 63 74 69 6f 6e 49 64 2c 20 6e 47 72 6f 75 70  ActionId, nGroup
2cc0: 29 0a 20 20 20 20 20 20 20 20 69 66 20 22 2e 6d  ).        if ".m
2cd0: 61 74 63 68 22 20 69 6e 20 73 43 6f 6e 64 69 74  atch" in sCondit
2ce0: 69 6f 6e 3a 0a 20 20 20 20 20 20 20 20 20 20 20  ion:.           
2cf0: 20 70 72 69 6e 74 28 66 22 23 20 45 72 72 6f 72   print(f"# Error
2d00: 20 61 74 20 6c 69 6e 65 20 7b 73 4c 69 6e 65 49   at line {sLineI
2d10: 64 7d 20 2f 20 7b 73 41 63 74 69 6f 6e 49 64 7d  d} / {sActionId}
2d20: 2e 20 4a 53 20 63 6f 6d 70 61 74 69 62 69 6c 69  . JS compatibili
2d30: 74 79 2e 20 44 6f 6e 27 74 20 75 73 65 20 2e 6d  ty. Don't use .m
2d40: 61 74 63 68 28 29 20 69 6e 20 63 6f 6e 64 69 74  atch() in condit
2d50: 69 6f 6e 2c 20 75 73 65 20 2e 73 65 61 72 63 68  ion, use .search
2d60: 28 29 22 29 0a 20 20 20 20 20 20 20 20 73 43 6f  ()").        sCo
2d70: 6e 64 69 74 69 6f 6e 20 3d 20 22 5f 63 5f 22 2b  ndition = "_c_"+
2d80: 73 41 63 74 69 6f 6e 49 64 0a 20 20 20 20 65 6c  sActionId.    el
2d90: 73 65 3a 0a 20 20 20 20 20 20 20 20 73 43 6f 6e  se:.        sCon
2da0: 64 69 74 69 6f 6e 20 3d 20 4e 6f 6e 65 0a 0a 20  dition = None.. 
2db0: 20 20 20 23 23 23 23 20 69 47 72 6f 75 70 20 2f     #### iGroup /
2dc0: 20 70 6f 73 69 74 69 6f 6e 69 6e 67 0a 20 20 20   positioning.   
2dd0: 20 69 47 72 6f 75 70 20 3d 20 69 6e 74 28 6d 2e   iGroup = int(m.
2de0: 67 72 6f 75 70 28 32 29 29 20 69 66 20 6d 2e 67  group(2)) if m.g
2df0: 72 6f 75 70 28 32 29 20 65 6c 73 65 20 30 0a 20  roup(2) else 0. 
2e00: 20 20 20 69 66 20 69 47 72 6f 75 70 20 3e 20 6e     if iGroup > n
2e10: 47 72 6f 75 70 3a 0a 20 20 20 20 20 20 20 20 70  Group:.        p
2e20: 72 69 6e 74 28 66 22 23 20 45 72 72 6f 72 2e 20  rint(f"# Error. 
2e30: 53 65 6c 65 63 74 65 64 20 67 72 6f 75 70 20 3e  Selected group >
2e40: 20 67 72 6f 75 70 20 6e 75 6d 62 65 72 20 69 6e   group number in
2e50: 20 72 65 67 65 78 20 61 74 20 6c 69 6e 65 20 7b   regex at line {
2e60: 73 4c 69 6e 65 49 64 7d 20 2f 20 7b 73 41 63 74  sLineId} / {sAct
2e70: 69 6f 6e 49 64 7d 22 29 0a 0a 20 20 20 20 23 23  ionId}")..    ##
2e80: 23 23 20 41 43 54 49 4f 4e 0a 20 20 20 20 73 41  ## ACTION.    sA
2e90: 63 74 69 6f 6e 20 3d 20 73 41 63 74 69 6f 6e 5b  ction = sAction[
2ea0: 6d 2e 65 6e 64 28 29 3a 5d 2e 73 74 72 69 70 28  m.end():].strip(
2eb0: 29 0a 20 20 20 20 63 41 63 74 69 6f 6e 20 3d 20  ).    cAction = 
2ec0: 6d 2e 67 72 6f 75 70 28 31 29 0a 20 20 20 20 69  m.group(1).    i
2ed0: 66 20 63 41 63 74 69 6f 6e 20 3d 3d 20 22 2d 22  f cAction == "-"
2ee0: 3a 0a 20 20 20 20 20 20 20 20 23 23 20 65 72 72  :.        ## err
2ef0: 6f 72 0a 20 20 20 20 20 20 20 20 69 4d 73 67 20  or.        iMsg 
2f00: 3d 20 73 41 63 74 69 6f 6e 2e 66 69 6e 64 28 22  = sAction.find("
2f10: 20 26 26 20 22 29 0a 20 20 20 20 20 20 20 20 69   && ").        i
2f20: 66 20 69 4d 73 67 20 3d 3d 20 2d 31 3a 0a 20 20  f iMsg == -1:.  
2f30: 20 20 20 20 20 20 20 20 20 20 73 4d 73 67 20 3d            sMsg =
2f40: 20 22 23 20 45 72 72 6f 72 2e 20 45 72 72 6f 72   "# Error. Error
2f50: 20 6d 65 73 73 61 67 65 20 6e 6f 74 20 66 6f 75   message not fou
2f60: 6e 64 2e 22 0a 20 20 20 20 20 20 20 20 20 20 20  nd.".           
2f70: 20 73 55 52 4c 20 3d 20 22 22 0a 20 20 20 20 20   sURL = "".     
2f80: 20 20 20 20 20 20 20 70 72 69 6e 74 28 66 22 23         print(f"#
2f90: 20 4e 6f 20 6d 65 73 73 61 67 65 2e 20 49 64 3a   No message. Id:
2fa0: 20 7b 73 4c 69 6e 65 49 64 7d 20 2f 20 7b 73 41   {sLineId} / {sA
2fb0: 63 74 69 6f 6e 49 64 7d 22 29 0a 20 20 20 20 20  ctionId}").     
2fc0: 20 20 20 65 6c 73 65 3a 0a 20 20 20 20 20 20 20     else:.       
2fd0: 20 20 20 20 20 73 4d 73 67 20 3d 20 73 41 63 74       sMsg = sAct
2fe0: 69 6f 6e 5b 69 4d 73 67 2b 34 3a 5d 2e 73 74 72  ion[iMsg+4:].str
2ff0: 69 70 28 29 0a 20 20 20 20 20 20 20 20 20 20 20  ip().           
3000: 20 73 41 63 74 69 6f 6e 20 3d 20 73 41 63 74 69   sAction = sActi
3010: 6f 6e 5b 3a 69 4d 73 67 5d 2e 73 74 72 69 70 28  on[:iMsg].strip(
3020: 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 73 55  ).            sU
3030: 52 4c 20 3d 20 22 22 0a 20 20 20 20 20 20 20 20  RL = "".        
3040: 20 20 20 20 6d 55 52 4c 20 3d 20 72 65 2e 73 65      mURL = re.se
3050: 61 72 63 68 28 22 5b 7c 5d 20 2a 28 68 74 74 70  arch("[|] *(http
3060: 73 3f 3a 2f 2f 2e 2a 29 22 2c 20 73 4d 73 67 29  s?://.*)", sMsg)
3070: 0a 20 20 20 20 20 20 20 20 20 20 20 20 69 66 20  .            if 
3080: 6d 55 52 4c 3a 0a 20 20 20 20 20 20 20 20 20 20  mURL:.          
3090: 20 20 20 20 20 20 73 55 52 4c 20 3d 20 6d 55 52        sURL = mUR
30a0: 4c 2e 67 72 6f 75 70 28 31 29 2e 73 74 72 69 70  L.group(1).strip
30b0: 28 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 20  ().             
30c0: 20 20 20 73 4d 73 67 20 3d 20 73 4d 73 67 5b 3a     sMsg = sMsg[:
30d0: 6d 55 52 4c 2e 73 74 61 72 74 28 30 29 5d 2e 73  mURL.start(0)].s
30e0: 74 72 69 70 28 29 0a 20 20 20 20 20 20 20 20 20  trip().         
30f0: 20 20 20 63 68 65 63 6b 52 65 66 65 72 65 6e 63     checkReferenc
3100: 65 4e 75 6d 62 65 72 73 28 73 4d 73 67 2c 20 73  eNumbers(sMsg, s
3110: 41 63 74 69 6f 6e 49 64 2c 20 6e 47 72 6f 75 70  ActionId, nGroup
3120: 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 69 66  ).            if
3130: 20 73 4d 73 67 5b 30 3a 31 5d 20 3d 3d 20 22 3d   sMsg[0:1] == "=
3140: 22 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 20  ":.             
3150: 20 20 20 73 4d 73 67 20 3d 20 70 72 65 70 61 72     sMsg = prepar
3160: 65 46 75 6e 63 74 69 6f 6e 28 73 4d 73 67 5b 31  eFunction(sMsg[1
3170: 3a 5d 29 0a 20 20 20 20 20 20 20 20 20 20 20 20  :]).            
3180: 20 20 20 20 6c 46 55 4e 43 54 49 4f 4e 53 2e 61      lFUNCTIONS.a
3190: 70 70 65 6e 64 28 28 22 5f 6d 5f 22 2b 73 41 63  ppend(("_m_"+sAc
31a0: 74 69 6f 6e 49 64 2c 20 73 4d 73 67 29 29 0a 20  tionId, sMsg)). 
31b0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 73                 s
31c0: 4d 73 67 20 3d 20 22 3d 5f 6d 5f 22 2b 73 41 63  Msg = "=_m_"+sAc
31d0: 74 69 6f 6e 49 64 0a 20 20 20 20 20 20 20 20 20  tionId.         
31e0: 20 20 20 65 6c 73 65 3a 0a 20 20 20 20 20 20 20     else:.       
31f0: 20 20 20 20 20 20 20 20 20 63 68 65 63 6b 49 66           checkIf
3200: 54 68 65 72 65 49 73 43 6f 64 65 28 73 4d 73 67  ThereIsCode(sMsg
3210: 2c 20 73 4c 69 6e 65 49 64 2c 20 73 41 63 74 69  , sLineId, sActi
3220: 6f 6e 49 64 29 0a 0a 20 20 20 20 63 68 65 63 6b  onId)..    check
3230: 52 65 66 65 72 65 6e 63 65 4e 75 6d 62 65 72 73  ReferenceNumbers
3240: 28 73 41 63 74 69 6f 6e 2c 20 73 41 63 74 69 6f  (sAction, sActio
3250: 6e 49 64 2c 20 6e 47 72 6f 75 70 29 0a 20 20 20  nId, nGroup).   
3260: 20 69 66 20 73 41 63 74 69 6f 6e 5b 30 3a 31 5d   if sAction[0:1]
3270: 20 3d 3d 20 22 3d 22 20 6f 72 20 63 41 63 74 69   == "=" or cActi
3280: 6f 6e 20 3d 3d 20 22 3d 22 3a 0a 20 20 20 20 20  on == "=":.     
3290: 20 20 20 73 41 63 74 69 6f 6e 20 3d 20 70 72 65     sAction = pre
32a0: 70 61 72 65 46 75 6e 63 74 69 6f 6e 28 73 41 63  pareFunction(sAc
32b0: 74 69 6f 6e 29 0a 20 20 20 20 20 20 20 20 73 41  tion).        sA
32c0: 63 74 69 6f 6e 20 3d 20 73 41 63 74 69 6f 6e 2e  ction = sAction.
32d0: 72 65 70 6c 61 63 65 28 22 6d 2e 67 72 6f 75 70  replace("m.group
32e0: 28 69 5b 34 5d 29 22 2c 20 22 6d 2e 67 72 6f 75  (i[4])", "m.grou
32f0: 70 28 22 2b 73 74 72 28 69 47 72 6f 75 70 29 2b  p("+str(iGroup)+
3300: 22 29 22 29 0a 20 20 20 20 65 6c 73 65 3a 0a 20  ")").    else:. 
3310: 20 20 20 20 20 20 20 63 68 65 63 6b 49 66 54 68         checkIfTh
3320: 65 72 65 49 73 43 6f 64 65 28 73 41 63 74 69 6f  ereIsCode(sActio
3330: 6e 2c 20 73 4c 69 6e 65 49 64 2c 20 73 41 63 74  n, sLineId, sAct
3340: 69 6f 6e 49 64 29 0a 0a 20 20 20 20 69 66 20 63  ionId)..    if c
3350: 41 63 74 69 6f 6e 20 3d 3d 20 22 3e 22 3a 0a 20  Action == ">":. 
3360: 20 20 20 20 20 20 20 23 23 20 6e 6f 20 61 63 74         ## no act
3370: 69 6f 6e 2c 20 62 72 65 61 6b 20 6c 6f 6f 70 20  ion, break loop 
3380: 69 66 20 63 6f 6e 64 69 74 69 6f 6e 20 69 73 20  if condition is 
3390: 46 61 6c 73 65 0a 20 20 20 20 20 20 20 20 72 65  False.        re
33a0: 74 75 72 6e 20 5b 73 43 6f 6e 64 69 74 69 6f 6e  turn [sCondition
33b0: 2c 20 63 41 63 74 69 6f 6e 2c 20 22 22 5d 0a 0a  , cAction, ""]..
33c0: 20 20 20 20 69 66 20 6e 6f 74 20 73 41 63 74 69      if not sActi
33d0: 6f 6e 3a 0a 20 20 20 20 20 20 20 20 70 72 69 6e  on:.        prin
33e0: 74 28 66 22 23 20 45 72 72 6f 72 20 69 6e 20 61  t(f"# Error in a
33f0: 63 74 69 6f 6e 20 61 74 20 6c 69 6e 65 20 7b 73  ction at line {s
3400: 4c 69 6e 65 49 64 7d 20 2f 20 7b 73 41 63 74 69  LineId} / {sActi
3410: 6f 6e 49 64 7d 3a 20 20 54 68 69 73 20 61 63 74  onId}:  This act
3420: 69 6f 6e 20 69 73 20 65 6d 70 74 79 2e 22 29 0a  ion is empty.").
3430: 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 4e          return N
3440: 6f 6e 65 0a 0a 20 20 20 20 69 66 20 63 41 63 74  one..    if cAct
3450: 69 6f 6e 20 3d 3d 20 22 2d 22 3a 0a 20 20 20 20  ion == "-":.    
3460: 20 20 20 20 23 23 20 65 72 72 6f 72 20 64 65 74      ## error det
3470: 65 63 74 65 64 20 2d 2d 3e 20 73 75 67 67 65 73  ected --> sugges
3480: 74 69 6f 6e 0a 20 20 20 20 20 20 20 20 69 66 20  tion.        if 
3490: 73 41 63 74 69 6f 6e 5b 30 3a 31 5d 20 3d 3d 20  sAction[0:1] == 
34a0: 22 3d 22 3a 0a 20 20 20 20 20 20 20 20 20 20 20  "=":.           
34b0: 20 6c 46 55 4e 43 54 49 4f 4e 53 2e 61 70 70 65   lFUNCTIONS.appe
34c0: 6e 64 28 28 22 5f 73 5f 22 2b 73 41 63 74 69 6f  nd(("_s_"+sActio
34d0: 6e 49 64 2c 20 73 41 63 74 69 6f 6e 5b 31 3a 5d  nId, sAction[1:]
34e0: 29 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 73  )).            s
34f0: 41 63 74 69 6f 6e 20 3d 20 22 3d 5f 73 5f 22 2b  Action = "=_s_"+
3500: 73 41 63 74 69 6f 6e 49 64 0a 20 20 20 20 20 20  sActionId.      
3510: 20 20 65 6c 69 66 20 73 41 63 74 69 6f 6e 2e 73    elif sAction.s
3520: 74 61 72 74 73 77 69 74 68 28 27 22 27 29 20 61  tartswith('"') a
3530: 6e 64 20 73 41 63 74 69 6f 6e 2e 65 6e 64 73 77  nd sAction.endsw
3540: 69 74 68 28 27 22 27 29 3a 0a 20 20 20 20 20 20  ith('"'):.      
3550: 20 20 20 20 20 20 73 41 63 74 69 6f 6e 20 3d 20        sAction = 
3560: 73 41 63 74 69 6f 6e 5b 31 3a 2d 31 5d 0a 20 20  sAction[1:-1].  
3570: 20 20 20 20 20 20 69 66 20 6e 6f 74 20 73 4d 73        if not sMs
3580: 67 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 70  g:.            p
3590: 72 69 6e 74 28 66 22 23 20 45 72 72 6f 72 20 69  rint(f"# Error i
35a0: 6e 20 61 63 74 69 6f 6e 20 61 74 20 6c 69 6e 65  n action at line
35b0: 20 7b 73 4c 69 6e 65 49 64 7d 20 2f 20 7b 73 41   {sLineId} / {sA
35c0: 63 74 69 6f 6e 49 64 7d 3a 20 20 74 68 65 20 6d  ctionId}:  the m
35d0: 65 73 73 61 67 65 20 69 73 20 65 6d 70 74 79 2e  essage is empty.
35e0: 22 29 0a 20 20 20 20 20 20 20 20 72 65 74 75 72  ").        retur
35f0: 6e 20 5b 73 43 6f 6e 64 69 74 69 6f 6e 2c 20 63  n [sCondition, c
3600: 41 63 74 69 6f 6e 2c 20 73 41 63 74 69 6f 6e 2c  Action, sAction,
3610: 20 69 47 72 6f 75 70 2c 20 73 4d 73 67 2c 20 73   iGroup, sMsg, s
3620: 55 52 4c 5d 0a 20 20 20 20 69 66 20 63 41 63 74  URL].    if cAct
3630: 69 6f 6e 20 3d 3d 20 22 7e 22 3a 0a 20 20 20 20  ion == "~":.    
3640: 20 20 20 20 23 23 20 74 65 78 74 20 70 72 6f 63      ## text proc
3650: 65 73 73 6f 72 0a 20 20 20 20 20 20 20 20 69 66  essor.        if
3660: 20 73 41 63 74 69 6f 6e 5b 30 3a 31 5d 20 3d 3d   sAction[0:1] ==
3670: 20 22 3d 22 3a 0a 20 20 20 20 20 20 20 20 20 20   "=":.          
3680: 20 20 6c 46 55 4e 43 54 49 4f 4e 53 2e 61 70 70    lFUNCTIONS.app
3690: 65 6e 64 28 28 22 5f 70 5f 22 2b 73 41 63 74 69  end(("_p_"+sActi
36a0: 6f 6e 49 64 2c 20 73 41 63 74 69 6f 6e 5b 31 3a  onId, sAction[1:
36b0: 5d 29 29 0a 20 20 20 20 20 20 20 20 20 20 20 20  ])).            
36c0: 73 41 63 74 69 6f 6e 20 3d 20 22 3d 5f 70 5f 22  sAction = "=_p_"
36d0: 2b 73 41 63 74 69 6f 6e 49 64 0a 20 20 20 20 20  +sActionId.     
36e0: 20 20 20 65 6c 69 66 20 73 41 63 74 69 6f 6e 2e     elif sAction.
36f0: 73 74 61 72 74 73 77 69 74 68 28 27 22 27 29 20  startswith('"') 
3700: 61 6e 64 20 73 41 63 74 69 6f 6e 2e 65 6e 64 73  and sAction.ends
3710: 77 69 74 68 28 27 22 27 29 3a 0a 20 20 20 20 20  with('"'):.     
3720: 20 20 20 20 20 20 20 73 41 63 74 69 6f 6e 20 3d         sAction =
3730: 20 73 41 63 74 69 6f 6e 5b 31 3a 2d 31 5d 0a 20   sAction[1:-1]. 
3740: 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 5b 73         return [s
3750: 43 6f 6e 64 69 74 69 6f 6e 2c 20 63 41 63 74 69  Condition, cActi
3760: 6f 6e 2c 20 73 41 63 74 69 6f 6e 2c 20 69 47 72  on, sAction, iGr
3770: 6f 75 70 5d 0a 20 20 20 20 69 66 20 63 41 63 74  oup].    if cAct
3780: 69 6f 6e 20 3d 3d 20 22 3d 22 3a 0a 20 20 20 20  ion == "=":.    
3790: 20 20 20 20 23 23 20 64 69 73 61 6d 62 69 67 75      ## disambigu
37a0: 61 74 6f 72 0a 20 20 20 20 20 20 20 20 69 66 20  ator.        if 
37b0: 73 41 63 74 69 6f 6e 5b 30 3a 31 5d 20 3d 3d 20  sAction[0:1] == 
37c0: 22 3d 22 3a 0a 20 20 20 20 20 20 20 20 20 20 20  "=":.           
37d0: 20 73 41 63 74 69 6f 6e 20 3d 20 73 41 63 74 69   sAction = sActi
37e0: 6f 6e 5b 31 3a 5d 0a 20 20 20 20 20 20 20 20 6c  on[1:].        l
37f0: 46 55 4e 43 54 49 4f 4e 53 2e 61 70 70 65 6e 64  FUNCTIONS.append
3800: 28 28 22 5f 64 5f 22 2b 73 41 63 74 69 6f 6e 49  (("_d_"+sActionI
3810: 64 2c 20 73 41 63 74 69 6f 6e 29 29 0a 20 20 20  d, sAction)).   
3820: 20 20 20 20 20 73 41 63 74 69 6f 6e 20 3d 20 22       sAction = "
3830: 5f 64 5f 22 2b 73 41 63 74 69 6f 6e 49 64 0a 20  _d_"+sActionId. 
3840: 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 5b 73         return [s
3850: 43 6f 6e 64 69 74 69 6f 6e 2c 20 63 41 63 74 69  Condition, cActi
3860: 6f 6e 2c 20 73 41 63 74 69 6f 6e 5d 0a 20 20 20  on, sAction].   
3870: 20 70 72 69 6e 74 28 66 22 23 20 55 6e 6b 6e 6f   print(f"# Unkno
3880: 77 6e 20 61 63 74 69 6f 6e 20 61 74 20 6c 69 6e  wn action at lin
3890: 65 20 7b 73 4c 69 6e 65 49 64 7d 20 2f 20 7b 73  e {sLineId} / {s
38a0: 41 63 74 69 6f 6e 49 64 7d 22 29 0a 20 20 20 20  ActionId}").    
38b0: 72 65 74 75 72 6e 20 4e 6f 6e 65 0a 0a 0a 64 65  return None...de
38c0: 66 20 5f 63 61 6c 63 52 75 6c 65 73 53 74 61 74  f _calcRulesStat
38d0: 73 20 28 6c 52 75 6c 65 73 29 3a 0a 20 20 20 20  s (lRules):.    
38e0: 22 63 6f 75 6e 74 20 72 75 6c 65 73 20 61 6e 64  "count rules and
38f0: 20 61 63 74 69 6f 6e 73 22 0a 20 20 20 20 64 20   actions".    d 
3900: 3d 20 7b 27 3d 27 3a 30 2c 20 27 7e 27 3a 20 30  = {'=':0, '~': 0
3910: 2c 20 27 2d 27 3a 20 30 2c 20 27 3e 27 3a 20 30  , '-': 0, '>': 0
3920: 7d 0a 20 20 20 20 66 6f 72 20 61 52 75 6c 65 20  }.    for aRule 
3930: 69 6e 20 6c 52 75 6c 65 73 3a 0a 20 20 20 20 20  in lRules:.     
3940: 20 20 20 69 66 20 61 52 75 6c 65 5b 30 5d 20 21     if aRule[0] !
3950: 3d 20 22 40 40 40 40 22 3a 0a 20 20 20 20 20 20  = "@@@@":.      
3960: 20 20 20 20 20 20 66 6f 72 20 61 41 63 74 69 6f        for aActio
3970: 6e 20 69 6e 20 61 52 75 6c 65 5b 36 5d 3a 0a 20  n in aRule[6]:. 
3980: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 64                 d
3990: 5b 61 41 63 74 69 6f 6e 5b 31 5d 5d 20 3d 20 64  [aAction[1]] = d
39a0: 5b 61 41 63 74 69 6f 6e 5b 31 5d 5d 20 2b 20 31  [aAction[1]] + 1
39b0: 0a 20 20 20 20 72 65 74 75 72 6e 20 28 64 2c 20  .    return (d, 
39c0: 6c 65 6e 28 6c 52 75 6c 65 73 29 29 0a 0a 0a 64  len(lRules))...d
39d0: 65 66 20 64 69 73 70 6c 61 79 53 74 61 74 73 20  ef displayStats 
39e0: 28 6c 50 61 72 61 67 72 61 70 68 52 75 6c 65 73  (lParagraphRules
39f0: 2c 20 6c 53 65 6e 74 65 6e 63 65 52 75 6c 65 73  , lSentenceRules
3a00: 29 3a 0a 20 20 20 20 22 64 69 73 70 6c 61 79 20  ):.    "display 
3a10: 72 75 6c 65 73 20 6e 75 6d 62 65 72 73 22 0a 20  rules numbers". 
3a20: 20 20 20 70 72 69 6e 74 28 22 20 20 20 20 20 20     print("      
3a30: 20 20 20 20 20 20 20 20 20 7b 3a 3e 31 38 7d 20           {:>18} 
3a40: 7b 3a 3e 31 38 7d 20 7b 3a 3e 31 38 7d 20 7b 3a  {:>18} {:>18} {:
3a50: 3e 31 38 7d 22 2e 66 6f 72 6d 61 74 28 22 44 49  >18}".format("DI
3a60: 53 41 4d 42 49 47 55 41 54 4f 52 22 2c 20 22 54  SAMBIGUATOR", "T
3a70: 45 58 54 20 50 52 4f 43 45 53 53 4f 52 22 2c 20  EXT PROCESSOR", 
3a80: 22 47 52 41 4d 4d 41 52 20 43 48 45 43 4b 49 4e  "GRAMMAR CHECKIN
3a90: 47 22 2c 20 22 52 45 47 45 58 22 29 29 0a 20 20  G", "REGEX")).  
3aa0: 20 20 64 2c 20 6e 52 75 6c 65 20 3d 20 5f 63 61    d, nRule = _ca
3ab0: 6c 63 52 75 6c 65 73 53 74 61 74 73 28 6c 50 61  lcRulesStats(lPa
3ac0: 72 61 67 72 61 70 68 52 75 6c 65 73 29 0a 20 20  ragraphRules).  
3ad0: 20 20 70 72 69 6e 74 28 22 20 20 20 20 70 61 72    print("    par
3ae0: 61 67 72 61 70 68 3a 20 7b 3a 3e 31 30 7d 20 61  agraph: {:>10} a
3af0: 63 74 69 6f 6e 73 20 7b 3a 3e 31 30 7d 20 61 63  ctions {:>10} ac
3b00: 74 69 6f 6e 73 20 7b 3a 3e 31 30 7d 20 61 63 74  tions {:>10} act
3b10: 69 6f 6e 73 20 20 69 6e 20 7b 3a 3e 38 7d 20 72  ions  in {:>8} r
3b20: 75 6c 65 73 22 2e 66 6f 72 6d 61 74 28 64 5b 27  ules".format(d['
3b30: 3d 27 5d 2c 20 64 5b 27 7e 27 5d 2c 20 64 5b 27  ='], d['~'], d['
3b40: 2d 27 5d 2c 20 6e 52 75 6c 65 29 29 0a 20 20 20  -'], nRule)).   
3b50: 20 64 2c 20 6e 52 75 6c 65 20 3d 20 5f 63 61 6c   d, nRule = _cal
3b60: 63 52 75 6c 65 73 53 74 61 74 73 28 6c 53 65 6e  cRulesStats(lSen
3b70: 74 65 6e 63 65 52 75 6c 65 73 29 0a 20 20 20 20  tenceRules).    
3b80: 70 72 69 6e 74 28 22 20 20 20 20 73 65 6e 74 65  print("    sente
3b90: 6e 63 65 3a 20 20 7b 3a 3e 31 30 7d 20 61 63 74  nce:  {:>10} act
3ba0: 69 6f 6e 73 20 7b 3a 3e 31 30 7d 20 61 63 74 69  ions {:>10} acti
3bb0: 6f 6e 73 20 7b 3a 3e 31 30 7d 20 61 63 74 69 6f  ons {:>10} actio
3bc0: 6e 73 20 20 69 6e 20 7b 3a 3e 38 7d 20 72 75 6c  ns  in {:>8} rul
3bd0: 65 73 22 2e 66 6f 72 6d 61 74 28 64 5b 27 3d 27  es".format(d['='
3be0: 5d 2c 20 64 5b 27 7e 27 5d 2c 20 64 5b 27 2d 27  ], d['~'], d['-'
3bf0: 5d 2c 20 6e 52 75 6c 65 29 29 0a 0a 0a 64 65 66  ], nRule))...def
3c00: 20 6d 65 72 67 65 52 75 6c 65 73 42 79 4f 70 74   mergeRulesByOpt
3c10: 69 6f 6e 20 28 6c 52 75 6c 65 73 29 3a 0a 20 20  ion (lRules):.  
3c20: 20 20 22 72 65 74 75 72 6e 73 20 61 20 6c 69 73    "returns a lis
3c30: 74 20 6f 66 20 74 75 70 6c 65 73 20 5b 6f 70 74  t of tuples [opt
3c40: 69 6f 6e 2c 20 6c 69 73 74 20 6f 66 20 72 75 6c  ion, list of rul
3c50: 65 73 5d 20 6b 65 65 70 69 6e 67 20 74 68 65 20  es] keeping the 
3c60: 72 75 6c 65 73 20 6f 72 64 65 72 22 0a 20 20 20  rules order".   
3c70: 20 6c 46 69 6e 61 6c 20 3d 20 5b 5d 0a 20 20 20   lFinal = [].   
3c80: 20 6c 54 65 6d 70 20 3d 20 5b 5d 0a 20 20 20 20   lTemp = [].    
3c90: 73 4f 70 74 69 6f 6e 20 3d 20 4e 6f 6e 65 0a 20  sOption = None. 
3ca0: 20 20 20 66 6f 72 20 61 52 75 6c 65 20 69 6e 20     for aRule in 
3cb0: 6c 52 75 6c 65 73 3a 0a 20 20 20 20 20 20 20 20  lRules:.        
3cc0: 69 66 20 61 52 75 6c 65 5b 30 5d 20 21 3d 20 73  if aRule[0] != s
3cd0: 4f 70 74 69 6f 6e 3a 0a 20 20 20 20 20 20 20 20  Option:.        
3ce0: 20 20 20 20 69 66 20 73 4f 70 74 69 6f 6e 20 69      if sOption i
3cf0: 73 20 6e 6f 74 20 4e 6f 6e 65 3a 0a 20 20 20 20  s not None:.    
3d00: 20 20 20 20 20 20 20 20 20 20 20 20 6c 46 69 6e              lFin
3d10: 61 6c 2e 61 70 70 65 6e 64 28 5b 73 4f 70 74 69  al.append([sOpti
3d20: 6f 6e 2c 20 6c 54 65 6d 70 5d 29 0a 20 20 20 20  on, lTemp]).    
3d30: 20 20 20 20 20 20 20 20 23 20 6e 65 77 20 74 75          # new tu
3d40: 70 6c 65 0a 20 20 20 20 20 20 20 20 20 20 20 20  ple.            
3d50: 73 4f 70 74 69 6f 6e 20 3d 20 61 52 75 6c 65 5b  sOption = aRule[
3d60: 30 5d 0a 20 20 20 20 20 20 20 20 20 20 20 20 6c  0].            l
3d70: 54 65 6d 70 20 3d 20 5b 5d 0a 20 20 20 20 20 20  Temp = [].      
3d80: 20 20 6c 54 65 6d 70 2e 61 70 70 65 6e 64 28 61    lTemp.append(a
3d90: 52 75 6c 65 5b 31 3a 5d 29 0a 20 20 20 20 6c 46  Rule[1:]).    lF
3da0: 69 6e 61 6c 2e 61 70 70 65 6e 64 28 5b 73 4f 70  inal.append([sOp
3db0: 74 69 6f 6e 2c 20 6c 54 65 6d 70 5d 29 0a 20 20  tion, lTemp]).  
3dc0: 20 20 72 65 74 75 72 6e 20 6c 46 69 6e 61 6c 0a    return lFinal.
3dd0: 0a 0a 64 65 66 20 63 72 65 61 74 65 52 75 6c 65  ..def createRule
3de0: 73 41 73 53 74 72 69 6e 67 20 28 6c 52 75 6c 65  sAsString (lRule
3df0: 73 29 3a 0a 20 20 20 20 22 63 72 65 61 74 65 20  s):.    "create 
3e00: 72 75 6c 65 73 20 61 73 20 61 20 73 74 72 69 6e  rules as a strin
3e10: 67 20 6f 66 20 61 72 72 61 79 73 20 28 74 6f 20  g of arrays (to 
3e20: 62 65 20 62 75 6e 64 6c 65 64 20 69 6e 20 61 20  be bundled in a 
3e30: 4a 53 4f 4e 20 73 74 72 69 6e 67 29 22 0a 20 20  JSON string)".  
3e40: 20 20 73 41 72 72 61 79 20 3d 20 22 5b 5c 6e 22    sArray = "[\n"
3e50: 0a 20 20 20 20 66 6f 72 20 73 4f 70 74 69 6f 6e  .    for sOption
3e60: 2c 20 61 52 75 6c 65 47 72 6f 75 70 20 69 6e 20  , aRuleGroup in 
3e70: 6c 52 75 6c 65 73 3a 0a 20 20 20 20 20 20 20 20  lRules:.        
3e80: 73 41 72 72 61 79 20 2b 3d 20 66 27 20 20 5b 22  sArray += f'  ["
3e90: 7b 73 4f 70 74 69 6f 6e 7d 22 2c 20 5b 5c 6e 27  {sOption}", [\n'
3ea0: 0a 20 20 20 20 20 20 20 20 66 6f 72 20 61 52 75  .        for aRu
3eb0: 6c 65 20 69 6e 20 61 52 75 6c 65 47 72 6f 75 70  le in aRuleGroup
3ec0: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 73 41  :.            sA
3ed0: 72 72 61 79 20 2b 3d 20 66 27 20 20 20 20 7b 61  rray += f'    {a
3ee0: 52 75 6c 65 7d 2c 5c 6e 27 0a 20 20 20 20 20 20  Rule},\n'.      
3ef0: 20 20 73 41 72 72 61 79 20 2b 3d 20 22 20 20 5d    sArray += "  ]
3f00: 5d 2c 5c 6e 22 0a 20 20 20 20 73 41 72 72 61 79  ],\n".    sArray
3f10: 20 2b 3d 20 22 5d 22 0a 20 20 20 20 72 65 74 75   += "]".    retu
3f20: 72 6e 20 73 41 72 72 61 79 0a 0a 0a 64 65 66 20  rn sArray...def 
3f30: 70 72 65 70 61 72 65 4f 70 74 69 6f 6e 73 20 28  prepareOptions (
3f40: 6c 4f 70 74 69 6f 6e 4c 69 6e 65 73 29 3a 0a 20  lOptionLines):. 
3f50: 20 20 20 22 72 65 74 75 72 6e 73 20 61 20 64 69     "returns a di
3f60: 63 74 69 6f 6e 61 72 79 20 77 69 74 68 20 64 61  ctionary with da
3f70: 74 61 20 61 62 6f 75 74 20 6f 70 74 69 6f 6e 73  ta about options
3f80: 22 0a 20 20 20 20 73 4c 61 6e 67 20 3d 20 22 22  ".    sLang = ""
3f90: 0a 20 20 20 20 73 44 65 66 61 75 6c 74 55 49 4c  .    sDefaultUIL
3fa0: 61 6e 67 20 3d 20 22 22 0a 20 20 20 20 6c 53 74  ang = "".    lSt
3fb0: 72 75 63 74 4f 70 74 20 3d 20 5b 5d 0a 20 20 20  ructOpt = [].   
3fc0: 20 6c 4f 70 74 20 3d 20 5b 5d 0a 20 20 20 20 6c   lOpt = [].    l
3fd0: 4f 70 74 43 6f 6c 6f 72 20 3d 20 5b 5d 0a 20 20  OptColor = [].  
3fe0: 20 20 64 43 6f 6c 6f 72 20 3d 20 7b 7d 0a 20 20    dColor = {}.  
3ff0: 20 20 64 4f 70 74 4c 61 62 65 6c 20 3d 20 7b 7d    dOptLabel = {}
4000: 0a 20 20 20 20 64 4f 70 74 50 72 69 6f 72 69 74  .    dOptPriorit
4010: 79 20 3d 20 7b 7d 0a 20 20 20 20 66 6f 72 20 73  y = {}.    for s
4020: 4c 69 6e 65 20 69 6e 20 6c 4f 70 74 69 6f 6e 4c  Line in lOptionL
4030: 69 6e 65 73 3a 0a 20 20 20 20 20 20 20 20 73 4c  ines:.        sL
4040: 69 6e 65 20 3d 20 73 4c 69 6e 65 2e 73 74 72 69  ine = sLine.stri
4050: 70 28 29 0a 20 20 20 20 20 20 20 20 69 66 20 73  p().        if s
4060: 4c 69 6e 65 2e 73 74 61 72 74 73 77 69 74 68 28  Line.startswith(
4070: 22 4f 50 54 47 52 4f 55 50 2f 22 29 3a 0a 20 20  "OPTGROUP/"):.  
4080: 20 20 20 20 20 20 20 20 20 20 6d 20 3d 20 72 65            m = re
4090: 2e 6d 61 74 63 68 28 22 4f 50 54 47 52 4f 55 50  .match("OPTGROUP
40a0: 2f 28 5b 61 2d 7a 30 2d 39 5d 2b 29 3a 28 2e 2b  /([a-z0-9]+):(.+
40b0: 29 24 22 2c 20 73 4c 69 6e 65 29 0a 20 20 20 20  )$", sLine).    
40c0: 20 20 20 20 20 20 20 20 6c 53 74 72 75 63 74 4f          lStructO
40d0: 70 74 2e 61 70 70 65 6e 64 28 20 5b 6d 2e 67 72  pt.append( [m.gr
40e0: 6f 75 70 28 31 29 2c 20 6c 69 73 74 28 6d 61 70  oup(1), list(map
40f0: 28 73 74 72 2e 73 70 6c 69 74 2c 20 6d 2e 67 72  (str.split, m.gr
4100: 6f 75 70 28 32 29 2e 73 70 6c 69 74 28 22 2c 22  oup(2).split(","
4110: 29 29 29 5d 20 29 0a 20 20 20 20 20 20 20 20 65  )))] ).        e
4120: 6c 69 66 20 73 4c 69 6e 65 2e 73 74 61 72 74 73  lif sLine.starts
4130: 77 69 74 68 28 22 4f 50 54 53 4f 46 54 57 41 52  with("OPTSOFTWAR
4140: 45 3a 22 29 3a 0a 20 20 20 20 20 20 20 20 20 20  E:"):.          
4150: 20 20 6c 4f 70 74 20 3d 20 5b 20 5b 73 2c 20 7b    lOpt = [ [s, {
4160: 7d 5d 20 20 66 6f 72 20 73 20 69 6e 20 73 4c 69  }]  for s in sLi
4170: 6e 65 5b 31 32 3a 5d 2e 73 74 72 69 70 28 29 2e  ne[12:].strip().
4180: 73 70 6c 69 74 28 29 20 5d 20 20 23 20 64 6f 6e  split() ]  # don
4190: e2 80 99 74 20 75 73 65 20 74 75 70 6c 65 73 20  ...t use tuples 
41a0: 28 73 2c 20 7b 7d 29 2c 20 62 65 63 61 75 73 65  (s, {}), because
41b0: 20 75 6e 6b 6e 6f 77 6e 20 74 6f 20 4a 53 0a 20   unknown to JS. 
41c0: 20 20 20 20 20 20 20 65 6c 69 66 20 73 4c 69 6e         elif sLin
41d0: 65 2e 73 74 61 72 74 73 77 69 74 68 28 22 4f 50  e.startswith("OP
41e0: 54 2f 22 29 3a 0a 20 20 20 20 20 20 20 20 20 20  T/"):.          
41f0: 20 20 6d 20 3d 20 72 65 2e 6d 61 74 63 68 28 22    m = re.match("
4200: 4f 50 54 2f 28 5b 61 2d 7a 30 2d 39 5d 2b 29 3a  OPT/([a-z0-9]+):
4210: 28 2e 2b 29 24 22 2c 20 73 4c 69 6e 65 29 0a 20  (.+)$", sLine). 
4220: 20 20 20 20 20 20 20 20 20 20 20 66 6f 72 20 69             for i
4230: 2c 20 73 4f 70 74 20 69 6e 20 65 6e 75 6d 65 72  , sOpt in enumer
4240: 61 74 65 28 6d 2e 67 72 6f 75 70 28 32 29 2e 73  ate(m.group(2).s
4250: 70 6c 69 74 28 29 29 3a 0a 20 20 20 20 20 20 20  plit()):.       
4260: 20 20 20 20 20 20 20 20 20 6c 4f 70 74 5b 69 5d           lOpt[i]
4270: 5b 31 5d 5b 6d 2e 67 72 6f 75 70 28 31 29 5d 20  [1][m.group(1)] 
4280: 3d 20 73 4f 70 74 20 69 6e 20 28 22 54 72 75 65  = sOpt in ("True
4290: 22 2c 20 22 74 72 75 65 22 2c 20 22 59 65 73 22  ", "true", "Yes"
42a0: 2c 20 22 79 65 73 22 29 0a 20 20 20 20 20 20 20  , "yes").       
42b0: 20 65 6c 69 66 20 73 4c 69 6e 65 2e 73 74 61 72   elif sLine.star
42c0: 74 73 77 69 74 68 28 22 4f 50 54 43 4f 4c 4f 52  tswith("OPTCOLOR
42d0: 54 48 45 4d 45 3a 22 29 3a 0a 20 20 20 20 20 20  THEME:"):.      
42e0: 20 20 20 20 20 20 6c 4f 70 74 43 6f 6c 6f 72 20        lOptColor 
42f0: 3d 20 5b 20 5b 73 2c 20 7b 7d 5d 20 20 66 6f 72  = [ [s, {}]  for
4300: 20 73 20 69 6e 20 73 4c 69 6e 65 5b 31 34 3a 5d   s in sLine[14:]
4310: 2e 73 74 72 69 70 28 29 2e 73 70 6c 69 74 28 29  .strip().split()
4320: 20 5d 20 20 23 20 64 6f 6e e2 80 99 74 20 75 73   ]  # don...t us
4330: 65 20 74 75 70 6c 65 73 20 28 73 2c 20 7b 7d 29  e tuples (s, {})
4340: 2c 20 62 65 63 61 75 73 65 20 75 6e 6b 6e 6f 77  , because unknow
4350: 6e 20 74 6f 20 4a 53 0a 20 20 20 20 20 20 20 20  n to JS.        
4360: 65 6c 69 66 20 73 4c 69 6e 65 2e 73 74 61 72 74  elif sLine.start
4370: 73 77 69 74 68 28 22 4f 50 54 43 4f 4c 4f 52 2f  swith("OPTCOLOR/
4380: 22 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  "):.            
4390: 6d 20 3d 20 72 65 2e 6d 61 74 63 68 28 22 4f 50  m = re.match("OP
43a0: 54 43 4f 4c 4f 52 2f 28 5b 61 2d 7a 30 2d 39 5d  TCOLOR/([a-z0-9]
43b0: 2b 29 3a 28 2e 2b 29 24 22 2c 20 73 4c 69 6e 65  +):(.+)$", sLine
43c0: 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 66 6f  ).            fo
43d0: 72 20 69 2c 20 73 43 6f 6c 6f 72 20 69 6e 20 65  r i, sColor in e
43e0: 6e 75 6d 65 72 61 74 65 28 6d 2e 67 72 6f 75 70  numerate(m.group
43f0: 28 32 29 2e 73 70 6c 69 74 28 29 29 3a 0a 20 20  (2).split()):.  
4400: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 6c 4f                lO
4410: 70 74 43 6f 6c 6f 72 5b 69 5d 5b 31 5d 5b 6d 2e  ptColor[i][1][m.
4420: 67 72 6f 75 70 28 31 29 5d 20 3d 20 73 43 6f 6c  group(1)] = sCol
4430: 6f 72 0a 20 20 20 20 20 20 20 20 65 6c 69 66 20  or.        elif 
4440: 73 4c 69 6e 65 2e 73 74 61 72 74 73 77 69 74 68  sLine.startswith
4450: 28 22 43 4f 4c 4f 52 2f 22 29 3a 0a 20 20 20 20  ("COLOR/"):.    
4460: 20 20 20 20 20 20 20 20 6d 20 3d 20 72 65 2e 6d          m = re.m
4470: 61 74 63 68 28 22 43 4f 4c 4f 52 2f 28 5b 61 2d  atch("COLOR/([a-
4480: 7a 41 2d 5a 30 2d 39 5f 5d 2b 29 3a 28 2e 2b 29  zA-Z0-9_]+):(.+)
4490: 24 22 2c 20 73 4c 69 6e 65 29 0a 20 20 20 20 20  $", sLine).     
44a0: 20 20 20 20 20 20 20 64 43 6f 6c 6f 72 5b 6d 2e         dColor[m.
44b0: 67 72 6f 75 70 28 31 29 5d 20 3d 20 5b 20 69 6e  group(1)] = [ in
44c0: 74 28 73 29 20 66 6f 72 20 73 20 69 6e 20 6d 2e  t(s) for s in m.
44d0: 67 72 6f 75 70 28 32 29 2e 73 74 72 69 70 28 29  group(2).strip()
44e0: 2e 73 70 6c 69 74 28 22 2c 22 29 20 5d 0a 20 20  .split(",") ].  
44f0: 20 20 20 20 20 20 65 6c 69 66 20 73 4c 69 6e 65        elif sLine
4500: 2e 73 74 61 72 74 73 77 69 74 68 28 22 4f 50 54  .startswith("OPT
4510: 50 52 49 4f 52 49 54 59 2f 22 29 3a 0a 20 20 20  PRIORITY/"):.   
4520: 20 20 20 20 20 20 20 20 20 6d 20 3d 20 72 65 2e           m = re.
4530: 6d 61 74 63 68 28 22 4f 50 54 50 52 49 4f 52 49  match("OPTPRIORI
4540: 54 59 2f 28 5b 61 2d 7a 30 2d 39 5d 2b 29 3a 20  TY/([a-z0-9]+): 
4550: 2a 28 5b 30 2d 39 5d 29 24 22 2c 20 73 4c 69 6e  *([0-9])$", sLin
4560: 65 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 64  e).            d
4570: 4f 70 74 50 72 69 6f 72 69 74 79 5b 6d 2e 67 72  OptPriority[m.gr
4580: 6f 75 70 28 31 29 5d 20 3d 20 69 6e 74 28 6d 2e  oup(1)] = int(m.
4590: 67 72 6f 75 70 28 32 29 29 0a 20 20 20 20 20 20  group(2)).      
45a0: 20 20 65 6c 69 66 20 73 4c 69 6e 65 2e 73 74 61    elif sLine.sta
45b0: 72 74 73 77 69 74 68 28 22 4f 50 54 4c 41 4e 47  rtswith("OPTLANG
45c0: 2f 22 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20  /"):.           
45d0: 20 6d 20 3d 20 72 65 2e 6d 61 74 63 68 28 22 4f   m = re.match("O
45e0: 50 54 4c 41 4e 47 2f 28 5b 61 2d 7a 5d 5b 61 2d  PTLANG/([a-z][a-
45f0: 7a 5d 28 3f 3a 5f 5b 41 2d 5a 5d 5b 41 2d 5a 5d  z](?:_[A-Z][A-Z]
4600: 7c 29 29 3a 28 2e 2b 29 24 22 2c 20 73 4c 69 6e  |)):(.+)$", sLin
4610: 65 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 73  e).            s
4620: 4c 61 6e 67 20 3d 20 6d 2e 67 72 6f 75 70 28 31  Lang = m.group(1
4630: 29 5b 3a 32 5d 0a 20 20 20 20 20 20 20 20 20 20  )[:2].          
4640: 20 20 64 4f 70 74 4c 61 62 65 6c 5b 73 4c 61 6e    dOptLabel[sLan
4650: 67 5d 20 3d 20 7b 20 22 5f 5f 6f 70 74 69 6f 6e  g] = { "__option
4660: 74 69 74 6c 65 5f 5f 22 3a 20 6d 2e 67 72 6f 75  title__": m.grou
4670: 70 28 32 29 2e 73 74 72 69 70 28 29 20 7d 0a 20  p(2).strip() }. 
4680: 20 20 20 20 20 20 20 65 6c 69 66 20 73 4c 69 6e         elif sLin
4690: 65 2e 73 74 61 72 74 73 77 69 74 68 28 22 4f 50  e.startswith("OP
46a0: 54 44 45 46 41 55 4c 54 55 49 4c 41 4e 47 3a 22  TDEFAULTUILANG:"
46b0: 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 6d  ):.            m
46c0: 20 3d 20 72 65 2e 6d 61 74 63 68 28 22 4f 50 54   = re.match("OPT
46d0: 44 45 46 41 55 4c 54 55 49 4c 41 4e 47 3a 20 2a  DEFAULTUILANG: *
46e0: 28 5b 61 2d 7a 5d 5b 61 2d 7a 5d 28 3f 3a 5f 5b  ([a-z][a-z](?:_[
46f0: 41 2d 5a 5d 5b 41 2d 5a 5d 7c 29 29 24 22 2c 20  A-Z][A-Z]|))$", 
4700: 73 4c 69 6e 65 29 0a 20 20 20 20 20 20 20 20 20  sLine).         
4710: 20 20 20 73 44 65 66 61 75 6c 74 55 49 4c 61 6e     sDefaultUILan
4720: 67 20 3d 20 6d 2e 67 72 6f 75 70 28 31 29 5b 3a  g = m.group(1)[:
4730: 32 5d 0a 20 20 20 20 20 20 20 20 65 6c 69 66 20  2].        elif 
4740: 73 4c 69 6e 65 2e 73 74 61 72 74 73 77 69 74 68  sLine.startswith
4750: 28 22 4f 50 54 4c 41 42 45 4c 2f 22 29 3a 0a 20  ("OPTLABEL/"):. 
4760: 20 20 20 20 20 20 20 20 20 20 20 6d 20 3d 20 72             m = r
4770: 65 2e 6d 61 74 63 68 28 22 4f 50 54 4c 41 42 45  e.match("OPTLABE
4780: 4c 2f 28 5b 61 2d 7a 30 2d 39 5d 2b 29 3a 28 2e  L/([a-z0-9]+):(.
4790: 2b 29 24 22 2c 20 73 4c 69 6e 65 29 0a 20 20 20  +)$", sLine).   
47a0: 20 20 20 20 20 20 20 20 20 64 4f 70 74 4c 61 62           dOptLab
47b0: 65 6c 5b 73 4c 61 6e 67 5d 5b 6d 2e 67 72 6f 75  el[sLang][m.grou
47c0: 70 28 31 29 5d 20 3d 20 6c 69 73 74 28 6d 61 70  p(1)] = list(map
47d0: 28 73 74 72 2e 73 74 72 69 70 2c 20 6d 2e 67 72  (str.strip, m.gr
47e0: 6f 75 70 28 32 29 2e 73 70 6c 69 74 28 22 7c 22  oup(2).split("|"
47f0: 29 29 29 20 20 69 66 20 22 7c 22 20 69 6e 20 6d  )))  if "|" in m
4800: 2e 67 72 6f 75 70 28 32 29 20 20 65 6c 73 65 20  .group(2)  else 
4810: 20 5b 6d 2e 67 72 6f 75 70 28 32 29 2e 73 74 72   [m.group(2).str
4820: 69 70 28 29 2c 20 22 22 5d 0a 20 20 20 20 20 20  ip(), ""].      
4830: 20 20 65 6c 73 65 3a 0a 20 20 20 20 20 20 20 20    else:.        
4840: 20 20 20 20 70 72 69 6e 74 28 22 23 20 45 72 72      print("# Err
4850: 6f 72 2e 20 57 72 6f 6e 67 20 6f 70 74 69 6f 6e  or. Wrong option
4860: 20 6c 69 6e 65 20 69 6e 3a 5c 6e 20 20 22 29 0a   line in:\n  ").
4870: 20 20 20 20 20 20 20 20 20 20 20 20 70 72 69 6e              prin
4880: 74 28 73 4c 69 6e 65 29 0a 20 20 20 20 70 72 69  t(sLine).    pri
4890: 6e 74 28 22 20 20 6f 70 74 69 6f 6e 73 20 64 65  nt("  options de
48a0: 66 69 6e 65 64 20 66 6f 72 3a 20 22 20 2b 20 22  fined for: " + "
48b0: 2c 20 22 2e 6a 6f 69 6e 28 5b 20 74 5b 30 5d 20  , ".join([ t[0] 
48c0: 66 6f 72 20 74 20 69 6e 20 6c 4f 70 74 20 5d 29  for t in lOpt ])
48d0: 29 0a 20 20 20 20 64 4f 70 74 69 6f 6e 73 20 3d  ).    dOptions =
48e0: 20 7b 0a 20 20 20 20 20 20 20 20 22 6c 53 74 72   {.        "lStr
48f0: 75 63 74 4f 70 74 22 3a 20 6c 53 74 72 75 63 74  uctOpt": lStruct
4900: 4f 70 74 2c 20 22 64 4f 70 74 4c 61 62 65 6c 22  Opt, "dOptLabel"
4910: 3a 20 64 4f 70 74 4c 61 62 65 6c 2c 20 22 73 44  : dOptLabel, "sD
4920: 65 66 61 75 6c 74 55 49 4c 61 6e 67 22 3a 20 73  efaultUILang": s
4930: 44 65 66 61 75 6c 74 55 49 4c 61 6e 67 2c 20 5c  DefaultUILang, \
4940: 0a 20 20 20 20 20 20 20 20 22 64 43 6f 6c 6f 72  .        "dColor
4950: 54 79 70 65 22 3a 20 63 72 65 61 74 65 43 6f 6c  Type": createCol
4960: 6f 72 73 28 64 43 6f 6c 6f 72 29 2c 20 22 64 4f  ors(dColor), "dO
4970: 70 74 43 6f 6c 6f 72 22 3a 20 7b 20 73 3a 20 64  ptColor": { s: d
4980: 20 20 66 6f 72 20 73 2c 20 64 20 69 6e 20 6c 4f    for s, d in lO
4990: 70 74 43 6f 6c 6f 72 20 7d 0a 20 20 20 20 7d 0a  ptColor }.    }.
49a0: 20 20 20 20 64 4f 70 74 69 6f 6e 73 2e 75 70 64      dOptions.upd
49b0: 61 74 65 28 7b 20 22 64 4f 70 74 22 2b 6b 3a 20  ate({ "dOpt"+k: 
49c0: 76 20 20 66 6f 72 20 6b 2c 20 76 20 69 6e 20 6c  v  for k, v in l
49d0: 4f 70 74 20 7d 29 0a 20 20 20 20 72 65 74 75 72  Opt }).    retur
49e0: 6e 20 64 4f 70 74 69 6f 6e 73 2c 20 64 4f 70 74  n dOptions, dOpt
49f0: 50 72 69 6f 72 69 74 79 0a 0a 0a 64 65 66 20 70  Priority...def p
4a00: 72 69 6e 74 42 6f 6f 6b 6d 61 72 6b 20 28 6e 4c  rintBookmark (nL
4a10: 65 76 65 6c 2c 20 73 43 6f 6d 6d 65 6e 74 2c 20  evel, sComment, 
4a20: 6e 4c 69 6e 65 29 3a 0a 20 20 20 20 22 70 72 69  nLine):.    "pri
4a30: 6e 74 20 62 6f 6f 6b 6d 61 72 6b 20 77 69 74 68  nt bookmark with
4a40: 69 6e 20 74 68 65 20 72 75 6c 65 73 20 66 69 6c  in the rules fil
4a50: 65 22 0a 20 20 20 20 70 72 69 6e 74 28 22 20 20  e".    print("  
4a60: 7b 3a 3e 36 7d 3a 20 20 7b 7d 22 2e 66 6f 72 6d  {:>6}:  {}".form
4a70: 61 74 28 6e 4c 69 6e 65 2c 20 22 20 20 22 20 2a  at(nLine, "  " *
4a80: 20 6e 4c 65 76 65 6c 20 2b 20 73 43 6f 6d 6d 65   nLevel + sComme
4a90: 6e 74 29 29 0a 0a 0a 64 65 66 20 6d 61 6b 65 20  nt))...def make 
4aa0: 28 73 70 4c 61 6e 67 2c 20 73 4c 61 6e 67 2c 20  (spLang, sLang, 
4ab0: 62 55 73 65 43 61 63 68 65 3d 4e 6f 6e 65 29 3a  bUseCache=None):
4ac0: 0a 20 20 20 20 22 63 6f 6d 70 69 6c 65 20 72 75  .    "compile ru
4ad0: 6c 65 73 2c 20 72 65 74 75 72 6e 73 20 61 20 64  les, returns a d
4ae0: 69 63 74 69 6f 6e 61 72 79 20 6f 66 20 76 61 6c  ictionary of val
4af0: 75 65 73 22 0a 20 20 20 20 23 20 66 6f 72 20 63  ues".    # for c
4b00: 6c 61 72 69 74 79 20 70 75 72 70 6f 73 65 2c 20  larity purpose, 
4b10: 64 6f 6e e2 80 99 74 20 63 72 65 61 74 65 20 61  don...t create a
4b20: 6e 79 20 66 69 6c 65 20 68 65 72 65 20 28 65 78  ny file here (ex
4b30: 63 65 70 74 20 63 61 63 68 65 29 0a 0a 20 20 20  cept cache)..   
4b40: 20 64 43 61 63 68 65 56 61 72 73 20 3d 20 4e 6f   dCacheVars = No
4b50: 6e 65 0a 0a 20 20 20 20 69 66 20 6f 73 2e 70 61  ne..    if os.pa
4b60: 74 68 2e 69 73 66 69 6c 65 28 22 5f 62 75 69 6c  th.isfile("_buil
4b70: 64 2f 64 61 74 61 5f 63 61 63 68 65 2e 6a 73 6f  d/data_cache.jso
4b80: 6e 22 29 3a 0a 20 20 20 20 20 20 20 20 70 72 69  n"):.        pri
4b90: 6e 74 28 22 3e 20 64 61 74 61 20 63 61 63 68 65  nt("> data cache
4ba0: 20 66 6f 75 6e 64 22 29 0a 20 20 20 20 20 20 20   found").       
4bb0: 20 73 4a 53 4f 4e 20 3d 20 6f 70 65 6e 28 22 5f   sJSON = open("_
4bc0: 62 75 69 6c 64 2f 64 61 74 61 5f 63 61 63 68 65  build/data_cache
4bd0: 2e 6a 73 6f 6e 22 2c 20 22 72 22 2c 20 65 6e 63  .json", "r", enc
4be0: 6f 64 69 6e 67 3d 22 75 74 66 2d 38 22 29 2e 72  oding="utf-8").r
4bf0: 65 61 64 28 29 0a 20 20 20 20 20 20 20 20 64 43  ead().        dC
4c00: 61 63 68 65 56 61 72 73 20 3d 20 6a 73 6f 6e 2e  acheVars = json.
4c10: 6c 6f 61 64 73 28 73 4a 53 4f 4e 29 0a 20 20 20  loads(sJSON).   
4c20: 20 20 20 20 20 73 42 75 69 6c 64 44 61 74 65 20       sBuildDate 
4c30: 3d 20 74 69 6d 65 2e 73 74 72 66 74 69 6d 65 28  = time.strftime(
4c40: 22 25 59 2d 25 6d 2d 25 64 20 25 48 3a 25 4d 3a  "%Y-%m-%d %H:%M:
4c50: 25 53 22 2c 20 74 69 6d 65 2e 67 6d 74 69 6d 65  %S", time.gmtime
4c60: 28 64 43 61 63 68 65 56 61 72 73 2e 67 65 74 28  (dCacheVars.get(
4c70: 22 66 42 75 69 6c 64 54 69 6d 65 22 2c 20 30 29  "fBuildTime", 0)
4c80: 29 29 0a 20 20 20 20 20 20 20 20 69 66 20 62 55  )).        if bU
4c90: 73 65 43 61 63 68 65 3a 0a 20 20 20 20 20 20 20  seCache:.       
4ca0: 20 20 20 20 20 70 72 69 6e 74 28 22 3e 20 75 73       print("> us
4cb0: 65 20 63 61 63 68 65 20 28 6e 6f 20 72 65 62 75  e cache (no rebu
4cc0: 69 6c 64 20 61 73 6b 65 64 29 22 29 0a 20 20 20  ild asked)").   
4cd0: 20 20 20 20 20 20 20 20 20 70 72 69 6e 74 28 22           print("
4ce0: 20 20 62 75 69 6c 64 20 6d 61 64 65 20 61 74 3a    build made at:
4cf0: 20 22 20 2b 20 73 42 75 69 6c 64 44 61 74 65 29   " + sBuildDate)
4d00: 0a 20 20 20 20 20 20 20 20 20 20 20 20 72 65 74  .            ret
4d10: 75 72 6e 20 64 43 61 63 68 65 56 61 72 73 0a 0a  urn dCacheVars..
4d20: 20 20 20 20 70 72 69 6e 74 28 22 3e 20 72 65 61      print("> rea
4d30: 64 20 72 75 6c 65 73 20 66 69 6c 65 2e 2e 2e 22  d rules file..."
4d40: 29 0a 20 20 20 20 74 72 79 3a 0a 20 20 20 20 20  ).    try:.     
4d50: 20 20 20 73 46 69 6c 65 43 6f 6e 74 65 6e 74 20     sFileContent 
4d60: 3d 20 6f 70 65 6e 28 73 70 4c 61 6e 67 20 2b 20  = open(spLang + 
4d70: 22 2f 72 75 6c 65 73 2e 67 72 78 22 2c 20 27 72  "/rules.grx", 'r
4d80: 27 2c 20 65 6e 63 6f 64 69 6e 67 3d 22 75 74 66  ', encoding="utf
4d90: 2d 38 22 29 2e 72 65 61 64 28 29 0a 20 20 20 20  -8").read().    
4da0: 65 78 63 65 70 74 20 4f 53 45 72 72 6f 72 3a 0a  except OSError:.
4db0: 20 20 20 20 20 20 20 20 70 72 69 6e 74 28 66 22          print(f"
4dc0: 23 20 45 72 72 6f 72 2e 20 52 75 6c 65 73 20 66  # Error. Rules f
4dd0: 69 6c 65 20 69 6e 20 70 72 6f 6a 65 63 74 20 3c  ile in project <
4de0: 7b 73 4c 61 6e 67 7d 3e 20 6e 6f 74 20 66 6f 75  {sLang}> not fou
4df0: 6e 64 2e 22 29 0a 20 20 20 20 20 20 20 20 65 78  nd.").        ex
4e00: 69 74 28 29 0a 0a 20 20 20 20 23 20 63 61 6c 63  it()..    # calc
4e10: 75 6c 61 74 65 20 68 61 73 68 20 6f 66 20 6c 6f  ulate hash of lo
4e20: 61 64 65 64 20 66 69 6c 65 0a 20 20 20 20 78 48  aded file.    xH
4e30: 61 73 68 65 72 20 3d 20 68 61 73 68 6c 69 62 2e  asher = hashlib.
4e40: 6e 65 77 28 22 73 68 61 33 5f 35 31 32 22 29 0a  new("sha3_512").
4e50: 20 20 20 20 78 48 61 73 68 65 72 2e 75 70 64 61      xHasher.upda
4e60: 74 65 28 73 46 69 6c 65 43 6f 6e 74 65 6e 74 2e  te(sFileContent.
4e70: 65 6e 63 6f 64 65 28 22 75 74 66 2d 38 22 29 29  encode("utf-8"))
4e80: 0a 20 20 20 20 73 46 69 6c 65 48 61 73 68 20 3d  .    sFileHash =
4e90: 20 78 48 61 73 68 65 72 2e 68 65 78 64 69 67 65   xHasher.hexdige
4ea0: 73 74 28 29 0a 0a 20 20 20 20 69 66 20 64 43 61  st()..    if dCa
4eb0: 63 68 65 56 61 72 73 20 61 6e 64 20 62 55 73 65  cheVars and bUse
4ec0: 43 61 63 68 65 20 21 3d 20 46 61 6c 73 65 20 61  Cache != False a
4ed0: 6e 64 20 73 46 69 6c 65 48 61 73 68 20 3d 3d 20  nd sFileHash == 
4ee0: 64 43 61 63 68 65 56 61 72 73 2e 67 65 74 28 22  dCacheVars.get("
4ef0: 73 46 69 6c 65 48 61 73 68 22 2c 20 22 22 29 3a  sFileHash", ""):
4f00: 0a 20 20 20 20 20 20 20 20 23 20 69 66 20 3c 62  .        # if <b
4f10: 55 73 65 43 61 63 68 65 3e 20 69 73 20 4e 6f 6e  UseCache> is Non
4f20: 65 20 6f 72 20 54 72 75 65 2c 20 77 65 20 63 61  e or True, we ca
4f30: 6e 20 75 73 65 20 74 68 65 20 63 61 63 68 65 0a  n use the cache.
4f40: 20 20 20 20 20 20 20 20 70 72 69 6e 74 28 22 3e          print(">
4f50: 20 63 61 63 68 65 20 68 61 73 68 20 69 64 65 6e   cache hash iden
4f60: 74 69 63 61 6c 20 74 6f 20 66 69 6c 65 20 68 61  tical to file ha
4f70: 73 68 2c 20 75 73 65 20 63 61 63 68 65 22 29 0a  sh, use cache").
4f80: 20 20 20 20 20 20 20 20 70 72 69 6e 74 28 22 20          print(" 
4f90: 20 62 75 69 6c 64 20 6d 61 64 65 20 61 74 3a 20   build made at: 
4fa0: 22 20 2b 20 73 42 75 69 6c 64 44 61 74 65 29 0a  " + sBuildDate).
4fb0: 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 64          return d
4fc0: 43 61 63 68 65 56 61 72 73 0a 0a 20 20 20 20 23  CacheVars..    #
4fd0: 20 72 65 6d 6f 76 69 6e 67 20 63 6f 6d 6d 65 6e   removing commen
4fe0: 74 73 2c 20 7a 65 72 6f 69 6e 67 20 65 6d 70 74  ts, zeroing empt
4ff0: 79 20 6c 69 6e 65 73 2c 20 63 72 65 61 74 69 6e  y lines, creatin
5000: 67 20 64 65 66 69 6e 69 74 69 6f 6e 73 2c 20 73  g definitions, s
5010: 74 6f 72 69 6e 67 20 74 65 73 74 73 2c 20 6d 65  toring tests, me
5020: 72 67 69 6e 67 20 72 75 6c 65 20 6c 69 6e 65 73  rging rule lines
5030: 0a 20 20 20 20 70 72 69 6e 74 28 22 20 20 70 61  .    print("  pa
5040: 72 73 69 6e 67 20 72 75 6c 65 73 2e 2e 2e 22 29  rsing rules...")
5050: 0a 20 20 20 20 66 42 75 69 6c 64 54 69 6d 65 20  .    fBuildTime 
5060: 3d 20 74 69 6d 65 2e 74 69 6d 65 28 29 0a 20 20  = time.time().  
5070: 20 20 6c 52 75 6c 65 4c 69 6e 65 20 3d 20 5b 5d    lRuleLine = []
5080: 0a 20 20 20 20 6c 54 65 73 74 20 3d 20 5b 5d 0a  .    lTest = [].
5090: 20 20 20 20 6c 4f 70 74 20 3d 20 5b 5d 0a 20 20      lOpt = [].  
50a0: 20 20 62 47 72 61 70 68 20 3d 20 46 61 6c 73 65    bGraph = False
50b0: 0a 20 20 20 20 6c 47 72 61 70 68 52 75 6c 65 20  .    lGraphRule 
50c0: 3d 20 5b 5d 0a 0a 20 20 20 20 66 6f 72 20 69 2c  = []..    for i,
50d0: 20 73 4c 69 6e 65 20 69 6e 20 65 6e 75 6d 65 72   sLine in enumer
50e0: 61 74 65 28 73 46 69 6c 65 43 6f 6e 74 65 6e 74  ate(sFileContent
50f0: 2e 73 70 6c 69 74 28 22 5c 6e 22 29 2c 20 31 29  .split("\n"), 1)
5100: 3a 0a 20 20 20 20 20 20 20 20 69 66 20 73 4c 69  :.        if sLi
5110: 6e 65 2e 73 74 61 72 74 73 77 69 74 68 28 27 23  ne.startswith('#
5120: 45 4e 44 27 29 3a 0a 20 20 20 20 20 20 20 20 20  END'):.         
5130: 20 20 20 23 20 61 72 62 69 74 72 61 72 79 20 65     # arbitrary e
5140: 6e 64 0a 20 20 20 20 20 20 20 20 20 20 20 20 70  nd.            p
5150: 72 69 6e 74 42 6f 6f 6b 6d 61 72 6b 28 30 2c 20  rintBookmark(0, 
5160: 22 42 52 45 41 4b 20 42 59 20 23 45 4e 44 22 2c  "BREAK BY #END",
5170: 20 69 29 0a 20 20 20 20 20 20 20 20 20 20 20 20   i).            
5180: 62 72 65 61 6b 0a 20 20 20 20 20 20 20 20 65 6c  break.        el
5190: 69 66 20 73 4c 69 6e 65 2e 73 74 61 72 74 73 77  if sLine.startsw
51a0: 69 74 68 28 28 22 23 22 2c 20 22 20 20 20 20 23  ith(("#", "    #
51b0: 23 22 29 29 3a 0a 20 20 20 20 20 20 20 20 20 20  #")):.          
51c0: 20 20 23 20 63 6f 6d 6d 65 6e 74 0a 20 20 20 20    # comment.    
51d0: 20 20 20 20 20 20 20 20 70 61 73 73 0a 20 20 20          pass.   
51e0: 20 20 20 20 20 65 6c 69 66 20 73 4c 69 6e 65 2e       elif sLine.
51f0: 73 74 61 72 74 73 77 69 74 68 28 22 44 45 46 3a  startswith("DEF:
5200: 22 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  "):.            
5210: 23 20 64 65 66 69 6e 69 74 69 6f 6e 0a 20 20 20  # definition.   
5220: 20 20 20 20 20 20 20 20 20 6d 20 3d 20 72 65 2e           m = re.
5230: 6d 61 74 63 68 28 22 44 45 46 3a 20 2b 28 5b 61  match("DEF: +([a
5240: 2d 7a 41 2d 5a 5f 5d 5b 61 2d 7a 41 2d 5a 5f 30  -zA-Z_][a-zA-Z_0
5250: 2d 39 5d 2a 29 20 2b 28 2e 2b 29 24 22 2c 20 73  -9]*) +(.+)$", s
5260: 4c 69 6e 65 2e 73 74 72 69 70 28 29 29 0a 20 20  Line.strip()).  
5270: 20 20 20 20 20 20 20 20 20 20 69 66 20 6d 3a 0a            if m:.
5280: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
5290: 64 44 45 46 49 4e 49 54 49 4f 4e 53 5b 22 7b 22  dDEFINITIONS["{"
52a0: 2b 6d 2e 67 72 6f 75 70 28 31 29 2b 22 7d 22 5d  +m.group(1)+"}"]
52b0: 20 3d 20 6d 2e 67 72 6f 75 70 28 32 29 0a 20 20   = m.group(2).  
52c0: 20 20 20 20 20 20 20 20 20 20 65 6c 73 65 3a 0a            else:.
52d0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
52e0: 70 72 69 6e 74 28 22 23 20 45 72 72 6f 72 20 69  print("# Error i
52f0: 6e 20 64 65 66 69 6e 69 74 69 6f 6e 3a 20 22 2c  n definition: ",
5300: 20 65 6e 64 3d 22 22 29 0a 20 20 20 20 20 20 20   end="").       
5310: 20 20 20 20 20 20 20 20 20 70 72 69 6e 74 28 73           print(s
5320: 4c 69 6e 65 2e 73 74 72 69 70 28 29 29 0a 20 20  Line.strip()).  
5330: 20 20 20 20 20 20 65 6c 69 66 20 73 4c 69 6e 65        elif sLine
5340: 2e 73 74 61 72 74 73 77 69 74 68 28 22 44 45 43  .startswith("DEC
5350: 4c 3a 22 29 3a 0a 20 20 20 20 20 20 20 20 20 20  L:"):.          
5360: 20 20 23 20 64 65 63 6c 65 6e 73 69 6f 6e 73 0a    # declensions.
5370: 20 20 20 20 20 20 20 20 20 20 20 20 6d 20 3d 20              m = 
5380: 72 65 2e 6d 61 74 63 68 28 72 22 44 45 43 4c 3a  re.match(r"DECL:
5390: 20 2b 28 5c 2b 5c 77 2b 29 20 28 2e 2b 29 24 22   +(\+\w+) (.+)$"
53a0: 2c 20 73 4c 69 6e 65 2e 73 74 72 69 70 28 29 29  , sLine.strip())
53b0: 0a 20 20 20 20 20 20 20 20 20 20 20 20 69 66 20  .            if 
53c0: 6d 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 20  m:.             
53d0: 20 20 20 64 44 45 43 4c 45 4e 53 49 4f 4e 53 5b     dDECLENSIONS[
53e0: 6d 2e 67 72 6f 75 70 28 31 29 5d 20 3d 20 6d 2e  m.group(1)] = m.
53f0: 67 72 6f 75 70 28 32 29 2e 73 74 72 69 70 28 29  group(2).strip()
5400: 2e 73 70 6c 69 74 28 29 0a 20 20 20 20 20 20 20  .split().       
5410: 20 20 20 20 20 65 6c 73 65 3a 0a 20 20 20 20 20       else:.     
5420: 20 20 20 20 20 20 20 20 20 20 20 70 72 69 6e 74             print
5430: 28 22 45 72 72 6f 72 20 69 6e 20 64 65 63 6c 65  ("Error in decle
5440: 6e 73 69 6f 6e 20 6c 69 73 74 3a 20 22 2c 20 65  nsion list: ", e
5450: 6e 64 3d 22 22 29 0a 20 20 20 20 20 20 20 20 20  nd="").         
5460: 20 20 20 20 20 20 20 70 72 69 6e 74 28 73 4c 69         print(sLi
5470: 6e 65 2e 73 74 72 69 70 28 29 29 0a 20 20 20 20  ne.strip()).    
5480: 20 20 20 20 65 6c 69 66 20 73 4c 69 6e 65 2e 73      elif sLine.s
5490: 74 61 72 74 73 77 69 74 68 28 22 54 45 53 54 3a  tartswith("TEST:
54a0: 22 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  "):.            
54b0: 23 20 74 65 73 74 0a 20 20 20 20 20 20 20 20 20  # test.         
54c0: 20 20 20 6c 54 65 73 74 2e 61 70 70 65 6e 64 28     lTest.append(
54d0: 22 7b 3a 3c 38 7d 22 2e 66 6f 72 6d 61 74 28 69  "{:<8}".format(i
54e0: 29 20 2b 20 22 20 20 22 20 2b 20 73 4c 69 6e 65  ) + "  " + sLine
54f0: 5b 35 3a 5d 2e 73 74 72 69 70 28 29 29 0a 20 20  [5:].strip()).  
5500: 20 20 20 20 20 20 65 6c 69 66 20 73 4c 69 6e 65        elif sLine
5510: 2e 73 74 61 72 74 73 77 69 74 68 28 22 54 4f 44  .startswith("TOD
5520: 4f 3a 22 29 3a 0a 20 20 20 20 20 20 20 20 20 20  O:"):.          
5530: 20 20 23 20 74 6f 64 6f 0a 20 20 20 20 20 20 20    # todo.       
5540: 20 20 20 20 20 70 61 73 73 0a 20 20 20 20 20 20       pass.      
5550: 20 20 65 6c 69 66 20 73 4c 69 6e 65 2e 73 74 61    elif sLine.sta
5560: 72 74 73 77 69 74 68 28 28 22 4f 50 54 47 52 4f  rtswith(("OPTGRO
5570: 55 50 2f 22 2c 20 22 4f 50 54 53 4f 46 54 57 41  UP/", "OPTSOFTWA
5580: 52 45 3a 22 2c 20 22 4f 50 54 2f 22 2c 20 5c 0a  RE:", "OPT/", \.
5590: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
55a0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
55b0: 22 43 4f 4c 4f 52 2f 22 2c 20 22 4f 50 54 43 4f  "COLOR/", "OPTCO
55c0: 4c 4f 52 54 48 45 4d 45 3a 22 2c 20 22 4f 50 54  LORTHEME:", "OPT
55d0: 43 4f 4c 4f 52 2f 22 2c 20 5c 0a 20 20 20 20 20  COLOR/", \.     
55e0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
55f0: 20 20 20 20 20 20 20 20 20 20 20 22 4f 50 54 4c             "OPTL
5600: 41 4e 47 2f 22 2c 20 22 4f 50 54 44 45 46 41 55  ANG/", "OPTDEFAU
5610: 4c 54 55 49 4c 41 4e 47 3a 22 2c 20 5c 0a 20 20  LTUILANG:", \.  
5620: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
5630: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 22 4f                "O
5640: 50 54 4c 41 42 45 4c 2f 22 2c 20 22 4f 50 54 50  PTLABEL/", "OPTP
5650: 52 49 4f 52 49 54 59 2f 22 29 29 3a 0a 20 20 20  RIORITY/")):.   
5660: 20 20 20 20 20 20 20 20 20 23 20 6f 70 74 69 6f           # optio
5670: 6e 73 0a 20 20 20 20 20 20 20 20 20 20 20 20 6c  ns.            l
5680: 4f 70 74 2e 61 70 70 65 6e 64 28 73 4c 69 6e 65  Opt.append(sLine
5690: 29 0a 20 20 20 20 20 20 20 20 65 6c 69 66 20 73  ).        elif s
56a0: 4c 69 6e 65 2e 73 74 61 72 74 73 77 69 74 68 28  Line.startswith(
56b0: 22 21 21 22 29 3a 0a 20 20 20 20 20 20 20 20 20  "!!"):.         
56c0: 20 20 20 23 20 62 6f 6f 6b 6d 61 72 6b 0a 20 20     # bookmark.  
56d0: 20 20 20 20 20 20 20 20 20 20 6d 20 3d 20 72 65            m = re
56e0: 2e 6d 61 74 63 68 28 22 21 21 2b 22 2c 20 73 4c  .match("!!+", sL
56f0: 69 6e 65 29 0a 20 20 20 20 20 20 20 20 20 20 20  ine).           
5700: 20 6e 45 78 4d 6b 20 3d 20 6c 65 6e 28 6d 2e 67   nExMk = len(m.g
5710: 72 6f 75 70 28 30 29 29 0a 20 20 20 20 20 20 20  roup(0)).       
5720: 20 20 20 20 20 69 66 20 73 4c 69 6e 65 5b 6e 45       if sLine[nE
5730: 78 4d 6b 3a 5d 2e 73 74 72 69 70 28 29 3a 0a 20  xMk:].strip():. 
5740: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 70                 p
5750: 72 69 6e 74 42 6f 6f 6b 6d 61 72 6b 28 6e 45 78  rintBookmark(nEx
5760: 4d 6b 2d 32 2c 20 73 4c 69 6e 65 5b 6e 45 78 4d  Mk-2, sLine[nExM
5770: 6b 3a 2d 33 5d 2e 73 74 72 69 70 28 29 2c 20 69  k:-3].strip(), i
5780: 29 0a 20 20 20 20 20 20 20 20 23 20 47 72 61 70  ).        # Grap
5790: 68 20 72 75 6c 65 73 0a 20 20 20 20 20 20 20 20  h rules.        
57a0: 65 6c 69 66 20 73 4c 69 6e 65 2e 73 74 61 72 74  elif sLine.start
57b0: 73 77 69 74 68 28 22 40 40 40 40 47 52 41 50 48  swith("@@@@GRAPH
57c0: 3a 22 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20  :"):.           
57d0: 20 23 20 72 75 6c 65 73 20 67 72 61 70 68 20 63   # rules graph c
57e0: 61 6c 6c 0a 20 20 20 20 20 20 20 20 20 20 20 20  all.            
57f0: 6d 20 3d 20 72 65 2e 6d 61 74 63 68 28 72 22 40  m = re.match(r"@
5800: 40 40 40 47 52 41 50 48 3a 20 2a 28 5c 77 2b 29  @@@GRAPH: *(\w+)
5810: 22 2c 20 73 4c 69 6e 65 2e 73 74 72 69 70 28 29  ", sLine.strip()
5820: 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 69 66  ).            if
5830: 20 6d 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20   m:.            
5840: 20 20 20 20 70 72 69 6e 74 42 6f 6f 6b 6d 61 72      printBookmar
5850: 6b 28 30 2c 20 22 47 52 41 50 48 3a 20 22 20 2b  k(0, "GRAPH: " +
5860: 20 6d 2e 67 72 6f 75 70 28 31 29 2c 20 69 29 0a   m.group(1), i).
5870: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
5880: 6c 52 75 6c 65 4c 69 6e 65 2e 61 70 70 65 6e 64  lRuleLine.append
5890: 28 5b 69 2c 20 22 40 40 40 40 22 2b 6d 2e 67 72  ([i, "@@@@"+m.gr
58a0: 6f 75 70 28 31 29 5d 29 0a 20 20 20 20 20 20 20  oup(1)]).       
58b0: 20 20 20 20 20 20 20 20 20 6c 47 72 61 70 68 52           lGraphR
58c0: 75 6c 65 2e 61 70 70 65 6e 64 28 5b 69 2c 20 73  ule.append([i, s
58d0: 4c 69 6e 65 5d 29 0a 20 20 20 20 20 20 20 20 20  Line]).         
58e0: 20 20 20 20 20 20 20 62 47 72 61 70 68 20 3d 20         bGraph = 
58f0: 54 72 75 65 0a 20 20 20 20 20 20 20 20 20 20 20  True.           
5900: 20 65 6c 73 65 3a 0a 20 20 20 20 20 20 20 20 20   else:.         
5910: 20 20 20 20 20 20 20 70 72 69 6e 74 28 22 47 72         print("Gr
5920: 61 70 68 20 65 72 72 6f 72 20 61 74 20 6c 69 6e  aph error at lin
5930: 65 22 2c 20 69 29 0a 20 20 20 20 20 20 20 20 65  e", i).        e
5940: 6c 69 66 20 73 4c 69 6e 65 2e 73 74 61 72 74 73  lif sLine.starts
5950: 77 69 74 68 28 28 22 40 40 40 40 45 4e 44 5f 47  with(("@@@@END_G
5960: 52 41 50 48 22 2c 20 22 40 40 40 40 45 4e 44 47  RAPH", "@@@@ENDG
5970: 52 41 50 48 22 29 29 3a 0a 20 20 20 20 20 20 20  RAPH")):.       
5980: 20 20 20 20 20 23 6c 47 72 61 70 68 52 75 6c 65       #lGraphRule
5990: 2e 61 70 70 65 6e 64 28 5b 69 2c 20 73 4c 69 6e  .append([i, sLin
59a0: 65 5d 29 0a 20 20 20 20 20 20 20 20 20 20 20 20  e]).            
59b0: 70 72 69 6e 74 42 6f 6f 6b 6d 61 72 6b 28 30 2c  printBookmark(0,
59c0: 20 22 45 4e 44 47 52 41 50 48 22 2c 20 69 29 0a   "ENDGRAPH", i).
59d0: 20 20 20 20 20 20 20 20 20 20 20 20 62 47 72 61              bGra
59e0: 70 68 20 3d 20 46 61 6c 73 65 0a 20 20 20 20 20  ph = False.     
59f0: 20 20 20 65 6c 69 66 20 72 65 2e 6d 61 74 63 68     elif re.match
5a00: 28 22 40 40 40 40 20 2a 24 22 2c 20 73 4c 69 6e  ("@@@@ *$", sLin
5a10: 65 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  e):.            
5a20: 70 61 73 73 0a 20 20 20 20 20 20 20 20 65 6c 69  pass.        eli
5a30: 66 20 62 47 72 61 70 68 3a 0a 20 20 20 20 20 20  f bGraph:.      
5a40: 20 20 20 20 20 20 6c 47 72 61 70 68 52 75 6c 65        lGraphRule
5a50: 2e 61 70 70 65 6e 64 28 5b 69 2c 20 73 4c 69 6e  .append([i, sLin
5a60: 65 5d 29 0a 20 20 20 20 20 20 20 20 23 20 52 65  e]).        # Re
5a70: 67 65 78 20 72 75 6c 65 73 0a 20 20 20 20 20 20  gex rules.      
5a80: 20 20 65 6c 69 66 20 72 65 2e 6d 61 74 63 68 28    elif re.match(
5a90: 22 5b 20 c2 a0 5c 74 5d 2a 24 22 2c 20 73 4c 69  "[ ..\t]*$", sLi
5aa0: 6e 65 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20  ne):.           
5ab0: 20 23 20 65 6d 70 74 79 20 6c 69 6e 65 0a 20 20   # empty line.  
5ac0: 20 20 20 20 20 20 20 20 20 20 70 61 73 73 0a 20            pass. 
5ad0: 20 20 20 20 20 20 20 65 6c 69 66 20 73 4c 69 6e         elif sLin
5ae0: 65 2e 73 74 61 72 74 73 77 69 74 68 28 22 20 20  e.startswith("  
5af0: 20 20 22 29 3a 0a 20 20 20 20 20 20 20 20 20 20    "):.          
5b00: 20 20 23 20 72 75 6c 65 20 28 63 6f 6e 74 69 6e    # rule (contin
5b10: 75 61 74 69 6f 6e 29 0a 20 20 20 20 20 20 20 20  uation).        
5b20: 20 20 20 20 6c 52 75 6c 65 4c 69 6e 65 5b 2d 31      lRuleLine[-1
5b30: 5d 5b 31 5d 20 2b 3d 20 22 20 22 20 2b 20 73 4c  ][1] += " " + sL
5b40: 69 6e 65 2e 73 74 72 69 70 28 29 0a 20 20 20 20  ine.strip().    
5b50: 20 20 20 20 65 6c 73 65 3a 0a 20 20 20 20 20 20      else:.      
5b60: 20 20 20 20 20 20 23 20 6e 65 77 20 72 75 6c 65        # new rule
5b70: 0a 20 20 20 20 20 20 20 20 20 20 20 20 6c 52 75  .            lRu
5b80: 6c 65 4c 69 6e 65 2e 61 70 70 65 6e 64 28 5b 69  leLine.append([i
5b90: 2c 20 73 4c 69 6e 65 2e 73 74 72 69 70 28 29 5d  , sLine.strip()]
5ba0: 29 0a 0a 20 20 20 20 23 20 67 65 6e 65 72 61 74  )..    # generat
5bb0: 69 6e 67 20 6f 70 74 69 6f 6e 73 20 66 69 6c 65  ing options file
5bc0: 73 0a 20 20 20 20 70 72 69 6e 74 28 22 20 20 70  s.    print("  p
5bd0: 61 72 73 69 6e 67 20 6f 70 74 69 6f 6e 73 2e 2e  arsing options..
5be0: 2e 22 29 0a 20 20 20 20 64 4f 70 74 69 6f 6e 73  .").    dOptions
5bf0: 2c 20 64 4f 70 74 50 72 69 6f 72 69 74 79 20 3d  , dOptPriority =
5c00: 20 70 72 65 70 61 72 65 4f 70 74 69 6f 6e 73 28   prepareOptions(
5c10: 6c 4f 70 74 29 0a 0a 20 20 20 20 23 20 74 65 73  lOpt)..    # tes
5c20: 74 73 0a 20 20 20 20 70 72 69 6e 74 28 22 20 20  ts.    print("  
5c30: 6c 69 73 74 20 74 65 73 74 73 2e 2e 2e 22 29 0a  list tests...").
5c40: 20 20 20 20 73 47 43 54 65 73 74 73 20 3d 20 22      sGCTests = "
5c50: 5c 6e 22 2e 6a 6f 69 6e 28 6c 54 65 73 74 29 0a  \n".join(lTest).
5c60: 20 20 20 20 73 47 43 54 65 73 74 73 4a 53 20 3d      sGCTestsJS =
5c70: 20 27 7b 20 22 61 44 61 74 61 22 3a 20 27 20 2b   '{ "aData": ' +
5c80: 20 6a 73 6f 6e 2e 64 75 6d 70 73 28 6c 54 65 73   json.dumps(lTes
5c90: 74 2c 20 65 6e 73 75 72 65 5f 61 73 63 69 69 3d  t, ensure_ascii=
5ca0: 46 61 6c 73 65 29 20 2b 20 22 20 7d 5c 6e 22 0a  False) + " }\n".
5cb0: 0a 20 20 20 20 23 20 70 72 6f 63 65 73 73 69 6e  .    # processin
5cc0: 67 0a 20 20 20 20 70 72 69 6e 74 28 22 20 20 70  g.    print("  p
5cd0: 72 65 70 61 72 69 6e 67 20 72 75 6c 65 73 2e 2e  reparing rules..
5ce0: 2e 22 29 0a 20 20 20 20 62 50 61 72 61 67 72 61  .").    bParagra
5cf0: 70 68 20 3d 20 54 72 75 65 0a 20 20 20 20 6c 50  ph = True.    lP
5d00: 61 72 61 67 72 61 70 68 52 75 6c 65 73 20 3d 20  aragraphRules = 
5d10: 5b 5d 0a 20 20 20 20 6c 53 65 6e 74 65 6e 63 65  [].    lSentence
5d20: 52 75 6c 65 73 20 3d 20 5b 5d 0a 20 20 20 20 6c  Rules = [].    l
5d30: 50 61 72 61 67 72 61 70 68 52 75 6c 65 73 4a 53  ParagraphRulesJS
5d40: 20 3d 20 5b 5d 0a 20 20 20 20 6c 53 65 6e 74 65   = [].    lSente
5d50: 6e 63 65 52 75 6c 65 73 4a 53 20 3d 20 5b 5d 0a  nceRulesJS = [].
5d60: 0a 20 20 20 20 66 6f 72 20 6e 4c 69 6e 65 2c 20  .    for nLine, 
5d70: 73 4c 69 6e 65 20 69 6e 20 6c 52 75 6c 65 4c 69  sLine in lRuleLi
5d80: 6e 65 3a 0a 20 20 20 20 20 20 20 20 69 66 20 73  ne:.        if s
5d90: 4c 69 6e 65 3a 0a 20 20 20 20 20 20 20 20 20 20  Line:.          
5da0: 20 20 69 66 20 73 4c 69 6e 65 20 3d 3d 20 22 5b    if sLine == "[
5db0: 2b 2b 5d 22 3a 0a 20 20 20 20 20 20 20 20 20 20  ++]":.          
5dc0: 20 20 20 20 20 20 62 50 61 72 61 67 72 61 70 68        bParagraph
5dd0: 20 3d 20 46 61 6c 73 65 0a 20 20 20 20 20 20 20   = False.       
5de0: 20 20 20 20 20 65 6c 73 65 3a 0a 20 20 20 20 20       else:.     
5df0: 20 20 20 20 20 20 20 20 20 20 20 61 52 75 6c 65             aRule
5e00: 20 3d 20 63 72 65 61 74 65 52 75 6c 65 28 73 4c   = createRule(sL
5e10: 69 6e 65 2c 20 6e 4c 69 6e 65 2c 20 73 4c 61 6e  ine, nLine, sLan
5e20: 67 2c 20 62 50 61 72 61 67 72 61 70 68 2c 20 64  g, bParagraph, d
5e30: 4f 70 74 50 72 69 6f 72 69 74 79 29 0a 20 20 20  OptPriority).   
5e40: 20 20 20 20 20 20 20 20 20 20 20 20 20 69 66 20               if 
5e50: 61 52 75 6c 65 3a 0a 20 20 20 20 20 20 20 20 20  aRule:.         
5e60: 20 20 20 20 20 20 20 20 20 20 20 69 66 20 62 50             if bP
5e70: 61 72 61 67 72 61 70 68 3a 0a 20 20 20 20 20 20  aragraph:.      
5e80: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
5e90: 20 20 6c 50 61 72 61 67 72 61 70 68 52 75 6c 65    lParagraphRule
5ea0: 73 2e 61 70 70 65 6e 64 28 61 52 75 6c 65 29 0a  s.append(aRule).
5eb0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
5ec0: 20 20 20 20 20 20 20 20 6c 50 61 72 61 67 72 61          lParagra
5ed0: 70 68 52 75 6c 65 73 4a 53 2e 61 70 70 65 6e 64  phRulesJS.append
5ee0: 28 6a 73 63 6f 6e 76 2e 70 79 52 75 6c 65 54 6f  (jsconv.pyRuleTo
5ef0: 4a 53 28 61 52 75 6c 65 2c 20 64 4a 53 52 45 47  JS(aRule, dJSREG
5f00: 45 58 45 53 2c 20 73 57 4f 52 44 4c 49 4d 49 54  EXES, sWORDLIMIT
5f10: 4c 45 46 54 29 29 0a 20 20 20 20 20 20 20 20 20  LEFT)).         
5f20: 20 20 20 20 20 20 20 20 20 20 20 65 6c 73 65 3a             else:
5f30: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
5f40: 20 20 20 20 20 20 20 20 20 6c 53 65 6e 74 65 6e           lSenten
5f50: 63 65 52 75 6c 65 73 2e 61 70 70 65 6e 64 28 61  ceRules.append(a
5f60: 52 75 6c 65 29 0a 20 20 20 20 20 20 20 20 20 20  Rule).          
5f70: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 6c 53                lS
5f80: 65 6e 74 65 6e 63 65 52 75 6c 65 73 4a 53 2e 61  entenceRulesJS.a
5f90: 70 70 65 6e 64 28 6a 73 63 6f 6e 76 2e 70 79 52  ppend(jsconv.pyR
5fa0: 75 6c 65 54 6f 4a 53 28 61 52 75 6c 65 2c 20 64  uleToJS(aRule, d
5fb0: 4a 53 52 45 47 45 58 45 53 2c 20 73 57 4f 52 44  JSREGEXES, sWORD
5fc0: 4c 49 4d 49 54 4c 45 46 54 29 29 0a 0a 20 20 20  LIMITLEFT))..   
5fd0: 20 23 20 63 72 65 61 74 69 6e 67 20 66 69 6c 65   # creating file
5fe0: 20 77 69 74 68 20 61 6c 6c 20 66 75 6e 63 74 69   with all functi
5ff0: 6f 6e 73 20 63 61 6c 6c 61 62 6c 65 20 62 79 20  ons callable by 
6000: 72 75 6c 65 73 0a 20 20 20 20 70 72 69 6e 74 28  rules.    print(
6010: 22 20 20 63 72 65 61 74 69 6e 67 20 63 61 6c 6c  "  creating call
6020: 61 62 6c 65 73 20 66 6f 72 20 72 65 67 65 78 20  ables for regex 
6030: 72 75 6c 65 73 2e 2e 2e 22 29 0a 20 20 20 20 73  rules...").    s
6040: 50 79 43 61 6c 6c 61 62 6c 65 73 20 3d 20 22 22  PyCallables = ""
6050: 0a 20 20 20 20 73 4a 53 43 61 6c 6c 61 62 6c 65  .    sJSCallable
6060: 73 20 3d 20 22 22 0a 20 20 20 20 66 6f 72 20 73  s = "".    for s
6070: 46 75 6e 63 4e 61 6d 65 2c 20 73 52 65 74 75 72  FuncName, sRetur
6080: 6e 20 69 6e 20 6c 46 55 4e 43 54 49 4f 4e 53 3a  n in lFUNCTIONS:
6090: 0a 20 20 20 20 20 20 20 20 69 66 20 73 46 75 6e  .        if sFun
60a0: 63 4e 61 6d 65 2e 73 74 61 72 74 73 77 69 74 68  cName.startswith
60b0: 28 22 5f 63 5f 22 29 3a 20 23 20 63 6f 6e 64 69  ("_c_"): # condi
60c0: 74 69 6f 6e 0a 20 20 20 20 20 20 20 20 20 20 20  tion.           
60d0: 20 73 50 61 72 61 6d 73 20 3d 20 22 73 53 65 6e   sParams = "sSen
60e0: 74 65 6e 63 65 2c 20 73 53 65 6e 74 65 6e 63 65  tence, sSentence
60f0: 30 2c 20 6d 2c 20 64 54 6f 6b 65 6e 50 6f 73 2c  0, m, dTokenPos,
6100: 20 73 43 6f 75 6e 74 72 79 2c 20 62 43 6f 6e 64   sCountry, bCond
6110: 4d 65 6d 6f 22 0a 20 20 20 20 20 20 20 20 65 6c  Memo".        el
6120: 69 66 20 73 46 75 6e 63 4e 61 6d 65 2e 73 74 61  if sFuncName.sta
6130: 72 74 73 77 69 74 68 28 22 5f 6d 5f 22 29 3a 20  rtswith("_m_"): 
6140: 23 20 6d 65 73 73 61 67 65 0a 20 20 20 20 20 20  # message.      
6150: 20 20 20 20 20 20 73 50 61 72 61 6d 73 20 3d 20        sParams = 
6160: 22 73 53 65 6e 74 65 6e 63 65 2c 20 6d 22 0a 20  "sSentence, m". 
6170: 20 20 20 20 20 20 20 65 6c 69 66 20 73 46 75 6e         elif sFun
6180: 63 4e 61 6d 65 2e 73 74 61 72 74 73 77 69 74 68  cName.startswith
6190: 28 22 5f 73 5f 22 29 3a 20 23 20 73 75 67 67 65  ("_s_"): # sugge
61a0: 73 74 69 6f 6e 0a 20 20 20 20 20 20 20 20 20 20  stion.          
61b0: 20 20 73 50 61 72 61 6d 73 20 3d 20 22 73 53 65    sParams = "sSe
61c0: 6e 74 65 6e 63 65 2c 20 6d 22 0a 20 20 20 20 20  ntence, m".     
61d0: 20 20 20 65 6c 69 66 20 73 46 75 6e 63 4e 61 6d     elif sFuncNam
61e0: 65 2e 73 74 61 72 74 73 77 69 74 68 28 22 5f 70  e.startswith("_p
61f0: 5f 22 29 3a 20 23 20 70 72 65 70 72 6f 63 65 73  _"): # preproces
6200: 73 6f 72 0a 20 20 20 20 20 20 20 20 20 20 20 20  sor.            
6210: 73 50 61 72 61 6d 73 20 3d 20 22 73 53 65 6e 74  sParams = "sSent
6220: 65 6e 63 65 2c 20 6d 22 0a 20 20 20 20 20 20 20  ence, m".       
6230: 20 65 6c 69 66 20 73 46 75 6e 63 4e 61 6d 65 2e   elif sFuncName.
6240: 73 74 61 72 74 73 77 69 74 68 28 22 5f 64 5f 22  startswith("_d_"
6250: 29 3a 20 23 20 64 69 73 61 6d 62 69 67 75 61 74  ): # disambiguat
6260: 6f 72 0a 20 20 20 20 20 20 20 20 20 20 20 20 73  or.            s
6270: 50 61 72 61 6d 73 20 3d 20 22 73 53 65 6e 74 65  Params = "sSente
6280: 6e 63 65 2c 20 6d 2c 20 64 54 6f 6b 65 6e 50 6f  nce, m, dTokenPo
6290: 73 22 0a 20 20 20 20 20 20 20 20 65 6c 73 65 3a  s".        else:
62a0: 0a 20 20 20 20 20 20 20 20 20 20 20 20 70 72 69  .            pri
62b0: 6e 74 28 66 22 23 20 55 6e 6b 6e 6f 77 6e 20 66  nt(f"# Unknown f
62c0: 75 6e 63 74 69 6f 6e 20 74 79 70 65 20 69 6e 20  unction type in 
62d0: 3c 7b 73 46 75 6e 63 4e 61 6d 65 7d 3e 22 29 0a  <{sFuncName}>").
62e0: 20 20 20 20 20 20 20 20 20 20 20 20 63 6f 6e 74              cont
62f0: 69 6e 75 65 0a 20 20 20 20 20 20 20 20 23 20 50  inue.        # P
6300: 79 74 68 6f 6e 0a 20 20 20 20 20 20 20 20 73 50  ython.        sP
6310: 79 43 61 6c 6c 61 62 6c 65 73 20 2b 3d 20 66 22  yCallables += f"
6320: 64 65 66 20 7b 73 46 75 6e 63 4e 61 6d 65 7d 20  def {sFuncName} 
6330: 28 7b 73 50 61 72 61 6d 73 7d 29 3a 5c 6e 22 0a  ({sParams}):\n".
6340: 20 20 20 20 20 20 20 20 73 50 79 43 61 6c 6c 61          sPyCalla
6350: 62 6c 65 73 20 2b 3d 20 66 22 20 20 20 20 72 65  bles += f"    re
6360: 74 75 72 6e 20 7b 73 52 65 74 75 72 6e 7d 5c 6e  turn {sReturn}\n
6370: 22 0a 20 20 20 20 20 20 20 20 23 20 4a 61 76 61  ".        # Java
6380: 53 63 72 69 70 74 0a 20 20 20 20 20 20 20 20 73  Script.        s
6390: 4a 53 43 61 6c 6c 61 62 6c 65 73 20 2b 3d 20 66  JSCallables += f
63a0: 22 20 20 20 20 7b 73 46 75 6e 63 4e 61 6d 65 7d  "    {sFuncName}
63b0: 3a 20 66 75 6e 63 74 69 6f 6e 20 28 7b 73 50 61  : function ({sPa
63c0: 72 61 6d 73 7d 29 20 7b 7b 5c 6e 22 0a 20 20 20  rams}) {{\n".   
63d0: 20 20 20 20 20 73 4a 53 43 61 6c 6c 61 62 6c 65       sJSCallable
63e0: 73 20 2b 3d 20 22 20 20 20 20 20 20 20 20 72 65  s += "        re
63f0: 74 75 72 6e 20 22 20 2b 20 6a 73 63 6f 6e 76 2e  turn " + jsconv.
6400: 70 79 32 6a 73 28 73 52 65 74 75 72 6e 29 20 2b  py2js(sReturn) +
6410: 20 22 3b 5c 6e 22 0a 20 20 20 20 20 20 20 20 73   ";\n".        s
6420: 4a 53 43 61 6c 6c 61 62 6c 65 73 20 2b 3d 20 22  JSCallables += "
6430: 20 20 20 20 7d 2c 5c 6e 22 0a 0a 20 20 20 20 64      },\n"..    d
6440: 69 73 70 6c 61 79 53 74 61 74 73 28 6c 50 61 72  isplayStats(lPar
6450: 61 67 72 61 70 68 52 75 6c 65 73 2c 20 6c 53 65  agraphRules, lSe
6460: 6e 74 65 6e 63 65 52 75 6c 65 73 29 0a 0a 20 20  ntenceRules)..  
6470: 20 20 64 56 61 72 73 20 3d 20 7b 0a 20 20 20 20    dVars = {.    
6480: 20 20 20 20 22 66 42 75 69 6c 64 54 69 6d 65 22      "fBuildTime"
6490: 3a 20 66 42 75 69 6c 64 54 69 6d 65 2c 0a 20 20  : fBuildTime,.  
64a0: 20 20 20 20 20 20 22 73 46 69 6c 65 48 61 73 68        "sFileHash
64b0: 22 3a 20 73 46 69 6c 65 48 61 73 68 2c 0a 20 20  ": sFileHash,.  
64c0: 20 20 20 20 20 20 22 63 61 6c 6c 61 62 6c 65 73        "callables
64d0: 22 3a 20 73 50 79 43 61 6c 6c 61 62 6c 65 73 2c  ": sPyCallables,
64e0: 0a 20 20 20 20 20 20 20 20 22 63 61 6c 6c 61 62  .        "callab
64f0: 6c 65 73 4a 53 22 3a 20 73 4a 53 43 61 6c 6c 61  lesJS": sJSCalla
6500: 62 6c 65 73 2c 0a 20 20 20 20 20 20 20 20 22 67  bles,.        "g
6510: 63 74 65 73 74 73 22 3a 20 73 47 43 54 65 73 74  ctests": sGCTest
6520: 73 2c 0a 20 20 20 20 20 20 20 20 22 67 63 74 65  s,.        "gcte
6530: 73 74 73 4a 53 22 3a 20 73 47 43 54 65 73 74 73  stsJS": sGCTests
6540: 4a 53 2c 0a 20 20 20 20 20 20 20 20 22 70 61 72  JS,.        "par
6550: 61 67 72 61 70 68 5f 72 75 6c 65 73 22 3a 20 63  agraph_rules": c
6560: 72 65 61 74 65 52 75 6c 65 73 41 73 53 74 72 69  reateRulesAsStri
6570: 6e 67 28 6d 65 72 67 65 52 75 6c 65 73 42 79 4f  ng(mergeRulesByO
6580: 70 74 69 6f 6e 28 6c 50 61 72 61 67 72 61 70 68  ption(lParagraph
6590: 52 75 6c 65 73 29 29 2c 0a 20 20 20 20 20 20 20  Rules)),.       
65a0: 20 22 73 65 6e 74 65 6e 63 65 5f 72 75 6c 65 73   "sentence_rules
65b0: 22 3a 20 63 72 65 61 74 65 52 75 6c 65 73 41 73  ": createRulesAs
65c0: 53 74 72 69 6e 67 28 6d 65 72 67 65 52 75 6c 65  String(mergeRule
65d0: 73 42 79 4f 70 74 69 6f 6e 28 6c 53 65 6e 74 65  sByOption(lSente
65e0: 6e 63 65 52 75 6c 65 73 29 29 2c 0a 20 20 20 20  nceRules)),.    
65f0: 20 20 20 20 22 70 61 72 61 67 72 61 70 68 5f 72      "paragraph_r
6600: 75 6c 65 73 5f 4a 53 22 3a 20 6a 73 63 6f 6e 76  ules_JS": jsconv
6610: 2e 77 72 69 74 65 52 75 6c 65 73 54 6f 4a 53 41  .writeRulesToJSA
6620: 72 72 61 79 28 6d 65 72 67 65 52 75 6c 65 73 42  rray(mergeRulesB
6630: 79 4f 70 74 69 6f 6e 28 6c 50 61 72 61 67 72 61  yOption(lParagra
6640: 70 68 52 75 6c 65 73 4a 53 29 29 2c 0a 20 20 20  phRulesJS)),.   
6650: 20 20 20 20 20 22 73 65 6e 74 65 6e 63 65 5f 72       "sentence_r
6660: 75 6c 65 73 5f 4a 53 22 3a 20 6a 73 63 6f 6e 76  ules_JS": jsconv
6670: 2e 77 72 69 74 65 52 75 6c 65 73 54 6f 4a 53 41  .writeRulesToJSA
6680: 72 72 61 79 28 6d 65 72 67 65 52 75 6c 65 73 42  rray(mergeRulesB
6690: 79 4f 70 74 69 6f 6e 28 6c 53 65 6e 74 65 6e 63  yOption(lSentenc
66a0: 65 52 75 6c 65 73 4a 53 29 29 0a 20 20 20 20 7d  eRulesJS)).    }
66b0: 0a 20 20 20 20 64 56 61 72 73 2e 75 70 64 61 74  .    dVars.updat
66c0: 65 28 64 4f 70 74 69 6f 6e 73 29 0a 0a 20 20 20  e(dOptions)..   
66d0: 20 23 20 63 6f 6d 70 69 6c 65 20 67 72 61 70 68   # compile graph
66e0: 20 72 75 6c 65 73 0a 20 20 20 20 64 56 61 72 73   rules.    dVars
66f0: 32 20 3d 20 63 72 67 2e 6d 61 6b 65 28 6c 47 72  2 = crg.make(lGr
6700: 61 70 68 52 75 6c 65 2c 20 73 4c 61 6e 67 2c 20  aphRule, sLang, 
6710: 64 44 45 46 49 4e 49 54 49 4f 4e 53 2c 20 64 44  dDEFINITIONS, dD
6720: 45 43 4c 45 4e 53 49 4f 4e 53 2c 20 64 4f 70 74  ECLENSIONS, dOpt
6730: 50 72 69 6f 72 69 74 79 29 0a 20 20 20 20 64 56  Priority).    dV
6740: 61 72 73 2e 75 70 64 61 74 65 28 64 56 61 72 73  ars.update(dVars
6750: 32 29 0a 0a 20 20 20 20 77 69 74 68 20 6f 70 65  2)..    with ope
6760: 6e 28 22 5f 62 75 69 6c 64 2f 64 61 74 61 5f 63  n("_build/data_c
6770: 61 63 68 65 2e 6a 73 6f 6e 22 2c 20 22 77 22 2c  ache.json", "w",
6780: 20 65 6e 63 6f 64 69 6e 67 3d 22 75 74 66 2d 38   encoding="utf-8
6790: 22 29 20 61 73 20 68 44 73 74 3a 0a 20 20 20 20  ") as hDst:.    
67a0: 20 20 20 20 68 44 73 74 2e 77 72 69 74 65 28 6a      hDst.write(j
67b0: 73 6f 6e 2e 64 75 6d 70 73 28 64 56 61 72 73 2c  son.dumps(dVars,
67c0: 20 65 6e 73 75 72 65 5f 61 73 63 69 69 3d 46 61   ensure_ascii=Fa
67d0: 6c 73 65 29 29 0a 20 20 20 20 72 65 74 75 72 6e  lse)).    return
67e0: 20 64 56 61 72 73 0a                              dVars.