-- file: IntBracketsCom.Mesa
-- edited by Brotz, June 24, 1982 1:36 PM
-- edited by Schroeder, December 2, 1980 9:59 AM
-- edited by Levin, January 27, 1981 12:20 PM

DIRECTORY
AltoFile USING [CloseDirectory, DEfile, DirHandle, DVPtr, Enumerate, OpenDirectory,
sysDirFP],
Ascii USING [BS, ControlA, ControlW, CR, DEL, ESC, SP, TAB],
Core USING [CacheEntry, localCacheHead],
displayCommon USING [bitMapReady, charPropertyTable],
dsD: FROM "DisplayDefs" USING [ChangeCursor, ClearRectangle, CursorShape, FaceType,
GetCursor, GetStringWidth, GetVisibleCharWidth, PutCharInBitMap, PutStringInBitMap,
ScreenXCoord, SetCursor, SlideRectangleHorizontally],
Editor USING [cancelCode, ClearSourceSelection, insertDeletionCode, nextBracketStringCode,
shiftedSelectionFlag],
exD: FROM "ExceptionDefs" USING [ClearExceptionsRegion, confirmMessage,
DisplayBothExceptionLines, DisplayException, DisplayExceptionLine, Exception,
illegalCommand, pressToContinue],
FrameDefs USING [IsBound],
inD: FROM "InteractorDefs" USING [CharIndex, HousePtr, IdleLoop, KeyboardInputAcceptor,
keyboardInputAcceptorPtr, maxBracketStringLength, MouseButton, realTimeClock,
rightMargin, ScreenTracker, ScreenXCoord, StartBlinkingCaret, StopBlinkingCaret,
TextSelection],
Inline USING [BITAND, BITOR],
intCommon USING [autoConfirm, cmTextNbr, commandMode, editorType, keystream,
source],
KeyDefs USING [Keys],
ovD: FROM "OverviewDefs" USING [CharMask, LineBreakValue],
Process USING [DisableTimeout],
Storage USING [FreeString, String],
StreamDefs USING [StreamHandle],
String USING [AppendChar, AppendString, AppendSubString, EquivalentSubStrings,
StringBoundsFault, SubString, SubStringDescriptor],
vmD: FROM "VirtualMgrDefs" USING [CharIndex, GetMessageChar, GetMessageSize,
VirtualMessagePtr];

IntBracketsCom: MONITOR
IMPORTS AltoFile, Core, disC: displayCommon, dsD, Editor, exD, FrameDefs, inD, Inline,
intC: intCommon, Process, Storage, String, vmD
EXPORTS inD =

BEGIN
OPEN inD;

-- Purpose: handles user interactions including the display, keyboard and
-- mouse. This division gathers together commands and their arguments and is
-- responsible for the display of all error messages.

-- Global variables --

currentBracketsHouse: HousePtr ← NIL;
currentBracketsX: ScreenXCoord;

externalConfirmProc: PROCEDURE RETURNS [BOOLEAN] ← NIL;


ConfirmBrackets: PUBLIC PROC
[hp: HousePtr, acceptWhiteSpace: BOOLEAN ← FALSE, fileExtension: STRING ← NIL]
RETURNS [confirmed: BOOLEAN] =
-- Accepts keyboard input file name, sets hp.text to this file name, and displays
-- it in its display position. Changes area of screen sensitive to mouse to
-- reflect new brackets size. Returns Boolean value FALSE if brackets fill in
-- is aborted, TRUE if completed.
BEGIN
aborted: BOOLEAN;
dir: AltoFile.DirHandle ← NIL;
dying: BOOLEAN ← FALSE;
found: BOOLEAN ← FALSE;
EnumProcess: PROCESS;
EnumeratorCanRun: CONDITION;
GetNextFileCanReturn: CONDITION;
cacheEntry: Core.CacheEntry
← IF Core.localCacheHead = NIL THEN NIL ELSE Core.localCacheHead.firstEntry;
getNextFileString: STRING;

GetNextFile: ENTRY PROCEDURE [s: STRING] =
BEGIN
-- first cycle through the Alto Core file cache.
UNTIL cacheEntry = NIL DO
IF IsMatch[cacheEntry.name, s] THEN {cacheEntry ← cacheEntry.next; RETURN}
ELSE cacheEntry ← cacheEntry.next;
ENDLOOP;
getNextFileString ← s;
IF dir = NIL THEN
BEGIN
dir ← AltoFile.OpenDirectory[AltoFile.sysDirFP];
Process.DisableTimeout[@EnumeratorCanRun];
Process.DisableTimeout[@GetNextFileCanReturn];
EnumProcess ← FORK Enum;
END
ELSE NOTIFY EnumeratorCanRun;
WAIT GetNextFileCanReturn;
END; -- of GetNextFile --

Enum: PROCEDURE =
BEGIN
DO
[] ← AltoFile.Enumerate[dir, CallBack];
IF dying THEN RETURN;
IF ~found THEN StopGetNextFile[];
found ← FALSE;
ENDLOOP;
END; -- of Enum --

CallBack: ENTRY PROCEDURE [entry: AltoFile.DVPtr, name: STRING]
RETURNS [BOOLEAN] =
BEGIN
IF dying THEN RETURN[TRUE];
IF entry.type # AltoFile.DEfile THEN RETURN[FALSE];
IF IsMatch[name, getNextFileString] THEN
BEGIN
found ← TRUE;
NOTIFY GetNextFileCanReturn;
WAIT EnumeratorCanRun;
END;
RETURN[dying];
END; -- of CallBack --

StopEnumerator: ENTRY PROCEDURE =
BEGIN
dying ← TRUE;
NOTIFY EnumeratorCanRun;
END; -- of StopEnumerator --

StopGetNextFile: ENTRY PROCEDURE =
BEGIN
NOTIFY GetNextFileCanReturn;
WAIT EnumeratorCanRun;
END; -- of StopGetNextFile --

IsMatch: PROCEDURE [file, s: STRING] RETURNS [BOOLEAN] =
BEGIN
ssd: String.SubStringDescriptor;
IF file.length <= fileExtension.length THEN RETURN[FALSE];
ssd ← [file, file.length - fileExtension.length, fileExtension.length];
IF EquivPart[fileExtension, @ssd] THEN
BEGIN
ssd.length ← ssd.offset; ssd.offset ← 0;
IF ~EquivPart[s, @ssd] THEN
{s.length ← 0; String.AppendSubString[s, @ssd]; RETURN[TRUE]};
END;
RETURN[FALSE];
END; -- of IsMatch --

EquivPart: PROCEDURE [s: STRING, part: String.SubString] RETURNS [BOOLEAN] =
BEGIN
ssd: String.SubStringDescriptor ← [s, 0, s.length];
RETURN[String.EquivalentSubStrings[@ssd, part]];
END; -- of EquivPart --

dsD.ChangeCursor[charArrow];
[aborted, hp.rightX] ← GetStringForBrackets
[hp: hp, leftX: hp.leftX, rightX: hp.rightX,
maxDeltaX: (IF hp.nextHouse = NIL
OR hp.nextHouse.lineNumber # hp.lineNumber
THEN inD.rightMargin ELSE hp.nextHouse.leftX) - hp.leftX,
bracketFace: boldFace, displayChars: TRUE, initialDisplayString: hp.text,
abortString: hp.text, outputString: hp.text, acceptWhiteSpace: acceptWhiteSpace,
enumerate: IF fileExtension = NIL THEN NIL ELSE GetNextFile];
IF dir ~= NIL THEN
BEGIN
StopEnumerator[];
JOIN EnumProcess;
AltoFile.CloseDirectory[dir];
END;
dsD.ChangeCursor[hourGlass];
exD.ClearExceptionsRegion[];
RETURN[~aborted]
END; -- of ConfirmBrackets --


Confirm: PUBLIC PROC [lineNumber: CARDINAL] RETURNS [confirmed: BOOLEAN] =
-- Displays confirmation message on lineNumber of exception region, waits for
-- confirmation input from user, displays exception if unexpected input
-- received.
BEGIN
char: CHARACTER;
keystream: StreamDefs.StreamHandle = intC.keystream;

IF ~disC.bitMapReady THEN RETURN[FALSE];
IF intC.autoConfirm THEN RETURN[TRUE];
IF externalConfirmProc # NIL AND FrameDefs.IsBound[externalConfirmProc]
THEN RETURN[externalConfirmProc[]];

SELECT (char ← ConfirmInner[lineNumber]) FROM
Ascii.DEL, Editor.cancelCode, ’N, ’n => confirmed ← FALSE;
Ascii.ESC, Ascii.SP, ’Y, ’y, Ascii.CR => confirmed ← TRUE;
ENDCASE =>
BEGIN
savedInputAcceptor: KeyboardInputAcceptor ← inD.keyboardInputAcceptorPtr↑;

ConfirmInputAcceptor: KeyboardInputAcceptor =
{intC.keystream.putback[intC.keystream, char]};

confirmed ← FALSE;
exD.DisplayBothExceptionLines[NIL, exD.illegalCommand, NIL, exD.pressToContinue];
keyboardInputAcceptorPtr↑ ← ConfirmInputAcceptor;
DO
WHILE keystream.endof[keystream] DO IdleLoop[]; ENDLOOP;
IF (char ← keystream.get[keystream]) = Ascii.DEL OR char = Editor.cancelCode
THEN EXIT;
ENDLOOP;
keyboardInputAcceptorPtr↑ ← savedInputAcceptor;
END;
exD.ClearExceptionsRegion[];
END; -- of Confirm --


ConfirmInner: PUBLIC PROC [lineNumber: CARDINAL] RETURNS [char: CHARACTER] =
-- Displays confirmation message on lineNumber of exception region, waits for
-- confirmation input from user, returns character typed by user.
BEGIN
cursorState: {black, white} ← white;
cursorLastUpdated: CARDINAL;
oldCursor: dsD.CursorShape ← dsD.GetCursor[].shape;
keystream: StreamDefs.StreamHandle = intC.keystream;
savedInputAcceptor: KeyboardInputAcceptor ← inD.keyboardInputAcceptorPtr↑;

ConfirmInputAcceptor: KeyboardInputAcceptor =
{intC.keystream.putback[intC.keystream, char]};

HoldYellow: PROCEDURE RETURNS [char: CHARACTER] =
BEGIN
char ← Ascii.ESC;
UNTIL MouseButton[middle, up] DO
IdleLoop[];
IF ~keystream.endof[keystream] THEN char ← keystream.get[keystream];
IF MouseButton[left, down] OR MouseButton[right, down] THEN
char ← IF intC.editorType = modeless THEN Editor.cancelCode ELSE Ascii.DEL;
ENDLOOP;
END; -- of HoldYellow --

keyboardInputAcceptorPtr↑ ← ConfirmInputAcceptor;
keystream.reset[keystream];
SELECT lineNumber FROM
0 => NULL;
1 => exD.DisplayException[exD.confirmMessage];
ENDCASE => exD.DisplayExceptionLine[exD.confirmMessage, lineNumber];
dsD.SetCursor[questionMark];
cursorLastUpdated ← realTimeClock↑;
DO
SELECT TRUE FROM
~keystream.endof[keystream] => {char ← keystream.get[keystream]; EXIT};
MouseButton[middle, down] => {char ← HoldYellow[]; EXIT};
ENDCASE =>
BEGIN
IdleLoop[];
IF LOOPHOLE[realTimeClock↑ - cursorLastUpdated, CARDINAL] >= 9 THEN
BEGIN
IF cursorState = white THEN {cursorState ← black; dsD.SetCursor[invertQuestionMark]}
ELSE {cursorState ← white; dsD.SetCursor[questionMark]};
cursorLastUpdated ← realTimeClock↑;
END;
END;
ENDLOOP;
dsD.SetCursor[oldCursor];
keyboardInputAcceptorPtr↑ ← savedInputAcceptor;
END; -- of ConfirmInner --


AskUserToConfirm: PUBLIC PROCEDURE [exception: exD.Exception]
RETURNS [confirmed: BOOLEAN] =
-- Displays string corresponding to exception and the confirmation request
-- message to user. Returns the user’s answer.
BEGIN
exD.DisplayException[exception];
RETURN[Confirm[2]]
END; -- of AskUserToConfirm --


GetStringForBrackets: PUBLIC PROCEDURE [hp: HousePtr, leftX, rightX: ScreenXCoord,
maxDeltaX: CARDINAL, bracketFace: dsD.FaceType, displayChars: BOOLEAN,
initialDisplayString, abortString, outputString: STRING,
acceptWhiteSpace: BOOLEAN ← FALSE, enumerate: PROC [STRING] ← NIL]
RETURNS [aborted: BOOLEAN, newRightX: ScreenXCoord] =
-- Displays initialDisplayString in brackets. Accepts keyboard input and
-- displays it appended to initialDisplayString. If abort (DEL or CANCEL),
-- displays abortString in brackets and terminates. On termination (DEL or
-- CANCEL or ESC (or DO)), puts the then displayed string in outputString.
-- Returns the new right x position.
BEGIN
state: {fullString, dots};
s: STRING;
limX, stringStartX, endOfDots: ScreenXCoord;
keystream: StreamDefs.StreamHandle = intC.keystream;
charWidth: CARDINAL;
trailer: STRING ← " }"L;
trailingWidth: CARDINAL = dsD.GetStringWidth[trailer, bracketFace];
i: CARDINAL;
firstChar: BOOLEAN ← TRUE;
savedInputAcceptor: KeyboardInputAcceptor ← inD.keyboardInputAcceptorPtr↑;
savedCommandMode: BOOLEAN ← intC.commandMode;
FinishedWithBrackets: ERROR = CODE;

BracketsInputAcceptor: KeyboardInputAcceptor =
BEGIN

TerminateBrackets: PROCEDURE [abort: BOOLEAN] =
BEGIN
IF (aborted ← abort) AND displayChars THEN PutStringInBrackets[abortString];
IF ~aborted OR outputString # abortString THEN
BEGIN
outputString.length ← 0;
String.AppendString[outputString, IF aborted THEN abortString ELSE s];
END;
ReplaceTrailerWithBracket[];
ERROR FinishedWithBrackets;
END;

AcceptNormalChar: PROCEDURE =
BEGIN
IF firstChar THEN MakeBracketsAndStringEmpty[];
String.AppendChar[s, char ! String.StringBoundsFault => GO TO Ignore];
IF displayChars THEN
BEGIN
charWidth ← dsD.GetVisibleCharWidth[char];
SELECT state FROM
fullString =>
IF currentBracketsX + charWidth > limX THEN PutLongStringInBrackets[s]
ELSE {SlideTrailer[charWidth]; PutCharInBitMap[char]};
dots => RefreshAfterDots[s];
ENDCASE;
END;
EXITS
Ignore => NULL;
END; -- of AcceptNormalChar --

StopBlinkingCaret[];
SELECT char FROM
Editor.cancelCode, Ascii.DEL => TerminateBrackets[abort: TRUE];
Ascii.ControlW => BackWord[];
Ascii.ESC => TerminateBrackets[abort: FALSE];
Editor.nextBracketStringCode =>
BEGIN
IF enumerate # NIL THEN {enumerate[s]; PutStringInBrackets[s]; firstChar ← TRUE};
SetBracketsCaretBlinking[];
RETURN;
END;
Ascii.CR, Ascii.SP, Ascii.TAB =>
IF acceptWhiteSpace THEN
BEGIN
IF char # Ascii.SP THEN char ← Inline.BITOR[char, ovD.LineBreakValue];
AcceptNormalChar[];
END
ELSE TerminateBrackets[abort: FALSE];
Editor.shiftedSelectionFlag =>
BEGIN
IF firstChar THEN MakeBracketsAndStringEmpty[];
InsertSourceSelection[];
END;
Editor.insertDeletionCode =>
BEGIN
IF firstChar THEN MakeBracketsAndStringEmpty[];
InsertLastDeletion[];
END;
Ascii.BS, Ascii.ControlA => BackSpace[];
ENDCASE => AcceptNormalChar[];
firstChar ← FALSE;
SetBracketsCaretBlinking[];
END; -- of BracketsInputAcceptor --

PutCharInBitMap: PROCEDURE [char: CHARACTER] =
BEGIN
currentBracketsX ← dsD.PutCharInBitMap[char, currentBracketsX,
currentBracketsHouse.topY, plainFace];
END; -- of PutCharInBitMap --

PutStringInBitMap: PROCEDURE [s: STRING] =
BEGIN
FOR i: CARDINAL IN [0 .. s.length) DO
PutCharInBitMap[s[i]];
ENDLOOP;
END; -- of PutStringInBitMap --

GetVisibleStringWidth: PROCEDURE [s: STRING] RETURNS [width: CARDINAL] =
BEGIN
width ← 0;
FOR i: CARDINAL IN [0 .. s.length) DO
width ← width + dsD.GetVisibleCharWidth[s[i]];
ENDLOOP;
END; -- of GetVisibleStringWidth --

SlideTrailer: PROCEDURE [amount: INTEGER] = INLINE
BEGIN
dsD.SlideRectangleHorizontally[currentBracketsX, currentBracketsX + trailingWidth,
currentBracketsHouse.topY, currentBracketsHouse.bottomY, amount];
END; -- of SlideTrailer --

ReplaceTrailerWithBracket: PROCEDURE =
BEGIN
dsD.ClearRectangle[currentBracketsX, currentBracketsX + trailingWidth,
currentBracketsHouse.topY, currentBracketsHouse.bottomY];
newRightX ← dsD.PutCharInBitMap[’}, currentBracketsX,
currentBracketsHouse.topY, bracketFace];
END; -- of ReplaceTrailerWithBracket --

MakeBracketsAndStringEmpty: PROCEDURE =
BEGIN
IF s.length > 0 THEN
BEGIN
s.length ← 0;
SlideTrailer[stringStartX - currentBracketsX];
currentBracketsX ← stringStartX;
state ← fullString;
END;
END; -- of MakeBracketsAndStringEmpty --

ResetBrackets: PROCEDURE =
BEGIN
dsD.ClearRectangle[leftX, currentBracketsX + trailingWidth,
currentBracketsHouse.topY, currentBracketsHouse.bottomY];
currentBracketsX ← dsD.PutCharInBitMap
[’{, leftX, currentBracketsHouse.topY, bracketFace];
END; -- of ResetBrackets --

RefreshAfterDots: PROCEDURE[s: STRING] =
BEGIN
x: ScreenXCoord ← endOfDots;
FOR i ← s.length-1, i-1 DO
IF (x ← dsD.GetVisibleCharWidth[s[i]] + x) > limX THEN EXIT;
ENDLOOP;
dsD.ClearRectangle[endOfDots, currentBracketsX + trailingWidth,
currentBracketsHouse.topY, currentBracketsHouse.bottomY];
currentBracketsX ← endOfDots;
FOR i IN [i + 1 .. s.length) DO
PutCharInBitMap[s[i]];
ENDLOOP;
[] ← dsD.PutStringInBitMap[currentBracketsX, currentBracketsHouse.topY,
trailer, bracketFace];
END; -- of RefreshAfterDots --

PutLongStringInBrackets: PROCEDURE [s: STRING] =
BEGIN
ResetBrackets[];
FOR i IN [0..5] DO
PutCharInBitMap[s[i]];
ENDLOOP;
PutStringInBitMap["..."L];
endOfDots ← currentBracketsX;
state ← dots;
RefreshAfterDots[s];
END; -- of PutLongStringInBrackets --

PutShortStringInBrackets: PROCEDURE [s: STRING] = INLINE
BEGIN
ResetBrackets[];
PutStringInBitMap[s];
[] ← dsD.PutStringInBitMap[currentBracketsX, currentBracketsHouse.topY,
trailer, bracketFace];
state ← fullString;
END; -- of PutShortStringInBrackets --

PutStringInBrackets: PROCEDURE [s: STRING] =
BEGIN
IF stringStartX + GetVisibleStringWidth[s] > limX THEN PutLongStringInBrackets[s]
ELSE PutShortStringInBrackets[s];
END; -- of PutStringInBrackets --

BackSpace: PROCEDURE =
BEGIN
IF s.length > 0 THEN
BEGIN
IF intC.editorType = modal OR (KeyDefs.Keys.FL4 = up
AND KeyDefs.Keys.FR5 = up AND KeyDefs.Keys.Spare3 = up)
THEN BEGIN -- just a backspace.
char: CHARACTER ← s[s.length ← s.length - 1];
IF displayChars THEN
BEGIN
charWidth ← dsD.GetVisibleCharWidth[char];
SELECT state FROM
fullString => BEGIN
SlideTrailer[-charWidth];
currentBracketsX ← currentBracketsX - charWidth;
END;
dots =>
IF stringStartX + GetVisibleStringWidth[s] <= limX
THEN BEGIN
ResetBrackets[];
PutStringInBitMap[s];
[] ← dsD.PutStringInBitMap[currentBracketsX,
currentBracketsHouse.topY, trailer, bracketFace];
state ← fullString;
END
ELSE RefreshAfterDots[s];
ENDCASE;
END;
END
ELSE BackWord[]; -- modeless backword.
END;
END; -- of BackSpace --

BackWord: PROCEDURE =
BEGIN
-- First, back up over punctuation characters.
UNTIL s.length = 0 DO
SELECT disC.charPropertyTable[s[s.length - 1]] FROM
punctuation, white => s.length ← s.length - 1;
ENDCASE => EXIT;
ENDLOOP;
-- Then, back up over non-punctuation characters.
UNTIL s.length = 0 DO
SELECT disC.charPropertyTable[s[s.length - 1]] FROM
punctuation, white => EXIT;
ENDCASE => s.length ← s.length - 1;
ENDLOOP;
PutStringInBrackets[s];
END; -- of BackWord --

InsertSourceSelection: PROCEDURE = INLINE
BEGIN
selection: TextSelection ← intC.source;
InsertFromMessage[selection.start, selection.end, selection.mnp.message];
Editor.ClearSourceSelection[];
END; -- of InsertSourceSelection --

InsertLastDeletion: PROCEDURE = INLINE
BEGIN
message: vmD.VirtualMessagePtr = intC.cmTextNbr.deletionBuffer;
InsertFromMessage[0, vmD.GetMessageSize[message], message];
END; -- of InsertLastDeletion --

InsertFromMessage: PROCEDURE [start, end: CharIndex,
message: vmD.VirtualMessagePtr] =
BEGIN
width: CARDINAL;
string: STRING ← [maxBracketStringLength];
char: CHARACTER;
end ← MIN[end, start + s.maxlength - s.length];
FOR i: CharIndex IN [start .. end) DO
SELECT (char ← Inline.BITAND[vmD.GetMessageChar[message, i], ovD.CharMask]) FROM
Ascii.CR, Ascii.SP, Ascii.TAB =>
IF acceptWhiteSpace THEN
BEGIN
IF char # Ascii.SP THEN char ← Inline.BITOR[char, ovD.LineBreakValue];
String.AppendChar[string, char];
END
ELSE {keystream.putback[keystream, Ascii.ESC]; EXIT};
ENDCASE => String.AppendChar[string, char];
ENDLOOP;
String.AppendString[s, string];
width ← GetVisibleStringWidth[string];
IF displayChars THEN
SELECT state FROM
fullString =>
IF currentBracketsX + width > limX THEN PutLongStringInBrackets[s]
ELSE {SlideTrailer[width]; PutStringInBitMap[string]};
dots => RefreshAfterDots[s];
ENDCASE;
END; -- of InsertFromMessage --

currentBracketsHouse ← hp;
s ← Storage.String[outputString.maxlength];
String.AppendString[s, initialDisplayString];
limX ← leftX + maxDeltaX - trailingWidth;
currentBracketsX ← rightX - trailingWidth; -- rightX may not equal leftX+maxDeltaX
stringStartX ← dsD.GetStringWidth["{"L, bracketFace] + leftX;
PutStringInBrackets[s];
keyboardInputAcceptorPtr↑ ← BracketsInputAcceptor;
intC.commandMode ← FALSE;
SetBracketsCaretBlinking[];
ScreenTracker[brackets ! FinishedWithBrackets => CONTINUE];
currentBracketsHouse ← NIL;
Storage.FreeString[s];
keyboardInputAcceptorPtr↑ ← savedInputAcceptor;
intC.commandMode ← savedCommandMode;
END; -- of GetStringForBrackets --


SetBracketsCaretBlinking: PUBLIC PROCEDURE =
-- Like StartBlinkingCaret, but works with the current caret in brackets.
BEGIN
IF currentBracketsHouse = NIL THEN ERROR;
StartBlinkingCaret[currentBracketsX,
(currentBracketsHouse.topY + currentBracketsHouse.bottomY) / 2];
END; -- of SetBracketsCaretBlinking --


SetExternalConfirmProc: PUBLIC PROCEDURE [proc: PROCEDURE RETURNS [BOOLEAN] ] =
-- Allows a loaded program to redirect confirmation input and output. To cancel, call this
-- procedure with argument NIL.
BEGIN
externalConfirmProc ← proc;
END; -- of SetExternalConfirmProc --


END. -- of IntBracketsCom --