[0001]
[0002]
[0003]
[0004]
[0005]
[0006]
[0007]
[0008]
[0009]
[0010]
[0011]
[0012]
[0013]
[0014]
[0015]
[0016]
[0017]
[0018]
[0019]
[0020]
[0021]
[0022]
[0023]
[0024]
[0025]
[0026]
[0027]
[0028]
[0029]
[0030]
[0031]
[0032]
[0033]
[0034]
[0035]
[0036]
[0037]
[0038]
[0039]
[0040]
[0041]
[0042]
[0043]
[0044]
[0045]
[0046]
[0047]
[0048]
[0049]
[0050]
[0051]
[0052]
[0053]
[0054]
[0055]
[0056]
[0057]
[0058]
[0059]
[0060]
[0061]
[0062]
[0063]
[0064]
[0065]
[0066]
[0067]
[0068]
[0069]
[0070]
[0071]
[0072]
[0073]
[0074]
[0075]
[0076]
[0077]
[0078]
[0079]
[0080]
[0081]
[0082]
[0083]
[0084]
[0085]
[0086]
[0087]
[0088]
[0089]
[0090]
[0091]
[0092]
[0093]
[0094]
[0095]
[0096]
[0097]
[0098]
[0099]
[0100]
[0101]
[0102]
[0103]
[0104]
[0105]
[0106]
[0107]
[0108]
[0109]
[0110]
[0111]
[0112]
[0113]
[0114]
[0115]
[0116]
[0117]
[0118]
[0119]
[0120]
[0121]
[0122]
[0123]
[0124]
[0125]
[0126]
[0127]
[0128]
[0129]
[0130]
[0131]
[0132]
[0133]
[0134]
[0135]
[0136]
[0137]
[0138]
[0139]
[0140]
[0141]
[0142]
[0143]
[0144]
[0145]
[0146]
[0147]
[0148]
[0149]
[0150]
[0151]
[0152]
[0153]
[0154]
[0155]
[0156]
[0157]
[0158]
[0159]
[0160]
[0161]
[0162]
[0163]
[0164]
[0165]
[0166]
[0167]
[0168]
[0169]
[0170]
[0171]
[0172]
[0173]
[0174]
[0175]
[0176]
[0177]
[0178]
[0179]
[0180]
[0181]
[0182]
[0183]
[0184]
[0185]
[0186]
[0187]
[0188]
[0189]
[0190]
[0191]
[0192]
[0193]
[0194]
[0195]
[0196]
[0197]
[0198]
[0199]
[0200]
[0201]
[0202]
[0203]
[0204]
[0205]
[0206]
[0207]
[0208]
[0209]
[0210]
[0211]
[0212]
[0213]
[0214]
[0215]
[0216]
[0217]
[0218]
[0219]
[0220]
[0221]
[0222]
[0223]
[0224]
[0225]
[0226]
[0227]
[0228]
[0229]
[0230]
[0231]
[0232]
[0233]
[0234]
[0235]
[0236]
[0237]
[0238]
[0239]
[0240]
[0241]
[0242]
[0243]
[0244]
[0245]
[0246]
[0247]
[0248]
[0249]
[0250]
[0251]
[0252]
[0253]
[0254]
[0255]
[0256]
[0257]
[0258]
[0259]
[0260]
[0261]
[0262]
[0263]
[0264]
[0265]
[0266]
[0267]
[0268]
[0269]
[0270]
[0271]
[0272]
[0273]
[0274]
[0275]
[0276]
[0277]
[0278]
[0279]
[0280]
[0281]
[0282]
[0283]
[0284]
[0285]
[0286]
[0287]
[0288]
[0289]
[0290]
[0291]
[0292]
[0293]
[0294]
[0295]
[0296]
[0297]
[0298]
[0299]
[0300]
[0301]
[0302]
[0303]
[0304]
[0305]
[0306]
[0307]
[0308]
[0309]
[0310]
[0311]
[0312]
[0313]
[0314]
[0315]
[0316]
[0317]
[0318]
[0319]
[0320]
[0321]
[0322]
[0323]
[0324]
[0325]
[0326]
[0327]
[0328]
[0329]
[0330]
[0331]
[0332]
[0333]
[0334]
[0335]
[0336]
[0337]
[0338]
[0339]
[0340]
[0341]
[0342]
[0343]
[0344]
[0345]
[0346]
[0347]
[0348]
[0349]
[0350]
[0351]
[0352]
[0353]
[0354]
[0355]
[0356]
[0357]
[0358]
[0359]
[0360]
[0361]
[0362]
[0363]
[0364]
[0365]
[0366]
[0367]
[0368]
[0369]
[0370]
[0371]
[0372]
[0373]
[0374]
[0375]
[0376]
[0377]
[0378]
[0379]
[0380]
[0381]
[0382]
[0383]
[0384]
[0385]
[0386]
[0387]
[0388]
[0389]
[0390]
[0391]
[0392]
[0393]
[0394]
[0395]
[0396]
[0397]
[0398]
[0399]
[0400]
[0401]
[0402]
[0403]
[0404]
[0405]
[0406]
[0407]
[0408]
[0409]
[0410]
[0411]
[0412]
[0413]
[0414]
[0415]
[0416]
[0417]
[0418]
[0419]
[0420]
[0421]
[0422]
[0423]
[0424]
[0425]
[0426]
[0427]
[0428]
[0429]
[0430]
[0431]
[0432]
[0433]
[0434]
[0435]
[0436]
[0437]
[0438]
[0439]
[0440]
[0441]
[0442]
[0443]
[0444]
[0445]
[0446]
[0447]
[0448]
[0449]
[0450]
[0451]
[0452]
[0453]
[0454]
[0455]
[0456]
[0457]
[0458]
[0459]
[0460]
[0461]
[0462]
[0463]
[0464]
[0465]
[0466]
[0467]
[0468]
[0469]
[0470]
[0471]
[0472]
[0473]
[0474]
[0475]
[0476]
[0477]
[0478]
[0479]
[0480]
[0481]
[0482]
[0483]
[0484]
[0485]
[0486]
[0487]
[0488]
[0489]
[0490]
[0491]
[0492]
[0493]
[0494]
[0495]
[0496]
[0497]
[0498]
[0499]
[0500]
[0501]
[0502]
[0503]
[0504]
[0505]
[0506]
[0507]
[0508]
[0509]
[0510]
[0511]
[0512]
[0513]
[0514]
[0515]
[0516]
[0517]
[0518]
[0519]
[0520]
[0521]
[0522]
[0523]
[0524]
[0525]
[0526]
[0527]
[0528]
[0529]
[0530]
[0531]
[0532]
[0533]
[0534]
[0535]
[0536]
[0537]
[0538]
[0539]
[0540]
[0541]
[0542]
[0543]
[0544]
[0545]
[0546]
[0547]
[0548]
[0549]
[0550]
[0551]
[0552]
[0553]
[0554]
[0555]
[0556]
[0557]
[0558]
[0559]
[0560]
[0561]
[0562]
[0563]
[0564]
[0565]
[0566]
[0567]
[0568]
[0569]
[0570]
[0571]
[0572]
[0573]
[0574]
[0575]
[0576]
[0577]
[0578]
[0579]
[0580]
[0581]
[0582]
[0583]
[0584]
[0585]
[0586]
[0587]
[0588]
[0589]
[0590]
[0591]
[0592]
[0593]
[0594]
[0595]
[0596]
[0597]
[0598]
[0599]
[0600]
[0601]
[0602]
[0603]
[0604]
[0605]
[0606]
[0607]
[0608]
[0609]
[0610]
[0611]
[0612]
[0613]
[0614]
[0615]
[0616]
[0617]
[0618]
[0619]
[0620]
[0621]
[0622]
[0623]
[0624]
[0625]
[0626]
[0627]
[0628]
[0629]
[0630]
[0631]
[0632]
[0633]
[0634]
[0635]
[0636]
[0637]
[0638]
[0639]
[0640]
[0641]
[0642]
[0643]
[0644]
[0645]
[0646]
[0647]
[0648]
[0649]
[0650]
[0651]
[0652]
[0653]
[0654]
[0655]
[0656]
[0657]
[0658]
[0659]
[0660]
[0661]
[0662]
[0663]
[0664]
[0665]
[0666]
[0667]
[0668]
[0669]
[0670]
[0671]
[0672]
[0673]
[0674]
[0675]
[0676]
[0677]
[0678]
[0679]
[0680]
[0681]
[0682]
[0683]
[0684]
[0685]
[0686]
[0687]
[0688]
[0689]
[0690]
[0691]
[0692]
[0693]
[0694]
[0695]
[0696]
[0697]
[0698]
[0699]
[0700]
[0701]
[0702]
[0703]
[0704]
[0705]
[0706]
[0707]
[0708]
[0709]
[0710]
[0711]
[0712]
[0713]
[0714]
[0715]
[0716]
[0717]
[0718]
[0719]
[0720]
[0721]
[0722]
[0723]
[0724]
[0725]
[0726]
[0727]
[0728]
[0729]
[0730]
[0731]
[0732]
[0733]
[0734]
[0735]
[0736]
[0737]
[0738]
[0739]
[0740]
[0741]
[0742]
[0743]
[0744]
[0745]
[0746]
[0747]
[0748]
[0749]
[0750]
[0751]
[0752]
[0753]
[0754]
[0755]
[0756]
[0757]
[0758]
[0759]
[0760]
[0761]
[0762]
[0763]
[0764]
[0765]
[0766]
[0767]
[0768]
[0769]
[0770]
[0771]
[0772]
[0773]
[0774]
[0775]
[0776]
[0777]
[0778]
[0779]
[0780]
[0781]
[0782]
[0783]
[0784]
[0785]
[0786]
[0787]
[0788]
[0789]
[0790]
[0791]
[0792]
[0793]
[0794]
[0795]
[0796]
[0797]
[0798]
[0799]
[0800]
[0801]
[0802]
[0803]
[0804]
[0805]
[0806]
[0807]
[0808]
[0809]
[0810]
[0811]
[0812]
[0813]
[0814]
[0815]
[0816]
[0817]
[0818]
[0819]
[0820]
[0821]
[0822]
[0823]
[0824]
[0825]
[0826]
[0827]
[0828]
[0829]
[0830]
[0831]
[0832]
[0833]
[0834]
[0835]
[0836]
[0837]
[0838]
[0839]
[0840]
[0841]
[0842]
[0843]
[0844]
[0845]
[0846]
[0847]
[0848]
[0849]
[0850]
[0851]
[0852]
[0853]
[0854]
[0855]
[0856]
[0857]
[0858]
[0859]
[0860]
[0861]
[0862]
[0863]
[0864]
[0865]
[0866]
[0867]
[0868]
[0869]
[0870]
[0871]
[0872]
[0873]
[0874]
[0875]
[0876]
[0877]
[0878]
[0879]
[0880]
[0881]
[0882]
[0883]
[0884]
[0885]
[0886]
[0887]
[0888]
[0889]
[0890]
[0891]
[0892]
[0893]
[0894]
[0895]
[0896]
[0897]
[0898]
[0899]
[0900]
[0901]
[0902]
[0903]
[0904]
[0905]
[0906]
[0907]
[0908]
[0909]
[0910]
[0911]
[0912]
[0913]
[0914]
[0915]
[0916]
[0917]
[0918]
[0919]
[0920]
[0921]
[0922]
[0923]
[0924]
[0925]
[0926]
[0927]
[0928]
[0929]
[0930]
[0931]
[0932]
[0933]
[0934]
[0935]
[0936]
[0937]
[0938]
[0939]
[0940]
[0941]
[0942]
[0943]
[0944]
[0945]
[0946]
[0947]
[0948]
[0949]
[0950]
[0951]
[0952]
[0953]
[0954]
[0955]
[0956]
[0957]
[0958]
[0959]
[0960]
[0961]
[0962]
[0963]
[0964]
[0965]
[0966]
[0967]
[0968]
[0969]
[0970]
[0971]
[0972]
[0973]
[0974]
[0975]
[0976]
[0977]
[0978]
[0979]
[0980]
[0981]
[0982]
[0983]
[0984]
[0985]
[0986]
[0987]
[0988]
[0989]
[0990]
[0991]
[0992]
[0993]
[0994]
[0995]
[0996]
[0997]
[0998]
[0999]
[1000]
[1001]
[1002]
[1003]
[1004]
[1005]
[1006]
[1007]
[1008]
[1009]
[1010]
[1011]
[1012]
[1013]
[1014]
[1015]
[1016]
[1017]
[1018]
[1019]
[1020]
[1021]
[1022]
[1023]
[1024]
[1025]
[1026]
[1027]
[1028]
[1029]
[1030]
[1031]
[1032]
[1033]
[1034]
[1035]
[1036]
[1037]
[1038]
[1039]
[1040]
[1041]
[1042]
[1043]
[1044]
[1045]
[1046]
[1047]
[1048]
[1049]
[1050]
[1051]
[1052]
[1053]
[1054]
[1055]
[1056]
[1057]
[1058]
[1059]
[1060]
[1061]
[1062]
[1063]
[1064]
[1065]
[1066]
[1067]
[1068]
[1069]
[1070]
[1071]
[1072]
[1073]
[1074]
[1075]
[1076]
[1077]
[1078]
[1079]
[1080]
[1081]
[1082]
[1083]
[1084]
[1085]
[1086]
[1087]
[1088]
[1089]
[1090]
[1091]
[1092]
[1093]
[1094]
[1095]
[1096]
[1097]
[1098]
[1099]
[1100]
[1101]
[1102]
[1103]
[1104]
[1105]
[1106]
[1107]
[1108]
[1109]
[1110]
[1111]
[1112]
[1113]
[1114]
[1115]
[1116]
[1117]
[1118]
[1119]
[1120]
[1121]
[1122]
[1123]
[1124]
[1125]
[1126]
[1127]
[1128]
[1129]
[1130]
[1131]
[1132]
[1133]
[1134]
[1135]
[1136]
[1137]
[1138]
[1139]
[1140]
[1141]
[1142]
[1143]
[1144]
[1145]
[1146]
[1147]
[1148]
[1149]
[1150]
[1151]
[1152]
[1153]
[1154]
[1155]
[1156]
[1157]
[1158]
[1159]
[1160]
[1161]
[1162]
[1163]
[1164]
[1165]
[1166]
[1167]
[1168]
[1169]
[1170]
[1171]
[1172]
[1173]
[1174]
[1175]
[1176]
[1177]
[1178]
[1179]
[1180]
[1181]
[1182]
[1183]
[1184]
[1185]
[1186]
[1187]
[1188]
[1189]
[1190]
[1191]
[1192]
[1193]
[1194]
[1195]
[1196]
[1197]
[1198]
[1199]
[1200]
[1201]
[1202]
[1203]
[1204]
[1205]
[1206]
[1207]
[1208]
[1209]
[1210]
[1211]
[1212]
[1213]
[1214]
[1215]
[1216]
[1217]
[1218]
[1219]
[1220]
[1221]
[1222]
[1223]
[1224]
[1225]
[1226]
[1227]
[1228]
[1229]
[1230]
[1231]
[1232]
[1233]
[1234]
[1235]
[1236]
[1237]
[1238]
[1239]
[1240]
[1241]
[1242]
[1243]
[1244]
[1245]
[1246]
[1247]
[1248]
[1249]
[1250]
[1251]
[1252]
[1253]
[1254]
[1255]
[1256]
[1257]
[1258]
[1259]
[1260]
[1261]
[1262]
[1263]
[1264]
[1265]
[1266]
[1267]
[1268]
[1269]
[1270]
[1271]
[1272]
[1273]
[1274]
[1275]
[1276]
[1277]
[1278]
[1279]
[1280]
[1281]
[1282]
[1283]
[1284]
[1285]
[1286]
[1287]
[1288]
[1289]
[1290]
[1291]
[1292]
[1293]
[1294]
[1295]
[1296]
[1297]
[1298]
[1299]
[1300]
[1301]
[1302]
[1303]
[1304]
[1305]
[1306]
[1307]
[1308]
[1309]
[1310]
[1311]
[1312]
[1313]
[1314]
[1315]
[1316]
[1317]
[1318]
[1319]
[1320]
[1321]
[1322]
[1323]
[1324]
[1325]
[1326]
[1327]
[1328]
[1329]
[1330]
[1331]
[1332]
[1333]
[1334]
[1335]
[1336]
[1337]
[1338]
[1339]
[1340]
[1341]
[1342]
[1343]
[1344]
[1345]
[1346]
[1347]
[1348]
[1349]
[1350]
[1351]
[1352]
[1353]
[1354]
[1355]
[1356]
[1357]
[1358]
[1359]
[1360]
[1361]
[1362]
[1363]
[1364]
[1365]
[1366]
[1367]
[1368]
[1369]
[1370]
[1371]
[1372]
[1373]
[1374]
[1375]
[1376]
[1377]
[1378]
[1379]
[1380]
[1381]
[1382]
[1383]
[1384]
[1385]
[1386]
[1387]
[1388]
[1389]
[1390]
[1391]
[1392]
[1393]
[1394]
[1395]
[1396]
[1397]
[1398]
[1399]
[1400]
[1401]
[1402]
[1403]
[1404]
[1405]
[1406]
[1407]
[1408]
[1409]
[1410]
[1411]
[1412]
[1413]
[1414]
[1415]
[1416]
[1417]
[1418]
[1419]
[1420]
[1421]
[1422]
[1423]
[1424]
[1425]
[1426]
[1427]
[1428]
[1429]
[1430]
[1431]
[1432]
[1433]
[1434]
[1435]
[1436]
[1437]
[1438]
[1439]
[1440]
[1441]
[1442]
[1443]
[1444]
[1445]
[1446]
[1447]
[1448]
[1449]
[1450]
[1451]
[1452]
[1453]
[1454]
[1455]
[1456]
[1457]
[1458]
[1459]
[1460]
[1461]
[1462]
[1463]
[1464]
[1465]
[1466]
[1467]
[1468]
[1469]
[1470]
[1471]
[1472]
[1473]
[1474]
[1475]
[1476]
[1477]
[1478]
[1479]
[1480]
[1481]
[1482]
[1483]
[1484]
[1485]
[1486]
[1487]
[1488]
[1489]
[1490]
[1491]
[1492]
[1493]
[1494]
[1495]
[1496]
[1497]
[1498]
[1499]
[1500]
[1501]
[1502]
[1503]
[1504]
[1505]
[1506]
[1507]
[1508]
[1509]
[1510]
[1511]
[1512]
[1513]
[1514]
[1515]
[1516]
[1517]
[1518]
[1519]
[1520]
[1521]
[1522]
[1523]
[1524]
[1525]
[1526]
[1527]
[1528]
[1529]
[1530]
[1531]
[1532]
[1533]
[1534]
[1535]
[1536]
[1537]
[1538]
[1539]
[1540]
[1541]
[1542]
[1543]
[1544]
[1545]
[1546]
[1547]
[1548]
[1549]
[1550]
[1551]
[1552]
[1553]
[1554]
[1555]
[1556]
[1557]
[1558]
[1559]
[1560]
[1561]
[1562]
[1563]
[1564]
[1565]
[1566]
[1567]
[1568]
[1569]
[1570]
[1571]
[1572]
[1573]
[1574]
[1575]
[1576]
[1577]
[1578]
[1579]
[1580]
[1581]
[1582]
[1583]
[1584]
[1585]
[1586]
[1587]
[1588]
[1589]
[1590]
[1591]
[1592]
[1593]
[1594]
[1595]
[1596]
[1597]
[1598]
[1599]
[1600]
[1601]
[1602]
[1603]
[1604]
[1605]
[1606]
[1607]
[1608]
[1609]
[1610]
[1611]
[1612]
[1613]
[1614]
[1615]
[1616]
[1617]
[1618]
[1619]
[1620]
[1621]
[1622]
[1623]
[1624]
[1625]
[1626]
[1627]
[1628]
[1629]
[1630]
[1631]
[1632]
[1633]
[1634]
[1635]
[1636]
[1637]
[1638]
[1639]
[1640]
[1641]
[1642]
[1643]
[1644]
[1645]
[1646]
[1647]
[1648]
[1649]
[1650]
[1651]
[1652]
[1653]
[1654]
[1655]
[1656]
[1657]
[1658]
[1659]
[1660]
[1661]
[1662]
[1663]
[1664]
[1665]
[1666]
[1667]
[1668]
[1669]
[1670]
[1671]
[1672]
[1673]
[1674]
[1675]
[1676]
[1677]
[1678]
[1679]
[1680]
[1681]
[1682]
[1683]
[1684]
[1685]
[1686]
[1687]
[1688]
[1689]
[1690]
[1691]
[1692]
[1693]
[1694]
[1695]
[1696]
[1697]
[1698]
[1699]
[1700]
[1701]
[1702]
[1703]
[1704]
[1705]
[1706]
[1707]
[1708]
[1709]
[1710]
[1711]
[1712]
[1713]
[1714]
[1715]
[1716]
[1717]
[1718]
[1719]
[1720]
[1721]
[1722]
[1723]
[1724]
[1725]
[1726]
[1727]
[1728]
[1729]
[1730]
[1731]
[1732]
[1733]
[1734]
[1735]
[1736]
[1737]
[1738]
[1739]
[1740]
[1741]
[1742]
[1743]
[1744]
[1745]
[1746]
[1747]
[1748]
[1749]
[1750]
[1751]
[1752]
[1753]
[1754]
[1755]
[1756]
[1757]
[1758]
[1759]
[1760]
[1761]
[1762]
[1763]
[1764]
[1765]
[1766]
[1767]
[1768]
[1769]
[1770]
[1771]
[1772]
[1773]
[1774]
[1775]
[1776]
[1777]
[1778]
[1779]
[1780]
[1781]
[1782]
[1783]
[1784]
[1785]
[1786]
[1787]
[1788]
[1789]
[1790]
[1791]
[1792]
[1793]
[1794]
[1795]
[1796]
[1797]
[1798]
[1799]
[1800]
[1801]
[1802]
[1803]
[1804]
[1805]
[1806]
[1807]
[1808]
[1809]
[1810]
[1811]
[1812]
[1813]
[1814]
[1815]
[1816]
[1817]
[1818]
[1819]
[1820]
[1821]
[1822]
[1823]
[1824]
[1825]
[1826]
[1827]
[1828]
[1829]
[1830]
[1831]
[1832]
[1833]
[1834]
[1835]
[1836]
[1837]
[1838]
[1839]
[1840]
[1841]
[1842]
[1843]
[1844]
[1845]
[1846]
[1847]
[1848]
[1849]
[1850]
[1851]
[1852]
[1853]
[1854]
[1855]
[1856]
[1857]
[1858]
[1859]
[1860]
[1861]
[1862]
[1863]
[1864]
[1865]
[1866]
[1867]
[1868]
[1869]
[1870]
[1871]
[1872]
[1873]
[1874]
[1875]
[1876]
[1877]
[1878]
[1879]
[1880]
[1881]
[1882]
[1883]
[1884]
[1885]
[1886]
[1887]
[1888]
[1889]
[1890]
[1891]
[1892]
[1893]
[1894]
[1895]
[1896]
[1897]
[1898]
[1899]
[1900]
[1901]
[1902]
[1903]
[1904]
[1905]
[1906]
[1907]
[1908]
[1909]
[1910]
[1911]
[1912]
[1913]
[1914]
[1915]
[1916]
[1917]
[1918]
[1919]
[1920]
[1921]
[1922]
[1923]
[1924]
[1925]
[1926]
[1927]
[1928]
[1929]
[1930]
[1931]
[1932]
[1933]
[1934]
[1935]
[1936]
[1937]
[1938]
[1939]
[1940]
[1941]
[1942]
[1943]
[1944]
[1945]
[1946]
[1947]
[1948]
[1949]
[1950]
[1951]
[1952]
[1953]
[1954]
[1955]
[1956]
[1957]
[1958]
[1959]
[1960]
[1961]
[1962]
[1963]
[1964]
[1965]
[1966]
[1967]
[1968]
[1969]
[1970]
[1971]
[1972]
[1973]
[1974]
[1975]
[1976]
[1977]
[1978]
[1979]
[1980]
[1981]
[1982]
[1983]
[1984]
[1985]
[1986]
[1987]
[1988]
[1989]
[1990]
[1991]
[1992]
[1993]
[1994]
[1995]
[1996]
[1997]
[1998]
[1999]
[2000]
[2001]
[2002]
[2003]
[2004]
[2005]
[2006]
[2007]
[2008]
[2009]
[2010]
[2011]
[2012]
[2013]
[2014]
[2015]
[2016]
[2017]
[2018]
[2019]
[2020]
[2021]
[2022]
[2023]
[2024]
[2025]
[2026]
[2027]
[2028]
[2029]
[2030]
[2031]
[2032]
[2033]
[2034]
[2035]
[2036]
[2037]
[2038]
[2039]
[2040]
[2041]
[2042]
[2043]
[2044]
[2045]
[2046]
[2047]
[2048]
[2049]
[2050]
[2051]
[2052]
[2053]
[2054]
[2055]
[2056]
[2057]
[2058]
[2059]
[2060]
[2061]
[2062]
[2063]
[2064]
[2065]
[2066]
[2067]
[2068]
[2069]
[2070]
[2071]
[2072]
[2073]
[2074]
[2075]
[2076]
[2077]
[2078]
[2079]
[2080]
[2081]
[2082]
[2083]
[2084]
[2085]
[2086]
[2087]
[2088]
[2089]
[2090]
[2091]
[2092]
[2093]
[2094]
[2095]
[2096]
[2097]
[2098]
[2099]
[2100]
[2101]
[2102]
[2103]
[2104]
[2105]
[2106]
[2107]
[2108]
[2109]
[2110]
[2111]
[2112]
[2113]
[2114]
[2115]
[2116]
[2117]
[2118]
[2119]
[2120]
[2121]
[2122]
[2123]
[2124]
[2125]
[2126]
[2127]
[2128]
[2129]
[2130]
[2131]
[2132]
[2133]
[2134]
[2135]
[2136]
[2137]
[2138]
[2139]
[2140]
[2141]
[2142]
[2143]
[2144]
[2145]
[2146]
[2147]
[2148]
[2149]
[2150]
[2151]
[2152]
[2153]
[2154]
[2155]
[2156]
[2157]
[2158]
[2159]
[2160]
[2161]
[2162]
[2163]
[2164]
[2165]
[2166]
[2167]
[2168]
[2169]
[2170]
[2171]
[2172]
[2173]
[2174]
[2175]
[2176]
[2177]
[2178]
[2179]
[2180]
[2181]
[2182]
[2183]
[2184]
[2185]
[2186]
[2187]
[2188]
[2189]
[2190]
[2191]
[2192]
[2193]
[2194]
[2195]
[2196]
[2197]
[2198]
[2199]
[2200]
[2201]
[2202]
[2203]
[2204]
[2205]
[2206]
[2207]
[2208]
[2209]
[2210]
[2211]
[2212]
[2213]
[2214]
[2215]
[2216]
[2217]
[2218]
[2219]
[2220]
[2221]
[2222]
[2223]
[2224]
[2225]
[2226]
[2227]
[2228]
[2229]
[2230]
[2231]
[2232]
[2233]
[2234]
[2235]
[2236]
[2237]
[2238]
[2239]
[2240]
[2241]
[2242]
[2243]
[2244]
[2245]
[2246]
[2247]
[2248]
[2249]
[2250]
[2251]
[2252]
[2253]
[2254]
[2255]
[2256]
[2257]
[2258]
[2259]
[2260]
[2261]
[2262]
[2263]
[2264]
[2265]
[2266]
[2267]
[2268]
[2269]
[2270]
[2271]
[2272]
[2273]
[2274]
[2275]
[2276]
[2277]
[2278]
[2279]
[2280]
[2281]
[2282]
[2283]
[2284]
[2285]
[2286]
[2287]
[2288]
[2289]
[2290]
[2291]
[2292]
[2293]
[2294]
[2295]
[2296]
[2297]
[2298]
[2299]
[2300]
[2301]
[2302]
[2303]
[2304]
[2305]
[2306]
[2307]
[2308]
[2309]
[2310]
[2311]
[2312]
[2313]
[2314]
[2315]
[2316]
[2317]
[2318]
[2319]
[2320]
[2321]
[2322]
[2323]
[2324]
[2325]
[2326]
[2327]
[2328]
[2329]
[2330]
[2331]
[2332]
[2333]
[2334]
[2335]
[2336]
[2337]
[2338]
[2339]
[2340]
[2341]
[2342]
[2343]
[2344]
[2345]
[2346]
[2347]
[2348]
[2349]
[2350]
[2351]
[2352]
[2353]
[2354]
[2355]
[2356]
[2357]
[2358]
[2359]
[2360]
[2361]
[2362]
[2363]
[2364]
[2365]
[2366]
[2367]
[2368]
[2369]
[2370]
[2371]
[2372]
[2373]
[2374]
[2375]
[2376]
[2377]
[2378]
[2379]
[2380]
[2381]
[2382]
[2383]
[2384]
[2385]
[2386]
[2387]
[2388]
[2389]
[2390]
[2391]
[2392]
[2393]
[2394]
[2395]
[2396]
[2397]
[2398]
[2399]
[2400]
[2401]
[2402]
[2403]
[2404]
[2405]
[2406]
[2407]
[2408]
[2409]
[2410]
[2411]
[2412]
[2413]
[2414]
[2415]
[2416]
[2417]
[2418]
[2419]
[2420]
[2421]
[2422]
[2423]
[2424]
[2425]
[2426]
[2427]
[2428]
[2429]
[2430]
[2431]
[2432]
[2433]
[2434]
[2435]
[2436]
[2437]
[2438]
[2439]
[2440]
[2441]
[2442]
[2443]
[2444]
[2445]
[2446]
[2447]
[2448]
[2449]
[2450]
[2451]
[2452]
[2453]
[2454]
[2455]
[2456]
[2457]
[2458]
[2459]
[2460]
[2461]
[2462]
[2463]
[2464]
[2465]
[2466]
[2467]
[2468]
[2469]
[2470]
[2471]
[2472]
[2473]
[2474]
[2475]
[2476]
[2477]
[2478]
[2479]
[2480]
[2481]
[2482]
[2483]
[2484]
[2485]
[2486]
[2487]
[2488]
[2489]
[2490]
[2491]
[2492]
[2493]
[2494]
[2495]
[2496]
[2497]
[2498]
[2499]
[2500]
[2501]
[2502]
[2503]
[2504]
[2505]
[2506]
[2507]
[2508]
[2509]
[2510]
[2511]
[2512]
[2513]
[2514]
[2515]
[2516]
[2517]
[2518]
[2519]
[2520]
[2521]
[2522]
[2523]
[2524]
[2525]
[2526]
[2527]
[2528]
[2529]
[2530]
[2531]
[2532]
[2533]
[2534]
[2535]
[2536]
[2537]
[2538]
[2539]
[2540]
[2541]
[2542]
[2543]
[2544]
[2545]
[2546]
[2547]
[2548]
[2549]
[2550]
[2551]
[2552]
[2553]
[2554]
[2555]
[2556]
[2557]
[2558]
[2559]
[2560]
[2561]
[2562]
[2563]
[2564]
[2565]
[2566]
[2567]
[2568]
[2569]
[2570]
[2571]
[2572]
[2573]
[2574]
[2575]
[2576]
[2577]
[2578]
[2579]
[2580]
[2581]
[2582]
[2583]
[2584]
[2585]
[2586]
[2587]
[2588]
[2589]
[2590]
[2591]
[2592]
[2593]
[2594]
[2595]
[2596]
[2597]
[2598]
[2599]
[2600]
[2601]
[2602]
[2603]
[2604]
[2605]
[2606]
[2607]
[2608]
[2609]
[2610]
[2611]
[2612]
[2613]
[2614]
[2615]
[2616]
[2617]
[2618]
[2619]
[2620]
[2621]
[2622]
[2623]
[2624]
[2625]
[2626]
[2627]
[2628]
[2629]
[2630]
[2631]
[2632]
[2633]
[2634]
[2635]
[2636]
[2637]
[2638]
[2639]
[2640]
[2641]
[2642]
[2643]
[2644]
[2645]
[2646]
[2647]
[2648]
[2649]
[2650]
[2651]
[2652]
[2653]
[2654]
[2655]
[2656]
[2657]
[2658]
[2659]
[2660]
[2661]
[2662]
[2663]
[2664]
[2665]
[2666]
[2667]
[2668]
[2669]
[2670]
[2671]
[2672]
[2673]
[2674]
[2675]
[2676]
[2677]
[2678]
[2679]
[2680]
[2681]
[2682]
[2683]
[2684]
[2685]
[2686]
[2687]
[2688]
[2689]
[2690]
[2691]
[2692]
[2693]
[2694]
[2695]
[2696]
[2697]
[2698]
[2699]
[2700]
[2701]
[2702]
[2703]
[2704]
[2705]
[2706]
[2707]
[2708]
[2709]
[2710]
[2711]
[2712]
[2713]
[2714]
[2715]
[2716]
[2717]
[2718]
[2719]
[2720]
[2721]
[2722]
[2723]
[2724]
[2725]
[2726]
[2727]
[2728]
[2729]
[2730]
[2731]
[2732]
[2733]
[2734]
[2735]
[2736]
[2737]
[2738]
[2739]
[2740]
[2741]
[2742]
[2743]
[2744]
[2745]
[2746]
[2747]
[2748]
[2749]
[2750]
[2751]
[2752]
[2753]
[2754]
[2755]
[2756]
[2757]
[2758]
[2759]
[2760]
[2761]
[2762]
[2763]
[2764]
[2765]
[2766]
[2767]
[2768]
[2769]
[2770]
[2771]
[2772]
[2773]
[2774]
[2775]
[2776]
[2777]
[2778]
[2779]
[2780]
[2781]
[2782]
[2783]
[2784]
[2785]
[2786]
[2787]
[2788]
[2789]
[2790]
[2791]
[2792]
[2793]
[2794]
[2795]
[2796]
[2797]
[2798]
[2799]
[2800]
[2801]
[2802]
[2803]
[2804]
[2805]
[2806]
[2807]
[2808]
[2809]
[2810]
[2811]
[2812]
[2813]
[2814]
[2815]
[2816]
[2817]
[2818]
[2819]
[2820]
[2821]
[2822]
[2823]
[2824]
[2825]
[2826]
[2827]
[2828]
[2829]
[2830]
[2831]
[2832]
[2833]
[2834]
[2835]
[2836]
[2837]
[2838]
[2839]
[2840]
[2841]
[2842]
[2843]
[2844]
[2845]
[2846]
[2847]
[2848]
[2849]
[2850]
[2851]
[2852]
[2853]
[2854]
[2855]
[2856]
[2857]
[2858]
[2859]
[2860]
[2861]
[2862]
[2863]
[2864]
[2865]
[2866]
[2867]
[2868]
[2869]
[2870]
[2871]
[2872]
[2873]
[2874]
[2875]
[2876]
[2877]
[2878]
[2879]
[2880]
[2881]
[2882]
[2883]
[2884]
[2885]
[2886]
[2887]
[2888]
[2889]
[2890]
[2891]
[2892]
[2893]
[2894]
[2895]
[2896]
[2897]
[2898]
[2899]
[2900]
[2901]
[2902]
[2903]
[2904]
[2905]
[2906]
[2907]
[2908]
[2909]
[2910]
[2911]
[2912]
[2913]
[2914]
[2915]
[2916]
[2917]
[2918]
[2919]
[2920]
[2921]
[2922]
[2923]
[2924]
[2925]
[2926]
[2927]
[2928]
[2929]
[2930]
[2931]
[2932]
[2933]
[2934]
[2935]
[2936]
[2937]
[2938]
[2939]
[2940]
[2941]
[2942]
[2943]
[2944]
[2945]
[2946]
[2947]
[2948]
[2949]
[2950]
[2951]
[2952]
[2953]
[2954]
[2955]
[2956]
[2957]
[2958]
[2959]
[2960]
[2961]
[2962]
[2963]
[2964]
[2965]
[2966]
[2967]
[2968]
[2969]
[2970]
[2971]
[2972]
[2973]
[2974]
[2975]
[2976]
[2977]
[2978]
[2979]
[2980]
[2981]
[2982]
[2983]
[2984]
[2985]
[2986]
[2987]
[2988]
[2989]
[2990]
[2991]
[2992]
[2993]
[2994]
[2995]
[2996]
[2997]
[2998]
[2999]
[3000]
[3001]
[3002]
[3003]
[3004]
[3005]
[3006]
[3007]
[3008]
[3009]
[3010]
[3011]
[3012]
[3013]
[3014]
[3015]
[3016]
[3017]
[3018]
[3019]
[3020]
[3021]
[3022]
[3023]
[3024]
[3025]
[3026]
[3027]
[3028]
[3029]
[3030]
[3031]
[3032]
[3033]
[3034]
[3035]
[3036]
[3037]
[3038]
[3039]
[3040]
[3041]
[3042]
[3043]
[3044]
[3045]
[3046]
[3047]
[3048]
[3049]
[3050]
[3051]
[3052]
[3053]
[3054]
[3055]
[3056]
[3057]
[3058]
[3059]
[3060]
[3061]
[3062]
[3063]
[3064]
[3065]
[3066]
[3067]
[3068]
[3069]
[3070]
[3071]
[3072]
[3073]
[3074]
[3075]
[3076]
[3077]
[3078]
[3079]
[3080]
[3081]
[3082]
[3083]
[3084]
[3085]
[3086]
[3087]
[3088]
[3089]
[3090]
[3091]
[3092]
[3093]
[3094]
[3095]
[3096]
[3097]
[3098]
[3099]
[3100]
[3101]
[3102]
[3103]
[3104]
[3105]
[3106]
[3107]
[3108]
[3109]
[3110]
[3111]
[3112]
[3113]
[3114]
[3115]
[3116]
[3117]
[3118]
[3119]
[3120]
[3121]
[3122]
[3123]
[3124]
[3125]
[3126]
[3127]
[3128]
[3129]
[3130]
[3131]
[3132]
[3133]
[3134]
[3135]
[3136]
[3137]
[3138]
[3139]
[3140]
[3141]
[3142]
[3143]
[3144]
[3145]
[3146]
[3147]
[3148]
[3149]
[3150]
[3151]
[3152]
[3153]
[3154]
[3155]
[3156]
[3157]
[3158]
[3159]
[3160]
[3161]
[3162]
[3163]
[3164]
[3165]
[3166]
[3167]
[3168]
[3169]
[3170]
[3171]
[3172]
[3173]
[3174]
[3175]
[3176]
[3177]
[3178]
[3179]
[3180]
[3181]
[3182]
[3183]
[3184]
[3185]
[3186]
[3187]
[3188]
[3189]
[3190]
[3191]
[3192]
[3193]
[3194]
[3195]
[3196]
[3197]
[3198]
[3199]
[3200]
[3201]
[3202]
[3203]
[3204]
[3205]
[3206]
[3207]
[3208]
[3209]
[3210]
[3211]
[3212]
[3213]
[3214]
[3215]
[3216]
[3217]
[3218]
[3219]
[3220]
[3221]
[3222]
[3223]
[3224]
[3225]
[3226]
[3227]
[3228]
[3229]
[3230]
[3231]
[3232]
[3233]
[3234]
[3235]
[3236]
[3237]
[3238]
[3239]
[3240]
[3241]
[3242]
[3243]
[3244]
[3245]
[3246]
[3247]
[3248]
[3249]
[3250]
[3251]
[3252]
[3253]
[3254]
[3255]
[3256]
[3257]
[3258]
[3259]
[3260]
[3261]
[3262]
[3263]
[3264]
[3265]
[3266]
[3267]
[3268]
[3269]
[3270]
[3271]
[3272]
[3273]
[3274]
[3275]
[3276]
[3277]
[3278]
[3279]
[3280]
[3281]
[3282]
[3283]
[3284]
[3285]
[3286]
[3287]
[3288]
[3289]
[3290]
[3291]
[3292]
[3293]
[3294]
[3295]
[3296]
[3297]
[3298]
[3299]
[3300]
[3301]
[3302]
[3303]
[3304]
[3305]
[3306]
[3307]
[3308]
[3309]
[3310]
[3311]
[3312]
[3313]
[3314]
[3315]
[3316]
[3317]
[3318]
[3319]
[3320]
[3321]
[3322]
[3323]
[3324]
[3325]
[3326]
[3327]
[3328]
[3329]
[3330]
[3331]
[3332]
[3333]
[3334]
[3335]
[3336]
[3337]
[3338]
[3339]
[3340]
[3341]
[3342]
[3343]
[3344]
[3345]
[3346]
[3347]
[3348]
[3349]
[3350]
[3351]
[3352]
[3353]
[3354]
[3355]
[3356]
[3357]
[3358]
[3359]
[3360]
[3361]
[3362]
[3363]
[3364]
[3365]
[3366]
[3367]
[3368]
[3369]
[3370]
[3371]
[3372]
[3373]
[3374]
[3375]
[3376]
[3377]
[3378]
[3379]
[3380]
[3381]
[3382]
[3383]
[3384]
[3385]
[3386]
[3387]
[3388]
[3389]
[3390]
[3391]
[3392]
[3393]
[3394]
[3395]
[3396]
[3397]
[3398]
[3399]
[3400]
[3401]
[3402]
[3403]
[3404]
[3405]
[3406]
[3407]
[3408]
[3409]
[3410]
[3411]
[3412]
[3413]
[3414]
[3415]
[3416]
[3417]
[3418]
[3419]
[3420]
[3421]
[3422]
[3423]
[3424]
[3425]
[3426]
[3427]
[3428]
[3429]
[3430]
[3431]
[3432]
[3433]
[3434]
[3435]
[3436]
[3437]
[3438]
[3439]
[3440]
[3441]
[3442]
[3443]
[3444]
[3445]
[3446]
[3447]
[3448]
[3449]
[3450]
[3451]
[3452]
[3453]
[3454]
[3455]
[3456]
[3457]
[3458]
[3459]
[3460]
[3461]
[3462]
[3463]
[3464]
[3465]
[3466]
[3467]
[3468]
[3469]
[3470]
[3471]
[3472]
[3473]
[3474]
[3475]
[3476]
[3477]
[3478]
[3479]
[3480]
[3481]
[3482]
[3483]
[3484]
[3485]
[3486]
[3487]
[3488]
[3489]
[3490]
[3491]
[3492]
[3493]
[3494]
[3495]
[3496]
[3497]
[3498]
[3499]
[3500]
[3501]
[3502]
[3503]
[3504]
[3505]
[3506]
[3507]
[3508]
[3509]
[3510]
[3511]
[3512]
[3513]
[3514]
[3515]
[3516]
[3517]
[3518]
[3519]
[3520]
[3521]
[3522]
[3523]
[3524]
[3525]
[3526]
[3527]
[3528]
[3529]
[3530]
[3531]
[3532]
[3533]
[3534]
[3535]
[3536]
[3537]
[3538]
[3539]
[3540]
[3541]
[3542]
[3543]
[3544]
[3545]
[3546]
[3547]
[3548]
[3549]
[3550]
[3551]
[3552]
[3553]
[3554]
[3555]
[3556]
[3557]
[3558]
[3559]
[3560]
[3561]
[3562]
[3563]
[3564]
[3565]
[3566]
[3567]
[3568]
[3569]
[3570]
[3571]
[3572]
[3573]
[3574]
[3575]
[3576]
[3577]
[3578]
[3579]
[3580]
[3581]
[3582]
[3583]
[3584]
[3585]
[3586]
[3587]
[3588]
[3589]
[3590]
[3591]
[3592]
[3593]
[3594]
[3595]
[3596]
[3597]
[3598]
[3599]
[3600]
[3601]
[3602]
[3603]
[3604]
[3605]
[3606]
[3607]
[3608]
[3609]
[3610]
[3611]
[3612]
[3613]
[3614]
[3615]
[3616]
[3617]
[3618]
[3619]
[3620]
[3621]
[3622]
[3623]
[3624]
[3625]
[3626]
[3627]
[3628]
[3629]
[3630]
[3631]
[3632]
[3633]
[3634]
[3635]
[3636]
[3637]
[3638]
[3639]
[3640]
[3641]
[3642]
[3643]
[3644]
[3645]
[3646]
[3647]
[3648]
[3649]
[3650]
[3651]
[3652]
[3653]
[3654]
[3655]
[3656]
[3657]
[3658]
[3659]
[3660]
[3661]
[3662]
[3663]
[3664]
[3665]
[3666]
[3667]
[3668]
[3669]
[3670]
[3671]
[3672]
[3673]
[3674]
[3675]
[3676]
[3677]
[3678]
[3679]
[3680]
[3681]
[3682]
[3683]
[3684]
[3685]
[3686]
[3687]
[3688]
[3689]
[3690]
[3691]
[3692]
[3693]
[3694]
[3695]
[3696]
[3697]
[3698]
[3699]
[3700]
[3701]
[3702]
[3703]
[3704]
[3705]
[3706]
[3707]
[3708]
[3709]
[3710]
[3711]
[3712]
[3713]
[3714]
[3715]
[3716]
[3717]
[3718]
[3719]
[3720]
[3721]
[3722]
[3723]
[3724]
[3725]
[3726]
[3727]
[3728]
[3729]
[3730]
[3731]
[3732]
[3733]
[3734]
[3735]
[3736]
[3737]
[3738]
[3739]
[3740]
[3741]
[3742]
[3743]
[3744]
[3745]
[3746]
[3747]
[3748]
[3749]
[3750]
[3751]
[3752]
[3753]
[3754]
[3755]
[3756]
[3757]
[3758]
[3759]
[3760]
[3761]
[3762]
[3763]
[3764]
[3765]
[3766]
[3767]
[3768]
[3769]
[3770]
[3771]
[3772]
[3773]
[3774]
[3775]
[3776]
[3777]
[3778]
[3779]
[3780]
[3781]
[3782]
[3783]
[3784]
[3785]
[3786]
[3787]
[3788]
[3789]
[3790]
[3791]
[3792]
[3793]
[3794]
[3795]
[3796]
[3797]
[3798]
[3799]
[3800]
[3801]
[3802]
[3803]
[3804]
[3805]
[3806]
[3807]
[3808]
[3809]
[3810]
[3811]
[3812]
[3813]
[3814]
[3815]
[3816]
[3817]
[3818]
[3819]
[3820]
[3821]
[3822]
[3823]
[3824]
[3825]
[3826]
[3827]
[3828]
[3829]
[3830]
[3831]
[3832]
[3833]
[3834]
[3835]
[3836]
[3837]
[3838]
[3839]
[3840]
[3841]
[3842]
[3843]
[3844]
[3845]
[3846]
[3847]
[3848]
[3849]
[3850]
[3851]
[3852]
[3853]
[3854]
[3855]
[3856]
[3857]
[3858]
[3859]
[3860]
[3861]
[3862]
[3863]
[3864]
[3865]
[3866]
[3867]
[3868]
[3869]
[3870]
[3871]
[3872]
[3873]
[3874]
[3875]
[3876]
[3877]
[3878]
[3879]
[3880]
[3881]
[3882]
[3883]
[3884]
[3885]
[3886]
[3887]
[3888]
[3889]
[3890]
[3891]
[3892]
[3893]
[3894]
[3895]
[3896]
[3897]
[3898]
[3899]
[3900]
[3901]
[3902]
[3903]
[3904]
[3905]
[3906]
[3907]
[3908]
[3909]
[3910]
[3911]
[3912]
[3913]
[3914]
[3915]
[3916]
[3917]
[3918]
[3919]
[3920]
[3921]
[3922]
[3923]
[3924]
[3925]
[3926]
[3927]
[3928]
[3929]
[3930]
[3931]
[3932]
[3933]
[3934]
[3935]
[3936]
[3937]
[3938]
[3939]
[3940]
[3941]
[3942]
[3943]
[3944]
[3945]
[3946]
[3947]
[3948]
[3949]
[3950]
[3951]
[3952]
[3953]
[3954]
[3955]
[3956]
[3957]
[3958]
[3959]
[3960]
[3961]
[3962]
[3963]
[3964]
[3965]
[3966]
[3967]
[3968]
[3969]
[3970]
[3971]
[3972]
[3973]
[3974]
[3975]
[3976]
[3977]
[3978]
[3979]
[3980]
[3981]
[3982]
[3983]
[3984]
[3985]
[3986]
[3987]
[3988]
[3989]
[3990]
[3991]
[3992]
[3993]
[3994]
[3995]
[3996]
[3997]
[3998]
[3999]
[4000]
[4001]
[4002]
[4003]
[4004]
[4005]
[4006]
[4007]
[4008]
[4009]
[4010]
[4011]
[4012]
[4013]
[4014]
[4015]
[4016]
[4017]
[4018]
[4019]
[4020]
[4021]
[4022]
[4023]
[4024]
[4025]
[4026]
[4027]
[4028]
[4029]
[4030]
[4031]
[4032]
[4033]
[4034]
[4035]
[4036]
[4037]
[4038]
[4039]
[4040]
[4041]
[4042]
[4043]
[4044]
[4045]
[4046]
[4047]
[4048]
[4049]
[4050]
[4051]
[4052]
[4053]
[4054]
[4055]
[4056]
[4057]
[4058]
[4059]
[4060]
[4061]
[4062]
[4063]
[4064]
[4065]
[4066]
[4067]
[4068]
[4069]
[4070]
[4071]
[4072]
[4073]
[4074]
[4075]
[4076]
[4077]
[4078]
[4079]
[4080]
[4081]
[4082]
[4083]
[4084]
[4085]
[4086]
[4087]
[4088]
[4089]
[4090]
[4091]
[4092]
[4093]
[4094]
[4095]
[4096]
[4097]
[4098]
[4099]
[4100]
[4101]
[4102]
[4103]
[4104]
[4105]
[4106]
[4107]
[4108]
[4109]
[4110]
[4111]
[4112]
[4113]
[4114]
[4115]
[4116]
[4117]
[4118]
[4119]
[4120]
[4121]
[4122]
[4123]
[4124]
[4125]
[4126]
[4127]
[4128]
[4129]
[4130]
[4131]
[4132]
[4133]
[4134]
[4135]
[4136]
[4137]
[4138]
[4139]
[4140]
[4141]
[4142]
[4143]
[4144]
[4145]
[4146]
[4147]
[4148]
[4149]
[4150]
[4151]
[4152]
[4153]
[4154]
[4155]
[4156]
[4157]
[4158]
[4159]
[4160]
[4161]
[4162]
[4163]
[4164]
[4165]
[4166]
[4167]
[4168]
[4169]
[4170]
[4171]
[4172]
[4173]
[4174]
[4175]
[4176]
[4177]
[4178]
[4179]
[4180]
[4181]
[4182]
[4183]
[4184]
[4185]
[4186]
[4187]
[4188]
[4189]
[4190]
[4191]
[4192]
[4193]
[4194]
[4195]
[4196]
[4197]
[4198]
[4199]
[4200]
[4201]
[4202]
[4203]
[4204]
[4205]
[4206]
[4207]
[4208]
[4209]
[4210]
[4211]
[4212]
[4213]
[4214]
[4215]
[4216]
[4217]
[4218]
[4219]
[4220]
[4221]
[4222]
[4223]
[4224]
[4225]
[4226]
[4227]
[4228]
[4229]
[4230]
[4231]
[4232]
[4233]
[4234]
[4235]
[4236]
[4237]
[4238]
[4239]
[4240]
[4241]
[4242]
[4243]
[4244]
[4245]
[4246]
[4247]
[4248]
[4249]
[4250]
[4251]
[4252]
[4253]
[4254]
[4255]
[4256]
[4257]
[4258]
[4259]
[4260]
[4261]
[4262]
[4263]
[4264]
[4265]
[4266]
[4267]
[4268]
[4269]
[4270]
[4271]
[4272]
[4273]
[4274]
[4275]
[4276]
[4277]
[4278]
[4279]
[4280]
[4281]
[4282]
[4283]
[4284]
[4285]
[4286]
[4287]
[4288]
[4289]
[4290]
[4291]
[4292]
[4293]
[4294]
[4295]
[4296]
[4297]
[4298]
[4299]
[4300]
[4301]
[4302]
[4303]
[4304]
[4305]
[4306]
[4307]
[4308]
[4309]
[4310]
[4311]
[4312]
[4313]
[4314]
[4315]
[4316]
[4317]
[4318]
[4319]
[4320]
[4321]
[4322]
[4323]
[4324]
[4325]
[4326]
[4327]
[4328]
[4329]
[4330]
[4331]
[4332]
[4333]
[4334]
[4335]
[4336]
[4337]
[4338]
[4339]
[4340]
[4341]
[4342]
[4343]
[4344]
[4345]
[4346]
[4347]
[4348]
[4349]
[4350]
[4351]
[4352]
[4353]
[4354]
[4355]
[4356]
[4357]
[4358]
[4359]
[4360]
[4361]
[4362]
[4363]
[4364]
[4365]
[4366]
[4367]
[4368]
[4369]
[4370]
[4371]
[4372]
[4373]
[4374]
[4375]
[4376]
[4377]
[4378]
[4379]
[4380]
[4381]
[4382]
[4383]
[4384]
[4385]
[4386]
[4387]
[4388]
[4389]
[4390]
[4391]
[4392]
[4393]
[4394]
[4395]
[4396]
[4397]
[4398]
[4399]
[4400]
[4401]
[4402]
[4403]
[4404]
[4405]
[4406]
[4407]
[4408]
[4409]
[4410]
[4411]
[4412]
[4413]
[4414]
[4415]
[4416]
[4417]
[4418]
[4419]
[4420]
[4421]
[4422]
[4423]
[4424]
[4425]
[4426]
[4427]
[4428]
[4429]
[4430]
[4431]
[4432]
[4433]
[4434]
[4435]
[4436]
[4437]
[4438]
[4439]
[4440]
[4441]
[4442]
[4443]
[4444]
[4445]
[4446]
[4447]
[4448]
[4449]
[4450]
[4451]
[4452]
[4453]
[4454]
[4455]
[4456]
[4457]
[4458]
[4459]
[4460]
[4461]
[4462]
[4463]
[4464]
[4465]
[4466]
[4467]
[4468]
[4469]
[4470]
[4471]
[4472]
[4473]
[4474]
[4475]
[4476]
[4477]
[4478]
[4479]
[4480]
[4481]
[4482]
[4483]
[4484]
[4485]
[4486]
[4487]
[4488]
[4489]
[4490]
[4491]
[4492]
[4493]
[4494]
[4495]
[4496]
[4497]
[4498]
[4499]
/*****************************************************************************/
/*
                                  render.c

This renders HTML5 syntax.

  https://www.w3.org/TR/html50/
  https://www.w3.org/TR/html52/
  https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5

Some HTML tags designated self-closing

  https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags

(<li>, <tr>, <th>, <td>) are left explicitly unclosed by this render engine.


wasDOC TAGS
-----------
There are basically two types of tag.

First; those that have punctuation immediately following the introducing vbar. 
These are text highlight flags and generally continue up to the first
alphabetic or period, escape or vbar character.  They are intended as terse
and syntactically efficient mechanisms to highlight narrative text.

Second; an alphabetic keyword follows the introducing vbar.  The keyword
optionally can have trailing highlight and formatting punctuation and allied
characters.  For this purpose the heading tags (|0..|4 and |9) are considered
keyword tags.  A keyword tag commonly (but by no means exclusively) operates on
an immediately following, vbar terminated parameter.  Sometimes more than one. 
No white-space is permitted between the keyword tag and any parameter.  Source
documents may be made more readable by judicious use of the line-escape (\<LF>).

The markup syntax has a lot of commonality but ultimately is pragmatic and some
inconsistency is sprinkled throughout the application.  Highlight and
formatting characters similarly have much in common but ultimately prostrate
themselves before what was necessary and worked.  And, of course, the absence
of a detailed design at the outset tends to manifest itself.

Brief mnemonic for tags:

|*bolded text|
|/italicised text|
|-strikethrough text|
|_underscored text|
|=monospace text|
|><centered text|
|>>no wrap|
|<<pre-wrap|
|"text not HTML escaped||
|'class.some text|
|&style.some text|

|0Heading without TOC entry|
|1Major Heading (toc 1)|
|2Sub Heading (toc 1.2)|
|3Further Sub Heading (toc 1.2.3)|
|4LowestSub Heading (toc 1.2.3.4)|
|5 n/a
|6 n/a
|7 n/a
|8 n/a
|9Cross-reference heading|

|asis|     completely unescaped text terminated by \n||||\n
|block|    block of content
|code|     function times2 (int num) { return num * 2; } |
|draw|     box drawing for simple diagrams
|example|  dashed line to delineate
|inline|   in-line block
|prop|     pre-formatted (proportional) text |
|mono|     monospace pre-formatted text |
|note|     note text |

|^         paragraph break (must be followed by white space)
|^+        paragraph indented
|^-        line break
|ppage|    page break when printed
|toc|      table of content inserted here
|index|    document index inserted here
|insert|param|   insert a file content, spawned command, or other data

NOTE: alternates are personal preference

|simple|   begin simple list
|sl|       ditto
|bullet|   begin unordered list
|ul|       ditto
|number|   begin unordered list
|ol|       ditto
|item|     list item
|li|       ditto
|&         ditto ("shorthand" form)
||         end list

NOTE: no explicit closure for table elements

|table|    table
|tablular| table
|row|      row of cells
|tr|       ditto
|~         ditto
|head|     header cell
|tr|       ditto
|:         ditto
|data|     data cell
|td|       ditto
|.         ditto
||         end of table

|image|image-name.jpg||
|image|//host/image-name.png|This is the caption|
|image|https://host/image-name.png|This is the caption|

|link|The Heading Name||
|link|link-URL|caption||
|link|https://an.example/|This is an Example||
|link+|https://an.example/|=In a New Tab/Page||

|if|          false
|if|0|        false
|if|1|        true
|if|dynamic|  a CGI script
|if|static|   not a CGI script
|if|multi|    multiple parts (chunked)
|if|single|   single part (not chunked)
|if|hide|     not visible unless ?nohide=1
|if|apache|   apache server
|if|wasd|     WASD server
|if|osu|      osu server
|elif|...|
|else|
|endif|
|if|+|        show conditional stack
|if|-|        disable show conditional stack

|break|     break as if the source was exhausted
|exit|      exit the document processor
|hide|      hide the HTML until a |resume|
|insight!|  a snapshot of the stack content
|insight@|  buttons to access the text and HTML and some stats
|print|     document section only in a printed version |
|noprint|   document section not in printed version |
|style|     set document style element

|set|chunked=..|      1 enables, 0 let the client decide, -1 disables
|set|idx=cols=..|     1, 2, 3, 4 columns in the index
|set|idx=sort=..|     index sorted 1, unsorted 0
|set|idx=collate=..|  collation characters for index (26 alphabetics default)
|set|insight=..|      1, 2, 3, 4 levels of informational
|set|locale=..|       set an aspect of C-locale (CTYPE)
|set|navigate=..|     1 enables navigation arrows
|set|note=..|         set default (e.g. non-English) note heading
|set|paginate=..|     enable automatic pagination (horizontal rules)
|set|table=margin=..| default table margin indicator
|set|title=..|        explicitly set the title of the document
|set|toc=cols=..|     1, 2, 3, 4 columns in the main Table Of Content
|set|toc2=..|         secondry TOC is generated
|set|toc2=cols=..|    1, 2, 3, 4 columns in the secondary Table Of Content
|set|FLAG=..|         set a flag value

// comment to end-of-line (except inside text as-is)


VERSION HISTORY
---------------
28-APR-2020  MGD  rework memory management
25-JAN-2020  MGD  add |draw| via drawThis()
07-JUL-2019  MGD  bugfix; broken nested conditionals
21-FEB-2019  MGD  initial
*/
/*****************************************************************************/

#include "wasdoc.h"
#include "css.h"
#include <locale.h>
#include <descrip.h>
#include <lnmdef.h>
#include <starlet.h>
#include <syidef.h>
#include <cgilib.h>

#ifndef STYLE_DEFAULT
#define STYLE_DEFAULT "<style type=\"text/css\">\n</style>\n"
#endif

char styleDefault [] = STYLE_DEFAULT;

extern int  bvbar, dbug,
            CgiPlusCount,
            isCgi,
            isCgiPlus;

extern char  CopyrightDate [], 
             SoftwareID [],
             SoftwareVersion [];

/*****************************************************************************/
/*
Parse the source text markup rendering the HTML document.
*/

int renderParse (struct wasdoc_st *docptr)

{
   static char  vtime [18];
   static $DESCRIPTOR (vtimeDsc, vtime);
   static $DESCRIPTOR (faoDsc, "!17%D\0");

   int  ch, error, idx, length;
   char  *aptr, *cptr, *sptr, *rowptr = NULL, *tagptr, *tptr,  *zptr;
   char  buf [1024],
         frag [128];

   /*********/
   /* begin */
   /*********/

   if (dbug>1) dbugThis (FI_LI, "renderParse()");

   docptr->asis = docptr->insightAt = docptr->noescape = 0;

   memset (docptr->section, 0, sizeof(docptr->section));
   for (idx = 0; idx < docptr->flagCount; idx++) free (docptr->flags[idx]); 
   docptr->flagCount = 0;
   docptr->conditional[docptr->conLevel = 0] = 1;

   if (!(tptr = docptr->text)) RETURN_FI_LI (docptr, SS$_NOSUCHOBJECT)

   /* to be applied to the whole document it needs to be handled up-front */
   for (cptr = tptr; *cptr && *cptr != '\n'; cptr++);
   while (*cptr == '\n') cptr++;
   if (MATCH12 (cptr, "|set|insight"))
   {
      error = renderSet (docptr, cptr+5);
      if (error) { SET_FI_LI (docptr); goto param_error; }
   }

   for (;;)
   {
      if (HMORE(docptr)) wasDocMoreHtml (docptr);

      if (!docptr->hlength)
      {
         sys$fao (&faoDsc, 0, &vtimeDsc, 0);
         error = wasDocPrintf (docptr,
"<!DOCTYPE html>\n\
<!-- %s%s%s%s -->\n\
<!-- wasDOC Copyright (C) %s Mark G.Daniel - Apache-2.0 licenced -->\n\
<!-- %s -->\n\
<noscript>NOTE: SOME FUNCTIONALITY EMPLOYS JAVASCRIPT</noscript>\n\
<div id=\"erreport1\" style=\"display:none;\"></div>\n\
<script>\n\
function errorReport(string) {\n\
   for (var cnt = 1; cnt <= 2; cnt++) {\n\
      var err = document.getElementById(\'erreport\'+cnt);\n\
      err.style.display = \'block\';\n\
      err.innerHTML += string;\n\
   }\n\
}\n\
</script>\n",
                          SoftwareID,
                          isCgi ? " CGI" : "",
                          isCgiPlus ? "plus" : "",
                          docptr->isDynamic ? " CLI" : "",
                          CopyrightDate,
                          vtime);
         if (docptr->errorValue) GOTO_FI_LI (docptr, insert_error)

         /* must follow the <!DOCTYPE..> */
         if (docptr->insight >= 2)
         {
            wasDocInsight (docptr, "BEGIN");
            if (docptr->insight >= 2)
               wasDocInsight (docptr, "%d/%d bytes",
                              docptr->hlength, docptr->hsize);
         }
      }

      /* Th-th-th-that's all folks! */
      if (!*tptr) break;

      if (docptr->conditional[docptr->conLevel] <= 0)
      {
         /******************/
         /* not processing */
         /******************/

         while (*tptr)
         {
            while (*tptr && *tptr != '|') tptr++;
            if (!*tptr) break;
            if (MATCH4 (tptr, "|if|") ||
                MATCH6 (tptr, "|elif|") ||
                MATCH6 (tptr, "|else|") ||
                MATCH7 (tptr, "|endif|"))
            {
               TPUT (docptr, tptr);
               error = renderCondition (docptr);
               if (error) GOTO_FI_LI (docptr, conditional_error) 
               TGET (docptr, tptr);
               if (docptr->conditional[docptr->conLevel] > 0) break;
            }
            else
            if (MATCH7 (tptr, "|break|"))
            {
               wasDocAsIs (docptr, "\n<!-- $$BREAK$$ -->\n");
               break;
            }
            else
            if (MATCH6 (tptr, "|exit|"))
            {
               wasDocAsIs (docptr, "\n<!-- $$EXIT$$ -->\n");
               return (SS$_ABORT);
            }
            else
               tptr++;
         }
         continue;
      }

      if (!isspace(*tptr))
      {
         if (!(*tptr == '|' && (MATCH5 (tptr, "|set|") ||
                                MATCH7 (tptr, "|style|"))))
         {
            /* provide default wasDOC style if not yet otherwise specified */
            if (!docptr->styled)
            {
               renderStyle (docptr, NULL);
               continue;
            }
         }
      }

      if (docptr->asis)
      {
         /********/
         /* asis */
         /********/

         /* as-is only terminated by \n||||\n (i.e 4 on a line by itself) */
         while (*tptr)
         {
            if (HMORE(docptr)) wasDocMoreHtml (docptr);

            if (*tptr == '\n')
            {   
               if (MATCH7 (tptr, "\n\\||||\n"))
               {
                  /* seems obvious this is needed if to be documented :-) */
                  HONE (docptr, tptr);
               }
               else
               if (MATCH6 (tptr, "\n||||\n"))
               {
                  if (docptr->insight >= 4) renderInsightTag (docptr);

                  /* 1 is "standalone" while 2 is a <div> */
                  if (docptr->asis == 2)
                  {
                     if (docptr->stindex > 0)
                     {
                        if (MATCH4 (docptr->cstack[docptr->stindex], "||||"))
                        {
                           /* turn it into a <div> closure */
                           wasDocAsIs (docptr, "</div>");
                           docptr->stindex--;
                        }
                     }
                  }
                  tptr += 6;
                  docptr->asis = 0;
                  break;
               }
            }
            HONE (docptr, tptr);
         }
         continue;
      }

      if (docptr->noescape)
      {
         /******************/
         /* no-HTML-escape */
         /******************/

         /* can only be terminated by || or |!"| */
         while (*tptr)
         {
            if (HMORE(docptr)) wasDocMoreHtml (docptr);

            if (docptr->insight >= 2)
               if (MATCH4 (tptr, "\\<!-"))
                  if (MATCH0 (tptr, "\\<!-- source:", 13))
                     renderInsightSource (docptr, tptr+13);

            if (*tptr == '\\')
            {
               if (MATCH2 (tptr, "\\\n"))
               {
                  /* escaped newline - no newline at all */
                  tptr += 2;
                  continue;
               }
               if (MATCH2 (tptr, "\\ "))
               {
                  /* escaped space */
                  tptr += 2;
                  wasDocAsIs (docptr, "&nbsp;");
                  continue;
               }
               if (MATCH2 (tptr, "\\|"))
               {
                  /* escaped bar */
                  tptr += 2;
                  wasDocAsIs (docptr, "&verbar;");
                  continue;
               }
               if (MATCH4 (tptr, "\\\\\\\\"))
               {
                  /* four consecutive backslashes just ignore */
                  tptr += 4;
                  continue;
               }
               if (!MATCH2 (tptr, "\\\0"))
               {
                  /* escape any other character */
                  tptr++;
                  HONE (docptr, tptr);
                  continue;
               }
            }

            if (MATCH2 (tptr, "||"))
            {
               /* 1 is "standalone" and 2 is a <span>/<div> */
               if (docptr->noescape == 1) tptr += 2;
               docptr->noescape = 0;
               break;
            }
            if (MATCH4 (tptr, "|!\"|"))
            {
               /* ditto */
               if (docptr->noescape == 1) tptr += 4;
               docptr->noescape = 0;
               break;
            }

            if (*tptr == '\n')
            {
               if (MATCH3 (tptr, "\n|\n"))
               {
                  /* a non-breaking newline */
                  tptr += 2;
               }
            }

            HONE (docptr, tptr);
         }

         continue;
      }

      while (*tptr && *tptr != '|')
      {
         /***************/
         /* HTML escape */
         /***************/

         if (HMORE(docptr)) wasDocMoreHtml (docptr);

         if (docptr->insight >= 2)
            if (MATCH4 (tptr, "\\<!-"))
               if (MATCH0 (tptr, "\\<!-- source:", 13))
                  renderInsightSource (docptr, tptr+13);

         if (*tptr == '<')
         {
            tptr++;
            wasDocAsIs (docptr, "&lt;");
            continue;
         }

         if (*tptr == '>')
         {
            tptr++;
            wasDocAsIs (docptr, "&gt;");
            continue;
         }

         if (*tptr == '&')
         {
            tptr++;
            wasDocAsIs (docptr, "&amp;");
            continue;
         }

         if (*tptr == '\"')
         {
            tptr++;
            wasDocAsIs (docptr, "&quot;");
            continue;
         }

         if (*tptr == '$')
         {
            /* wasDOC uses back-to-back $s for control sequences */
            tptr++;
            wasDocAsIs (docptr, "&dollar;");
            continue;
         }

         if (*tptr == '\\')
         {
            if (MATCH2 (tptr, "\\\n"))
            {
               /* escaped newline - no newline at all */
               tptr += 2;
               continue;
            }
            if (MATCH2 (tptr, "\\ "))
            {
               /* escaped space */
               tptr += 2;
               wasDocAsIs (docptr, "&nbsp;");
               continue;
            }
            if (MATCH2 (tptr, "\\|"))
            {
               /* escaped bar */
               tptr += 2;
               wasDocAsIs (docptr, "&verbar;");
               continue;
            }
            if (MATCH4 (tptr, "\\\\\\\\"))
            {
               /* four consecutive backslashes just ignore */
               tptr += 4;
               continue;
            }
            if (!MATCH2 (tptr, "\\\0"))
            {
               /* escape any other character */
               tptr++;
               HONE (docptr, tptr);
               continue;
            }
         }

         if (MATCH2 (tptr, "//") && *(tptr-1) == '\n')
         {
            /* line begins with // */
            while (*tptr && *tptr != '\n') tptr++;
            while (*tptr && *tptr == '\n') tptr++;
            continue;
         }

         if (*tptr == '\n')
         {
            if (MATCH3 (tptr, "\n|\n"))
            {
               /* a non-breaking newline */
               tptr += 2;
            }
         }

         HONE (docptr, tptr);
      }

      if (!*tptr) break;

      /*****************/
      /* must be a '|' */
      /*****************/

      if (ENDTAG (tptr))
      {
         /***************/
         /* end element */
         /***************/

         tagptr = tptr;

         if (MATCH2 (tptr, "||"))
            tptr += 2;
         else
         if (MATCH2 (tptr, "|!"))
         {
            /* documented end */
            if (isspace(*(tptr+2))) GOTO_FI_LI (docptr, BADPARAM_error)
            for (cptr = tptr + 2;
                 *cptr && *cptr != '\n' && *cptr != '|';
                 cptr++);
            if (*cptr != '|') GOTO_FI_LI (docptr, BADPARAM_error)
            tptr = cptr + 1;
         }
         else
            tptr++;

         if (!docptr->stindex) GOTO_FI_LI (docptr, stack_uflow)
         aptr = docptr->cstack[docptr->stindex];

         if (MATCH3 (aptr, "</h") && isdigit(aptr[3]))
         {
            wasDocAsIs (docptr, aptr);
            if (docptr->notable == NOTE_HEADING)
            {
               /* explicit heading has been provided so now in |note| text */
               docptr->notable = NOTE_TEXT;
               wasDocAsIs (docptr, "\n<hr class=\"note_hr\">");
            }
         }
         else
         if (MATCH8 (aptr, "</table>"))
         {
            if (docptr->table) docptr->table--;
            /* for the outermost table cancel any row highlight */
            if (!docptr->table) docptr->rowlight = 0;
            wasDocAsIs (docptr, aptr);
         }
         else
         if (MATCH6 (aptr, "<-div>"))
         {
            /* faux tag; reset any flag and convert to a div closure */
            if (!docptr->bfindex) GOTO_FI_LI (docptr, stack_uflow)
            docptr->bflag[docptr->bfindex--] = 0;
            wasDocAsIs (docptr, "</div>");
         }
         else
         if (MATCH7 (aptr, "<-note>"))
         {
            /* faux tag similar in purpose to above */
            if (!docptr->bfindex) GOTO_FI_LI (docptr, stack_uflow)
            docptr->notable = 0;
            docptr->bflag[docptr->bfindex--] = 0;
            wasDocAsIs (docptr, "<hr class=\"note_hr\">\n</div>");
         }
         else
         if (aptr)
            wasDocAsIs (docptr, aptr);

         /* already checked the stack depth above */
         docptr->stindex--;

         if (docptr->insight >= 4) renderInsightTag (docptr);

         continue;
      }

      /*****************/
      /* special cases */
      /*****************/

      if (docptr->insight >= 4)
         if (MATCH5 (tptr, "|...|") ||
             MATCH5 (tptr, "|:::|")) renderInsightTag (docptr);

      /* must be parsed before table |. */
      if (MATCH5 (tptr, "|...|"))
      {
         tptr += 5;
         wasDocAsIs (docptr, "&hellip;");
         continue;
      }

      if (MATCH5 (tptr, "|:::|"))
      {
         tptr += 5;
         wasDocAsIs (docptr, "&vellip;");
         continue;
      }

      if (docptr->table)
      {
         /********************/
         /* table processing */
         /********************/

         if (MATCH2 (tptr, "|~") ||
             MATCH4 (tptr, "|row") ||
             MATCH3 (tptr, "|tr"))
         {
            /*******/
            /* row */
            /*******/

            /* table insight is messy! */
            rowptr = tptr;

            /* compress intervening white-space */
            cptr = renderTrimWhite (docptr);
            /* ensuring that empty elements work with CSS :empty */
            if (!MATCH4 (cptr, "<tr ") &&
                !MATCH4 (cptr, "<th ") &&
                !MATCH4 (cptr, "<td ")) wasDocAsIs (docptr, "\n"); 

            TPUT (docptr, tptr);
            error = renderInsertTag (docptr, "<tr");
            if (error) { SET_FI_LI (docptr); goto param_error; }
            TGET (docptr, tptr);

            if (MATCH2 (tptr, "||")) tptr++;
            if (*tptr == '|') tptr++;

            continue;
         }
                                           
         if (MATCH2 (tptr, "|:") ||
             (MATCH3 (tptr, "|th") && ispunct(tptr[3])) ||
             (MATCH3 (tptr, "|th") && isdigit(tptr[3])) ||
             (MATCH5 (tptr, "|head") && ispunct(tptr[5])) ||
             (MATCH5 (tptr, "|head") && isdigit(tptr[5])))
         {
            /********/
            /* head */
            /********/

            tagptr = tptr;

            /* compress intervening white-space */
            cptr = renderTrimWhite (docptr);
            /* ensuring that empty elements work with CSS :empty */
            if (!MATCH4 (cptr, "<tr ") &&
                !MATCH4 (cptr, "<th ") &&
                !MATCH4 (cptr, "<td ")) wasDocAsIs (docptr, "\n"); 

            TPUT (docptr, tptr);
            error = renderInsertTag (docptr, "<th");
            if (error) { SET_FI_LI (docptr); goto param_error; }
            TGET (docptr, tptr);

            if (MATCH2 (tptr, "||")) tptr++;
            if (*tptr == '|') tptr++;

            /* absorb leading white-space */
            while (*tptr && isspace(*tptr)) tptr++;

            if (docptr->insight >= 4)
            {
               /* table insight is messy! */
               if (rowptr)
               {
                  renderInsightTag (docptr);
                  rowptr = NULL;
               }
               renderInsightTag (docptr);
            }

            continue;
         }

         if (MATCH2 (tptr, "|.") ||
             (MATCH3 (tptr, "|td") && ispunct(tptr[3])) ||
             (MATCH3 (tptr, "|td") && isdigit(tptr[3])) ||
             (MATCH5 (tptr, "|data") && ispunct(tptr[5])) ||
             (MATCH5 (tptr, "|data") && isdigit(tptr[5])))
         {
            /********/
            /* data */
            /********/

            tagptr = tptr;

            /* compress intervening white-space */
            cptr = renderTrimWhite (docptr);
            /* ensuring that empty elements work with CSS :empty */
            if (!MATCH4 (cptr, "<tr ") &&
                !MATCH4 (cptr, "<th ") &&
                !MATCH4 (cptr, "<td ")) wasDocAsIs (docptr, "\n"); 

            TPUT (docptr, tptr);
            error = renderInsertTag (docptr, "<td");
            if (error) { SET_FI_LI (docptr); goto param_error; }
            TGET (docptr, tptr);

            if (MATCH2 (tptr, "||")) tptr++;
            if (*tptr == '|') tptr++;

            /* absorb leading white-space */
            while (*tptr && isspace(*tptr)) tptr++;

            if (docptr->insight >= 4)
            {
               /* table insight is messy! */
               if (rowptr)
               {
                  renderInsightTag (docptr);
                  rowptr = NULL;
               }
               renderInsightTag (docptr);
            }

            continue;
         }
      }
      else
      if (MATCH2 (tptr, "|~") || MATCH2 (tptr, "|:") || MATCH2 (tptr, "|."))
         GOTO_FI_LI (docptr, outside_table_error)
      else
      if ((MATCH3 (tptr, "|tr") && ispunct(tptr[3])) ||
          (MATCH4 (tptr, "|row") && ispunct(tptr[4])))
         GOTO_FI_LI (docptr, outside_table_error)
      else
      if ((MATCH3 (tptr, "|th") && ispunct(tptr[3])) ||
          (MATCH5 (tptr, "|head") && ispunct(tptr[5])))
         GOTO_FI_LI (docptr, outside_table_error)
      else
      if ((MATCH3 (tptr, "|td") && ispunct(tptr[3])) ||
          (MATCH5 (tptr, "|data") && ispunct(tptr[5])))
         GOTO_FI_LI (docptr, outside_table_error)

      /* a few cycles could have been saved by stepping over the '|' */
      /* just seemed to make the tags clearer in the code left in :-/ */

      /*********/
      /* other */
      /*********/

      if (docptr->insight >= 4) renderInsightTag (docptr);

      if (MATCH2 (tptr, "|\""))
      {
         /* 1 is "standalone" and 2 is a <span>/<div> */
         docptr->noescape = 1;
         tptr += 2;
         continue;
      }

      if (MATCH2 (tptr, "|\\"))
      {
         /* leading backslash; ignore the rest of the tag */
         for (tptr++; *tptr; tptr++)
         {
            if (MATCH2 (tptr, "\\|"))
               tptr += 2;
            else
            if (*tptr == '|' && ENDTAG (tptr))
               break;
         }
         if (!*tptr) break;
         if (MATCH2 (tptr, "||")) tptr++;
         tptr++;
         continue;
      }

      /* especially this one needs to be before "strike" */
      if (MATCH3 (tptr, "|-|"))
      {
         tptr += 3;
         wasDocAsIs (docptr, "&ndash;");
         continue;
      }

      if (MATCH4 (tptr, "|--|"))
      {
         tptr += 4;
         wasDocAsIs (docptr, "&mdash;");
         continue;
      }

      if (MATCH3 (tptr, "|//"))
      {
         /* comment (must come before "|/" - italic) */
         if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow)
         docptr->tstack[docptr->stindex] = tptr;
         docptr->cstack[docptr->stindex] = " -->";
         wasDocAsIs (docptr, "<!-- ");
         tptr += 3;
         continue;
      }

      /*************/
      /* list item */
      /*************/

      /* must precede the highlight equivalent */
      if (MATCH2 (tptr, "|&") && isspace(tptr[2]))
      {
         tptr += 2;
         wasDocAsIs (docptr, "<li class=\"item\">");
         continue;
      }

      /*************/
      /* highlight */
      /*************/

      if (MATCH2 (tptr, "|*") ||
          MATCH2 (tptr, "|-") ||
          MATCH2 (tptr, "|_") ||
          MATCH2 (tptr, "|=") ||
          MATCH2 (tptr, "|\'") ||  /* single quote */
          MATCH2 (tptr, "|/") ||   /* double quote */
          MATCH2 (tptr, "|>") ||
          MATCH2 (tptr, "|<") ||
          MATCH2 (tptr, "|&"))
      {
         if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow)
         docptr->tstack[docptr->stindex] = tptr;
         docptr->cstack[docptr->stindex] = "</span>";
         TPUT (docptr, tptr);
         error = renderInsertTag (docptr, "<span");
         if (error) { SET_FI_LI (docptr); goto param_error; }
         TGET (docptr, tptr);
         continue;
      }

      /*********/
      /* break */
      /*********/

      if (MATCH2 (tptr, "|^") && isspace(tptr[2]))
      {
         tptr += 2;
         wasDocAsIs (docptr, "<p>");
         continue;
      }

      if (MATCH3 (tptr, "|^-"))
      {
         /* line */
         tptr += 3;
         wasDocAsIs (docptr, "<br>");
         continue;
      }

      if (MATCH3 (tptr, "|^+"))
      {
         tptr += 3;
         wasDocAsIs (docptr, "<p class=\"indent\">");
         continue;
      }

      if (tptr[1] >= '0' && tptr[1] <= '9')
      {
         /***********/
         /* heading */
         /***********/
  
         /* all tags should be closed before each major heading */
         if (tptr[1] == '1' || MATCH2 (tptr+1, "01"))
         {
            if (docptr->conLevel > 0) GOTO_FI_LI (docptr, conditional_error)
            if (docptr->stindex > 0) GOTO_FI_LI (docptr, unbalanced_error)
         }

         /* if explicit heading for |note| */
         if (docptr->notable == NOTE_BEGIN)
            if (tptr[1] == '0')
               docptr->notable = NOTE_HEADING;

         TPUT (docptr, tptr);
         error = renderInsertHeading (docptr);
         if (error == SS$_ITEMNOTFOUND) goto unknown_tag;
         if (error == SS$_RESULTOVF) goto stack_oflow;
         if (error) { SET_FI_LI (docptr); goto param_error; }
         TGET (docptr, tptr);

         continue;
      }

      /**********/
      /* phrase */
      /**********/

      if (dbug>1) dbugThis (FI_LI, "%s %s", renderTag(tptr),
                                            renderLine(docptr));

      if (MATCH6 (tptr, "|asis|"))
      {
         /* 1 is "standalone" and 2 is a <div> */
         docptr->asis = 1;
         tptr += 6;
         if (*tptr == '\n') tptr++;
         continue;
      }

      if ((MATCH5 (tptr, "|asis") ||
           MATCH6 (tptr, "|block") ||
           MATCH5 (tptr, "|code") ||
           MATCH8 (tptr, "|example") ||
           MATCH7 (tptr, "|inline") ||
           MATCH5 (tptr, "|mono") ||
           MATCH5 (tptr, "|prop") ||
           MATCH6 (tptr, "|quote")) &&
          (ispunct(tptr[5]) ||
           ispunct(tptr[6]) ||
           ispunct(tptr[7]) ||
           ispunct(tptr[8])))
      {
         /*********/
         /* block */
         /*********/

         if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow)
         docptr->tstack[docptr->stindex] = tptr;
         cptr = "<div";
         if (MATCH4 (tptr, "|asi"))
         {
            docptr->cstack[docptr->stindex] = "||||";  /* special case */
            /* 1 is "standalone" and 2 is a <div> */
            docptr->asis = 2;
         }
         else
         if (MATCH4 (tptr, "|inl"))
         {
            cptr = "<span";
            docptr->cstack[docptr->stindex] = "</span>";
         }
         else
            docptr->cstack[docptr->stindex] = "<-div>";

         TPUT (docptr, tptr);
         error = renderInsertTag (docptr, cptr);
         if (error) { SET_FI_LI (docptr); goto param_error; }
         TGET (docptr, tptr);

         if (MATCH2 (tptr, "||")) tptr++;
         if (*tptr == '|') tptr++;
         /* absorb any trailing newline (backslash escape if required) */
         if (*tptr == '\n') tptr++;

         continue;
      }

      if (MATCH5 (tptr, "|note") && ispunct(tptr[5]))
      {
         /********/
         /* note */
         /********/

         /* one at a time thank you */
         if (docptr->notable) GOTO_FI_LI (docptr, BADPARAM_error)
         docptr->notable = NOTE_BEGIN;

         if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow)
         docptr->tstack[docptr->stindex] = tptr;
         docptr->cstack[docptr->stindex] = "<-note>";

         TPUT (docptr, tptr);
         error = renderInsertTag (docptr, "<div");
         if (error) { SET_FI_LI (docptr); goto param_error; }
         TGET (docptr, tptr);

         if (MATCH2 (tptr, "||")) tptr++;
         if (*tptr == '|') tptr++;

         /* scan ahead for an explicit note heading */
         for (cptr = tptr; *cptr && isspace(*cptr); cptr++);
         if (!MATCH2 (cptr, "|0"))
         {
            /* doesn't look like it so provide default */
            docptr->notable = NOTE_HEADING;
            error = renderInsertNote (docptr);
            if (error) { SET_FI_LI (docptr); goto param_error; }
            docptr->notable = NOTE_TEXT;
         }

         continue;
      }

      if (MATCH6 (tptr, "|table") ||
          MATCH8 (tptr, "|tabular"))
      {
         /*********/
         /* table */
         /*********/

         if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow)
         docptr->tstack[docptr->stindex] = tptr;
         docptr->cstack[docptr->stindex] = "</table>";

         TPUT (docptr, tptr);
         error = renderInsertTag (docptr, "<table");
         if (error) { SET_FI_LI (docptr); goto param_error; }
         TGET (docptr, tptr);

         if (MATCH2 (tptr, "||")) tptr++;
         if (*tptr == '|') tptr++;

         docptr->table++;

         continue;
      }

      if ((MATCH3 (tptr, "|ul") && ispunct(tptr[3])) ||
          (MATCH7 (tptr, "|bullet") && ispunct(tptr[7])))
      {
         /**********/
         /* bullet */
         /**********/

         if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow)
         docptr->tstack[docptr->stindex] = tptr;
         docptr->cstack[docptr->stindex] = "</ul>";

         TPUT (docptr, tptr);
         error = renderInsertTag (docptr, "<ul");
         if (error) { SET_FI_LI (docptr); goto param_error; }
         TGET (docptr, tptr);

         if (MATCH2 (tptr, "||")) tptr++;
         if (*tptr == '|') tptr++;
         continue;
      }

      if ((MATCH3 (tptr, "|ol") && ispunct(tptr[3])) ||
          (MATCH7 (tptr, "|number") && ispunct(tptr[7])))
      {
         /**********/
         /* number */
         /**********/

         if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow)
         docptr->tstack[docptr->stindex] = tptr;
         docptr->cstack[docptr->stindex] = "</ol>";

         TPUT (docptr, tptr);
         error = renderInsertTag (docptr, "<ol");
         if (error) { SET_FI_LI (docptr); goto param_error; }
         TGET (docptr, tptr);

         if (MATCH2 (tptr, "||")) tptr++;
         if (*tptr == '|') tptr++;
         continue;
      }

      if ((MATCH3 (tptr, "|sl") && ispunct(tptr[3])) ||
          (MATCH7 (tptr, "|simple") && ispunct(tptr[7])))
      {
         /**********/
         /* simple */
         /**********/
         
         /* no bullets, no item numbers */
         if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow)
         docptr->tstack[docptr->stindex] = tptr;
         docptr->cstack[docptr->stindex] = "</ul>";

         TPUT (docptr, tptr);
         error = renderInsertTag (docptr, "<sl");  /* faux tag */
         if (error) { SET_FI_LI (docptr); goto param_error; }
         TGET (docptr, tptr);

         if (MATCH2 (tptr, "||")) tptr++;
         if (*tptr == '|') tptr++;
         continue;
      }

      if ((MATCH3 (tptr, "|li") && ispunct(tptr[3])) ||
          (MATCH5 (tptr, "|item") && ispunct(tptr[5])))
      {
         TPUT (docptr, tptr);
         error = renderInsertTag (docptr, "<li");
         if (error) { SET_FI_LI (docptr); goto param_error; }
         TGET (docptr, tptr);

         if (MATCH2 (tptr, "||")) tptr++;
         if (*tptr == '|') tptr++;
         continue;
      }

      if (*(cptr = tptr + 1) == '%') cptr++;
      while (*cptr && cptr < tptr+8 && isalpha(*cptr)) cptr++;
      if (MATCH3 (cptr, "://") ||
          (MATCH5 (tptr, "|link") && ispunct(tptr[5])) ||
          MATCH8 (tptr, "|mailto:"))
      {
         /********/
         /* link */
         /********/

         int  image = 0, link, linkin = 0, target = 0;

         if (link = MATCH5 (tptr, "|link"))
         {
            target = (tptr[5] == '%');
            for (cptr = tptr+5; *cptr && *cptr != '|'; cptr++);
            if (*cptr) cptr++;
            while (*cptr && *cptr != '|') cptr++;
            /* allow an image to be the link description */
            image = MATCH6 (cptr, "|image") && ispunct(cptr[6]);
         }
         else
         if (target = (MATCH2(tptr,"|%")))
            tptr += 2;

         if (link)
         {
            TPUT (docptr, tptr);
            if (image)
               error = renderInsertTag (docptr, "<aimg ");  /* faux tag */
            else
               error = renderInsertTag (docptr, "<a ");
            if (error) { SET_FI_LI (docptr); goto param_error; }
            TGET (docptr, tptr);
         }
         else
         if (target)
         {
            if (image)
               wasDocAsIs (docptr, "<a class=\"link\" target=\"_blank\" href=\"");
            else
               wasDocAsIs (docptr, "<a class=\"link blank\" target=\"_blank\" href=\"");
         }
         else
            wasDocAsIs (docptr, "<a class=\"link\" href=\"");

         if (link)
         {
            /* get the URL (tag parameter) */
            tptr++;
            TPUT (docptr, tptr);
            error = renderGetParam (docptr, buf, sizeof(buf));
            if (error) { SET_FI_LI (docptr); goto param_error; }
            if (!buf[0]) GOTO_FI_LI (docptr, BADPARAM_error)
            TGET (docptr, tptr);
            /* ensure it only contains significant characters */
            for (sptr = cptr = buf; *cptr; cptr++)
               if (iscntrl(*cptr))
                  *sptr++ = ' ';
               else
                  *sptr++ = *cptr;
            *sptr = '\0';

            /* check for "<URL>##<heading>++in++<document-title>" */
            if (sptr = strstr (buf, "##"))
            {
               if (sptr = strstr (sptr+2, "++"))
               {
                  if (strstr (sptr+2, "++"))
                  {
                     if (image)
                        GOTO_FI_LI (docptr, BADPARAM_error)
                     else
                     {
                        error = renderInsertLinkIn (docptr, buf, target);
                        if (error) { SET_FI_LI (docptr); goto param_error; }
                        if (MATCH2 (tptr, "||")) tptr++;
                        if (*tptr) tptr++;
                        continue;
                     }
                  }
               }
            }
         }
         else
         {
            /* else an explicit URL */
            if (*tptr == '|') tptr++;
            for (zptr = (sptr = buf) + sizeof(buf)-1;
                 *tptr && *tptr != '|' && sptr < zptr;
                 tptr++)
               if (!iscntrl(*cptr) && !isspace(*tptr)) *sptr++ = *tptr;
            if (sptr == buf || sptr >= zptr)
               GOTO_FI_LI (docptr, BADPARAM_error);
            *sptr = '\0';
         }

         error = renderInsertLink (docptr, buf);
         if (error) { SET_FI_LI (docptr); goto param_error; }

         wasDocAsIs (docptr, "\">");

         if (image)
         {
            if (docptr->stindex++ >= STACK_MAX)
               GOTO_FI_LI (docptr, stack_oflow)
            docptr->tstack[docptr->stindex] = tptr;
            docptr->cstack[docptr->stindex] = "</a>";
            continue;  /*** NOTE ***/
         }
         else
         if (ENDTAG (tptr))
         {
            if (MATCH7 (buf, "mailto:"))
               /* reuse the URL as the link description */
               wasDocAsIs (docptr, buf+7);
            else
            if (buf[0] == '/' ||
                strstr (buf, "://"))
               /* reuse the URL as the link description */
               wasDocAsIs (docptr, buf);
            else
            if (cptr = strstr (buf, "##"))
               /* use the free text hash as the description */
               wasDocAsIs (docptr, cptr+2);
            /* else an empty description */
            wasDocAsIs (docptr, "</a>");
         }
         else
         {
            /* explicit description follows */
            if (docptr->stindex++ >= STACK_MAX)
               GOTO_FI_LI (docptr, stack_oflow)
            docptr->tstack[docptr->stindex] = tptr;
            docptr->cstack[docptr->stindex] = "</a>";
         }
 
         if (MATCH2 (tptr, "||")) tptr++;
         if (*tptr) tptr++;

         continue;
      }

      if (MATCH5 (tptr, "|draw") && ispunct(tptr[5]))
      {
         /********/
         /* draw */
         /********/

         TPUT (docptr, tptr);
         error = renderInsertTag (docptr, "<div");
         if (error) { SET_FI_LI (docptr); goto param_error; }
         error = drawThis (docptr);
         if (error) { SET_FI_LI (docptr); goto param_error; }
         wasDocAsIs (docptr, "</div>\n");
         TGET (docptr, tptr);
         continue;
      }

      if (MATCH6 (tptr, "|image") && ispunct(tptr[6]))  
      {
         /*********/
         /* image */
         /*********/

         int  linked, linked2;

         /* buffer the |image tptr */
         aptr = tptr;

         /* begin spanning towards the URL */
         for (tptr += 6; *tptr && *tptr != '|'; tptr++)
            if (*tptr == '%' || *tptr == '\'' || *tptr == '&')
               break;

         /* internal link cannot be used if the image is a link descriptor */
         if (linked = (*tptr == '%'))
         {
            if (docptr->stindex > 0)
               if (MATCH4 (docptr->cstack[docptr->stindex], "</a>"))
                  linked = 0;
            /* two indicate the link should open in a separate page */
            if (linked) linked2 = MATCH2 (tptr, "%%");
         }

         /* span to the start of the URL */
         while (*tptr && *tptr != '|') tptr++;
         if (*tptr) tptr++;

         /* get the URL */
         TPUT (docptr, tptr);
         error = renderGetParam (docptr, buf, sizeof(buf));
         if (!error && !buf[0]) GOTO_FI_LI (docptr, BADPARAM_error)
         if (error) { SET_FI_LI (docptr); goto param_error; }
         TGET (docptr, tptr);

         if (linked)
         {
            if (linked2)
               wasDocAsIs (docptr, "<a class=\"imglink\" target=\"_blank\" href=\"");
            else
               wasDocAsIs (docptr, "<a class=\"imglink\" href=\"");

            error = renderInsertUrl (docptr, buf);
            if (error) { SET_FI_LI (docptr); goto param_error; }
            wasDocAsIs (docptr, "\">");
         }

         /* use the original tptr that was buffered in aptr */
         cptr = tptr;
         tptr = aptr; 

         TPUT (docptr, tptr);
         error = renderInsertTag (docptr, "<img");
         if (error) { SET_FI_LI (docptr); goto param_error; }
         error = renderInsertUrl (docptr, buf);
         if (error) { SET_FI_LI (docptr); goto param_error; }
         TGET (docptr, tptr);
         wasDocAsIs (docptr, "\">");

         /* go back to the tptr just beyond the URL parameter */
         tptr = cptr;

         if (MATCH2 (tptr, "||")) tptr++;
         if (*tptr == '|') tptr++;

         if (linked)
            wasDocAsIs (docptr, "</a>");
         else
         if (docptr->stindex > 0)
            if (MATCH4 (docptr->cstack[docptr->stindex], "</a>"))
            {
               /* the image is being used as the link */
               docptr->stindex--;
               wasDocAsIs (docptr, "</a>");
            }

         continue;
      }

      if (MATCH7 (tptr, "|insert") && ispunct(tptr[7]))
      {
         /**********/
         /* insert */
         /**********/

         if (tptr[7] == '|')
         {
            tptr += 8;
            TPUT (docptr, tptr);
            error = renderGetParam (docptr, buf, sizeof(buf));
            if (!error && !buf[0]) GOTO_FI_LI (docptr, BADPARAM_error)
            if (error) { SET_FI_LI (docptr); goto param_error; }
            error = renderInsertOther (docptr, buf);
            if (error) { SET_FI_LI (docptr); goto insert_error; }
            TGET (docptr, tptr);
         }
         else
         {
            TPUT (docptr, tptr);
            error = renderInsertTag (docptr, "<span");
            if (error) { SET_FI_LI (docptr); goto param_error; }
            TGET (docptr, tptr);

            if (MATCH2 (tptr, "||")) tptr++;
            if (*tptr == '|') tptr++;
    
            TPUT (docptr, tptr);
            error = renderGetParam (docptr, buf, sizeof(buf));
            if (!error && !buf[0]) GOTO_FI_LI (docptr, BADPARAM_error)
            if (error) { SET_FI_LI (docptr); goto param_error; }
            error = renderInsertOther (docptr, buf);
            if (error) { SET_FI_LI (docptr); goto insert_error; }
            TGET (docptr, tptr);

            wasDocAsIs (docptr, "</span>");
         }

         if (MATCH2 (tptr, "||")) tptr++;
         if (*tptr == '|') tptr++;

         continue;
      }

      /**************/
      /* conditions */
      /**************/

      if (MATCH4 (tptr, "|if|") ||
          MATCH6 (tptr, "|elif|") ||
          MATCH6 (tptr, "|else|") ||
          MATCH7 (tptr, "|endif|"))
      {
         TPUT (docptr, tptr);
         error = renderCondition (docptr);
         if (error) { SET_FI_LI (docptr); goto conditional_error; }
         TGET (docptr, tptr);
         continue;
      }

      /**********/
      /* others */
      /**********/

      if (MATCH5 (tptr, "|set|"))
      {
         tptr += 5;
         TPUT (docptr, tptr);
         error = renderGetParam (docptr, buf, sizeof(buf));
         if (!error && !buf[0]) GOTO_FI_LI (docptr, BADPARAM_error)
         if (error) { SET_FI_LI (docptr); goto param_error; }
         TGET (docptr, tptr);
         error = renderSet (docptr, buf);
         if (error) { SET_FI_LI (docptr); goto param_error; }
         if (MATCH2 (tptr, "||")) tptr++;
         if (*++tptr == '\n') tptr++;
         continue;
      }

      if (MATCH7 (tptr, "|style|"))
      {
         tptr += 7;
         TPUT (docptr, tptr);
         error = renderGetParam (docptr, buf, sizeof(buf));
         if (!error && !buf[0]) GOTO_FI_LI (docptr, BADPARAM_error)
         if (error) { SET_FI_LI (docptr); goto param_error; }
         error = renderStyle (docptr, buf);
         if (error) { SET_FI_LI (docptr); goto param_error; }
         TGET (docptr, tptr);
         if (MATCH2 (tptr, "||")) tptr++;
         if (*tptr) tptr++;
         continue;
      }

      if (MATCH7 (tptr, "|print|"))
      {
         if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow)
         docptr->tstack[docptr->stindex] = tptr;
         docptr->cstack[docptr->stindex] = "</div>";
         wasDocAsIs (docptr, "<div class=\"print\">");
         tptr += 7;
         if (*tptr == '\n') tptr++;
         continue;
      }

      if (MATCH9 (tptr, "|noprint|"))
      {
         if (docptr->stindex++ >= STACK_MAX) GOTO_FI_LI (docptr, stack_oflow)
         docptr->tstack[docptr->stindex] = tptr;
         docptr->cstack[docptr->stindex] = "</div>";
         wasDocAsIs (docptr, "<div class=\"noprint\">");
         tptr += 9;
         if (*tptr == '\n') tptr++;
         continue;
      }

      if (MATCH6 (tptr, "|ppage|"))
      {
         /* at a page break all tags should have been closed */
         if (docptr->stindex > 0) GOTO_FI_LI (docptr, unbalanced_error)
         wasDocAsIs (docptr, "<hr class=\"ppage\">");
         tptr += 6;
         if (*tptr == '\n') tptr++;
         continue;
      }

      if (MATCH5 (tptr, "|toc|"))
      {
         /* insert a marker for where the TOC will be */
         tptr += 5;
         if (MATCH2 (tptr, "||")) tptr++;
         tptr++;
         wasDocAsIs (docptr, "<!--$$TOC$$-->");
         continue;
      }

      if (MATCH7 (tptr, "|index|"))
      {
         /* insert a marker for where the INDEX will be */
         tptr += 7;
         if (MATCH2 (tptr, "||")) tptr++;
         tptr++;
         wasDocAsIs (docptr, "<!--$$IDX$$-->");
         continue;
      }

      if (MATCH7 (tptr, "|break|"))
      {
         wasDocAsIs (docptr, "\n<!-- $$BREAK$$ -->\n");
         TPUT (docptr, tptr);
         break;
      }

      if (MATCH6 (tptr, "|exit|"))
      {
         wasDocAsIs (docptr, "\n<!-- $$EXIT$$ -->\n");
         TPUT (docptr, tptr);
         return (SS$_ABORT);
      }

      if (MATCH10 (tptr, "|insight!|"))
      {
         tptr += 10;
         TPUT (docptr, tptr);
         renderInsightStack (docptr);
         TGET (docptr, tptr);
         continue;
      }

      if (MATCH10 (tptr, "|insight@|"))
      {
         tptr += 10;
         if (docptr->isDynamic && docptr->insight)
         {
            wasDocAsIs (docptr,
"<div class=\"noprint\">\n\
<input type=\"button\" onclick=\"button(\'text\')\" value=\"TEXT\">\n\
<input type=\"button\" onclick=\"button(\'html\')\" value=\"HTML\">\n\
<span id=\"lookstats\"></span>\n\
</div>\n");
            docptr->insightAt = 1;
         }
         continue;
      }

      /***********/
      /* unknown */
      /***********/

      GOTO_FI_LI (docptr, unknown_tag)
   }

   /*******/
   /* end */
   /*******/

   if (docptr->stindex > 0) GOTO_FI_LI (docptr, unbalanced_error)

   if (pass2 (docptr) < 0)
   {
      TPUT (docptr, tptr);
      if (docptr->errorValue == SS$_NOSUCHOBJECT)
         renderErrorReport (docptr,
"\n<div class=\"error\">Link target %s not found</div>\n",
                        docptr->pass2At);
      else
      {
         cptr = strdup (strerror(EVMSERR,docptr->errorValue));
         *cptr = toupper(*cptr);
         renderErrorReport (docptr, "\n<div class=\"error\">%s %s</div>\n",
                            cptr, docptr->pass2At);
         free (cptr);
      }
      renderErrorReport (docptr, NULL);
      return (docptr->errorValue);
   }

   if (docptr->insight >= 2) wasDocInsight (docptr, "END");

   return (0);

post_condition_error:

   aptr = docptr->html + docptr->hparse;

   TPUT (docptr, tptr);
   renderErrorReport (docptr,
"\n<div class=\"error\">%s post processing error <i>%s</i> \
at &quot;<kbd>%s</kbd>&quot; %s</div>\n",
                      cptr, strerror(EVMSERR,error), renderLineEscape(aptr),
                      renderSource(docptr));
   renderErrorReport (docptr, NULL);
   return (error);

unknown_tag:

   TPUT (docptr, tptr);
   renderErrorReport (docptr,
"<div class=\"error\">Unknown tag &quot;<kbd>%s</kbd>&quot; at \
&quot;<kbd>%s</kbd>&quot; %s</div>\n",
                      renderTag(tptr), renderLine(docptr),
                      renderSource(docptr));
   renderErrorReport (docptr, NULL);
   return (error);

insert_error:

   TPUT (docptr, tptr);
   renderErrorReport (docptr,
"\n<div class=\"error\">Insert failed <i>%s</i> at \
&quot;<kbd>%s</kbd>&quot; %s</div>\n",
                      strerror(EVMSERR,error), renderLine(docptr),
                      renderSource(docptr));
   renderErrorReport (docptr, NULL);
   return (error);

BADPARAM_error:
   error = SS$_BADPARAM;
   goto param_error;

param_error:

   TPUT (docptr, tptr);
   renderErrorReport (docptr,
"\n<div class=\"error\">Parameter error <i>%s</i> at \
\"<kbd>%s</kbd>\" %s</div>\n",
                      strerror(EVMSERR,error), renderLine(docptr),
                      renderSource(docptr));
   renderErrorReport (docptr, NULL);
   return (error);

vms_status_error:

   TPUT (docptr, tptr);
   renderErrorReport (docptr,
"\n<div class=\"error\">VMS status %%X%08.08X error <i>%s</i> at \
\"<kbd>%s</kbd>\" %s</div>\n",
                      error, strerror(EVMSERR,error), renderLine(docptr),
                      renderSource(docptr));
   renderErrorReport (docptr, NULL);
   return (error);

outside_table_error:

   TPUT (docptr, tptr);
   renderErrorReport (docptr,
"\n<div class=\"error\">Tag &quot;<kbd>%s</kbd>&quot; used outside table at \
&quot;<kbd>%s</kbd>&quot; %s</div>\n",
                      renderTag(tptr), renderLine(docptr),
                      renderSource(docptr));
   renderErrorReport (docptr, NULL);
   return (error);

stack_oflow:

   TPUT (docptr, tptr);
   renderErrorReport (docptr,
"\n<div class=\"error\">Overflow at &quot;<kbd>%s</kbd>&quot;%s</div>\n",
                      renderLine(docptr));
   renderErrorReport (docptr, NULL);
   return (error);

stack_uflow:         

   TPUT (docptr, tptr);
   renderErrorReport (docptr,
"\n<div class=\"error\">Underflow at &quot;<kbd>%s</kbd>&quot; %s</div>\n",
                      renderLine(docptr), renderSource(docptr));
   renderErrorReport (docptr, NULL);
   return (error);

conditional_error:

   if (!error)
      cptr = "unbalanced";
   else
      cptr = strerror(EVMSERR,error);
   TPUT (docptr, tptr);
   renderErrorReport (docptr,
"<div class=\"error\">Conditional <i>%s</i> at \
&quot;<kbd>%s</kbd>&quot; %s</div>",
                      cptr, renderLine(docptr), renderSource(docptr));
   renderErrorReport (docptr, NULL);
   return (error);

unbalanced_error:

   TPUT (docptr, tptr);
   renderErrorReport (docptr,
"<div class=\"error\">Unbalanced at &quot;<kbd>%s</kbd>&quot; %s",
                      renderLine(docptr), renderSource(docptr));
   while (docptr->stindex)
   {
      renderErrorReport (docptr, "<br>%d &quot;<kbd>%s</kbd>&quot;",
                        docptr->stindex, renderLine(docptr));
      docptr->stindex--;
   }
   renderErrorReport (docptr, "</div>");
   renderErrorReport (docptr, NULL);
   return (error);
}

/*****************************************************************************/
/*
If the primary document reports an error in some indeterminate state (e.g.
inside a heading, monospace, italic, table, etc.) to get the error report out a
markup-clean environment is needed.  Hence the IFRAME.  The iframe is populated
using JavaScript.

An initial call sets up the dynamic created IFRAME and formats an initial
report line.  Subsequent calls can add lines to the report.  A final "cleanup"
call (mandatory) loses and displays the report.
*/

int renderErrorReport
(
struct wasdoc_st *docptr,
char *fmt,
...
)

{
   static int  init = 0;
   int  cnt, linum, retval, size;
   char  *aptr, *bptr, *fiptr, *cptr, *sptr, *tptr, *zptr;
   char finame [64];
   va_list args;

   if (dbug>2) dbugThis (FI_LI, "renderErrorReport() %s", dbugMax(fmt));

   if (!fmt)
   {
      /* end call */
      wasDocPrintf (docptr, "</script>\n");
      init = 0;
      return (0);
   }

   va_start (args, fmt);
   size = vsnprintf (NULL, 0, fmt, args);
   va_end (args);
   if (size < 0) return (vaxc$errno);

   bptr = calloc (1, size);
   if (!bptr) exit (vaxc$errno);

   va_start (args, fmt);
   retval = vsprintf (bptr, fmt, args);
   va_end (args);
   if (retval < 0) return (retval);
   if (retval != size) wasDocBugcheck(FI_LI);

   /* escape any forbiddens in the string */
   cnt = 0;
   for (cptr = bptr; *cptr; cptr++)
      if (*cptr == '\n' || *cptr == '\'' || *cptr == '\\') cnt++;
   if (cnt)
   {
      aptr = sptr = calloc (1, size + cnt);
      if (!aptr) exit (vaxc$errno);
      for (cptr = bptr; *cptr; cptr++)
      {
         if (*cptr == '\n' || *cptr == '\'' || *cptr == '\\') *sptr++ = '\\';
         if (*cptr == '\n')
            *sptr++ = 'n';
         else
         if (isprint(*cptr))
            *sptr++ = *cptr;
      }
      free (bptr);
      bptr = aptr;
   }

   if (!init)
   {
      if (fiptr = docptr->fiptr)
      {
         while (*fiptr) fiptr++;
         while (*(fiptr-1) != ']' && fiptr > docptr->fiptr) fiptr--;
         zptr = (sptr = finame) + sizeof(finame)-1;
         while (*fiptr && *fiptr != ';' && sptr < zptr) *sptr++ = *fiptr++;
         *sptr = '\0';
      }
      linum = docptr->linum;
      wasDocPrintf (docptr, "<!-- FILE:%s LINE:%d -->",
                     fiptr ? finame : "(null)", linum);
   }

   wasDocPrintf (docptr,
"\n<div id=\"erreport2\" style=\"display:none;\"></div>\n\
<script>errorReport(\'%s\')</script>\n", bptr);

   init = 1;
   free (bptr);

   return (0);
}

/*****************************************************************************/
/*
Return a pointer to the tag as a string.
*/

char* renderTag (char *tptr)

{
   static char  buf [32+3];
   char  *sptr, *zptr;

   if (dbug>2) dbugThis (FI_LI, "renderTag() %s", dbugMax(tptr));

   zptr = (sptr = buf) + sizeof(buf)-3;
   *sptr++ = bvbar;
   if (*tptr == '|') *sptr++ = *tptr++;
   if (isalpha(*tptr))
   {
      while (*tptr && *tptr != '|' && sptr < zptr) *sptr++ = *tptr++;
      *sptr++ = '|';
   }
   else
   if (isdigit(*tptr))
      while (*tptr && isdigit(*tptr)&& sptr < zptr) *sptr++ = *tptr++;
   else
      *sptr++ = *tptr;
   *sptr++ = bvbar;
   *sptr = '\0';

   return (buf);
}

/*****************************************************************************/
/*
Return a pointer to the line as a string. Call pointing at start of line.
*/

char* renderLine (struct wasdoc_st *docptr)

{
   static char  buf [96];
   char  *cptr, *sptr, *zptr;

   if (dbug>2) dbugThis (FI_LI, "renderLine() %s",
                         dbugMax(docptr->text+docptr->tparse));

   zptr = (sptr = buf) + sizeof(buf)-1;
   cptr = docptr->text + docptr->tparse;
   while (*cptr && *cptr != '\n') cptr++;
   while (*cptr == '\n') cptr++;
   while (cptr > docptr->text && *(cptr-1) == '\n') cptr--;
   while (cptr > docptr->text && *(cptr-1) != '\n') cptr--;
   while (*cptr && *cptr != '\n' && sptr < zptr) *sptr++ = *cptr++;
   *sptr = '\0';
   cptr = dbugAll (buf);

   if (dbug>2) dbugThis (FI_LI, "%s", cptr);

   return (cptr);
}

/*****************************************************************************/
/*
Return a pointer to a buffer containing the line number and source file name
(see ConditionFile()).
*/

char* renderSource (struct wasdoc_st *docptr)

{
   static char  buf [128];
   int  clnum = 1, slnum = 0;
   char  *cptr, *sptr, *tptr, *tzptr, *zptr;
   char sname [96];

   strcpy (buf, "BUGCHECK!");
   strcpy (sname, "BUGCHECK!");
   tzptr = docptr->text + docptr->tparse;
   for (tptr = docptr->text; *tptr && tptr < tzptr; tptr++)
   {
      if (*tptr == '\n') clnum++;
      if (*tptr != '\\') continue;
      if (!MATCH4 (tptr, "\\<!-")) continue;
      if (!MATCH0 (tptr, "\\<!-- source:", 13)) continue;
      tptr += 13;
      slnum = clnum;
      zptr = (sptr = sname) + sizeof(sname)-1;
      while (*tptr && sptr < zptr && !isspace(*tptr)) *sptr++ = *tptr++;
      *sptr = '\0';
   }
   sprintf (buf, "line %d in %s", clnum - slnum, sname);
   return (buf);
}

/*****************************************************************************/
/*
Return a pointer to the line as a string.  Escape HTML-forbiddens.  Call
pointing at start of line.
*/

char* renderLineEscape (char *hptr)

{
   static char  buf [96*3];
   char  *cptr, *sptr, *zptr;

   if (!hptr) hptr = "^0";
   if (!*hptr) hptr = "^Z";
   while (*hptr && *hptr == ' ') hptr++;
   zptr = (sptr = buf) + sizeof(buf)-1;
   while (*hptr && *hptr != '\n' && sptr < zptr)
   {
      switch (*hptr)
      {
         case '<' :
            for (cptr = "&lt;"; *cptr && sptr < zptr; *sptr++ = *cptr++);
            break;
         case '>' :
            for (cptr = "&gt;"; *cptr && sptr < zptr; *sptr++ = *cptr++);
            break;
         case '&' :
            for (cptr = "&amp;"; *cptr && sptr < zptr; *sptr++ = *cptr++);
            break;
         default: *sptr++ = *hptr;
      }
      hptr++;
   }
   *sptr = '\0';

   return (buf);
}

/*****************************************************************************/
/*
Evaluate the conditional depending on the current conditioning status.
Returns ECHILD on underflow, E2BIG on overflow, and SS$_BADPARAM if unknown.

The docptr->conditional datum has the value

 1) when processing
-1) has processed but hit |elif| or |else| and so no longer
 0) not processing

Document content is only processed when it has a value > 0.  So if an |elif|
hits a 1 at its own level then that level goes to -1.  Same for an |else|.

The condition processor parses all levels in nested conditionals, even when not
actually processing more nested levels due to non-processing less nested
levels, and so should catch and report syntactic errors of all levels.
*/

int renderCondition (struct wasdoc_st *docptr)

{
   int  error = 0, elif = 0, insight, isnot = 0, minus1, yes = 0;
   char  *aptr, *bptr, *cptr, *tptr;
   char  buf [1024];

   TGET (docptr, tptr);

   if (dbug>1)
      dbugThis (FI_LI, "renderCondition() %d %d %s",
                docptr->conLevel, docptr->conditional[docptr->conLevel],
                dbugMax(tptr));

   /* some processing determined by the preceding level */
   if (docptr->conLevel)
      minus1 = docptr->conditional[docptr->conLevel-1];
   else
      minus1 = 1;

   /* if deeper not processing then no insight unless 5 or more */
   insight = docptr->insight;
   if (minus1 <= 0)
      if (docptr->insight < 5)
         docptr->insight = 0;

   if ((elif = MATCH6 (tptr, "|elif|")) && !docptr->conLevel)
      error = ECHILD;
   else
   if (MATCH4 (tptr, "|if|") || elif)
   {
      tptr += 3;
      if (elif) tptr += 2;

      if (ENDTAG(tptr))
         buf[0] = '\0';
      else
      {
         tptr++;
         TPUT (docptr, tptr);
         renderGetParam (docptr, buf, sizeof(buf));
         TGET (docptr, tptr);
      }
      if (MATCH2 (tptr, "||")) tptr++;
      if (*tptr == '|') tptr++;

      if (docptr->insight >= 4)
         wasDocInsight (docptr, "%s", buf);

      bptr = buf;
      if (*bptr == '!')
      {
         isnot = 1;
         bptr++;
      }
      else
      if (MATCH2 (bptr, "\\!"))
         bptr++;

      if (!bptr[0])
         /* no conditional is false */
         yes = 0;
      else
      if (MATCH2 (bptr, "0"))
         yes = 0;
      else
      if (MATCH2 (bptr, "1"))
         yes = 1;
      else
      if (MATCH8 (bptr, "dynamic"))
         yes = docptr->isDynamic;
      else
      if (MATCH7 (bptr, "static"))
         yes = docptr->isStatic;
      else
      if (MATCH7 (bptr, "single"))
         yes = !docptr->chunked;
      else
      if (MATCH6 (bptr, "multi"))
         yes = docptr->chunked;
      else
      if (MATCH5 (bptr, "hide"))
         yes = CgiLibVarNull("WWW_FORM_NOHIDE") != NULL;
      else
      if (MATCH5 (bptr, "wasd"))
         yes = CgiLibEnvironmentIsWasd();
      else
      if (MATCH7 (bptr, "apache"))
         yes = CgiLibEnvironmentIsApache();
      else
      if (MATCH4 (bptr, "osu"))
         yes = CgiLibEnvironmentIsOsu();
      else
      if (MATCH4 (bptr, "cgi="))
      {
         if (isCgi || isCgiPlus)
         {
            /* <cgi-name>[:<keyword><regex>] */
            for (aptr = bptr + 4; *aptr && *aptr != ':'; aptr++);
            if (*aptr) *aptr++ = '\0';
            cptr = CgiLibVarNull (bptr+4);
            yes = testCondition (docptr, cptr, aptr);
         }
         else
            yes = 0;
      }
      else
      if (MATCH4 (bptr, "lnm="))
      {
         /* <log-name>[;<log-table>][:<keyword><regex>] */
         for (aptr = bptr + 4; *aptr && *aptr != ':'; aptr++);
         if (*aptr) *aptr++ = '\0';
         cptr = renderTrnLnm (docptr, bptr+7, 0);
         yes = testCondition (docptr, cptr, aptr);
      }
      else
      if (MATCH6 (bptr, "spawn="))
      {
         /* spawn=<command>[:<keyword><regex>] */
         for (aptr = cptr = bptr + 6; *aptr && *aptr != ':'; aptr++)
         {
            /* escape to allow ':' in the spawn command */
            if (*aptr == '\\' && *(aptr+1) == ':') aptr++;
            *cptr++ = *aptr;
         }
         if (*aptr) *aptr++ = '\0';
         *cptr = '\0';
         yes = SpawnCommand (docptr, bptr+6, aptr) < 0;
      }
      else
      if (MATCH4 (bptr, "syi="))
      {
         if (isCgi || isCgiPlus)
         {
            /* <SYI-name>[:<keyword><regex>] */
            for (aptr = bptr + 4; *aptr && *aptr != ':'; aptr++);
            if (*aptr) *aptr++ = '\0';
            cptr = renderGetSyi (docptr, bptr+4);
            yes = testCondition (docptr, cptr, aptr);
         }
         else
            yes = 0;
      }
      else
      if (MATCH5 (bptr, "time:"))
         yes = testTime (docptr, bptr+5);
      else
      if (MATCH8 (bptr, "insight:"))
      {
         /* is insight enabled is it at this value */
         if (isdigit(bptr[8]))
            yes = atoi(bptr+8) >= docptr->insight;
         else
            yes = docptr->insight > 0;
      }
      else
      if (isupper(bptr[0]))
      {
         /* <FLAG>[:<keyword><regex>] */
         for (aptr = bptr; *aptr && *aptr != ':'; aptr++);
         if (*aptr) *aptr++ = '\0';
         cptr = renderFlag (docptr, bptr, 0);
         if (cptr)
         {
            if (*aptr)
               yes = testCondition (docptr, cptr, aptr);
            else
            {
               while (cptr && isspace(*cptr)) cptr++;
               if (isdigit(*cptr))
                  yes = atoi(cptr);
               else
                  yes = !*cptr;
            }
         }
         else
            error = SS$_BADPARAM;
      }
      else
         error = SS$_BADPARAM;

      if (!error)
      {
         if (minus1 > 0)
         {
            /* deeper is processing */
            if (isnot) yes = !yes;
            if (elif)
               if (docptr->conditional[docptr->conLevel] == 0)
                  docptr->conditional[docptr->conLevel] = yes;
               else
                  docptr->conditional[docptr->conLevel] = -1;
            else
            if (docptr->conditional[docptr->conLevel] > 0)
               if (docptr->conLevel < CONDITION_MAX)
                  docptr->conditional[++docptr->conLevel] = yes;
               else
                  error = E2BIG;
            else
               docptr->conditional[++docptr->conLevel] = -1;
          }
          else
          {
            /* deeper is NOT processing */
            if (elif)
               docptr->conditional[docptr->conLevel] = -1;
            else
            if (docptr->conLevel < CONDITION_MAX)
               docptr->conditional[++docptr->conLevel] = -1;
            else
               error = E2BIG;
          }
       }
   }
   else
   if (MATCH6 (tptr, "|else|"))
   {
      if (docptr->insight >= 4) wasDocInsight (docptr, "|else|");
      if (!docptr->conLevel)
         error = ECHILD;
      else
      if (minus1 > 0)
         /* deeper is processing */
         if (docptr->conditional[docptr->conLevel] == 0)
            docptr->conditional[docptr->conLevel] = 1;
         else
            docptr->conditional[docptr->conLevel] = -1;
      else
         /* deeper is NOT processing */
         docptr->conditional[docptr->conLevel] = -1;
      tptr += 6;
   }
   else
   if (MATCH7 (tptr, "|endif|"))
   {
      if (docptr->insight >= 4) wasDocInsight (docptr, "|endif|");
      if (!docptr->conLevel)
         error = ECHILD;
      else
         docptr->conditional[docptr->conLevel--] = 0;
      tptr += 7;
   }
   else
      error = SS$_BADPARAM;

   if (docptr->insight >= 4)
      wasDocInsight (docptr, "%s%d/%d",
            docptr->conditional[docptr->conLevel] > 0 ? "&check;" : "&cross;",
            docptr->conLevel, docptr->conditional[docptr->conLevel]);

   if (*tptr == '\n') tptr++;
   TPUT (docptr, tptr);

   docptr->insight = insight;

   if (dbug>1)
      dbugThis (FI_LI, "%d %d %s",
                docptr->conLevel, docptr->conditional[docptr->conLevel],
                dbugMax(tptr));

   return (error);
}  

/*****************************************************************************/
/*
Copy a bar-delimited string into the supplied buffer.
Return 0 for success or any other vaxc%errno for error.
*/

int renderGetParam
(
struct wasdoc_st *docptr,
char *buf,
int size
)
{
   char  *sptr, *tptr, *zptr;

   TGET (docptr, tptr);

   if (dbug>1) dbugThis (FI_LI, "renderGetParam() %s", dbugMax(tptr));

   if (size) buf[0] = '\0';

   /* look slightly behind to check if one might not be supplied */
   if (ENDTAG (tptr-1) && !MATCH2 (tptr-1, "|!")) return (0);

   zptr = (sptr = buf) + size - 1;
   if (zptr <= sptr) RETURN_FI_LI (docptr, SS$_RESULTOVF)
   while (*tptr && *tptr != '|' && sptr < zptr)
   {
      if (*tptr == '\\')
      {
         tptr++;
         if (*tptr == '\n')
         {
            tptr++;
            continue;
         }
         if (!*tptr) break;
      }
      *sptr++ = *tptr++;
   }
   if (*tptr != '|') RETURN_FI_LI (docptr, SS$_BADPARAM)
   if (sptr >= zptr) RETURN_FI_LI (docptr, SS$_RESULTOVF)
   *sptr = '\0';

   TPUT (docptr, tptr);

   return (0);
}

/*****************************************************************************/
/*
Set document characteristic.
*/

int renderSet
(
struct wasdoc_st *docptr,
char *param
)
{
   int  error = 0, number;
   char  *cptr, *sptr, *tptr, *zptr;

   if (dbug>1) dbugThis (FI_LI, "renderSet() %s", dbugMax(param));

   if (MATCH8 (param, "chunked="))
   {
      /* 1 enables, 0 let the client decide, -1 disables */
      int  chunked;
      chunked = atoi(param+8);
      if (chunked < 0 || !docptr->chunked) docptr->chunked = chunked;
   }
   else
   if (MATCH6 (param, "found="))
   {
      /* explicitly set the default of 'this "in" that' */
      zptr = (sptr = docptr->setFoundIn) + sizeof(docptr->setFoundIn)-1;
      for (cptr = param + 6; *cptr && sptr < zptr; *sptr++ = *cptr++);
      *sptr = '\0';
   }
   else
   if (MATCH9 (param, "idx=cols="))
   {
      /* number of columns in the index */
      number = atoi(param+9);
      if (number == 1 || number == 2 || number == 3 || number == 4)
         docptr->setIdxCols = number;
      else
         error = SS$_BADPARAM;
   }
   else
   if (MATCH9 (param, "idx=sort="))
   {
      /* index entries sorted is 1, unsorted is 0 */
      docptr->setIdxSort = atoi(param+9);
   }
   else
   if (MATCH12 (param, "idx=collate="))
   {
      /* collation characters for index (26 Latin alphabetics default) */
      zptr = (sptr = docptr->idxCollate) + sizeof(docptr->idxCollate)-1;
      /* if plus then append to existing collation, otherwise replace */
      cptr = param + 12;
      if (*cptr == '+')
      {
         for (sptr = docptr->idxCollate; *sptr; sptr++);
         cptr++;
      }
      while (*cptr && sptr < zptr) *sptr++ = *cptr++;
      *sptr = '\0';
   }
   else
   if (MATCH8 (param, "insight="))
   {
      /* is explicitly looked for *very* early in document processing */
      if (docptr->insight = atoi(param+8))
         if (cptr = CgiLibVarNull ("FORM_INSIGHT"))
            docptr->insight = atoi(cptr);
   }
   else
   if (MATCH7 (param, "locale="))
   {
      if (MATCH0 (param, "locale=ctype=", 13)) {
         if (!setlocale (LC_CTYPE, param+13)) error = vaxc$errno;
      }
      else
      if (MATCH7 (param, "locale=") && isdigit(param[7]) && param[8] == '=') {
         if (!setlocale (atoi(param+8), param+10)) error = vaxc$errno;
      }
      else
      if (MATCH7 (param, "locale=")) {
         if (!setlocale (LC_ALL, param+7)) error = vaxc$errno;
      }
   }
   else
   if (MATCH9 (param, "navigate="))
   {
      /* leading integer can enable/disable navigation icons */
      cptr = param + 9;
      if (isdigit(*cptr))
      {
         docptr->setNavigate = atoi(cptr);
         while (isdigit(*cptr)) cptr++;
         if (*cptr == '|') cptr++;
      }
      if (!*cptr) return (0);
      /* navigation icons, <back>|<prev>|<top>|<next>|<forward> */
      if (*cptr != '|')
      {
         zptr = (sptr = docptr->iconBack) + sizeof(docptr->iconBack)-1;
         while (*cptr && *cptr != '|' && sptr < zptr) *sptr++ = *cptr++;
         *sptr = '\0';
         while (*cptr && *cptr != '|') cptr++;
      }
      if (*cptr) cptr++;
      if (*cptr != '|')
      {
         zptr = (sptr = docptr->iconPrev) + sizeof(docptr->iconPrev)-1;
         while (*cptr && *cptr != '|' && sptr < zptr) *sptr++ = *cptr++;
         *sptr = '\0';
         while (*cptr && *cptr != '|') cptr++;
      }
      if (*cptr) cptr++;
      if (*cptr != '|')
      {
         zptr = (sptr = docptr->iconTop) + sizeof(docptr->iconTop)-1;
         while (*cptr && *cptr != '|' && sptr < zptr) *sptr++ = *cptr++;
         *sptr = '\0';
         while (*cptr && *cptr != '|') cptr++;
      }
      if (*cptr) cptr++;
      if (*cptr != '|')
      {
         zptr = (sptr = docptr->iconNext) + sizeof(docptr->iconNext)-1;
         while (*cptr && *cptr != '|' && sptr < zptr) *sptr++ = *cptr++;
         *sptr = '\0';
         while (*cptr && *cptr != '|') cptr++;
      }
      if (*cptr) cptr++;
      if (*cptr != '|')
      {
         zptr = (sptr = docptr->iconForw) + sizeof(docptr->iconForw)-1;
         while (*cptr && *cptr != '|' && sptr < zptr) *sptr++ = *cptr++;
         *sptr = '\0';
         while (*cptr && *cptr != '|') cptr++;
      }
   }
   else
   if (MATCH5 (param, "note="))
   {
      /* explicitly set the default title of a note */
      zptr = (sptr = docptr->setNote) + sizeof(docptr->setNote)-1;
      for (cptr = param + 5; *cptr && sptr < zptr; *sptr++ = *cptr++);
      *sptr = '\0';
   }
   else
   if (MATCH9 (param, "paginate="))
   {
      /* enable automatic pagination */
      docptr->setPaginate = atoi(param+9);
   }
   else
   if (MATCH10 (param, "table=margin="))
   {
      /* table margin (+, -, \0) */
      docptr->setTabMargin = param[13];
      docptr->bflag[docptr->bfindex] &= ~BFLAG_CENTER;
   }
   else
   if (MATCH6 (param, "title="))
   {
      /* explicitly set the title of the document */
      zptr = (sptr = docptr->title) + sizeof(docptr->title)-1;
      for (cptr = param + 6; *cptr && sptr < zptr; *sptr++ = *cptr++);
      *sptr = '\0';
   }
   else
   if (MATCH12 (param, "toc2=next=cols="))
   {
      /* number of columns in NEXT secondary table of content */
      number = atoi(cptr = param+15);
      if (number == 1 || number == 2 || number == 3 || number == 4)
         /* propagate into second pass */
         wasDocPrintf (docptr, "<!--$$X:%s$$-->", param);
      else
         error = SS$_BADPARAM;
   }
   else
   if (MATCH10 (param, "toc2=cols="))
   {
      /* number of columns in secondary table of content */
      number = atoi(cptr = param+10);
      if (number == 1 || number == 2 || number == 3 || number == 4)
      {
         docptr->setToc2Cols = number;
         while (*cptr && isdigit(*cptr)) cptr++;
         while (*cptr && !isdigit(*cptr)) cptr++;
         if (isdigit(*cptr))
            if ((number = atoi(cptr)) <= 100)
               docptr->setToc2ColsWidth = number;
      }
      else
         error = SS$_BADPARAM;
   }
   else
   if (MATCH5 (param, "toc2="))
   {
      /* whether a secondary TOC is generated */
      cptr = param+5;
      if (isdigit(*cptr))
         docptr->setToc2 = atoi(param+5);
      else
         error = SS$_BADPARAM;
   }
   else
   if (MATCH9 (param, "toc=cols="))
   {
      /* number of colmns in table of content */
      number = atoi(param+9);
      if (number == 1 || number == 2 || number == 3 || number == 4)
         docptr->setTocCols = number;
      else
         error = SS$_BADPARAM;
   }
   else
   if (MATCH11 (param, "toc=format="))
   {
      /* explicitly set the format of the TOC */
      zptr = (sptr = docptr->setTocForm) + sizeof(docptr->setTocForm)-1;
      for (cptr = param + 11; *cptr && sptr < zptr; *sptr++ = *cptr++);
      *sptr = '\0';
   }
   else
   if (isupper (param[0]))
   {
      /* setting a flag */
      if (!renderFlag (docptr, param, 1)) error = SS$_BADPARAM;
   }
   else
      error = SS$_BADPARAM;

   return (error);
}

/*****************************************************************************/
/*
Flags begin with an upper-case alphabetic, have all upper-case alphabetics and
digits.  Flag strings are |set|FLAG[=<integer>|<string>]| by renderSet().

Search the array of flags strings for the specified flag. Can set a new
flag, reset an existing flag, and also just search for a flag. If the
parameter contains an equate symbol (=) then it's considered to be a (re)set.
A set/reset returns a pointer for success or a NULL if something failed.

If not found return NULL to indicate that.
If found and if the flag has a value return a pointer to that (even if empty).
*/

char* renderFlag
(
struct wasdoc_st *docptr,
char *flag,
int set
)
{
   int  idx;
   char  *cptr, *sptr;

   if (dbug>1) dbugThis (FI_LI, "renderFlag() %d %s", set, dbugAll(flag));

   /* search for an existing flag */
   for (idx = 0; idx < docptr->flagCount; idx++)
   {
      sptr = flag;
      for (cptr = docptr->flags[idx];
           *cptr && *cptr != '=' && *sptr && *sptr != '=';
           cptr++, sptr++)
         if (*cptr != *sptr) break;
      if (*cptr && *cptr != '=') continue;
      if (*sptr && *sptr != '=') continue;
      break;
   }

   if (idx >= docptr->flagCount)
   {
      /* not found */
      if (!set) return (NULL);

      /* check not an empty name and is all upper */
      for (cptr = flag;
           *cptr && *cptr != '=' && (isupper(*cptr) || isdigit(*cptr));
           cptr++);
      if (cptr == flag) return (NULL);
      if (*cptr && *cptr != '=' && !isupper(*cptr) && !isdigit(*cptr))
          return (NULL);

      /* set a new flag */
      if (docptr->flagCount >= FLAG_MAX) RETURN_FI_LI (docptr, NULL)
      docptr->flags[docptr->flagCount] = calloc (strlen(flag), 1);
      if (!docptr->flags[docptr->flagCount]) RETURN_FI_LI (docptr, NULL)
      strcpy (docptr->flags[docptr->flagCount], flag);
      docptr->flagCount++;
      for (cptr = flag; *cptr && *cptr != '='; cptr++);
      if (*cptr) cptr++;
      return (cptr);
   }

   /* if reset an existing flag */
   if (*sptr)
   {
      free (docptr->flags[idx]);
      docptr->flags[idx] = calloc (strlen(flag), 1);
      if (!docptr->flags[idx]) RETURN_FI_LI (docptr, NULL)
      strcpy (docptr->flags[idx], flag);
      for (cptr = flag; *cptr && *cptr != '='; cptr++);
      if (*cptr) cptr++;
      return (cptr);
   }

   /* if just searching for a flag */
   if (*cptr) cptr++;
   return (cptr);
}

/*****************************************************************************/
/*
The |1..|4 represent the primary TOC hierarchy.  |0 represents a secondary
heading without a primary TOC.  |0 is transformed into an <h5> heading. 
Cross-reference |9 into a <h6>.

Prefixing any section digit (01, 02, 03, 04) with a zero represents a heading
without a primary TOC entry.
*/

int renderInsertHeading (struct wasdoc_st *docptr)

{
   int  error = 0;
   char  nine9, zero0, zero1, zero2, zero3, zero4, zero9;
   char  *cptr, *tptr;

   if (dbug>1) dbugThis (FI_LI, "renderInsertHeading()");

   TGET (docptr, tptr);

   if (tptr[0] != '|') RETURN_FI_LI (docptr, SS$_FORMAT)

   if (docptr->stindex >= STACK_MAX) RETURN_FI_LI (docptr, SS$_RESULTOVF)
   docptr->tstack[++docptr->stindex] = tptr;

   /* leading zero suppresses primary TOC entry */
   cptr = tptr + 1;
   /* bit sloppy and inefficient but */
   zero0 = MATCH2(cptr, "00");
   zero1 = MATCH2(cptr, "01");
   zero2 = MATCH2(cptr, "02");
   zero3 = MATCH2(cptr, "03");
   zero4 = MATCH2(cptr, "04");
   zero9 = MATCH2(cptr, "09");
   nine9 = MATCH2(cptr, "99");
   if (isdigit(*cptr) && isdigit(*(cptr+1))) cptr++;

   /* first visible heading becomes top of document */
   if (*cptr >= '0' && *cptr <= '4')
      if (!(docptr->section[1] || docptr->section[2] || docptr->section[3] ||
            docptr->section[4] || docptr->section[5]))
         wasDocAsIs (docptr, "<a id=\"0.\" href=\"#\"></a>\n");

   switch (*cptr)
   {
      case '0' : if (zero0)
                    docptr->section[5] = SECTION_NOT_IN;
                 else
                    docptr->section[5]++;
                 docptr->section[6] = 0;
                 docptr->cstack[docptr->stindex] = "</h5>";
                 cptr = "<h5";
                 break;

      case '1' : if (zero1)
                    docptr->section[5]++;
                 else
                 {
                    docptr->section[1]++;
                    docptr->chunkTotal++;
                    docptr->section[2] = docptr->section[3] =
                       docptr->section[4] = docptr->section[5] =
                       docptr->section[6] = 0;
                 }
                 docptr->cstack[docptr->stindex] = "</h1>";
                 cptr = "<h1";
                 break;

      case '2' : if (zero2)
                    docptr->section[5]++;
                 else
                 {
                    docptr->section[2]++;
                    docptr->section[3] = docptr->section[4] =
                       docptr->section[5] = docptr->section[6] = 0;
                 }
                 docptr->cstack[docptr->stindex] = "</h2>";
                 cptr = "<h2";
                 break;

      case '3' : if (zero3)
                    docptr->section[5]++;
                 else
                 {
                    docptr->section[3]++;
                    docptr->section[4] = docptr->section[5] =
                       docptr->section[6] = 0;
                 }
                 docptr->cstack[docptr->stindex] = "</h3>";
                 cptr = "<h3";
                 break;

      case '4' :
                 if (zero4)
                    docptr->section[5]++;
                 else
                 {
                    docptr->section[4]++;
                    docptr->section[5] = docptr->section[6] = 0;
                 }
                 docptr->cstack[docptr->stindex] = "</h4>";
                 cptr = "<h4";
                 break;

      case '5' :
      case '6' :
      case '7' :
      case '8' :
      case '9' : if (zero0)
                    docptr->section[6] = SECTION_NO_INDEX;
                 else
                 if (nine9)
                    docptr->section[6] = SECTION_NOT_IN;
                 else
                    docptr->section[6]++;
                 docptr->cstack[docptr->stindex] = "</h6>";
                 cptr = "<h9";  /* faux tag */
                 break;

      default : RETURN_FI_LI (docptr, SS$_ITEMNOTFOUND)
   }

   error = wasDocPrintf (docptr, "<!--$$H:%s$$-->",
                         renderNumericId(docptr->section));
   if (error) RETURN_FI_LI (docptr, error);

   error = renderInsertTag (docptr, cptr);
   if (error) return (error);

   return (0);
}

/*****************************************************************************/
/*
*/

int renderInsertNote (struct wasdoc_st *docptr)

{
   int  error;
   char  *cptr;

   if (dbug>1) dbugThis (FI_LI, "renderInsertNote()");

   /* use the default heading */
   if (!*(cptr = docptr->setNote)) cptr = DEFAULT_NOTE;
   
   /* a note is implemented as a level 6 heading */
   docptr->section[6]++;
   
   error = wasDocPrintf (docptr,
"<!--$$H:%s$$-->\
<h5 class=\"head center\">%s</h5>\n\
<hr class=\"note_hr\">\n",
                          renderNumericId(docptr->section), cptr);

   return (error);
}

/*****************************************************************************/
/*
The parameter URL can be absolute, relative or in-document fragment generated
from a heading title.
*/

int renderInsertLink
(
struct wasdoc_st *docptr,
char *param
)
{
   char  *cptr, *sptr, *zptr;
   char  param2 [512];

   if (dbug>1) dbugThis (FI_LI, "renderInsertLink() %s", dbugAll(param));

   for (cptr = param; *cptr && isalpha(*cptr); cptr++);

   if (MATCH3 (cptr, "://") || MATCH7 (param, "mailto:"))
   {
      /* looks like a URL scheme */
      wasDocAsIs (docptr, param);
   }
   else
   if (strstr (cptr, "##"))
   {
      /* another document, munge the URI */
      zptr = (sptr = param2) + sizeof(param2)-1;

      /* any trailing chunk faux "directory" must be allowed for */
      if (docptr->chunked && docptr->isDynamic)
         if (MATCH2 (param, "./") || MATCH3 (param, "../"))
            for (cptr = "../"; *cptr; *sptr++ = *cptr++);

      /* essentially make it ODS-2 compliant */
      for (cptr = param; *cptr && *cptr != '#' && sptr < zptr; cptr++)
      {
         if (isalnum(*cptr) || *cptr == '-' || *cptr == '$' ||
                               *cptr == '.' || *cptr == '/')
            *sptr++ = tolower(*cptr);
         else
            *sptr++ = '_';
      }

      if (MATCH3 (cptr, "##\0"))
      {
         for (cptr = "#0."; *cptr && sptr < zptr; *sptr++ = *cptr++);
         *sptr = '\0';
         wasDocAsIs (docptr, param2);
      }
      else
      if (MATCH2 (cptr, "##"))
      {
         for (cptr++; *cptr && sptr < zptr; *sptr++ = *cptr++);
         *sptr = '\0';
         wasDocAsIs (docptr, param2);
         renderFragment (docptr);
      }
   }
   else
   if (param[0] == '#')
   {
      /* explicit fragment */
      wasDocEntify (docptr, param);
      renderFragment (docptr);
   }
   else
   if (param[0] == '/' ||
       MATCH2 (param, "./") ||
       MATCH3 (param, "../"))
   {
      /* any trailing chunk faux "directory" must be allowed for */
      if (docptr->chunked && docptr->isDynamic)
         if (MATCH2 (param, "./") || MATCH3 (param, "../"))
            wasDocAsIs (docptr, "../");
      /* relative URL */
      wasDocEntify (docptr, param);
      renderFragment (docptr);
   }
   else
   {
      /* to fragment ID added via heading */
      wasDocPrintf (docptr, "<!--$$L:&quot;%s&quot; at %s$#",
                    param, renderSource(docptr));
      wasDocEntify (docptr, param);
      renderFragment (docptr);
      wasDocAsIs (docptr, "$$-->");
   }

   return (0);
}

/*****************************************************************************/
/*
Create a link to another document like "Heading Name in Document Name". 
The parameter looks like "<URL>##<heading>++in++<document-title>".
*/

int renderInsertLinkIn
(
struct wasdoc_st *docptr,
char *param,
int target
)
{
   char  *cptr, *sptr, *zptr;
   char  heading [256],
         inof [256],
         title [256],
         url [256];

   if (dbug>1) dbugThis (FI_LI, "renderInsertLinkIn() %d %s",
                         target, dbugAll(param));

   zptr = (sptr = url) + sizeof(url)-1;

   /* any trailing chunk faux "directory" must be allowed for */
   if (docptr->chunked && docptr->isDynamic)
      if (MATCH2 (param, "./") || MATCH3 (param, "../"))
         for (cptr = "../"; *cptr; *sptr++ = *cptr++);

   /* essentially make it ODS-2 compliant */
   for (cptr = param; *cptr && !MATCH2(cptr,"##") && sptr < zptr; cptr++)
   {
      if (isalnum(*cptr) || *cptr == '-' || *cptr == '$' ||
                            *cptr == '.' || *cptr == '/')
         *sptr++ = tolower(*cptr);
      else
         *sptr++ = '_';
   }
   *sptr = '\0';
   if (*cptr != '#' || sptr >= zptr || !url[0])
      RETURN_FI_LI (docptr, SS$_BADPARAM)

   zptr = (sptr = heading) + sizeof(heading)-1;
   for (cptr+=2; *cptr && !MATCH2(cptr,"++") && sptr < zptr; *sptr++ = *cptr++)
      if (*cptr ==  '\\' && *(cptr+1)) cptr++;
   *sptr = '\0';
   if (*cptr != '+' || !heading[0] || sptr >= zptr)
      RETURN_FI_LI (docptr, SS$_BADPARAM)

   zptr = (sptr = inof) + sizeof(inof)-1;
   for (cptr+=2; *cptr && !MATCH2(cptr,"++") && sptr < zptr; *sptr++ = *cptr++)
      if (*cptr ==  '\\' && *(cptr+1)) cptr++;
   *sptr = '\0';
   if (*cptr != '+' || !inof[0] || sptr >= zptr)
      RETURN_FI_LI (docptr, SS$_BADPARAM)

   zptr = (sptr = title) + sizeof(title)-1;
   for (cptr+=2; *cptr && sptr < zptr; *sptr++ = *cptr++)
      if (*cptr ==  '\\' && *(cptr+1)) cptr++;
   *sptr = '\0';
   if (sptr >= zptr || !title[0]) RETURN_FI_LI (docptr, SS$_BADPARAM)

   /* the <a...href=\" has already been inserted by RenderLink() */
   wasDocAsIs (docptr, url);
   wasDocAsIs (docptr, "#");
   wasDocAsIs (docptr, heading);
   renderFragment (docptr);
   wasDocAsIs (docptr, "\">");
   wasDocAsIs (docptr, heading);
   wasDocAsIs (docptr, "</a> ");
   wasDocAsIs (docptr, inof);
   if (target)
      wasDocAsIs (docptr, " <a class=\"link blank\" target=\"_blank\" href=\"");
   else
      wasDocAsIs (docptr, " <a class=\"link\" href=\"");
   wasDocAsIs (docptr, url);
   wasDocAsIs (docptr, "#0.\">");
   wasDocAsIs (docptr, title);
   wasDocAsIs (docptr, "</a>");

   return (0);
}

/*****************************************************************************/
/*
The parameter URL can be absolute or relative.
*/

int renderInsertUrl
(
struct wasdoc_st *docptr,
char *param
)
{
   char  ch;
   char  *cptr, *sptr, *zptr;
   char  uri [256];

   if (dbug>1) dbugThis (FI_LI, "renderInsertUrl() %s", dbugAll(param));

   /* look for what might be a URL */ 
   for (cptr = param;
        *cptr && (isalpha(*cptr) || !MATCH3(cptr,"://"));
        cptr++);
   if (MATCH3(cptr,"://") || MATCH7 (param, "mailto:"))
   {
      /* looks like a URL scheme */
      wasDocAsIs (docptr, param);
   }
   else
   if (isalnum(*param) ||
       MATCH2 (param, "./") ||
       MATCH3 (param, "../"))
   {
      /* relative to the document location (which may be a script) */
      if (docptr->isDynamic)
      {
         zptr = (sptr = uri) + sizeof(uri)-1;
         for (cptr = docptr->pinfo; *cptr && sptr < zptr; *sptr++ = *cptr++);
         *sptr = '\0';
         while (sptr > uri && *sptr != '/') sptr--;
         if (MATCH2 (cptr = param, "./")) cptr += 2;

         while (sptr > uri)
         {
            if (!MATCH3 (cptr, "../")) break;
            if (sptr > uri) sptr--;
            while (sptr > uri && *sptr != '/') sptr--;
            cptr += 3;
         }
         if (sptr == uri) RETURN_FI_LI (docptr, SS$_BADPARAM)

         if (sptr < zptr) *sptr++ = '/';
         while (*cptr && sptr < zptr) *sptr++ = *cptr++;
         *sptr = '\0';
         if (sptr >= zptr) RETURN_FI_LI (docptr, SS$_RESULTOVF)

         wasDocAsIs (docptr, uri);
      }
      else
         wasDocAsIs (docptr, param);
   }
   else
      wasDocAsIs (docptr, param);

   return (0);
}

/*****************************************************************************/
/*
Insert the specified item into the HTML, escaped as required.
*/

int renderInsertOther
(
struct wasdoc_st *docptr,
char *param
)
{
   static char  RepeatFao [] = "!#*?\0";
   static $DESCRIPTOR (DateFaoDsc, "!%D\0");
   static $DESCRIPTOR (DateWidthFaoDsc, "!#%D\0");
   static $DESCRIPTOR (TimeFaoDsc, "!%T\0");
   static $DESCRIPTOR (TimeWidthFaoDsc, "!#%T\0");
   static $DESCRIPTOR (RepeatFaoDsc, RepeatFao);

   int  error, noescape, ignore = 0, number = 0, status, trim = 0;
   char  *cptr, *sptr;
   char  buf [256];
   time_t  t;
   struct tm  *tmp;
   $DESCRIPTOR (bdsc, buf);

   if (dbug>1) dbugThis (FI_LI, "renderInsertOther() %s", dbugAll(param));

   if (!param[0]) RETURN_FI_LI (docptr, SS$_BADPARAM)

   *(cptr = buf) = '\0';

   if (MATCH4 (param, "cgi="))
   {
      noescape = docptr->noescape;
      cptr = param + 4;
      while (*cptr == '!' || *cptr == '\"')
      {
         if (*cptr == '!') ignore = *cptr++;
         if (*cptr == '\"') noescape = *cptr++;
      }
      cptr = CgiLibVarNull (cptr);
      if (!cptr)
         if (ignore)
         {
            wasDocInsertStatus (docptr, SS$_BADPARAM);
            return (0);
         }
         else
            RETURN_FI_LI (docptr, SS$_BADPARAM)
   }
   else
   if (MATCH4 (param, "env="))
   {
      noescape = docptr->noescape;
      cptr = param + 4;
      while (*cptr == '!' || *cptr == '\"')
      {
         if (*cptr == '!') ignore = *cptr++;
         if (*cptr == '\"') noescape = *cptr++;
      }
      cptr = getenv (cptr);
      if (!cptr)
         if (ignore)
         {
            wasDocInsertStatus (docptr, SS$_BADPARAM);
            return (0);
         }
         else
            RETURN_FI_LI (docptr, SS$_BADPARAM)
   }
   else
   if (MATCH4 (param, "fao="))
   {
      param += 4;
      cptr = buf;
      noescape = docptr->noescape;
      if (isdigit(*param))
      {
         number = atoi(param);
         if (number > sizeof(buf)-1) number = sizeof(buf)-1;
         while (isdigit(*param)) param++;
      }
      if (MATCH2 (param, "%D"))
         if (number)
            sys$fao (&DateWidthFaoDsc, 0, &bdsc, number, 0);
         else
            sys$fao (&DateFaoDsc, 0, &bdsc, 0);
      else
      if (MATCH2 (param, "%T"))
         if (number)
            sys$fao (&TimeWidthFaoDsc, 0, &bdsc, number, 0);
         else
            sys$fao (&TimeFaoDsc, 0, &bdsc, 0);
      else
      if (param[0] == '*' && param[1])
      {
         RepeatFao[3] = param[1];
         sys$fao (&RepeatFaoDsc, 0, &bdsc, number, 0);
      }
      else
         cptr = NULL;
   }
   else
   if (MATCH5 (param, "file="))
      return (renderInsertFile (docptr, param+5, 0));
   else
   if (MATCH12 (param, "locale=ctype"))
      cptr = setlocale (LC_CTYPE, NULL);
   else
   if (MATCH7 (param, "locale="))
      cptr = setlocale (atoi(param+8), NULL);
   else
   if (MATCH7 (param, "locale"))
      cptr = setlocale (LC_ALL, NULL);
   else
   if (MATCH8 (param, "include="))
      return (renderIncludeFile (docptr, param+8));
   else
   if (MATCH8 (param, "Include="))
      return (0);
   else
   if (MATCH6 (param, "spawn="))
      return (SpawnCommand (docptr, param+6, NULL));
   else
   if (MATCH4 (param, "syi="))
      cptr = renderGetSyi (docptr, param+4);
   else
   if (MATCH4 (param, "time"))
   {
      if (param[4] == '=')
         cptr = param + 5;
      else
         cptr = "%a, %d %b %Y %T %z";
      t = time(NULL);
      tmp = localtime(&t);
      if (!tmp) RETURN_FI_LI (docptr, SS$_BADPARAM)
      if (!strftime (buf, sizeof(buf), cptr, tmp))
         RETURN_FI_LI (docptr, SS$_BADPARAM)
      cptr = buf;
   }
   else
   if (MATCH4 (param, "lnm="))
   {
      int  report = 0;
      noescape = docptr->noescape;
      for (cptr = sptr = param + 4; *cptr == '!' || *cptr == '\"'; cptr++)
      {
         if (*cptr == '!') report = 1;
         if (*cptr == '\"') noescape = 1;
      }
      cptr = renderTrnLnm (docptr, cptr, report);
   }
   else
   if (MATCH7 (param, "wasdoc="))
   {
      if (MATCH8 (param+7, "version"))
         cptr = SoftwareVersion;
      else
      if (MATCH8 (param+7, "software"))
         cptr = SoftwareID;
      else
      if (MATCH5 (param+7, "path"))
         cptr = docptr->pinfo;
      else
      if (MATCH10 (param+7, "directory"))
         cptr = docptr->dname;
   }
   else
   if (isupper(param[0]))
   {
      /* insert the flag value */
      noescape = 1;
      cptr = renderFlag (docptr, param, 0);
   }

   if (!cptr || !*cptr) RETURN_FI_LI (docptr, SS$_BADPARAM)

   if (noescape)
      wasDocAsIs (docptr, cptr);
   else
      wasDocEntify (docptr, cptr);

   return (0);
}

/*****************************************************************************/
/*
Insert the content of the specified file into the HTML, escaped as required.
*/

int renderInsertFile
(
struct wasdoc_st *docptr,
char *fname,
int noescape
)
{
   int  bytes, error, ignore = 0;
   char  *cptr, *fnptr, *sptr, *zptr;
   FILE  *ifptr;
   stat_t  fstatbuf;

   if (dbug>1) dbugThis (FI_LI, "renderInsertFile() %d %s",
                         noescape, dbugAll(fname));

   if (!noescape) noescape = docptr->noescape ? 1 : 0;
   fnptr = fname;
   while (*fnptr == '!' || *fnptr == '\"')
   {
      if (*fnptr == '!') ignore = *fnptr++;
      if (*fnptr == '\"') noescape = *fnptr++;
   }

   if (!*fnptr)
   {
      /* empty specification means include self */
      if (noescape)
         wasDocAsIs (docptr, docptr->text);
      else
         wasDocEntify (docptr, docptr->text);
      return (0);
   }

   cptr = getenv("PATH");
   chdir (docptr->dname);
   ifptr = fopen (fnptr, "r");
   error = vaxc$errno;
   chdir (cptr);

   if (!ifptr)
   {
      if (!ignore) return (error);
      wasDocInsertStatus (docptr, error);
      return (0);
   }

   if (fstat (fileno(ifptr), &fstatbuf) < 0)
   {
      error = vaxc$errno;
      fclose (ifptr);
      if (!ignore) return (error);
      wasDocInsertStatus (docptr, error);
      return (0);
   }

   /* extra bytes allow EOF when reading past the EOF */
   bytes = fstatbuf.st_size;
   bytes += 32;

   cptr = sptr = calloc (1, bytes);
   if (!cptr) exit (vaxc$errno);

   /* read the entire file into memory */
   while (fgets (sptr, bytes-(sptr-cptr), ifptr))
      while (*sptr) sptr++;

   fclose (ifptr);

   if (noescape)
      wasDocAsIs (docptr, cptr);
   else
      wasDocEntify (docptr, cptr);

   free (cptr);

   return (0);
}

/*****************************************************************************/
/*
Insert the content of the specified file into the source TEXT at the current
parse position.  The parser will then just continue with the included text.
If it has a ".css" type then we'll assume style has been set.
*/

int renderIncludeFile
(
struct wasdoc_st *docptr,
char *fname
)
{
   static char  asis1 [] = "\n|asis|\n",
                asis2 [] = "||||\n";

   int  asis = 0, bytes, error, ignore = 0;
   char  *aptr, *cptr, *fnptr, *sptr, *tptr, *zptr;
   FILE  *ifptr;
   stat_t  fstatbuf;

   if (dbug>1) dbugThis (FI_LI, "renderIncludeFile() %s", dbugAll(fname));

   fnptr = fname;
   while (*fnptr == '!' || *fnptr == '\"')
   {
      if (*fnptr == '!') ignore = *fnptr++;
      if (*fnptr == '\"') asis = *fnptr++;
   }

   /* if file extension is ".css" then assume the document has been styled */
   for (cptr = fnptr; *cptr; cptr++);
   while (cptr > fnptr && *cptr != '.' && !MATCH2((cptr-1), "^.")) cptr--;
   if (!strcasecmp (cptr, ".css")) docptr->styled = 1;

   if (dbug>1) dbugThis (FI_LI, "%s\n", dbugAll(fnptr));

   cptr = getenv("PATH");
   chdir (docptr->dname);
   ifptr = fopen (fnptr, "r");
   error = vaxc$errno;
   chdir (cptr);

   if (!ifptr)
   {
      if (!ignore) return (error);
      wasDocInsertStatus (docptr, error);
      return (0);
   }

   if (fstat (fileno(ifptr), &fstatbuf) < 0)
   {
      error = vaxc$errno;
      fclose (ifptr);
      if (ignore) return (0);
      return (error);
   }

   /* extra bytes allow EOF when reading past the EOF */
   bytes = fstatbuf.st_size + 32;
   aptr = sptr = calloc (1, bytes);
   if (!cptr) exit (vaxc$errno);

   /* read the entire file into memory */
   while (fgets (sptr, bytes-(sptr-aptr), ifptr))
      while (*sptr) sptr++;

   fclose (ifptr);

   /* adjust bytes to reflect the actual content */
   bytes = sptr - aptr;

   docptr->tsize += bytes;
   if (asis)
   {
      asis = sizeof(asis1)-1 + sizeof(asis2)-1;
      docptr->tsize += asis;
   }

   docptr->text = realloc (docptr->text, docptr->tsize);
   if (!docptr->text) exit (vaxc$errno);

   /* current parse position should be just before the end of the tag */
   tptr = docptr->text + docptr->tparse;
   if (MATCH2 (tptr, "||")) tptr++;
   if (*tptr == '|') tptr++;
   if (isspace(*tptr)) tptr++;

   /* first move the current content up */
   memmove (tptr + bytes + asis,
            sptr = tptr,
            docptr->tlength - (tptr - docptr->text));

   /* then insert the text into the space created */
   if (asis) for (cptr = asis1; *cptr; *sptr++ = *cptr++);
   memmove (sptr, aptr, bytes);
   sptr += bytes;
   if (asis) for (cptr = asis2; *cptr; *sptr++ = *cptr++);

   free (aptr);

   if (isspace(*(tptr-1))) tptr--;
   docptr->tparse = tptr - docptr->text;
   docptr->tlength += bytes + asis;

   return (0);
}

/*****************************************************************************/
/*
The trailing document text needs to be reduced to an alphanumeric ID
(fragment).  It is bounded by a leading hash.  Squash it down to that ID and
adjust the document length.
*/

void renderFragment (struct wasdoc_st *docptr)
{
   char  *aptr, *cptr, *sptr;

   for (sptr = docptr->html + docptr->hlength;
        sptr > docptr->html && *sptr != '#' && *sptr != '\"' && *sptr != '>';
        sptr--);
   if (dbug>1) dbugThis (FI_LI, "renderFragment() %s", dbugAll(aptr = sptr));
   if (*sptr != '#') return;
   for (cptr = ++sptr; *cptr; cptr++)
      if (isalnum (*cptr)) *sptr++ = tolower(*cptr);
   *sptr = '\0';
   if (dbug>1) dbugThis (FI_LI, "%s", dbugAll(aptr));
   docptr->hlength = sptr - docptr->html;
}

/*****************************************************************************/
/*
Insert a tag and any tag attributes into the HTML.  An attribute (&-introduced
and |-delimited) string can be used.  Characters may be escaped.  It a style
string.  Return zero for success or an error code.
*/

int renderInsertTag
(
struct wasdoc_st *docptr,
char *tag
)
{
   int  div = 0, clidx, head = 0, idx, image = 0, link = 0,
        linkimg = 0, list = 0, noescape = 0, note = 0, span = 0,
        table = 0, tabr = 0, tabh = 0, tabd = 0, tenths = 0;
   char  *cptr, *sptr, *tptr, *zptr;
   char  *align = "", *backlight = "", *blank = "", *bold = "", *inblock = "",
         *indent = "", *italic = "", *wrap = "", *mono = "", *strike = "",
         *tabauto = "", *target = "", *under = "",  *valign = "", *zero = "";
   char  *class [8];
   char  colspan [32] = "", empad [32] = "", fname[64], rowspan [32] = "";

   for (clidx = 0; (clidx * sizeof(char*)) < sizeof(class); clidx++)
      class[clidx] = NULL;
   clidx = 0;

   if (HMORE (docptr)) wasDocMoreHtml (docptr);

   tptr = docptr->text + docptr->tparse; 
   sptr = docptr->html + docptr->hlength; 
   /* right to the end of the buffer */
   zptr = docptr->html + docptr->hsize;

   if (dbug>1) dbugThis (FI_LI, "renderInsertTag() %c%s%c %s",
                         bvbar, tag, bvbar, dbugMax(tptr));

   if (!(span = MATCH5 (tag, "<span")))
      if (!(div = MATCH4 (tag, "<div")))
         if (!(head = MATCH2 (tag, "<h")))
            if (!(link = MATCH3 (tag, "<a ")))
               if (!(link = linkimg = MATCH3 (tag, "<aimg ")))  /* faux tag */
                  if (!(image = MATCH4 (tag, "<img")))
                     if (!(list = MATCH3 (tag, "<li")))
                        if (!(list = MATCH3 (tag, "<ol")))
                           if (!(list = MATCH3 (tag, "<sl")))  /* faux tag */
                              if (!(list = MATCH3 (tag, "<ul")))
                                 if (!(table = MATCH4 (tag, "<tab")))
                                    if (!(tabr = MATCH3 (tag, "<tr")))
                                       if (!(tabh = MATCH3 (tag, "<th")))
                                          if (!(tabd = MATCH3 (tag, "<td")))
                                             wasDocBugcheck(FI_LI); 

   if (div) docptr->bflag[++docptr->bfindex] = 0;

   if (span)
   {
      cptr = "<span class=\"high" ;
      while (*cptr && sptr < zptr) *sptr++ = *cptr++;
      for (tptr++; isalpha(*tptr) && sptr < zptr; *sptr++ = *tptr++);
      cptr = NULL;
   }
   else   
   if (div)
   {
      if (MATCH5 (tptr, "|note"))
         cptr = "<div class=\"";
      else
      if (MATCH5 (tptr, "|draw"))
      {
         cptr = "<div class=\"drawing dfont ";
         indent = " indent";
      }
      else
         cptr = "<div class=\"blockof ";
      while (*cptr && sptr < zptr) *sptr++ = *cptr++;         
      for (tptr++; isalpha(*tptr) && sptr < zptr; *sptr++ = *tptr++);
      cptr = NULL;
   }
   else   
   if (list)
   {
      if (MATCH3 (tag, "<li"))
         cptr = "<li class=\"item";
      else
      if (MATCH3 (tag, "<ol"))
         cptr = "<ol class=\"list";
      else
      if (MATCH3 (tag, "<ul"))
         cptr = "<ul class=\"list";
      else
         cptr = "<ul class=\"list simple";
   }
   else   
   if (table)
   {
      if (MATCH6 (tptr, "|table"))
         cptr = "<table class=\"tabl";
      else
         cptr = "<table class=\"tabu";
      if (docptr->bflag[docptr->bfindex] & BFLAG_CENTER) tabauto = " tabauto";
   }
   else   
   if (tabr)
   {
      if (MATCH2 (tptr, "|~")) tptr++;
      cptr = "<tr class=\"tabr";
   }
   else   
   if (tabh)
   {
      if (MATCH2 (tptr, "|:")) tptr++;
      cptr = "<th class=\"tabh";
   }
   else   
   if (tabd)
   {
      if (MATCH2 (tptr, "|.")) tptr++;
      cptr = "<td class=\"tabd";
   }
   else   
   if (link)
      cptr = "<a class=\"link";
   else   
   if (image)
      cptr = "<img class=\"image";
   else   
   if (head)
   {
      if (MATCH3 (tag, "<h9"))
      {
         for (cptr = "<h6"; *cptr && sptr < zptr; *sptr++ = *cptr++);
         cptr = " class=\"head display0";
      }
      else
      {
         for (cptr = tag; *cptr && sptr < zptr; *sptr++ = *cptr++);
         if (docptr->notable == NOTE_HEADING)
            cptr = " class=\"head center";
         else
            cptr = " class=\"head";
      }
   }

   if (cptr)
   {
      while (*cptr && sptr < zptr) *sptr++ = *cptr++;
      /* span over the tag characters */
      if (head)
         for (tptr++; isdigit(*tptr); tptr++);
      else
         for (tptr++; isalpha(*tptr); tptr++);
   }

   for (; *tptr; tptr++)
   {
      /* special case, cross-reference elipsis */
      if (head && MATCH3 (tptr, "...")) break;

      if (MATCH2 (tptr, "\\\n"))
      {
         tptr++;
         continue;
      }

      if ((tabd || tabh) && *tptr >= '1' && *tptr <= '9')
      {
         /* table heads and data are allowed digits */
         if (tabh || tabd)
         {
            if (!colspan[0])
               sprintf (colspan, " colspan=\"%c\"", *tptr);
            else
               sprintf (rowspan, " rowspan=\"%c\"", *tptr);
         }
         continue;
      }

      if (*tptr == '&') break;  /* rest of string is style */

      /* vbar or period or not-punctuation ends markup */
      if (*tptr == '|' || *tptr == '.' ||
          *tptr == '\\' || !ispunct(*tptr)) break;
      /* and if a table element then a space too */
      if ((tabr || tabd || tabh) && isspace(*tptr)) break;

      if (*tptr == '*')
         bold = " bold";
      else
      if (*tptr == '/')
         italic = " italic";
      else
      if (*tptr == '_')
         under = " under";
      else
      if (*tptr == '=')
         mono = " monosp";
      else
      if (*tptr == '-' && span)
         strike = " strike";
      else
      if (*tptr == '-' && !span)
         indent = " noindent";
      else
      if (*tptr == '+' && !span)
         indent = " indent";
      else
      if (MATCH2 (tptr, "<<"))
      {
         wrap = " prewrap";
         tptr++;
      }
      else
      if (MATCH2 (tptr, ">>"))
      {
         wrap = " nowrap";
         tptr++;
      }
      else
      if (MATCH2 (tptr, "><"))
      {
         if (table)
            tabauto = " tabauto";
         else
            align = " center";
         if (div) docptr->bflag[docptr->bfindex] |= BFLAG_CENTER;
         tptr++;
      }
      else
      if (*tptr == '>')
      {
         align = " right";
         if (div) docptr->bflag[docptr->bfindex] &= ~BFLAG_CENTER;
      }
      else
      if (*tptr == '<')
      {
         align = " left";
         if (div) docptr->bflag[docptr->bfindex] &= ~BFLAG_CENTER;
      }
      else
      if (MATCH2 (tptr, "#+"))
      {
         /* vertical align top */
         valign = " valtop";
         tptr++;
      }
      else
      if (MATCH2 (tptr, "#="))
      {
         /* vertical align middle */
         valign = " valmid";
         tptr++;
      }
      else
      if (MATCH2 (tptr, "#-"))
      {
         /* vertical align bottom */
         valign = " valbot";
         tptr++;
      }
      else
      if (MATCH2 (tptr, "#*"))
      {
         /* enable row highlight only for any outermost table */
         if (tabr && docptr->table == 1 && !docptr->rowlight)
            docptr->rowlight++;
         else
         /* otherwise apply a backlight to the element */
         if (!tabr)
            backlight = " backlight";
         tptr++;
      }
      else
      if (MATCH3 (tptr, "#^*"))
      {
         /* make this row the same highlight as the previous row */
         if (tabr && docptr->table == 1)
            if (docptr->rowlight & 1)
               docptr->rowlight--;
            else
            if (docptr->rowlight)
               docptr->rowlight++;
         tptr += 2;
      }
      else
      if (MATCH3 (tptr, "#!*"))
      {
         /* disable row highlight only for any outermost table */
         if (tabr && docptr->table == 1) docptr->rowlight = 0;
         tptr += 2;
      }
      else
      if (MATCH3 (tptr, "#1*"))
      {
         /* one-shot to any element but escpecially for table row */
         backlight = " backlight";
         tptr += 2;
      }
      else
      if (MATCH2 (tptr, "##"))
      {
         /* padding in 0.1 ems */
         tptr++;
         tenths = atoi(tptr+1);
         while (isdigit (*(tptr+1))) tptr++;
         if (tenths) sprintf (empad, "padding:%1.1fem;", (float)tenths / 10.0);
      }
      else
      if (MATCH3 (tptr, "#::"))
      {
         /* inline-block */
         inblock = " inblock";
         tptr + 2;
      }
      else
      if (*tptr == '#')
      {
         if (list)
            zero = " list0";
         else
         if (tabr || tabh || tabd)
            zero = " tab0";
         else
            zero = " display0";
      }
      else
      if (*tptr == '%')
      {
         if (link)
         {
            if (!linkimg) blank = " blank";
            target = " target=\"_blank\"";
         }
         else
         if (image)
         {
            /* % used to create a link to the image, see |image| */
            tptr++;
            if (*tptr == '%') tptr++;
         }
      }
      else
      if (*tptr == '\'')
      {
         /* single quote - append this class */
         if (tptr[1] == '_' || isalpha(tptr[1]))
         {
            class[clidx] = tptr + 1;
            if ((clidx * sizeof(char*)) < sizeof(class)) clidx++;
            if (tptr[1] == '_') tptr++;
            while (isalnum(tptr[1])) tptr++;
         }
      }
      else
      if (*tptr == '\"')
         /* 1 is "standalone" and 2 is a <span>/<div> */
         noescape = docptr->noescape = 2;
   }   

   /* apply row highlight only for any outermost table */
   if (tabr && docptr->rowlight && docptr->table == 1)
      if (docptr->rowlight++ & 1)
         backlight = " backlight";

   for (cptr = align; *cptr && sptr < zptr; *sptr++ = *cptr++);
   for (cptr = backlight; *cptr && sptr < zptr; *sptr++ = *cptr++);
   for (cptr = blank; *cptr && sptr < zptr; *sptr++ = *cptr++);
   for (cptr = bold; *cptr && sptr < zptr; *sptr++ = *cptr++);
   for (cptr = inblock; *cptr && sptr < zptr; *sptr++ = *cptr++);
   for (cptr = indent; *cptr && sptr < zptr; *sptr++ = *cptr++);
   for (cptr = italic; *cptr && sptr < zptr; *sptr++ = *cptr++);
   for (cptr = mono; *cptr && sptr < zptr; *sptr++ = *cptr++);
   for (cptr = strike; *cptr && sptr < zptr; *sptr++ = *cptr++);
   for (cptr = tabauto; *cptr && sptr < zptr; *sptr++ = *cptr++);
   for (cptr = under; *cptr && sptr < zptr; *sptr++ = *cptr++);
   for (cptr = valign; *cptr && sptr < zptr; *sptr++ = *cptr++);
   for (cptr = wrap; *cptr && sptr < zptr; *sptr++ = *cptr++);
   for (cptr = zero; *cptr && sptr < zptr; *sptr++ = *cptr++);

   /* append additional explicitly specified class names */
   for (clidx = 0; (clidx * sizeof(char*)) < sizeof(class); clidx++)
      if (class[clidx])
      {
         if (sptr < zptr) *sptr++ = ' ';
         for (cptr = class[clidx];
              *cptr && (*cptr == '_' || isalnum(*cptr)) && sptr < zptr;
              *sptr++ = *cptr++);
      }

   /* end of classes */
   if (sptr < zptr) *sptr++ = '\"';

   /* links can have additional attributes */
   for (cptr = target; *cptr && sptr < zptr; *sptr++ = *cptr++);

   /* table rows and columns can have additional attributes */
   for (cptr = colspan; *cptr && sptr < zptr; *sptr++ = *cptr++);
   for (cptr = rowspan; *cptr && sptr < zptr; *sptr++ = *cptr++);

   if (*tptr == '&' || empad[0])
   {
      /* append style string */
      for (cptr = " style=\""; *cptr && sptr < zptr; *sptr++ = *cptr++);
      if (*tptr == '&')
      {
         for (tptr++; *tptr && sptr < zptr;)
         {
            if (MATCH2 (tptr, "\\\n"))
            {
               tptr++;
               continue;
            }
            if (*tptr == '|') break;
            if (MATCH2 (tptr, ";.") || MATCH2 (tptr, ";\\"))
            {
               *sptr++ = *tptr++;
               if (MATCH2 (tptr, "\\\n")) continue;
               break;
            }
            if (*tptr == '\\' && tptr[1]) tptr++;
            *sptr++ = *tptr++;
         }
      }
      for (cptr = empad; *cptr && sptr < zptr; *sptr++ = *cptr++);
      if (sptr < zptr) *sptr++ = '\"';
   }

   if (image)
      for (cptr = " src=\""; *cptr && sptr < zptr; *sptr++ = *cptr++);
   else
   if (link)
      for (cptr = " href=\""; *cptr && sptr < zptr; *sptr++ = *cptr++);
   else
   if (sptr < zptr)
      *sptr++ = '>';
   *sptr = '\0';

   if (!(head && MATCH3 (tptr, "...")))
   {
      if (*tptr == '.')
         tptr++;
      else
      /* a " flag must be terminated by a period */
      if (noescape && *tptr != '\\' && *tptr != '|')
         RETURN_FI_LI (docptr, SS$_BADPARAM)
   }

   if (dbug>1) dbugThis (FI_LI, "%s", dbugMax(tptr));

   docptr->tparse = tptr - docptr->text; 
   docptr->hlength = sptr - docptr->html; 

   if (HMORE (docptr)) wasDocMoreHtml (docptr);

   if (sptr >= zptr)
      return (SS$_BADPARAM);
   else
      return (0);
}

/*****************************************************************************/
/*
Set document style element.
If parameter is NULL then default style.
*/

int renderStyle
(
struct wasdoc_st *docptr,
char *param
)
{
   int  error = 0;
   char  *cptr, *sptr, *zptr;

   if (dbug>1) dbugThis (FI_LI, "renderStyle() %s", dbugAll(param));

   if (!param || MATCH7 (param, "default"))
   {
      if (!docptr->styled) wasDocAsIs (docptr, styleDefault);
      docptr->styled = 1; 
   }
   else
   if (MATCH6 (param, "chunk="))
   {
      if (docptr->chunked)
         wasDocPrintf (docptr,
"<style type=\"text/css\">%s</style>",
                        param+6);
   }
   else
   if (MATCH5 (param, "file="))
   {
      renderInsertFile (docptr, param+5, 1);
      docptr->styled = 1; 
   }
   else
   if (MATCH6 (param, "sheet="))
   {
      wasDocPrintf (docptr,
"<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\">\n",
                     param + 6);
      docptr->styled = 1; 
   }
   else
   {
      for (cptr = param; *cptr && *cptr != '=' && *cptr != '{'; cptr++);
      if (*cptr == '=')
         error = SS$_BADPARAM;
      else
         wasDocPrintf (docptr,
"<style type=\"text/css\">%s</style>",
                        param);
   }

   return (error);
}

/*****************************************************************************/
/*
Translate a logical name.  The parameter name can followed by a semi-colon and
a table name, otherwise LNM$FILE_DEV is used.  Returns a pointer to the value
or NULL if an error (including not existing).  Document insight can show the
status returned.
*/

char* renderTrnLnm
(
struct wasdoc_st *docptr,
char *param,
int report
)
{
   static unsigned short  slen;
   static char  value [256];
   static $DESCRIPTOR (nameDsc, "");
   static $DESCRIPTOR (tableDsc, "");
   static struct {
      short int  buf_len;
      short int  item;
      void  *buf_addr;
      unsigned short  *ret_len;
   } items [] =
   {
      { 255, LNM$_STRING, value, &slen },
      { 0,0,0,0 }
   };

   int  status;
   char *cptr;

   if (dbug>1) fprintf (stdout, "renderTrnLnm() %s\n", param);

   /* <log-name>[;<log-table>]*/
   for (cptr = param; *cptr && *cptr != ';'; cptr++);
   nameDsc.dsc$a_pointer = param;
   nameDsc.dsc$w_length = cptr - nameDsc.dsc$a_pointer;
   if (*cptr == ';')
   {
      tableDsc.dsc$a_pointer = ++cptr;
      while (*cptr) cptr++;
      tableDsc.dsc$w_length = cptr - tableDsc.dsc$a_pointer;
   }
   else
   {
      tableDsc.dsc$a_pointer = "LNM$FILE_DEV";
      tableDsc.dsc$w_length = 12;
   }

   status = sys$trnlnm (0, &tableDsc, &nameDsc, 0, &items);
   if (dbug>1) fprintf (stdout, "sys$trnlnm() %%X%08.08X\n", status);
   if (!(status & 1))
   {
      if (!report)
      {
         if (docptr->insight >= 5) wasDocInsight (docptr, "%%X%08.08X", status);
         return (NULL);
      }
      sprintf (value, "%%X%08.08X", status);
   }
   else
      value[slen] = '\0';

   if (docptr->insight >= 5) wasDocInsight (docptr, "%s", value);

   return (value);
}

/*****************************************************************************/
/*
Copy a string where a '|' terminates and the '\' escapes the next character.
*/

int renderGetEscaped
(
char *string,
char *buf,
int size
)
{
   char *cptr, *sptr, *zptr;

   zptr = (sptr = buf) + size - 1;
   if (sptr > zptr) return (SS$_RESULTOVF);
   for (cptr = string; *cptr && sptr < zptr; cptr++)
   {
      if (*cptr == '|') break;
      if (*cptr == '\\' && cptr[1]) cptr++;
      *sptr++ = *cptr;
   }
   *sptr = '\0';
   if (sptr > zptr) return (SS$_RESULTOVF);
   return (0);
}

/*****************************************************************************/
/*
Remove preceding white-space.
*/

char* renderTrimWhite (struct wasdoc_st *docptr)
{
   char  *cptr;

   while (docptr->hlength && isspace(docptr->html[docptr->hlength-1]))
      docptr->hlength--;
   docptr->html[docptr->hlength] = '\0';
   cptr = docptr->html + docptr->hlength;
   if (docptr->hlength) cptr--;
   return (cptr);
}

/*****************************************************************************/
/*
Return a pointer the string representation of the specified $GETSYI item. 
Return NULL on error.  Definitely not reentrant.
*/

char* renderGetSyi
(
struct wasdoc_st *docptr,
char *param
)
{
   static int PrevCgiPlusCount;
   static ulong  SyiClusterEVotes,
                 SyiClusterMember,
                 SyiClusterNodes,
                 SyiClusterQuorum,
                 SyiClusterVotes,
                 SyiMemSize,
                 SyiPageSize;
   static ulong  SyiBootTime [2],
                 time64 [2],
                 upTime64 [2];
   static char  bootTime [24],
                clevotes [16],
                clmember [16],
                clnodes [16],
                clquorum [16],
                clvotes [16],
                memSize [16],
                SyiArchName [16],
                SyiHwName [64],
                SyiNodeName [16],
                SyiVersion [12],
                upTime [24];
   static struct
   {
      short  buf_len;
      short  item;
      char   *buf_addr;
      short  *short_ret_len;
   }
   SyiItem [] =
   {
     { sizeof(SyiArchName), SYI$_ARCH_NAME, (char*)&SyiArchName, 0 },
     { sizeof(SyiBootTime), SYI$_BOOTTIME, (char*)&SyiBootTime, 0 },
     { sizeof(SyiClusterEVotes), SYI$_CLUSTER_EVOTES, (char*)&SyiClusterEVotes, 0 },
     { sizeof(SyiClusterMember), SYI$_CLUSTER_MEMBER, (char*)&SyiClusterMember, 0 },
     { sizeof(SyiClusterNodes), SYI$_CLUSTER_NODES, (char*)&SyiClusterNodes, 0 },
     { sizeof(SyiClusterQuorum), SYI$_CLUSTER_QUORUM, (char*)&SyiClusterQuorum, 0 },
     { sizeof(SyiClusterVotes), SYI$_CLUSTER_VOTES, (char*)&SyiClusterVotes, 0 },
     { sizeof(SyiHwName), SYI$_HW_NAME, (char*)&SyiHwName, 0 },
     { sizeof(SyiMemSize), SYI$_MEMSIZE, (char*)&SyiMemSize, 0 },
     { sizeof(SyiNodeName), SYI$_NODENAME, (char*)&SyiNodeName, 0 },
     { sizeof(SyiPageSize), SYI$_PAGE_SIZE, (char*)&SyiPageSize, 0 },
     { sizeof(SyiVersion), SYI$_VERSION, (char*)&SyiVersion, 0 },
     { 0,0,0,0 }
   };
   $DESCRIPTOR (bootFaoDsc, "!20%D\0");
   $DESCRIPTOR (bootTimeDsc, bootTime);
   $DESCRIPTOR (upFaoDsc, "!%D");
   $DESCRIPTOR (upTimeDsc, upTime);

   int  status;
   short  slen;
   double  fmem;
   char  *cptr = NULL;

   if (dbug>1) dbugThis (FI_LI, "renderGetSyi() %s", dbugAll(param));

   if (!param[0]) return (NULL);

   if (CgiPlusCount > PrevCgiPlusCount)
   {
      PrevCgiPlusCount = CgiPlusCount;
      SyiArchName[0] = '\0';
   }

   if (!SyiArchName[0])
      if ((status = sys$getsyi (0, 0, 0, &SyiItem, 0, 0, 0)) & 1)
      {
         fmem = (double)SyiMemSize * (double)SyiPageSize;
         if (fmem >= 1073741824.0)
            sprintf (memSize, "%.02fGB", fmem / 1073741824.0);
         else
         if (fmem >= 1048576.0)
            sprintf (memSize, "%.02fMB", fmem / 1048576.0);
         else
            sprintf (memSize, "%.02fkB", fmem / 1024.0);
         sys$fao (&bootFaoDsc, 0, &bootTimeDsc, &SyiBootTime);
         sys$gettim (&time64);
         lib$sub_times (&time64, &SyiBootTime, &upTime64);
         sys$fao (&upFaoDsc, &slen, &upTimeDsc, &upTime64);
         upTime[slen-3] = '\0';
      }
      else
      {
         sprintf (SyiArchName, "%%X%08.08X", status);
         strcpy (bootTime, SyiArchName);
         strcpy (memSize, SyiArchName);
         strcpy (SyiHwName, SyiArchName);
         strcpy (SyiNodeName, SyiArchName);
         strcpy (SyiVersion, SyiArchName);
         strcpy (upTime, SyiArchName);
         SyiMemSize = 0;
      }

   if (MATCH7 (param, "arch_name"))
      cptr = SyiArchName;
   else
   if (MATCH8 (param, "cluster="))
   {
      if (MATCH6 (param+8, "evotes"))
         sprintf (cptr = clevotes, "%d", SyiClusterEVotes);
      else
      if (MATCH6 (param+8, "member"))
         sprintf (cptr = clmember, "%d", SyiClusterMember);
      else
      if (MATCH5 (param+8, "nodes"))
         sprintf (cptr = clnodes, "%d", SyiClusterNodes);
      else
      if (MATCH6 (param+8, "quorum"))
         sprintf (cptr = clquorum, "%d", SyiClusterQuorum);
      else
      if (MATCH5 (param+8, "votes"))
         sprintf (cptr = clvotes, "%d", SyiClusterVotes);
   }
   else
   if (MATCH8 (param, "boottime"))
      cptr = bootTime;
   else
   if (MATCH7 (param, "hw_name"))
      cptr = SyiHwName;
   else
   if (MATCH7 (param, "memsize"))
      cptr = memSize;
   else
   if (MATCH8 (param, "nodename"))
      cptr = SyiNodeName;
   else
   if (MATCH6 (param, "uptime"))
      cptr = upTime;
   else
   if (MATCH7 (param, "version"))
      cptr = SyiVersion;

   if (!cptr || !*cptr) return (NULL);

   return (cptr);
}

/*****************************************************************************/
/*
"n." or "n.n" or "n.n.n" or ...
*/

char* renderNumericId (int *digit6)

{
   static char buf [48];
   int  cnt, idx;
   char  *sptr;

   sptr = buf;
   for (cnt = 6; cnt > 1 && !digit6[cnt]; cnt--);
   for (idx = 1; idx <= cnt; idx++)
      sptr += sprintf (sptr, "%d.", digit6[idx]);
   if (cnt > 1) *(sptr-1) = '\0';
   if (dbug>1) dbugThis (FI_LI, "renderNumericId() %s", buf);
   return (buf);
}

/*****************************************************************************/
/*
Delineate a tag.  See module prologue for a description of tag syntax.
*/

void renderInsightTag (struct wasdoc_st *docptr)

{
   char  *aptr, *cptr, *sptr, *tptr, *zptr;
   char  buf [256];

   tptr = docptr->text + docptr->tparse;

   if (dbug>1) dbugThis (FI_LI, "renderInsightTag() %s", dbugMax(tptr));

   if (MATCH6 (tptr, "\n||||\n"))
   {
      wasDocInsight (docptr, "||||");
      return;
   }

   if (MATCH2 (tptr, "||") ||
       MATCH2 (tptr, "| ") ||
       MATCH2 (tptr, "|\n") ||
       MATCH2 (tptr, "|\t"))
   {
      wasDocInsight (docptr, "||");
      return;
   }

   if (MATCH2 (tptr, "|!"))
   {
      for (cptr = tptr + 2; *cptr && *cptr != '|'; cptr++);
      wasDocInsight (docptr, "%*.*s", cptr-tptr+1, cptr-tptr+1, tptr);
      return;
   }

   if (MATCH5 (tptr, "|...|") ||
       MATCH5 (tptr, "|:::|"))
   {
      wasDocInsight (docptr, "%5.5s", tptr);
      return;
   }

   if (MATCH4 (tptr, "|--|"))
   {
      wasDocInsight (docptr, "%4.4s", tptr);
      return;
   }

   if (MATCH3 (tptr, "|-|") ||
       MATCH3 (tptr, "|^+") ||
       MATCH3 (tptr, "|^-"))
   {
      wasDocInsight (docptr, "%3.3s", tptr);
      return;
   }

   if (MATCH3 (tptr, "|^ ") ||
       MATCH3 (tptr, "|^\t") ||
       MATCH3 (tptr, "|^\n"))
   {
      wasDocInsight (docptr, "%2.2s", tptr);
      return;
   }

   if (MATCH2 (tptr, "|0") ||
       MATCH2 (tptr, "|1") ||
       MATCH2 (tptr, "|2") ||
       MATCH2 (tptr, "|3") ||
       MATCH2 (tptr, "|4") ||
       MATCH2 (tptr, "|9"))
   {
      if (docptr->insight >= 5)
      {
         for (cptr = tptr + 1; *cptr && *cptr != '|'; cptr++);
         wasDocInsight (docptr, "%*.*s|", cptr-tptr, cptr-tptr, tptr);
      }
      else
      if (docptr->insight >= 4)
      {
         for (cptr = tptr + 1; *cptr && !isalpha(*cptr); cptr++);
         wasDocInsight (docptr, "%*.*s|", cptr-tptr, cptr-tptr, tptr);
      }
      else
         wasDocInsight (docptr, "%2.2s", tptr);
      return;
   }

   if (MATCH2 (tptr, "|~") ||
       MATCH2 (tptr, "|:") ||
       MATCH2 (tptr, "|.") ||
       MATCH2 (tptr, "|&"))
   {
      if (docptr->insight >= 5)
         for (cptr = tptr; *cptr && !isspace(*cptr); cptr++);
      else
         cptr = tptr + 2;
      wasDocInsight (docptr, "%*.*s", cptr-tptr, cptr-tptr, tptr);
      return;
   }

   if (*tptr == '|' && ispunct(tptr[1]))
   {
      zptr = (sptr = buf) + sizeof(buf)-1;
      *sptr++ = *tptr++;
      for (cptr = tptr; *cptr && sptr < zptr; cptr++)
      {
         if (*cptr == '&' || *cptr == '\\' || *cptr == '.' || *cptr == '|')
         {
            if (*cptr == '&') *sptr++ = *cptr;
            break;
         }
         if (*cptr == '\'')
         {
            *sptr++ = *cptr;
            for (cptr++; isalpha(*cptr); cptr++);
            continue;
         }
         if (isalpha(*cptr)) break;
         *sptr++ = *cptr;
      }
      *sptr = '\0';
      wasDocInsight (docptr, "%s", buf);
      return;
   }

   if ((MATCH5 (tptr, "|asis") && ispunct(tptr[5])) ||
       (MATCH6 (tptr, "|block") && ispunct(tptr[6])) ||
       (MATCH6 (tptr, "|break")&& ispunct(tptr[6])) ||
       (MATCH7 (tptr, "|bullet") && ispunct(tptr[7])) ||
       (MATCH5 (tptr, "|code") && ispunct(tptr[5])) ||
       (MATCH5 (tptr, "|data") && ispunct(tptr[5])) ||
       (MATCH5 (tptr, "|draw") && ispunct(tptr[5])) ||
       (MATCH5 (tptr, "|elif") && ispunct(tptr[5])) ||
       (MATCH5 (tptr, "|else") && ispunct(tptr[5])) ||
       (MATCH6 (tptr, "|endif") && ispunct(tptr[6])) ||
       (MATCH8 (tptr, "|example") && ispunct(tptr[8])) ||
       (MATCH5 (tptr, "|exit") && ispunct(tptr[5])) ||
       (MATCH5 (tptr, "|head") && ispunct(tptr[5])) ||
       (MATCH5 (tptr, "|hide") && ispunct(tptr[5])) ||
       (MATCH6 (tptr, "|image") && ispunct(tptr[6])) ||
       (MATCH6 (tptr, "|index") && ispunct(tptr[6])) ||
       (MATCH7 (tptr, "|insert") && ispunct(tptr[7])) ||
       (MATCH9 (tptr, "|insight!") && ispunct(tptr[9])) ||
       (MATCH9 (tptr, "|insight@") && ispunct(tptr[9])) ||
       (MATCH3 (tptr, "|if") && ispunct(tptr[3])) ||
       (MATCH7 (tptr, "|inline") && ispunct(tptr[7])) ||
       (MATCH6 (tptr, "|insert") && ispunct(tptr[6])) ||
       (MATCH5 (tptr, "|item") && ispunct(tptr[5])) ||
       (MATCH3 (tptr, "|li") && ispunct(tptr[3])) ||
       (MATCH5 (tptr, "|link") && ispunct(tptr[5])) ||
       (MATCH7 (tptr, "|mailto") && ispunct(tptr[7])) ||
       (MATCH5 (tptr, "|mono") && ispunct(tptr[5])) ||
       (MATCH5 (tptr, "|note") && ispunct(tptr[5])) ||
       (MATCH8 (tptr, "|noprint") && ispunct(tptr[8])) ||
       (MATCH7 (tptr, "|number") && ispunct(tptr[7])) ||
       (MATCH3 (tptr, "|ol") && ispunct(tptr[3])) ||
       (MATCH6 (tptr, "|ppage") && ispunct(tptr[6])) ||
       (MATCH6 (tptr, "|print") && ispunct(tptr[6])) ||
       (MATCH5 (tptr, "|prop") && ispunct(tptr[5])) ||
       (MATCH6 (tptr, "|quote") && ispunct(tptr[6])) ||
       (MATCH4 (tptr, "|row") && ispunct(tptr[4])) ||
       (MATCH3 (tptr, "|tr") && ispunct(tptr[3])) ||
       (MATCH4 (tptr, "|set") && ispunct(tptr[4])) ||
       (MATCH7 (tptr, "|simple") && ispunct(tptr[7])) ||
       (MATCH3 (tptr, "|sl") && ispunct(tptr[3])) ||
       (MATCH6 (tptr, "|style") && ispunct(tptr[6])) ||
       (MATCH6 (tptr, "|table") && ispunct(tptr[6])) ||
       (MATCH8 (tptr, "|tabular") && ispunct(tptr[8])) ||
       (MATCH4 (tptr, "|toc") && ispunct(tptr[4])) ||
       (MATCH3 (tptr, "|ul") && ispunct(tptr[3])))
   {
      if (docptr->insight >= 5)
      {
         if (MATCH4 (tptr, "|set") ||
             MATCH6 (tptr, "|style"))
         {
            for (cptr = tptr + 1; *cptr && *cptr != '|'; cptr++);
            if (*cptr) cptr++;
            while (*cptr && *cptr != '|') cptr++;
         }
         else
         for (cptr = tptr + 1; *cptr; cptr++)
            if (*cptr == '\\' || *cptr == '.' || *cptr == '|') break;
      }
      else
         for (cptr = tptr + 1; isalpha(*cptr); cptr++);
      wasDocInsight (docptr, "%*.*s|", cptr-tptr, cptr-tptr, tptr);
      return;
   }

   cptr = tptr + 1;
   if (*cptr == '%') cptr++;
   while (*cptr && cptr < tptr+8 && isalpha(*cptr)) cptr++;
   if (MATCH3 (cptr, "://"))
   {
      wasDocInsight (docptr, "|link|");
      return;
   }

   wasDocInsight (docptr, "\?\?\?");
}

/*****************************************************************************/
/*
Display the source text file name.
*/

void renderInsightSource
(
struct wasdoc_st *docptr,
char *tptr
)
{
    char  *cptr;
    for (cptr = tptr; *cptr && *cptr != ' '; cptr++);
    wasDocInsight (docptr, "%*.*s", cptr-tptr, cptr-tptr, tptr);
}

/*****************************************************************************/
/*
Document the stack contents.
*/

void renderInsightStack (struct wasdoc_st *docptr)

{
   int  idx;
   char  *aptr, *cptr, *sptr, *zptr;
   char  buf [1024];

   for (idx = 1; idx < STACK_MAX && docptr->cstack[idx]; idx++);
   idx--;

   for (; idx; idx--)
   {
      if (!docptr->cstack[idx]) continue;
      zptr = (sptr = buf) + sizeof(buf)-1;
      sptr += sprintf (sptr, "&#9776;%d%s",
                       idx, idx == docptr->stindex ? "&#10003 &#8251;" :
                                                     " &#8251;");
      for (cptr = docptr->cstack[idx]; *cptr && *cptr != '\n'; cptr++)
      {
         aptr = NULL;
         if (*cptr == '<') aptr = "&lt;";
         if (*cptr == '>') aptr = "&gt;";
         if (*cptr == '&') aptr = "&amp;";
         if (aptr)
            while (*aptr && sptr < zptr) *sptr++ = *aptr++;
         else
         if (sptr < zptr)
            *sptr++ = *cptr;
      }
      for (cptr = " &#8251;"; *cptr && sptr < zptr; *sptr++ = *cptr++);
      for (cptr = docptr->tstack[idx]; *cptr && *cptr != '\n'; cptr++)
      {
         aptr = NULL;
         if (*cptr == '<') aptr = "&lt;";
         if (*cptr == '>') aptr = "&gt;";
         if (*cptr == '&') aptr = "&amp;";
         if (aptr)
            while (*aptr && sptr < zptr) *sptr++ = *aptr++;
         else
         if (sptr < zptr)
            *sptr++ = *cptr;
      }
      *sptr = '\0';
      wasDocInsight (docptr, "%s", buf);
   }
}

/*****************************************************************************/