GGMenuImpl.mesa
Contents: Routines to build the Gargoyle control panel.
Copyright Ó 1985, 1987, 1988, 1989 by Xerox Corporation. All rights reserved.
Created by Pier on June 23, 1987 when GGMenuImpl overflowed
Last edited by Pier on April 27, 1992 2:42 pm PDT
Bier, September 23, 1991 11:12 am PDT
Eisenman, July 14, 1987 6:34:23 pm PDT
Doug Wyatt, December 18, 1989 2:04:01 pm PST
DIRECTORY
AtomButtons, EmbeddedButtons, Feedback, FeedbackOps, FeedbackTypes, GGActive, GGBasicTypes, GGCircleCache, GGContainer, GGControlPanelTypes, GGCoreOps, GGEvent, GGInterfaceTypes, GGMenu, GGModelTypes, GGScene, GGSceneType, GGSegmentTypes, GGShapes, GGState, GGUserInput, GGUserProfile, GGWindow, Imager, ImagerFont, List, Menus, PFS, PFSNames, PutGet, Rope, Rules, TextNode, TiogaActive, TiogaOps, UserProfile, ViewerClasses, ViewerTools;
GGMenuImpl:
CEDAR
PROGRAM
IMPORTS AtomButtons, EmbeddedButtons, Feedback, FeedbackOps, GGActive, GGCircleCache, GGContainer, GGCoreOps, GGEvent, GGScene, GGShapes, GGState, GGUserInput, GGUserProfile, GGWindow, Imager, ImagerFont, List, PFS, PFSNames, PutGet, Rope, Rules, TiogaActive, TiogaOps, UserProfile, ViewerTools
EXPORTS GGInterfaceTypes, GGModelTypes, GGMenu = BEGIN
ControlsObj: PUBLIC TYPE = GGControlPanelTypes.ControlsObj;
MsgRouter: TYPE = FeedbackTypes.MsgRouter;
GGData: TYPE = GGInterfaceTypes.GGData;
GravityExtentData: TYPE = REF GravityExtentDataObj;
GravityExtentDataObj: TYPE = GGInterfaceTypes.GravityExtentDataObj;
Point: TYPE = GGBasicTypes.Point;
SceneObj: PUBLIC TYPE = GGSceneType.SceneObj; -- export of opaque type
SceneRef: TYPE = REF SceneObj;
Viewer: TYPE = ViewerClasses.Viewer;
ROPE: TYPE = Rope.ROPE;
popUpFont: Imager.Font; -- initialized in Init below;
entryHeight: CARDINAL = 15; -- height of a line of items
docEntryHeight: CARDINAL = 19; -- height of a line of items
entryHSpace: CARDINAL = 2; -- horizontal space between items on a line
entryVSpace: CARDINAL = 2; -- vertical leading between lines
fullColumn: CARDINAL = 600; -- the width of the standard large left column.
smallNumberSize: CARDINAL = 60;
PUChoiceList: PROC [r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19: AtomButtons.PopUpChoice ← [] ] RETURNS [list: AtomButtons.PopUpChoices] = GGCoreOps.PUChoiceList;
RList: PROC [ref1, ref2, ref3: REF ANY ← NIL] RETURNS [LIST OF REF ANY] = GGCoreOps.List;
AddARule:
PROC [ggData: GGData] = {
rule: Rules.Rule ← Rules.Create[[
parent: ggData.controls.panel,
wy: ggData.height,
ww: ggData.controls.panel.cw,
wh: 2
]];
GGContainer.ChildXBound[ggData.controls.panel, rule];
ggData.height ← ggData.height + rule.wh + entryVSpace;
};
BuildControlPanel:
PUBLIC
PROC [ggData: GGData, fancyPanel:
BOOL ←
FALSE] = {
BuildActiveDocument[ggData, fancyPanel];
InitializeGravityLine[ggData];
BuildSlopeLine[ggData];
BuildAngleLine[ggData];
BuildRadiusLine[ggData];
BuildDistanceLine[ggData];
BuildMeasureLine[ggData];
BuildFeedbackLine[ggData];
AddARule[ggData];
};
BuildFeedbackLine:
PROC [ggData: GGData] = {
nextX:
NAT ← AtomButtons.BuildButtonLine[ggData.controls.panel, 0, ggData.height, ggData, GGUserInput.EventNotify,
LIST[
[label["Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Line", FeedbackLineInGGData, fullColumn]]
]];
ggData.height ← ggData.height + entryHeight;
};
FeedbackLineInGGData: AtomButtons.UpdateProc = {
If you update this routine, also update Init below.
Currently, we know of these message classes used in Gargoyle:
(BT) Complaint: Gargoyle informs the user of a user-initiated problem
(BT) Error: internal error. One of Gargoyle's invariants has been broken
(L) Confirm: Gargoyle asks the user to confirm a guarded operation
(L) DuringMouse: feedback generated each time the mouse is moved.
(L) Feedback: an acknowledgement that Gargoyle has done what you asked
(LT) Show: info that was explicitly requested (e.g. what color is this?)
(LT) Statistics: Gargoyle prints user requested statistics
(LT) Warning: Problems during a batch operation, like MergeInterpress
(T) Typescript: Output that only seems appropriate for the typescript, period.
(L) = send to label. (B) = send to label and blink. (T) = send to typescript
ggData: GGData ← NARROW[clientData];
router: MsgRouter ← Feedback.CreateRouter[];
FeedbackOps.SetMultiLabel[router, button, TRUE, LIST[$Error, $Complaint]]; -- blink
FeedbackOps.SetMultiLabel[router, button, FALSE, LIST[$DuringMouse, $Feedback, $Warning, $Confirm, $Show, $Statistics]];
FeedbackOps.SetMultiTypescript[router, $Gargoyle, LIST[$Error, $Warning, $Show, $Typescript, $Complaint, $Statistics]];
ggData.router ← router;
ggData.controls.feedbackLine ← button;
};
IsGargoyle:
PROC [path:
PFS.
PATH]
RETURNS [
BOOL] = {
shortname: ROPE ← PFSNames.ComponentRope[PFSNames.ShortName[PFSNames.StripVersionNumber[path]]];
RETURN[Rope.Match["*.gargoyle", shortname, FALSE] OR Rope.Match["*.gg", shortname, FALSE]];
};
panelNames: ARRAY [0..2] OF ROPE = ["[PCedar]<Gargoyle>GargoyleControlPanel.tioga", "[CedarCommon]<FamousFiles>GargoyleControlPanel.tioga", "[PCedar]<FamousFiles>GargoyleControlPanel.tioga"];
fancyPanelNames: ARRAY [0..2] OF ROPE = ["[PCedar]<Gargoyle>GargoyleControlPanel.gargoyle", "[CedarCommon]<FamousFiles>GargoyleControlPanel.gargoyle", "[PCedar]<FamousFiles>GargoyleControlPanel.gargoyle"];
FindControlPanel:
PROC []
RETURNS [filename:
ROPE ←
NIL, isGargoyle:
BOOL ←
FALSE] = {
There are several places to look in for the Gargoyle control panel:
(1) The file specified in Gargoyle.ControlPanelFile: in the user profile.
(2) The file "[PCedar]<Gargoyle>GargoyleControlPanel.tioga" (useful during development)
(3) The file "[CedarCommon]<FamousFiles>GargoyleControlPanel.tioga"
(4) The file "[PCedar]<FamousFiles>GargoyleControlPanel.tioga"
Use whichever is found first. Return NIL if none are found.
value: LIST OF ROPE;
fullName: PFS.PATH ← NIL;
path: PFS.PATH;
value ← UserProfile.ListOfTokens["Gargoyle.ControlPanelFile", NIL];
IF value #
NIL
THEN {
FOR list:
LIST
OF
ROPE ← value, list.rest
UNTIL list =
NIL
DO
path ← PFS.PathFromRope[list.first];
fullName ← PFS.FileInfo[name: path ! PFS.Error=>CONTINUE].fullFName;
IF fullName # NIL THEN RETURN[PFS.RopeFromPath[fullName], IsGargoyle[fullName]];
ENDLOOP;
};
If that failed, try this:
FOR i:
NAT
IN [0..2]
DO
path ← PFS.PathFromRope[panelNames[i]];
fullName ← PFS.FileInfo[name: path ! PFS.Error=>CONTINUE].fullFName;
IF fullName # NIL THEN RETURN[PFS.RopeFromPath[fullName], IsGargoyle[fullName]];
ENDLOOP;
};
FindFancyControlPanel:
PROC []
RETURNS [filename:
ROPE ←
NIL] = {
There are several places to look in for the Gargoyle control panel:
(1) The file specified in Gargoyle.ControlPanelFile: in the user profile.
(2) The file "[PCedar]<Gargoyle>GargoyleControlPanel.gargoyle" (useful during development)
(3) The file "[CedarCommon]<FamousFiles>GargoyleControlPanel.gargoyle"
(4) The file "[PCedar]<FamousFiles>GargoyleControlPanel.gargoyle"
Use whichever is found first. Return NIL if none are found.
value: LIST OF ROPE;
fullName: PFS.PATH ← NIL;
path: PFS.PATH;
value ← UserProfile.ListOfTokens["Gargoyle.ControlPanelFile", NIL];
IF value #
NIL
THEN {
FOR list:
LIST
OF
ROPE ← value, list.rest
UNTIL list =
NIL
DO
path ← PFS.PathFromRope[list.first];
fullName ← PFS.FileInfo[name: path ! PFS.Error=>CONTINUE].fullFName;
IF fullName #
NIL
THEN
{
IF IsGargoyle[fullName] THEN RETURN[PFS.RopeFromPath[fullName]]
};
ENDLOOP;
};
If that failed, try this:
FOR i:
NAT
IN [0..2]
DO
path ← PFS.PathFromRope[fancyPanelNames[i]];
fullName ← PFS.FileInfo[name: path ! PFS.Error=>CONTINUE].fullFName;
IF fullName # NIL THEN RETURN[PFS.RopeFromPath[fullName]];
ENDLOOP;
};
BuildActiveDocument:
PROC [ggData: GGData, fancyPanel:
BOOL] = {
nextX: NAT ← 0;
v: Viewer;
lines: NAT ← 6;
height: NAT ← lines*docEntryHeight;
doc: TextNode.Ref ← NIL;
filename: ROPE;
true: ROPE = "TRUE";
isGargoyle: BOOL ← FALSE;
IF fancyPanel THEN filename ← FindFancyControlPanel[];
IF filename #
NIL
THEN {
isGargoyle ← TRUE;
}
ELSE [filename, isGargoyle] ← FindControlPanel[];
IF filename = NIL THEN Feedback.AppendByName[$System, oneLiner, $Error, "No file found for Gargoyle control panel in [PCedar]<Gargoyle>, [CedarCommon]<FamousFiles>, [PCedar]<FamousFiles> nor in Gargoyle.ControlPanelFile user profile entry."]
ELSE {
Feedback.PutFByName[$System, oneLiner, $Feedback, "Loading %g as Gargoyle's control panel", [rope[filename]]];
IF NOT isGargoyle THEN doc ← PutGet.FromFile[filename];
};
IF isGargoyle
THEN {
thisData: GGData;
scene: GGModelTypes.Scene ← GGScene.CreateScene[];
height ← 140;
[v, thisData] ← GGWindow.CreateChildViewer[scene: scene,
wx: 0, wy: ggData.height, wh: height,
parent: ggData.controls.panel,
workingDirectory: "[PCedar]<FamousFiles>",
paint: TRUE
];
ggData.controls.controlPanel ← GGActive.LookupDoc[thisData];
GGUserInput.EventNotify[thisData, LIST[$MergeAll, filename]];
GGUserInput.EventNotify[thisData, LIST[$DeselectAll]];
GGUserInput.EventNotify[thisData, LIST[$SetActive, true]];
GGUserInput.EventNotify[thisData, LIST[$SetScaleUnit, NEW[REAL ← 1.0], $Quiet]];
GGUserInput.EventNotify[thisData, LIST[$CleanVersion]];
GGState.SetReadOnly[thisData, TRUE];
}
ELSE {
v ← ViewerTools.MakeNewTextViewer[[
wx: 0, wy: ggData.height, wh: height,
parent: ggData.controls.panel,
data: doc,
scrollable: TRUE, border: TRUE]];
ggData.controls.controlPanel ← TiogaActive.LookupDoc[v];
TiogaOps.Interpret[v, LIST[$ActivityOn]];
};
GGContainer.ChildXBound[ggData.controls.panel, v];
ggData.controls.controlPanelViewer ← v;
EmbeddedButtons.LinkDocToApplication[doc: ggData.controls.controlPanel, target: $Gargoyle, targetViewer: ggData.controls.actionArea, applicationData: ggData, notifyProc: ControlPanelNotify];
EmbeddedButtons.LinkDocToApplication[doc: ggData.controls.controlPanel, target: $UnQueuedGargoyle, targetViewer: ggData.controls.actionArea, applicationData: ggData, notifyProc: UnQueuedControlPanelNotify];
ggData.height ← ggData.height + height;
};
ControlPanelNotify: EmbeddedButtons.NotifyProc = {
PROC [buttonInfo: ButtonInfo, events: LIST OF REF ANY, targetViewer: Viewer, applicationData: REF] RETURNS [result: REF ← NIL];
newEvent: LIST OF REF ← List.Append[events]; -- make a copy of the eventList, because EmbeddedButtons resuses the original
ggData: GGData ← NARROW[applicationData];
[] ← GGActive.ControlPanelButtonHandler[ggData, newEvent, buttonInfo];
};
UnQueuedControlPanelNotify: EmbeddedButtons.NotifyProc = {
PROC [buttonInfo: ButtonInfo, events: LIST OF REF ANY, targetViewer: Viewer, applicationData: REF] RETURNS [result: REF ← NIL];
newEvent: LIST OF REF ANY ← List.Append[events]; -- make a copy of the eventList, because EmbeddedButtons resuses the original
GGUserInput.UnQueuedEventNotify[applicationData, newEvent];
};
<<BuildGravityLine: PROC [ggData: GGData] = {
nextX: NAT ← 0;
ggData.controls.gravityTypeMenu ←
AtomButtons.BuildEnumTypeSelection[viewer: ggData.controls.panel, x: 4, y: ggData.height, maxWidth: 140,
clientData: ggData,
handleProc: GGUserInput.EventNotify,
title: "GravType:", default: "PreferPoints",
borderOnButtons: TRUE, style: flipThru, allInOneRow: TRUE,
buttonNames: LIST["PreferLines", "PreferPoints"],
atom: $GravityChoiceChange];
ggData.hitTest.gravityType ← pointsPreferred;
nextX ← ggData.controls.gravityTypeMenu.nextx;
nextX ← AtomButtons.BuildButtonLine[
ggData.controls.panel, nextX + entryHSpace, ggData.height, ggData, GGUserInput.EventNotify,
LIST[
[button["GravExtent:", LIST[LIST[$ShowGravExtent]]]]
]];
nextX ← GraphicsButton.BuildGraphicsButton[
container: ggData.controls.panel,
x: nextX + entryHSpace,
y: ggData.height,
w: 60, -- changed from 72 to make more room in line
h: entryHeight,
clientData: ggData,
choices: LIST[
[LIST[$GravityExtentChange, $ValueDown]],
[LIST[$GravityExtentChange, $InitialValue]],
[LIST[$GravityExtentChange, $ValueUp]]],
handleProc: GGUserInput.EventNotify,
repaintProc: GravityExtentRepaint,
buttonData: NEW[GravityExtentDataObj ← [extent: GGUserProfile.GetDefaultGravityExtent[]]],
updateProc: GravityExtentInGGData
];
nextX ← AtomButtons.BuildButtonLine[
ggData.controls.panel, nextX + entryHSpace, ggData.height, ggData, GGUserInput.EventNotify,
LIST[
[twoState["Gravity", LIST[$ToggleGravity], TRUE, GravityInGGData]],
[twoState["Midpts", LIST[$ToggleMidpoints], FALSE, MidpointsInGGData]],
[twoState["Auto", LIST[$ToggleHeuristics], GGUserProfile.GetDefaultHeuristics[], HeuristicsInGGData]],
[twoState["Alignments", LIST[$ToggleShowAlignments], TRUE, AlignmentsInGGData]]
],
entryHSpace];
ggData.height ← ggData.height + entryHeight;
};
>>
InitializeGravityLine:
PROC [ggData: GGData] = {
ggData.hitTest.gravityType ← pointsPreferred;
GGState.SetGravityExtent[ggData, GGUserProfile.GetDefaultGravityExtent[]/72.0];
GGState.SetHeuristics[ggData, GGUserProfile.GetDefaultHeuristics[]];
};
BuildSlopeLine:
PROC [ggData: GGData] = {
buttonHandle: AtomButtons.SortedButtonHandle;
nextX:
NAT ← AtomButtons.BuildButtonLine[ggData.controls.panel, 0, ggData.height, ggData, GGUserInput.EventNotify,
LIST[
[button["Slope:", LIST[LIST[$SlopePrompt]] ]],
[button["Get!", LIST[LIST[$GetSlope]] ]],
[button["Add!", LIST[LIST[$AddSlope]] ]],
[button["Delete!", LIST[LIST[$DeleteSlope]] ]]
]];
buttonHandle ← AtomButtons.CreateSortedButtonViewer[ggData.controls.panel, nextX, ggData.height];
ggData.controls.slopeHandle ← buttonHandle;
GGEvent.StandardSlopes[ggData, LIST[$InitStandardSlopes]];
ggData.height ← ggData.height + entryHeight;
BuildAngleLine:
PROC [ggData: GGData] = {
buttonHandle: AtomButtons.SortedButtonHandle;
nextX:
NAT ← AtomButtons.BuildButtonLine[ggData.controls.panel, 0, ggData.height, ggData, GGUserInput.EventNotify,
LIST[
[button["Angle:", LIST[LIST[$AnglePrompt]] ]],
[button["Get!", LIST[LIST[$GetAngle]] ]],
[button["Add!", LIST[LIST[$AddAngle]] ]],
[button["Delete!", LIST[LIST[$DeleteAngle]] ]]
]];
buttonHandle ← AtomButtons.CreateSortedButtonViewer[ggData.controls.panel, nextX, ggData.height];
ggData.controls.angleHandle ← buttonHandle;
GGEvent.StandardAngles[ggData, LIST[$InitStandardAngles]];
ggData.height ← ggData.height + entryHeight;
};
BuildRadiusLine:
PROC [ggData: GGData] = {
buttonHandle: AtomButtons.SortedButtonHandle;
nextX:
NAT ← AtomButtons.BuildButtonLine[ggData.controls.panel, 0, ggData.height, ggData, GGUserInput.EventNotify,
LIST[
[button["Radius:", LIST[LIST[$RadiusPrompt]] ]],
[button["Get!", LIST[LIST[$GetRadius]] ]],
[button["Add!", LIST[LIST[$AddRadius]] ]],
[button["Delete!", LIST[LIST[$DeleteRadius]] ]]
]];
buttonHandle ← AtomButtons.CreateSortedButtonViewer[ggData.controls.panel, nextX, ggData.height];
ggData.controls.radiusHandle ← buttonHandle;
GGEvent.StandardRadii[ggData, LIST[$InitStandardRadii]];
ggData.controls.radiusCircleCache ← GGCircleCache.Create[];
ggData.height ← ggData.height + entryHeight;
};
BuildDistanceLine:
PROC [ggData: GGData] = {
buttonHandle: AtomButtons.SortedButtonHandle;
nextX:
NAT ← AtomButtons.BuildButtonLine[ggData.controls.panel, 0, ggData.height, ggData, GGUserInput.EventNotify,
LIST[
[button["LineDist:", LIST[LIST[$DistancePrompt]] ]],
[button["Get!", LIST[LIST[$GetDistance]] ]],
[button["Add!", LIST[LIST[$AddDistance]] ]],
[button["Delete!", LIST[LIST[$DeleteDistance]] ]]
]];
buttonHandle ← AtomButtons.CreateSortedButtonViewer[ggData.controls.panel, nextX, ggData.height];
ggData.controls.distanceHandle ← buttonHandle;
GGEvent.StandardDistances[ggData, LIST[$InitStandardDistances]];
ggData.height ← ggData.height + entryHeight;
};
BuildMeasureLine:
PROC [ggData: GGData] = {
nextX:
NAT ← AtomButtons.BuildButtonLine[ggData.controls.panel, 0, ggData.height, ggData, GGUserInput.EventNotify,
LIST[
[label["Measure- "]],
[button["←", LIST[LIST[$MeasureSlopeFromSelection]], -1, TRUE ]],
[button["Slope:", LIST[LIST[$MeasureSlopeHit]], -1, TRUE ]],
[text["0.0", SlopeViewInGGData, smallNumberSize]],
[button["←", LIST[LIST[$MeasureAngleFromSelection]], -1, TRUE ]],
[button["Angle:", LIST[LIST[$MeasureAngleHit]], -1, TRUE ]],
[text["0.0", AngleViewInGGData, smallNumberSize]],
[button["←", LIST[LIST[$MeasureRadiusFromSelection]], -1, TRUE ]],
[button["Radius:", LIST[LIST[$MeasureRadiusHit]], -1, TRUE ]],
[text["0.0", DistanceViewInGGData, smallNumberSize]],
[button["←", LIST[LIST[$MeasureLineDistFromSelection]], -1, TRUE ]],
[button["LineDist:", LIST[LIST[$MeasureLineDistHit]], -1, TRUE ]],
[text["0.0", LineDistViewInGGData, smallNumberSize]]
]];
ggData.height ← ggData.height + entryHeight;
};
Style Line:
GravityInGGData: AtomButtons.InitTwoStateProc = {
ggData: GGData ← NARROW[clientData];
ggData.controls.gravButton ← twoState;
};
AlignmentsInGGData: AtomButtons.InitTwoStateProc = {
ggData: GGData ← NARROW[clientData];
ggData.controls.alignments ← twoState;
};
MidpointsInGGData: AtomButtons.InitTwoStateProc = {
ggData: GGData ← NARROW[clientData];
ggData.controls.midpointButton ← twoState;
};
HeuristicsInGGData: AtomButtons.InitTwoStateProc = {
ggData: GGData ← NARROW[clientData];
ggData.controls.heuristicsButton ← twoState;
};
GravityExtentInGGData: GraphicsButton.UpdateGraphicsButtonProc = {
ggData: GGData ← NARROW[clientData];
ggData.controls.gravityExtentButton ← stateInfo;
};
GravityExtentRepaint:
PROC [dc: Imager.Context, clientData:
REF
ANY, buttonData:
REF
ANY, button: Viewer] = {
caretPoint: Point;
ged: GravityExtentData ← NARROW[buttonData];
extent: REAL ← ged.extent;
Imager.TranslateT[dc, [0, button.wh/2.0]];
caretPoint ← [extent, 0.0];
GGShapes.DrawCaret[dc, caretPoint, [0,-1], 1.0];
};
SlopeViewInGGData: AtomButtons.UpdateProc = {
ggData: GGData ← NARROW[clientData];
ggData.controls.slopeView ← button;
};
AngleViewInGGData: AtomButtons.UpdateProc = {
ggData: GGData ← NARROW[clientData];
ggData.controls.angleView ← button;
};
DistanceViewInGGData: AtomButtons.UpdateProc = {
ggData: GGData ← NARROW[clientData];
ggData.controls.radiusView ← button;
};
LineDistViewInGGData: AtomButtons.UpdateProc = {
ggData: GGData ← NARROW[clientData];
ggData.controls.lineDistView ← button;
};
Choice:
PROC [action:
LIST
OF
REF
ANY, actionImage: Rope.
ROPE, doc: Rope.
ROPE, font: Imager.Font ←
NIL]
RETURNS [AtomButtons.PopUpChoice]= {
RETURN[[action, actionImage, doc, font]];
};
gRouter: MsgRouter; -- the router used by routines that are too deep in Gargoyle to know what viewer they are working on behalf of. Sends output to the Gargoyle typescript and the Cedar Message Window.
Init:
PROC = {
popUpFont ← ImagerFont.Find["xerox/tiogafonts/helvetica10I", substituteQuietly];
If you update the router, remember to also correct it in FeedbackLineInGGData above.
gRouter ← Feedback.CreateRouter[];
[] ← Feedback.RegisterRouter[gRouter, $Gargoyle];
FeedbackOps.SetMultiMessageWindow[gRouter, TRUE, LIST[$Error, $Complaint]]; -- blink
FeedbackOps.SetMultiMessageWindow[gRouter, FALSE, LIST[$DuringMouse, $Feedback, $Warning, $Confirm, $Show, $Statistics]];
FeedbackOps.SetMultiTypescript[gRouter, $Gargoyle, LIST[$Error, $Warning, $Show, $Typescript, $Complaint, $Statistics]];
};
Init[];
END.