<> <> <> <> DIRECTORY CD, CDBasics, CDCallSpecific, CDDirectory, CDDirectoryOps, CDEvents, CDGenerate, CDRemote, CDImports, CDImportsExtras, CDInstances, CDInterestRects, CDIO, CDIOExtras, CDOps, CDOrient, CDProperties, CDValue, Rope, TerminalIO, TokenIO; CDImportsImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDDirectory, CDDirectoryOps, CDEvents, CDGenerate, CDRemote, CDInstances, CDInterestRects, CDIO, CDIOExtras, CDOps, CDOrient, CDProperties, CDValue, Rope, TerminalIO, TokenIO EXPORTS CDImports, CDImportsExtras SHARES CDDirectory, CDRemote = BEGIN BoolOrInteractive: TYPE = CDImports.BoolOrInteractive; ImportPtr: TYPE = CDImports.ImportPtr; ImportRep: TYPE = CDImports.ImportRep; ImportList: TYPE = CDImports.ImportList; ImportDesign: TYPE = CDImports.ImportDesign; ObList: TYPE = LIST OF CD.Object; ROPE: TYPE = Rope.ROPE; ImpList: TYPE = LIST OF REF ImportDesign; importListKey: ATOM = $ImportList; -- for CDValue importsClass: PUBLIC REF CD.ObjectClass = CD.RegisterObjectClass[$Import]; ImpPrivate: TYPE = RECORD [ d: CD.Design_NIL, obList: ObList_NIL ]; EnumerateItsObjects: PROC [me: CD.Object, p: CDDirectory.EnumerateObjectsProc, x: REF] = BEGIN <> <> END; ReplaceDirectChild: CDDirectory.ReplaceDChildsProc = <<-- PROC[me: CD.Object, design: CD.Design, replace: LIST OF REF ReplaceRec] -->> BEGIN <> <> END; InternalCreateImport: PROC [into: CD.Design, size: CD.Position_[1, 1], ir: CD.Rect _ [0, 0, -1, -1], objectName, importeeName: ROPE, autoLoad: BOOL _ FALSE, --loads file if neccessary; if loaded, import design is made autoImport: BOOL _ FALSE, --import design even if not loaded successfully autoCreateOb: BOOL _ FALSE, --creates ob if not found or design not loaded (but not if import not made) allowConflicts: BoolOrInteractive_false, --allow size conflicts on the object include: BOOL _ TRUE] RETURNS [ob: CD.Object _ NIL] = BEGIN referedOb: CD.Object _ NIL; iR: CD.Rect; import: REF ImportDesign; impPriv: REF ImpPrivate; probablySize: CD.Position _ CDBasics.MaxPoint[size, [1, 1]]; <<--make an import of the importee design >> import _ GetImportEntry[into, importeeName, false]; IF (import=NIL OR ~import.loaded) AND autoLoad THEN { loaded: BOOL _ Load[into: into, importeeName: importeeName, overload: false, allowConflicts: false]; }; IF import=NIL AND autoImport THEN import _ GetImportEntry[into, importeeName, true]; IF import=NIL THEN RETURN [NIL]; <<--search for an already existing import object >> IF CDBasics.NonEmpty[ir] THEN iR _ ir ELSE iR _ CDBasics.RectAt[[0, 0], probablySize]; impPriv _ NARROW[import.reservedForCDImports]; FOR list: ObList _ impPriv.obList, list.rest WHILE list#NIL DO iPtr: ImportPtr _ NARROW[list.first.specificRef, ImportPtr]; IF Rope.Equal[iPtr.objectName, objectName] AND Rope.Equal[iPtr.designName, importeeName] THEN { IF list.first.size=size AND (CD.InterestRect[list.first]=iR OR ~CDBasics.NonEmpty[ir]) THEN RETURN [list.first]; IF allowConflicts=true THEN RETURN [list.first]; IF allowConflicts=interactive AND TerminalIO.Confirm[choice: "ignore", label: "size conflicts"] THEN RETURN [list.first]; RETURN [NIL] }; ENDLOOP; <<>> <<--already existing imported object not found; make new object>> <<--if not load, trust for the size... it is checked at binding time>> IF import.loaded THEN referedOb _ CDDirectory.Fetch[impPriv.d, objectName].object; IF referedOb=NIL AND ~autoCreateOb THEN RETURN [NIL]; IF allowConflicts=true AND referedOb#NIL THEN { probablySize _ referedOb.size; iR _ CD.InterestRect[referedOb]; }; ob _ NEW[CD.ObjectRep_[ size: probablySize, class: importsClass, layer: CD.combined, specificRef: NEW[ImportRep _ [ objectName: objectName, ir: iR, designName: importeeName ]] ]]; impPriv.obList _ CONS[ob, impPriv.obList]; IF include THEN [] _ CDDirectory.Include[design: into, object: ob, alternateName: Rope.Cat[importeeName, ".", objectName]]; IF import.loaded THEN [] _ BindReference[into, ob, impPriv.d, allowConflicts]; END; CreateImport: PUBLIC PROC [into: CD.Design, objectName, importeeName: ROPE] RETURNS [ob: CD.Object] = BEGIN ob _ InternalCreateImport[into: into, objectName: objectName, importeeName: importeeName, autoCreateOb: FALSE, autoImport: FALSE, autoLoad: TRUE, allowConflicts: true, include: TRUE]; END; ShortName: PROC [me: CD.Object, iPtr: ImportPtr] RETURNS [n: ROPE] = INLINE BEGIN n _ CDDirectory.Name[me]; IF Rope.IsEmpty[n] THEN n _ iPtr.objectName; END; DescribeImport: PROC[me: CD.Object] RETURNS [ROPE] = BEGIN iPtr: ImportPtr = NARROW[me.specificRef]; RETURN [Rope.Cat["reference to ", iPtr.designName, ".", iPtr.objectName]]; END; DrawForImport: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, pr: CD.DrawRef] = BEGIN iPtr: ImportPtr = NARROW[inst.ob.specificRef]; IF iPtr.boundInstance#NIL THEN { pr.drawChild[iPtr.boundInstance, pos, orient, pr]; } ELSE { r: CD.Rect = MappedInterestRect[inst.ob, pos, orient]; pr.drawRect[r, CD.highLightShade, pr]; pr.drawComment[r, ShortName[inst.ob, iPtr], pr]; } END; MappedInterestRect: PROC [ob: CD.Object, pos: CD.Position, orient: CD.Orientation] RETURNS [CD.Rect] = INLINE BEGIN RETURN [CDOrient.MapRect[ itemInCell: CD.InterestRect[ob], cellSize: ob.size, cellInstOrient: orient, cellInstPos: pos ]] END; QuickDrawReference: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, pr: CD.DrawRef] = BEGIN iPtr: ImportPtr = NARROW[inst.ob.specificRef]; IF iPtr.boundInstance#NIL THEN { iPtr.boundInstance.ob.class.quickDrawMe[iPtr.boundInstance, pos, orient, pr]; } ELSE { r: CD.Rect = MappedInterestRect[inst.ob, pos, orient]; pr.drawRect[r, CD.highLightShade, pr]; pr.drawComment[r, ShortName[inst.ob, iPtr], pr]; } END; DrawSelectionForImport: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, pr: CD.DrawRef] = BEGIN iPtr: ImportPtr = NARROW[inst.ob.specificRef]; IF iPtr.boundInstance#NIL THEN iPtr.boundInstance.ob.class.showMeSelected[iPtr.boundInstance, pos, orient, pr] ELSE pr.drawOutLine[MappedInterestRect[inst.ob, pos, orient], pr] END; InterestRect: PROC [ob: CD.Object] RETURNS [CD.Rect] = BEGIN RETURN [NARROW[ob.specificRef, ImportPtr].ir] END; WriteImportOb: CD.InternalWriteProc -- PROC [me: Object] -- = BEGIN iPtr: ImportPtr = NARROW[me.specificRef]; CDIOExtras.WritePos[me.size]; CDIOExtras.WriteRect[iPtr.ir]; TokenIO.WriteRope[iPtr.objectName]; TokenIO.WriteRope[iPtr.designName]; END; ReadImportOb: CD.InternalReadProc --PROC [] RETURNS [Object]-- = BEGIN sz: CD.Position = CDIOExtras.ReadPos[]; ir: CD.Rect; objectName: ROPE; importeeName: ROPE; ob: CD.Object; IF CDIO.VersionKey[] >= 8 THEN ir _ CDIOExtras.ReadRect[] ELSE ir _ CDBasics.RectAt[[0, 0], sz]; objectName _ TokenIO.ReadRope[]; importeeName _ TokenIO.ReadRope[]; ob _ InternalCreateImport[ into: CDIO.DesignInReadOperation[], ir: ir, size: sz, objectName: objectName, importeeName: importeeName, autoCreateOb: TRUE, autoImport: TRUE, autoLoad: FALSE, allowConflicts: interactive, include: FALSE ]; RETURN [ob] END; GetImportList: PUBLIC PROC [design: CD.Design] RETURNS [imp: REF ImportList] = BEGIN WITH CDValue.Fetch[boundTo: design, key: importListKey, propagation: design] SELECT FROM imp: REF ImportList => RETURN[imp]; ENDCASE => { imp _ NEW[ImportList _ [list: NIL]]; [] _ CDValue.StoreConditional[boundTo: design, key: importListKey, value: imp]; RETURN [GetImportList[design]] }; END; GetImportEntry: PUBLIC PROC [into: CD.Design, importeeName: ROPE_NIL, createIfNotFound: BoolOrInteractive _ true] RETURNS [REF ImportDesign_NIL] = BEGIN ToBool: PROC[b: BoolOrInteractive, r: ROPE, r2: ROPE_NIL] RETURNS [BOOL] = BEGIN SELECT b FROM true => RETURN [TRUE]; false => RETURN [FALSE]; ENDCASE => { TerminalIO.WriteRopes[r, r2]; RETURN [TerminalIO.Confirm[r]] } END; mdata: REF ImportDesign _ NIL; impl: REF ImportList = GetImportList[into]; IF Rope.IsEmpty[importeeName] THEN ERROR CD.Error[ec: other, explanation: "design has empty name, but shouldn't"]; IF impl#NIL THEN FOR l: ImpList _ impl.list, l.rest WHILE l#NIL DO IF l.first#NIL AND Rope.Equal[l.first.importeeName, importeeName] THEN RETURN [l.first] ENDLOOP; IF ToBool[createIfNotFound, "create an import", importeeName] THEN { pData: REF ImpPrivate _ NEW[ImpPrivate]; mdata _ NEW[ImportDesign _ [importeeName: importeeName, loaded: FALSE, reservedForCDImports: pData]]; IF Rope.Equal[into.name, importeeName] THEN ERROR CD.Error[ec: other, explanation: "circular import"]; impl.list _ CONS[mdata, impl.list]; --should be atomic-- }; RETURN [mdata] END; BindImportee: PROC [importer, importee: CD.Design, allowSizeConflicts, overload: BoolOrInteractive _ true] = BEGIN ENABLE TerminalIO.UserAbort => GOTO UserAborted; done1: BOOL_TRUE; impPriv: REF ImpPrivate; mdata: REF ImportDesign; IF importer=importee THEN ERROR; mdata _ GetImportEntry[importer, importee.name, true]; IF mdata=NIL THEN ERROR; impPriv _ NARROW[mdata.reservedForCDImports]; IF mdata.loaded THEN { IF overload=false THEN RETURN ELSE IF overload=interactive THEN IF NOT TerminalIO.Confirm[label: "design already loaded", choice: "overload"] THEN { TerminalIO.WriteRope["dont overload; not done\n"]; RETURN } }; impPriv.d _ importee; mdata.loaded _ TRUE; FOR list: ObList _ impPriv.obList, list.rest WHILE list#NIL DO done1 _ done1 AND BindReference[importer, list.first, importee, allowSizeConflicts].ok ENDLOOP; IF NOT done1 THEN TerminalIO.WriteRope["some import not bound\n"]; CDOps.DelayedRedraw[importer]; EXITS UserAborted => {TerminalIO.WriteRope["aborted, design not bound\n"]}; END; BindReference: PROC [design: CD.Design, reference: CD.Object, importee: CD.Design, allowSizeConflicts: BoolOrInteractive _ true] RETURNS [ok: BOOL_FALSE] = BEGIN ENABLE TerminalIO.UserAbort => GOTO UserAborted; iPtr: ImportPtr = NARROW[reference.specificRef, ImportPtr]; oldRect, newRect: CD.Rect; referedOb: CD.Object _ CDDirectory.Fetch[importee, iPtr.objectName].object; IF referedOb=NIL THEN { TerminalIO.WriteRopes["entry ", iPtr.objectName]; TerminalIO.WriteRopes[" in ", importee.name, " not found\n"]; RETURN }; oldRect _ InterestRect[reference]; newRect _ CD.InterestRect[referedOb]; IF newRect#oldRect THEN { TerminalIO.WriteRopes["object ", iPtr.objectName, " has different size; "]; IF CDBasics.SizeOfRect[oldRect]=CDBasics.SizeOfRect[newRect] THEN TerminalIO.WriteRope[" has different outer size; "] ELSE TerminalIO.WriteRope[" has different interest size; "]; IF allowSizeConflicts=false THEN { TerminalIO.WriteRope["not resolved\n"]; RETURN }; IF allowSizeConflicts=interactive THEN { IF ~TerminalIO.Confirm[choice: "import anyway", label: "size conflict"] THEN { TerminalIO.WriteRope["no\n"]; RETURN }; TerminalIO.WriteRope["yes\n"]; }; }; iPtr.boundInstance _ CDInstances.NewInstance[ob: referedOb]; iPtr.boundInstance.location _ [0, 0]; BEGIN oldSize: CD.Position = reference.size; oldBase: CD.Position = CDBasics.BaseOfRect[oldRect]; newSize: CD.Position = referedOb.size; newBase: CD.Position = CDBasics.BaseOfRect[newRect]; IF oldSize#newSize OR oldRect#newRect THEN { reference.size _ newSize; iPtr.ir _ newRect; CDDirectory.RepositionObject[design: design, ob: reference, oldSize: oldSize, baseOff: CDBasics.SubPoints[oldBase, newBase] ]; }; END; ok _ TRUE; EXITS UserAborted => {TerminalIO.WriteRope["aborted, entry not replaced\n"]}; END; GetImportee: PROC [into: CD.Design, importeeName: ROPE] RETURNS [d: CD.Design_NIL] = BEGIN ENABLE CDRemote.ioFailed => GOTO thatsit; d _ CDRemote.FetchDesign[into, importeeName]; IF d=NIL THEN { [] _ CDRemote.GetTableUsingFile[for: into, remoteDesign: importeeName]; d _ CDRemote.FetchDesign[into, importeeName]; } EXITS thatsit => NULL; END; Load: PUBLIC PROC [into: CD.Design, importeeName: ROPE, overload, allowConflicts: BoolOrInteractive_true] RETURNS [done: BOOL_FALSE] = BEGIN indirectImport: REF ImportList; importee: CD.Design _ GetImportee[into, importeeName]; IF importee=NIL THEN { TerminalIO.WriteRope["load not done\n"]; RETURN }; indirectImport _ GetImportList[importee]; IF indirectImport^.list#NIL THEN TerminalIO.WriteRope["There are indirect imports\n"]; <<-- check for forbidden circular import>> FOR list: ImpList _ indirectImport^, list.rest WHILE list#NIL DO IF Rope.Equal[list.first.importeeName, into.name] THEN { TerminalIO.WriteRope["**creates circular imports\n"]; RETURN } ENDLOOP; <<-- now we certainly have no circular import>> <<-->> <<-- do the actual import>> BindImportee[importer: into, importee: importee, allowSizeConflicts: allowConflicts, overload: overload]; <<--check all already imported designs for importing the new design>> FOR list: ImpList _ GetImportList[into]^, list.rest WHILE list#NIL DO ip: REF ImpPrivate = NARROW[list.first.reservedForCDImports]; IF ip.d#NIL AND ip.d#importee THEN BindImportee[importer: ip.d, importee: importee, allowSizeConflicts: false, overload: true]; ENDLOOP; <<--check the new design for importing of already imported and loaded designs>> FOR list: ImpList _ indirectImport^, list.rest WHILE list#NIL DO ip: REF ImpPrivate = NARROW[list.first.reservedForCDImports]; IF ip.d=NIL THEN {--new design did not load.. imp: REF ImportDesign _ GetImportEntry[into, list.first.importeeName, false]; IF imp#NIL THEN { oldip: REF ImpPrivate = NARROW[imp.reservedForCDImports]; IF oldip.d#NIL AND oldip.d#importee THEN BindImportee[importer: importee, importee: oldip.d, allowSizeConflicts: false, overload: true]; }; } ENDLOOP; done _ TRUE; END; DesignHasBeenRenamed: CDEvents.EventProc --PROC [event: REF, design: CD.Design, x: REF] RETURNS [dont: BOOL_FALSE]-- = <<-- prevent a renaming which would cause circularity>> BEGIN imp: REF ImportDesign = GetImportEntry[into: design, importeeName: design.name, createIfNotFound: false]; IF imp#NIL THEN { dont _ TRUE; TerminalIO.WriteRope["rename causes circularities; not done\n"] }; END; OneLevelIncludedCopy: PUBLIC PROC [impObject: CD.Object, design: CD.Design] RETURNS [CD.Object] = <<--imp is an imported and bound object which will be made local to design>> BEGIN ReplaceChildrenByImports: PROC[me: CD.Object, design: CD.Design, importeeName: ROPE] = BEGIN replaceList: CDDirectory.ReplaceList_NIL; PerChild: CDDirectory.EnumerateObjectsProc --PROC [me: CD.Object, x: REF] -- = BEGIN IF me.class.inDirectory THEN { impChild: CD.Object; FOR list: CDDirectory.ReplaceList _ replaceList, list.rest WHILE list#NIL DO IF list.first.old=me THEN RETURN -- eliminate duplicates ENDLOOP; impChild _ InternalCreateImport[ into: design, objectName: CDDirectory.Name[me], importeeName: importeeName, size: me.size, autoImport: TRUE, autoLoad: FALSE, autoCreateOb: TRUE, allowConflicts: true, include: TRUE ]; replaceList _ CONS[ NEW[CDDirectory.ReplaceRec_[ old: me, oldSize: me.size, new: impChild, newSize: impChild.size, off: [0, 0] ]], replaceList ]; } END; <<>> <<--build list of direct children>> CDDirectory.EnumerateChildObjects[me: me, p: PerChild, x: NIL]; <<--replace each direct child by an import>> IF replaceList#NIL THEN [] _ CDDirectory.DoReplaceDirectChild[me: me, design: design, replace: replaceList]; END; --ReplaceChildrenByImports <<>> <<--OneLevelIncludedCopy>> WITH impObject.specificRef SELECT FROM impPtr: ImportPtr => { newOb: CD.Object; import: REF ImportDesign = GetImportEntry[design, impPtr.designName, false]; ip: REF ImpPrivate; IF impPtr.boundInstance=NIL OR import=NIL OR ~import.loaded THEN ERROR CD.Error[callingError, "OneLevelIncludedCopy impObject not bound "]; ip _ NARROW[import.reservedForCDImports]; newOb _ CDDirectory.Another[me: impPtr.boundInstance.ob, from: ip.d, to: design]; ReplaceChildrenByImports[me: newOb, design: design, importeeName: import.importeeName]; RETURN [newOb] }; ENDCASE => ERROR CD.Error[callingError, "OneLevelIncludedCopy impObject not reference"] END; --OneLevelIncludedCopy Another: PROC [me: CD.Object, from, to: CD.Design] RETURNS [newOb: CD.Object_NIL] = BEGIN impPtr: ImportPtr = NARROW[me.specificRef]; IF to=NIL THEN ERROR; newOb _ InternalCreateImport[into: to, objectName: impPtr.objectName, importeeName: impPtr.designName, autoCreateOb: TRUE, autoImport: TRUE, allowConflicts: true, include: TRUE, size: me.size, autoLoad: FALSE]; IF newOb=NIL THEN ERROR; CDProperties.AppendProps[looser: me.properties, winner: newOb.properties, putOnto: newOb]; END; Expand: PROC [me: CD.Object, from, to: CD.Design] RETURNS [ob: CD.Object_NIL] = BEGIN impPtr: ImportPtr = NARROW[me.specificRef]; IF to=NIL THEN RETURN [NIL]; --can't do an import without putting it into a design IF impPtr.boundInstance=NIL THEN RETURN [NIL]; --can not expand unloaded object IF from#to THEN me _ Another[me: me, from: from, to: to]; RETURN [ OneLevelIncludedCopy[impObject: me, design: to] ]; END; MergeInImports: PUBLIC PROC [into: CD.Design, importeeName: ROPE] = <<--Includes all the imported and bound objects from importeeName (including >> <<--their transitive closure; but not indirect imports) into design.>> BEGIN imp: REF ImportDesign _ GetImportEntry[into, importeeName, false]; IF imp=NIL THEN { TerminalIO.WriteRopes["MergeInImports not done; design ", importeeName, " is not imported\n"]; RETURN } ELSE IF ~imp.loaded THEN { TerminalIO.WriteRopes["MerginImport not done; design ", importeeName, " is not loaded\n"]; RETURN } ELSE { impPrivate: REF ImpPrivate = NARROW[imp.reservedForCDImports]; generatorTable: CDGenerate.Table; importee: CD.Design _ impPrivate.d; objectList: ObList _ NIL; doList: ObList _ NIL; dontList: ObList _ NIL; CDRemote.CacheDesign[for: into, remote: importee]; generatorTable _ CDRemote.GetTable[imp.importeeName]; <<--split the reference list in bounded and not bounded>> FOR list: ObList _ impPrivate.obList, list.rest WHILE list#NIL DO IF NARROW[list.first.specificRef, ImportPtr].boundInstance#NIL THEN doList _ CONS[list.first, doList] ELSE dontList _ CONS[list.first, dontList]; ENDLOOP; <<--make includes for all bounded references >> FOR list: ObList _ doList, list.rest WHILE list#NIL DO pr: ImportPtr = NARROW[list.first.specificRef]; newOb: CD.Object _ CDGenerate.FetchNCall[table: generatorTable, design: into, key: pr.objectName, cache: TRUE]; IF newOb#NIL THEN { CDDirectory.ReplaceObject[design: into, old: list.first, new: newOb]; IF CDDirectoryOps.RemoveObjectFromDirectory[design: into, ob: list.first].done THEN { [] _ CDDirectory.Rename[into, newOb, pr.objectName]; }; } ELSE dontList _ CONS[list.first, dontList]; ENDLOOP; impPrivate.obList _ dontList; } END; HasUnloadedImports: PUBLIC PROC [design: CD.Design] RETURNS [yes: BOOL_FALSE] = BEGIN impList: REF CDImports.ImportList = GetImportList[design]; IF impList#NIL THEN FOR list: LIST OF REF CDImports.ImportDesign _ impList^, list.rest WHILE list#NIL DO IF ~list.first.loaded THEN { <<--a directly imported design is not loaded>> RETURN [yes _ TRUE] } ELSE { <<--check all objects of this design>> p: REF ImpPrivate _ NARROW[list.first.reservedForCDImports]; FOR obl: ObList _ p.obList, obl.rest WHILE obl#NIL DO ip: ImportPtr = NARROW[obl.first.specificRef]; IF ip.boundInstance=NIL THEN RETURN [yes _ TRUE]; ENDLOOP; <<--check for indirect objects; there are no loops>> yes _ p.d#NIL AND HasUnloadedImports[p.d]; } ENDLOOP; END; OldSetInterest: PROC [ob: CD.Object, r: CD.Rect] = BEGIN cptr: ImportPtr = NARROW[ob.specificRef]; cptr.ir _ r; END; Init: PROC [] = BEGIN dirProcs: REF CDDirectory.DirectoryProcs = CDDirectory.InstallDirectoryProcs[importsClass]; dirProcs.enumerateChildObjects _ EnumerateItsObjects; dirProcs.replaceDirectChilds _ ReplaceDirectChild; dirProcs.another _ Another; dirProcs.expand _ Expand; importsClass.drawMe _ DrawForImport; importsClass.quickDrawMe _ QuickDrawReference; importsClass.showMeSelected _ DrawSelectionForImport; importsClass.internalRead _ ReadImportOb; importsClass.internalWrite _ WriteImportOb; importsClass.describe _ DescribeImport; importsClass.interestRect _ InterestRect; CDInterestRects.InstallOldSetInterest[importsClass, OldSetInterest]; CDValue.EnregisterKey[importListKey]; CDEvents.RegisterEventProc[$RenameDesign, DesignHasBeenRenamed]; END; Init[]; END.