home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / SCRIPT.PAK / FILTERS.SPP < prev    next >
Encoding:
Text File  |  1997-05-06  |  21.9 KB  |  701 lines

  1. //----------------------------------------------------------------------------
  2. // cScript
  3. // (C) Copyright 1995, 1997 by Borland International, All Rights Reserved
  4. //
  5. // FILTERS.SPP
  6. //
  7. // The scripts contained in this module process output from the IDE's
  8. // Transfer system.  They are called from the TransferOutputExists()
  9. // handler found in the FILTSTUB module.
  10. //
  11. // The scripts are passed a TransferOutput object from which they are
  12. // responsible for extracting the tool's raw output from the tool.  They
  13. // then perform any necessary formatting for the message and call the
  14. // MessageCreate method on the IDE object in order to have the messages
  15. // added to the IDE's Message Database.
  16. //
  17. // The scripts should return a non-zero error code if an error is detected
  18. // during processing of the raw data.  Otherwise the scripts should return 0.
  19. //
  20. // Processing scripts are:
  21. //     ParseGenericMessages()
  22. //     ParseGrepMessages()
  23. //     ParseHelpCompilerMessages()
  24. //     ParseResourceCompilerMessages()
  25. //     ParseAssemblerMessages()
  26. //     ParseFilenameMessages()
  27. //
  28. // $Revision:   1.29  $
  29. //
  30. //----------------------------------------------------------------------------
  31.  
  32. import IDE;
  33.  
  34. // mark this module as being a library module
  35. library;
  36.  
  37. //
  38. // Handle messages of the form:
  39. //    MessageText
  40. // where:
  41. //    MessageText is any output to standard IO
  42. //
  43. // Messages of any kind can be imported from transfer tools
  44. // but no file and line number information will be available
  45. //
  46. ParseGenericMessages(output){
  47.    declare input;          // The raw text output.
  48.    declare line;           // The input string that is processed.
  49.    declare p;              // A "pointer" into line.
  50.    declare fileName;       // The message filename.
  51.    declare fileRow;        // The message line number.
  52.    declare msgType;        // The message type.
  53.    declare message;        // The message.
  54.  
  55.    // Read output text until there is no more.
  56.    while((input = output.ReadLine()) != NULL){
  57.       // Convert the raw text into a String object.
  58.       line = new String(input);
  59.  
  60.       // Remove leading whitespace and skip empty lines
  61.       if(input == "" || line.Trim(1).Length <= 1){
  62.          continue;
  63.       }
  64.  
  65.       msgType = INFORMATION;
  66.  
  67.       // Move past the beginning.
  68.       p = line.Index(" ");
  69.  
  70.       // Ensure that there is some useful information.
  71.       if(p == 0){
  72.          continue;
  73.       }
  74.  
  75.       fileName = "";
  76.       fileRow  = 1;
  77.  
  78.        // Post the message to the IDE message database.
  79.        IDE.MessageCreate(NULL, "transfer", msgType, 0,
  80.                           NULL, 0, 0, line.Text, 0, 0);
  81.    }
  82.  
  83.    return 0;
  84. }
  85.  
  86. //
  87. // Handle messages of the form:
  88. //    [path]Filename
  89. // where:
  90. //    [path]Filename is any output to standard IO
  91. //
  92. // This filter can be used with tools that output filenames
  93. // such as the DOS "dir /s/b" command
  94. //
  95. ParseFilenameMessages(output){
  96.    declare input;          // The raw text output.
  97.    declare line;           // The input string that is processed.
  98.    declare fileName;       // The message filename.
  99.    declare msgType;        // The message type.
  100.    declare message;        // The message.
  101.    declare parentMsg;      // The message header.
  102.  
  103.    // Create a message header using the transfer provider
  104.  
  105.    msgType  = INFORMATION;
  106.    parentMsg = IDE.MessageCreate("Directory", "transfer", msgType, 0, NULL,
  107.             0, 0, "Output processed by "+output.Provider+" filter.", 0, 0);
  108.  
  109.    // Read output text until there is no more.
  110.    while((input = output.ReadLine()) != NULL){
  111.       // Convert the raw text into a String object.
  112.       line = new String(input);
  113.  
  114.       // Remove leading whitespace and skip empty lines
  115.       if(input == "" || line.Trim(1).Length <= 1){
  116.          continue;
  117.       }
  118.  
  119.       // Ensure that there is some useful information.
  120.       if(line == 0){
  121.         continue;
  122.       }
  123.  
  124.       fileName = line.Text;
  125.       message  = fileName;
  126.  
  127.       // Post the message to the IDE message database.  Use the initial
  128.       // MessageCreate return value, parentMsg, to group messages.
  129.  
  130.       IDE.MessageCreate("Directory", "transfer", msgType, parentMsg,
  131.                    fileName, 1, 1, message, 0, 0);
  132.    }
  133.  
  134.    return 0;
  135. }
  136.  
  137. //
  138. // Handle messages of the form:
  139. //    Type Filename:#### MessageText
  140. // where:
  141. //    Type is one of: "Error", "Warning", "Fatal"
  142. //    Filename is the name of the source module
  143. //    #### is a number representing the line in the source module
  144. //
  145. // Messages with this format are generated by most Borland Tools
  146. //
  147. ParseBorlandMessages(output){
  148.    declare input;          // The raw text output.
  149.    declare line;           // The input string that is processed.
  150.    declare p;              // A "pointer" into line.
  151.    declare fileName;       // The message filename.
  152.    declare fileRow;        // The message line number.
  153.    declare msgType;        // The message type.
  154.    declare message;        // The message.
  155.  
  156.    // Read output text until there is no more.
  157.    while((input = output.ReadLine()) != NULL){
  158.       // Convert the raw text into a String object.
  159.       line = new String(input);
  160.  
  161.       // Remove leading whitespace and skip empty lines
  162.       if(input == "" || line.Trim(1).Length <= 1){
  163.          continue;
  164.       }
  165.  
  166.       // Check for lines that begin with Error or Warning or Fatal.
  167.       if(line.SubString(0, 5).Text == "Error"){
  168.          msgType = ERROR;
  169.       }else if(line.SubString(0, 10).Text == "Stub error"){
  170.          // Borland App 32RTM stub gave an error, quit and cry fatal
  171.          IDE.MessageCreate(NULL, "transfer", FATAL, output.MessageId,
  172.                            "", 1, 1, line.Text, 0, 0);
  173.          return 0;
  174.       }else if(line.SubString(0, 5).Text == "Fatal"){
  175.          msgType = FATAL;
  176.       }else if (line.SubString(0, 7).Text == "Warning"){
  177.          msgType = WARNING;
  178.       }else{
  179.          msgType = INFORMATION;
  180.       }
  181.  
  182.       // If line begins with Error or Warning or Fatal we want
  183.       // to process it.
  184.       if(msgType != INFORMATION){
  185.          // Move past the beginning.
  186.          p = line.Index(" ");
  187.  
  188.          // Ensure that there is some useful information.
  189.          if(p == 0){
  190.             continue;
  191.          }
  192.  
  193.          // Extract a filename and line number.
  194.          if(line.SubString(p - 2, 1).Text == ":"){
  195.                fileName = "";
  196.                fileRow  = 1;
  197.          }else{
  198.             // Move to the filename.
  199.             line = line.SubString(p);
  200.  
  201.             // Extract the filename.
  202.             if((p = line.Index(" ")) != 0){
  203.                fileName = line.SubString(0, p).Text;
  204.  
  205.                // Move to the line number.
  206.                line = line.SubString(p);
  207.  
  208.                // Extract the line number.
  209.                if((p = line.Index(":")) != 0){
  210.                   fileRow = line.SubString(0, p).Integer;
  211.                }else{
  212.                   fileRow = 1;
  213.                }
  214.             }else{
  215.                fileName = "";
  216.                fileRow  = 1;
  217.             }
  218.          }
  219.  
  220.          // Post the message to the IDE message database.
  221.          IDE.MessageCreate(NULL, "transfer", msgType, output.MessageId,
  222.                 fileName, fileRow, 1, line.SubString(p).Text, "bcerrmsg.hlp",42);
  223.       }
  224.    }
  225.  
  226.    return 0;
  227. }
  228. //
  229. // Handle messages of the form:
  230. //    File Filename:
  231. //    #### MessageText
  232. // where:
  233. //    Filename is the name of the source module
  234. //    #### is a number representing the line in the source module
  235. //
  236. // We expect to start with a message of the form "File Filename:" which
  237. // serves as an indicator of the "current filename".  This file will then
  238. // be used as the source for subsequent messages of the form
  239. // "#### MessageText".
  240. //
  241. // Messages with this format are generated by Borland's Grep
  242. //
  243.  
  244. declare gnMessageCount = 0;
  245. declare gnMessageIndex = 0;
  246. declare gbGrepTabBroughtForward = false;
  247. declare gsMessageFileName = NULL;
  248. declare array gasMessageLines[];
  249. declare gbGrepMessagesOutput = false;
  250.  
  251. on IDE:>SecondElapsed() {
  252.    pass();
  253.    if (gbGrepMessagesOutput)
  254.       SecondElapsedParseGrepMessages();
  255. }
  256.  
  257. ParseGrepMessages(output){
  258.  
  259.    // Ask user if we are already processing messages to continue...
  260.    if (gbGrepMessagesOutput) {
  261.  
  262.       if (IDE.YesNoDialog("Abort processing of existing messages?")=="Yes") {
  263.          gbGrepMessagesOutput = false;
  264.          gbGrepTabBroughtForward = false;
  265.          gnMessageCount = 0;
  266.          gnMessageIndex = 0;
  267.       } else
  268.          return false;
  269.    }
  270.  
  271.    // Reset variables.
  272.    declare nIndex = 0;
  273.    declare input = NULL;
  274.  
  275.    gnMessageCount = 0;
  276.    gnMessageIndex = 0;
  277.  
  278.    // Notify user that messages are being processed.
  279.    IDE.StatusBar = "Transfering messages";
  280.  
  281.    // Move messages for processing.
  282.    while((input = output.ReadLine()) != NULL)
  283.       gasMessageLines[nIndex++] = new String(input);
  284.  
  285.    // Begin processing.
  286.    gnMessageCount = nIndex;
  287.    gbGrepMessagesOutput = true;
  288.    gbGrepTabBroughtForward = false;
  289.  
  290.    return 0;
  291. }
  292.  
  293. SecondElapsedParseGrepMessages() {
  294.    declare input;          // The raw text output.
  295.    declare line;           // The input string that is processed.
  296.    declare p;              // A "pointer" into line.
  297.    declare fileRow;
  298.  
  299.    declare nIndex = 0;
  300.    declare nIndexStart = gnMessageIndex;
  301.    declare nIndexEnd   = gnMessageIndex + 10;
  302.  
  303.    if (nIndexEnd > gnMessageCount)
  304.       nIndexEnd = gnMessageCount;
  305.  
  306.    if (gnMessageIndex >= gnMessageCount) {
  307.       gbGrepMessagesOutput = false;
  308.    } else if (nIndexStart < nIndexEnd) {
  309.  
  310.       for (nIndex = nIndexStart; (nIndex < nIndexEnd); nIndex++) {
  311.  
  312.          // Get Next line for processing.
  313.          line = gasMessageLines[gnMessageIndex++];
  314.  
  315.          // Remove leading whitespace and skip empty lines
  316.          if (line.Text == "" || line.Trim(1).Length <= 1){
  317.                return;
  318.          }
  319.  
  320.          // If there are no file matches, don't process output.
  321.          // but report this in the message window
  322.          if(line.SubString(0, 18).Text == "No files matching:"){
  323.                IDE.MessageCreate("&Grep", "transfer", INFORMATION,
  324.                                   0, "", 0, 0,
  325.                                   line.Text, 0, 0);
  326.                return;
  327.          }
  328.  
  329.          // Find the first blank in the line.
  330.          p = line.Index(" ");
  331.  
  332.          // Extract the filename if present.
  333.          if(line.SubString(0, 5).Text == "File "){
  334.             gsMessageFileName = line.SubString(p,
  335.                      line.Index(":", SEARCH_BACKWARD) - p - 1).Text;
  336.          }else{
  337.             if(p){
  338.                fileRow = 1;
  339.  
  340.                // Skip blank lines lines of the form "N lines match".
  341.                if(line.SubString(0, 11).Text != "lines match" &&
  342.                   line.Trim(1).Length > 1){
  343.                   // Extract the line number.
  344.                   fileRow = line.SubString(0, p - 1).Integer;
  345.  
  346.                   line = line.SubString(p);
  347.  
  348.                   // Post the message to the IDE message database.
  349.                   IDE.MessageCreate("&Grep", "transfer", INFORMATION,
  350.                      0, gsMessageFileName, fileRow, 1,
  351.                      line.Text, 0, 0);
  352.                   if(gbGrepTabBroughtForward == false){
  353.                      gbGrepTabBroughtForward = true;
  354.                      IDE.ViewMessage("&Grep");
  355.                   }
  356.                }
  357.             }
  358.          }
  359.       }
  360.    }
  361.    IDE.StatusBar = "Processed message "+ gnMessageIndex +" of "+ gnMessageCount;
  362. }
  363.  
  364. //
  365. // Handle messages of the form:
  366. //    Type @@@@: line...#### of Filename : MessageText
  367. // where:
  368. //    Type is one of: "Error", "Warning"
  369. //    @@@@ is a Microsoft internal error code (like anyone knows/cares)
  370. //    #### is a number representing the line in the source module
  371. //    Filename is the name of the source module
  372. //
  373. // Messages with this format are generated by the Microsoft Help Compiler
  374. ParseHelpCompilerMessages(output){
  375.    declare input;          // The raw text output.
  376.    declare line;           // The input string that is processed.
  377.    declare p;              // A "pointer" into line.
  378.    declare fileName;       // The message filename.
  379.    declare fileRow;        // The message line number.
  380.    declare msgType;        // The message type.
  381.    declare message;        // The message.
  382.  
  383.    // Read output text until there is no more.
  384.    while((input = output.ReadLine()) != NULL){
  385.       // Convert the raw text into a String object.
  386.       line = new String(input);
  387.  
  388.       // Remove leading whitespace and skip empty lines
  389.       if(input == "" || line.Trim(1).Length <= 1){
  390.          continue;
  391.       }
  392.  
  393.       if(line.SubString(0, 5).Text == "Error"){
  394.          msgType = ERROR;
  395.       }else if(line.SubString(0, 7).Text == "Warning"){
  396.          msgType = WARNING;
  397.       }else{
  398.          msgType = INFORMATION;
  399.       }
  400.  
  401.       if(msgType != INFORMATION){
  402.          p = line.Index(":");
  403.  
  404.          if(p){
  405.             line = line.SubString(p);
  406.  
  407.             if(line.SubString(0, 5).Text == " line"){
  408.                line = line.SubString(5);
  409.  
  410.                // Skip over any '.' characters.
  411.                while(line.SubString(0, 1).Text == "."){
  412.                   line = line.SubString(1);
  413.                }
  414.  
  415.                if(p = line.Index(" of")){
  416.                   fileRow = line.SubString(0, p - 1).Integer;
  417.  
  418.                   line = line.SubString(p + 3);
  419.  
  420.                   p = line.Index(" : ");
  421.  
  422.                   fileName = line.SubString(0, p - 1).Text;
  423.                   message  = line.SubString(p + 2).Text;
  424.                }else{
  425.                   fileName = "";
  426.                   fileRow  = 0;
  427.                   message  = line.Text;
  428.                }
  429.             }else{
  430.                fileName = "";
  431.                fileRow  = 1;
  432.                message  = line.Text;
  433.             }
  434.  
  435.             // Post the message to the IDE message database.
  436.             IDE.MessageCreate(NULL, "transfer", msgType, output.MessageId,
  437.                   fileName, fileRow, 1, message, 0, 0);
  438.                  }
  439.       }
  440.    }
  441.  
  442.    return 0;
  443. }
  444.  
  445.  
  446. //
  447. // Handle messages of the form:
  448. //    Filename(####) : error @@@@ : MessageText
  449. // where:
  450. //    Filename is the name of the source module
  451. //    #### is a number representing the line in the source module
  452. //    @@@@ is a Microsoft internal error code (like anyone knows/cares)
  453. //
  454. // Messages with this format are generated by Microsoft Resource Compiler
  455. //
  456. ParseResourceCompilerMessages(output){
  457.    declare input;          // The raw text output.
  458.    declare line;           // The input string that is processed.
  459.    declare p;              // A "pointer" into line.
  460.    declare q;              // A "pointer" into line.
  461.    declare fileName;       // The message filename.
  462.    declare fileRow;        // The message line number.
  463.    declare message;        // The message.
  464.  
  465.    // Read output text until there is no more.
  466.    while((input = output.ReadLine()) != NULL){
  467.       // Convert the raw text into a String object.
  468.       line = new String(input);
  469.  
  470.       // Remove leading whitespace and skip empty lines
  471.       if(input == "" || line.Trim(1).Length <= 1){
  472.          continue;
  473.       }
  474.  
  475.       // If line starts with "Microsoft" or "Copyright", it's not
  476.       // an error line.
  477.       if(line.SubString(0, 9).Text == "Microsoft"       ||
  478.          line.SubString(0, 9).Text == "Copyright"){
  479.          continue;
  480.       }
  481.  
  482.       // If there is a '(' in the line, the line may contain a line number.
  483.       p = line.Index("(");
  484.  
  485.       // If there is a line number, a ':' must be present
  486.       q = line.SubString(p).Index(":");
  487.  
  488.       if(p && q){
  489.          // Extract the file name.
  490.          fileName = line.SubString(0, p - 1).Text;
  491.  
  492.          // Extract the line number.
  493.          fileRow = line.SubString(p, line.Index(")") - 2).Integer;
  494.  
  495.          // Extract the message.
  496.          message = line.SubString(p + q).Text;
  497.       }else{
  498.          fileName = "";
  499.          fileRow  = 1;
  500.          message  = line.Text;
  501.       }
  502.  
  503.       // Post the message to the IDE message database.
  504.       IDE.MessageCreate(NULL, "transfer", INFORMATION, output.MessageId,
  505.          fileName, fileRow, 1, message, 0, 0);
  506.    }
  507.  
  508.    return 0;
  509. }
  510.  
  511.  
  512. //
  513. // This is a helper script called from ParseAssemblerMessages to handle output from
  514. // Assemblers other than TASM.  It returns TRUE if line is a recognized,
  515. // FALSE otherwise.
  516. //
  517. // Handle messages of the form:
  518. //
  519. //    filename.typ(####): error A@@@@: error message
  520. //    filename.typ(####): warning A@@@@: warning message
  521. //
  522. // where:
  523. //
  524. //    #### is a number representing the line in the source module
  525. //    @@@@ is a Microsoft internal error code (like anyone knows/cares)
  526. //
  527. // Messages with this format are generated by the Microsoft Assembler and
  528. // by SLR's OptAsm.
  529. //
  530. ProcessNonTasmLine(output, line){
  531.    declare fileName;       // The message filename.
  532.    declare fileRow;        // The message line number.
  533.    declare message;        // The message.
  534.    declare p;              // A "pointer" into line.
  535.  
  536.    if((p = line.Index("(")) != 0){
  537.       // Extract the file name.
  538.       fileName = line.SubString(0, p - 1).Text;
  539.  
  540.       line = line.SubString(p);
  541.  
  542.       if((p = line.Index(")")) != 0){
  543.          // Extract the file line number.
  544.          if((fileRow = line.SubString(0, p - 1).Integer) != 0){
  545.             line = line.SubString(p).Trim(1);
  546.  
  547.             if((p = line.Index(":")) == 0){
  548.                return FALSE;
  549.             }
  550.  
  551.             line = line.SubString(p).Trim(1);
  552.  
  553.             // Check for warning or error text from MASM.
  554.             if(line.SubString(0, 7).Text == "warning"){
  555.                if(line.SubString(0, 5).Text == "error"){
  556.                   return FALSE;      // Not error or warning, not MASM line.
  557.                }
  558.             }
  559.  
  560.             // Extract the message.
  561.             message = line.Trim(1).Text;
  562.  
  563.             // Post the message to the IDE message database.
  564.             IDE.MessageCreate(NULL, "transfer", INFORMATION, output.MessageId,
  565.                   fileName, fileRow, 1, message, 0, 0);
  566.  
  567.             return TRUE;      // MASM/OPTASM line.
  568.          }
  569.       }
  570.    }
  571.  
  572.    return FALSE;      // Not a MASM/OPTASM line.
  573. }
  574.  
  575. //
  576. // This is a helper script called from ParseAssemblerMessages to handle output from
  577. // TASM.  It returns TRUE if line is a Turbo Assembler line, FALSE otherwise.
  578. //
  579. // Handle messages of the form:
  580. //    Type Filename (####) MessageText
  581. // where:
  582. //    Type is one of: "**Error**", "*Warning*", "**Fatal**"
  583. //    Filename is the name of the source module
  584. //    #### is a number representing the line in the source module
  585. //
  586. // Messages with this format are generated by the Borland Turbo Assembler
  587. //
  588. ProcessTasmLine(output, line){
  589.    declare fileName;       // The message filename.
  590.    declare fileRow;        // The message line number.
  591.    declare message;        // The message.
  592.    declare msgType;        // The message type.
  593.    declare p;              // A "pointer" into line.
  594.  
  595.    if(line.SubString(0, 10).Text == "**Fatal** "){
  596.       msgType = FATAL;
  597.    }else if(line.SubString(0, 10).Text == "**Error** "){
  598.       msgType = ERROR;
  599.    }else if(line.SubString(0, 10).Text == "*Warning* "){
  600.       msgType = WARNING;
  601.    }else{
  602.       msgType = INFORMATION;
  603.    }
  604.  
  605.    if(msgType == INFORMATION){
  606.       return TRUE;  // just skip for now
  607.    }
  608.  
  609.    fileName = "";
  610.  
  611.    // Skip over fatal tasm text.
  612.    line = line.SubString(10);
  613.  
  614.    // Find the opening '('.
  615.    if((p = line.Index("(")) != 0){
  616.       // Extract the filename.
  617.       fileName = line.SubString(0, p - 1).Text;
  618.  
  619.       line = line.SubString(p);
  620.  
  621.       // Find the closing ')'.
  622.       if((p = line.Index(")")) != 0){
  623.          // Extract the file line number.
  624.          if((fileRow = line.SubString(0, p - 1).Integer) != 0){
  625.             line = line.SubString(p+1, line.Length);
  626.             // Extract the message.
  627.             message = line.Text;
  628.             // Post the message to the IDE message database.
  629.             IDE.MessageCreate(NULL, "transfer", msgType, output.MessageId,
  630.                     fileName, fileRow, 1, message, 0, 0);
  631.  
  632.             return TRUE;      // A TASM line.
  633.          }
  634.       }
  635.    }else{
  636.       // Fatal error, no line number or filename.
  637.  
  638.       fileName = "";
  639.       fileRow  = 1;
  640.       message  = line.Trim(1).Text;
  641.  
  642.       // Post the message to the IDE message database.
  643.       IDE.MessageCreate(NULL, "transfer", FATAL, output.MessageId, fileName,
  644.             fileRow, 1, message, 0, 0);
  645.  
  646.       return TRUE;      // A TASM line.
  647.    }
  648.  
  649.    return FALSE;      // Not a TASM line.
  650. }
  651.  
  652. //
  653. // ParseAssemblerMessages handles messages that look like they were generated by an
  654. // assembler.  It determines which assembler's format the message is in
  655. // and calls the appropriate script to handle the details.
  656. ParseAssemblerMessages(output){
  657.    declare filter = "NONE";        // The function to do the filtering.
  658.    declare input;                  // The raw text output.
  659.    declare line;                   // The input string that is processed.
  660.  
  661.    // Read output text until there is no more.
  662.    while((input = output.ReadLine()) != NULL){
  663.       // Convert the raw text into a String object.
  664.       line = new String(input);
  665.  
  666.       // Remove leading whitespace and skip empty lines
  667.       if(input == "" || line.Trim(1).Length <= 1){
  668.          continue;
  669.       }
  670.  
  671.       if(filter == "TASM"){
  672.          if(ProcessTasmLine(output, line) != 1){
  673.             return  1;
  674.          }
  675.       }else if(filter == "NONTASM"){
  676.          if(ProcessNonTasmLine(output, line) != 1){
  677.             return  1;
  678.          }
  679.       }else{
  680.          // Check for a TASM style line.
  681.          if(ProcessTasmLine(output, line)){
  682.             filter = "TASM";
  683.          }else{
  684.             // Check for a MASM or OPTASM style line.
  685.             if(ProcessNonTasmLine(output, line)){
  686.                filter = "NONTASM";
  687.             }
  688.          }
  689.       }
  690.    }
  691.  
  692.    return 0;
  693. }
  694.  
  695.  
  696.  
  697.  
  698.  
  699.  
  700.  
  701.