DIRECTORY Atom, Ascii, BasicTime, Commander, CD, CDBasics, CDCells, CDDirectory, CDEnvironment, CDEvents, CDInstances, CDIO, CDSequencer USING [CheckAborted], CDOps, CDPrivate, CDProperties, CDRects, CDValue, Convert, FileNames, FS, IO, PropertyLists, RefTab, Rope, RuntimeError USING [UNCAUGHT], TerminalIO, TokenIO, CDOldInterestRects; CDIn: CEDAR PROGRAM IMPORTS Atom, BasicTime, Commander, Convert, CD, CDBasics, CDCells, CDDirectory, CDEnvironment, CDEvents, CDInstances, CDIO, CDOps, CDPrivate, CDProperties, CDRects, CDSequencer, CDValue, FileNames, FS, IO, PropertyLists, RefTab, Rope, RuntimeError, TerminalIO, TokenIO, CDOldInterestRects EXPORTS CDIO SHARES CD, CDDirectory = BEGIN xChipndaleFile: INT = 12121983; xVersion: INT = 16; Version: PROC [h: TokenIO.Handle] RETURNS [INT] = INLINE { RETURN [IF h.oldVersion THEN VersionKey[h] ELSE xVersion ] }; IndexTable: TYPE = RECORD[table: SEQUENCE max: CARDINAL OF CD.Object]; TableTable: TYPE = RECORD[tt: SEQUENCE max: CARDINAL OF REF IndexTable]; maxTableSize: INT = 32000; signalOnPropertyProblem: BOOL _ TRUE; --set variable with debugger setManually: INT _ 0; --used for saving old designs specialForVersion4: BOOL _ FALSE; GetTableEntry: PROC[h: TokenIO.Handle, i: INT] RETURNS [ob: CD.Object_NIL] = INLINE { IF i=maxTableSize THEN { tableTable: REF TableTable _ NEW[TableTable[i/maxTableSize]]; CDProperties.PutPRefProp[h.properties, $TableTable, tableTable]; FOR n: INT IN [0..i/maxTableSize) DO -- don't be picky with size if it is anyway as big tableTable.tt[n] _ NEW[IndexTable[maxTableSize]] ENDLOOP }; }; ReadProperties: PUBLIC PROC [h: TokenIO.Handle] RETURNS [props: CD.PropList_NIL] = { PropertyProblem: PROC [h: TokenIO.Handle, key: ATOM_NIL, skip: BOOL_FALSE] = { TerminalIO.PutRope["**** property not readable"]; IF key#NIL THEN { TerminalIO.PutRopes["; probably ", Atom.GetPName[key]]; }; TerminalIO.PutRope["\n"]; IF signalOnPropertyProblem THEN SIGNAL TokenIO.EncodingError; IF skip THEN TokenIO.Skip[h]; }; CheckNoRegistration: PROC [a: ATOM] RETURNS [ok: BOOL] = { propProcs: CDProperties.PropertyProcs _ CDProperties.FetchProcs[a]; ok _ propProcs=NIL OR propProcs.internalRead=NIL; IF ~ok THEN { TerminalIO.PutRope["**** property registered and not readable"]; PropertyProblem[h, a]; }; }; ExplicitProperty: PROC [h: TokenIO.Handle] = { key: ATOM; propProcs: CDProperties.PropertyProcs; token: TokenIO.Token _ TokenIO.Read[h]; WITH token SELECT FROM push2: TokenIO.Token.push2 => key _ push2.value; push: TokenIO.Token.push => { IF Version[h]>=16 THEN SIGNAL TokenIO.EncodingError; key _ push.value; }; ENDCASE => SIGNAL TokenIO.EncodingError; propProcs _ CDProperties.FetchProcs[key]; IF propProcs#NIL AND propProcs.internalRead#NIL THEN { props _ PropertyLists.PutProp[props, key, propProcs.internalRead[h, key]]; } ELSE IF Version[h]>=12 THEN { n: Rope.ROPE _ Atom.GetPName[key]; TerminalIO.PutRopes["**** property ", n, " not registered\n"]; CDEnvironment.ExecFileEntry[n, CDIO.DesignInReadOperation[h].technology]; propProcs _ CDProperties.FetchProcs[key]; IF propProcs#NIL AND propProcs.internalRead#NIL THEN { props _ PropertyLists.PutProp[props, key, propProcs.internalRead[h, key]]; } ELSE { TerminalIO.PutRope["failed"]; IF signalOnPropertyProblem THEN SIGNAL TokenIO.EncodingError; }; } ELSE OldDefaultProperty[key]; TokenIO.ReadPop[h ! TokenIO.EncodingError => PropertyProblem[h, key, TRUE]]; }; DefaultProperty: PROC [h: TokenIO.Handle] = { PushCase: PROC [key: ATOM] = { IF CheckNoRegistration[key] THEN { SELECT TokenIO.ReadAtom[h] FROM $properties => { propertieProps: CD.PropList _ ReadProperties[h]; props _ PropertyLists.PutProp[props, key, propertieProps]; }; $layer => { layer: CD.Layer _ ReadLayer[h]; props _ PropertyLists.PutProp[props, key, CDPrivate.layers[layer]] }; $ropeList => { rList: LIST OF Rope.ROPE _ NIL; DO token: TokenIO.Token _ TokenIO.Read[h]; WITH token SELECT FROM rope: TokenIO.Token.rope => rList _ CONS[rope.value, rList]; ENDCASE => { TokenIO.ReadAgain[h, token]; props _ PropertyLists.PutProp[props, key, rList]; EXIT; } ENDLOOP }; ENDCASE => PropertyProblem[h, key, FALSE]; TokenIO.ReadPop[h ! TokenIO.EncodingError => PropertyProblem[h, key, TRUE]]; }; }; token: TokenIO.Token _ TokenIO.Read[h]; WITH token SELECT FROM atom: TokenIO.Token.atom => IF CheckNoRegistration[atom.value] THEN { token: TokenIO.Token _ TokenIO.Read[h]; WITH token SELECT FROM ropex: TokenIO.Token.rope => props _ PropertyLists.PutProp[props, atom.value, ropex.value]; atomx: TokenIO.Token.atom => props _ PropertyLists.PutProp[props, atom.value, atomx.value]; intx: TokenIO.Token.int => props _ PropertyLists.PutProp[props, atom.value, NEW[INT_intx.value]]; ENDCASE => PropertyProblem[h, atom.value]; }; push2: TokenIO.Token.push2 => PushCase[push2.value]; push: TokenIO.Token.push => { IF Version[h]>=16 THEN SIGNAL TokenIO.EncodingError; PushCase[push.value]; }; ENDCASE => PropertyProblem[h, NIL]; }; OldDefaultProperty: PROC [key: ATOM] = { token: TokenIO.Token _ TokenIO.Read[h]; WITH token SELECT FROM rope: TokenIO.Token.rope => props _ PropertyLists.PutProp[props, key, rope.value]; atom: TokenIO.Token.atom => props _ PropertyLists.PutProp[props, key, atom.value]; int: TokenIO.Token.int => props _ PropertyLists.PutProp[props, key, NEW[INT_int.value]]; pop: TokenIO.Token.pop => { TokenIO.ReadAgain[h, token]; props _ PropertyLists.PutProp[props, key, key] }; push: TokenIO.Token.push => { IF push.value=NIL OR push.value=$properties THEN { propertieProps: CD.PropList _ ReadProperties[h]; props _ PropertyLists.PutProp[props, key, propertieProps]; } ELSE IF push.value=$layer THEN { layer: CD.Layer _ ReadLayer[h]; props _ PropertyLists.PutProp[props, key, CDPrivate.layers[layer]] } ELSE PropertyProblem[h, key]; TokenIO.ReadPop[h ! TokenIO.EncodingError => PropertyProblem[h, key]]; }; ENDCASE => PropertyProblem[h, key]; }; DO token: TokenIO.Token _ TokenIO.Read[h]; WITH token SELECT FROM atom: TokenIO.Token.atom => SELECT atom.value FROM $Property => ExplicitProperty[h]; $DefaultProperty => DefaultProperty[h]; ENDCASE => {TokenIO.ReadAgain[h, token]; RETURN}; ENDCASE => {TokenIO.ReadAgain[h, token]; RETURN}; ENDLOOP; }; DirectoryOp: PROC [me: CD.Object, design: CD.Design, name: Rope.ROPE, function: CDDirectory.DirectoryFunction] RETURNS [proceed: BOOL] ~ INLINE { IF proceed_me.class.inDirectory THEN { dp: CDDirectory.DirectoryProc _ CDDirectory.ObToDirectoryProcs[me].directoryOp; IF dp#NIL THEN proceed _ dp[me, design, name, function] } }; ReadObjectDefinition: PROC [h: TokenIO.Handle, pushRec: BOOL _ FALSE] RETURNS [obj: CD.Object_NIL] = { index: INT _ -1; name: Rope.ROPE; versionKey: INT ~ Version[h]; atom: ATOM _ TokenIO.ReadPush[h]; design: CD.Design ~ InlineDesignInReadOperation[h]; class: CD.ObjectClass _ CD.FetchObjectClass[atom, design.technology]; CDSequencer.CheckAborted[design]; IF class=NIL OR class.internalRead=NIL THEN { IF atom#NIL THEN {TerminalIO.PutRope["NIL is a bad object class\n"]; RETURN} ELSE { n: Rope.ROPE ~ Atom.GetPName[atom]; TerminalIO.PutRopes["object class ", n, " not registered\n"]; CDEnvironment.ExecFileEntry[n, design.technology]; class _ CD.FetchObjectClass[atom, design.technology]; } }; IF class=NIL OR class.internalRead=NIL THEN { TerminalIO.PutF1["reading object class %g failed\n", [atom[atom]]]; TokenIO.Skip[h]; obj _ CDRects.CreateBareRect[[10, 10], CD.errorLayer]; RETURN }; IF versionKey>=15 THEN { IF class.inDirectory THEN { index _ TokenIO.ReadInt[h]; } ELSE { token: TokenIO.Token _ TokenIO.Read[h]; WITH token SELECT FROM atom: TokenIO.Token.atom => IF atom.value=$CDIOUseTable THEN index _ TokenIO.ReadInt[h] ELSE TokenIO.ReadAgain[h, token]; ENDCASE => TokenIO.ReadAgain[h, token]; }; }; obj _ class.internalRead[h, atom]; IF obj=NIL OR obj.class=NIL THEN obj _ NEW[CD.ObjectRep _ CDRects.CreateRect[[10, 10], CD.errorLayer]^]; IF index>0 THEN SetTableEntry[h, index, obj]; IF versionKey>0 THEN { IF class.inDirectory THEN { name _ TokenIO.ReadRope[h]; IF versionKey<=4 THEN [] _ TokenIO.ReadRope[h]; --ignore an old versionkey feature }; }; BEGIN token: TokenIO.Token _ TokenIO.Read[h]; WITH token SELECT FROM pop: TokenIO.Token.pop => NULL; ENDCASE => { TokenIO.ReadAgain[h, token]; obj.properties _ ReadProperties[h]; TokenIO.ReadPop[h]; IF versionKey<8 THEN CDOldInterestRects.AdjustInterest[h, obj]; }; END; IF obj.class.inDirectory THEN { [] _ DirectoryOp[obj, NIL, name, rename]; IF versionKey>=15 THEN { IF ~CDDirectory.IsOwner[design, obj] AND ~pushRec THEN [] _ CDDirectory.Include[design, obj, name]; }; }; }; ReadObject: PUBLIC PROC [h: TokenIO.Handle] RETURNS [ob: CD.Object_NIL] = { t: TokenIO.Token ~ TokenIO.Read[h]; WITH t SELECT FROM int: TokenIO.Token.int => ob _ GetTableEntry[h, int.value]; push: TokenIO.Token.push => { TokenIO.ReadAgain[h, t]; ob _ ReadObjectDefinition[h]; }; ENDCASE => SIGNAL TokenIO.EncodingError[]; }; Get23Table: PROC [h: TokenIO.Handle] RETURNS [RefTab.Ref_NIL] = { rt: RefTab.Ref; WITH PropertyLists.GetProp[h.properties^, $convert23] SELECT FROM tab: RefTab.Ref => rt _ tab; ENDCASE => { rt _ RefTab.Create[201]; h.properties^ _ PropertyLists.PutProp[h.properties^, $convert23, rt] }; RETURN [rt]; }; BBox23: PROC [ob: CD.Object, h: TokenIO.Handle] RETURNS [bbox: CD.Rect] = { bbox_ob.bbox; IF ob.class.inDirectory THEN WITH RefTab.Fetch[Get23Table[h], ob].val SELECT FROM rr: REF CD.Rect => RETURN [rr^] ENDCASE => NULL; }; FitObject23: PROC [ob: CD.Object, location: CD.Position _ [0, 0], orientation: CD.Orientation _ CD.Orientation[original], h: TokenIO.Handle] RETURNS [trans: CD.Transformation] = { oldR: CD.Rect _ ob.bbox; IF CDCells.IsCell[ob] THEN oldR _ BBox23[ob, h]; trans.orient _ orientation; trans.off _ CDBasics.SubPoints[location, CDBasics.BaseOfRect[CDBasics.MapRect[oldR, [[0, 0], orientation]]]]; }; FitObjectO: PROC [ob: CD.Object, location: CD.Position _ [0, 0], orientation: CD.Orientation _ CD.Orientation[original]] RETURNS [trans: CD.Transformation] = { trans.orient _ orientation; trans.off _ CDBasics.SubPoints[location, CDBasics.BaseOfRect[CDBasics.MapRect[ob.bbox, [[0, 0], orientation]]]]; }; OldReadInstance: PROC [h: TokenIO.Handle] RETURNS [inst: CD.Instance] = { location: CD.Position _ ReadPos[h]; orientation: CD.Orientation _ CDIO.ReadOrientation[h]; properties: CD.PropList _ ReadProperties[h]; ob: CD.Object _ ReadObject[h]; versionKey: INT ~ Version[h]; IF versionKey>=8 THEN { inst _ NEW[CD.InstanceRep _ [trans: FitObject23[ob, location, orientation, h], properties: properties, ob: ob]] } ELSE { IF versionKey>=5 THEN { inst _ NEW[CD.InstanceRep _ [trans: CDOps.FitObjectI[ob, location, orientation], properties: properties, ob: ob]] } ELSE { --ancient cases absoluteMode: BOOL _ TRUE; IF versionKey<3 THEN absoluteMode_TRUE ELSE IF versionKey=4 THEN { IF specialForVersion4 THEN IF ob.class.inDirectory THEN absoluteMode_TRUE ELSE absoluteMode_FALSE ELSE absoluteMode_FALSE } ELSE IF versionKey=3 THEN { IF ob.class.inDirectory THEN absoluteMode_TRUE ELSE absoluteMode_FALSE }; IF setManually=1 THEN absoluteMode_TRUE ELSE IF setManually=2 THEN absoluteMode_FALSE ELSE IF setManually=3 THEN absoluteMode_ob.class.inDirectory; IF absoluteMode THEN inst _ NEW[CD.InstanceRep _ [trans: FitObjectO[ob, location, orientation], properties: properties, ob: ob]] ELSE inst _ NEW[CD.InstanceRep _ [trans: CDOps.FitObjectI[ob, location, orientation], properties: properties, ob: ob]] }; }; }; ReadInstance: PUBLIC PROC [h: TokenIO.Handle] RETURNS [inst: CD.Instance] = { IF Version[h]<=15 THEN RETURN [OldReadInstance[h]] ELSE { location: CD.Position _ ReadPos[h]; orientation: CD.Orientation _ ReadOrientation[h]; properties: CD.PropList _ ReadProperties[h]; ob: CD.Object _ ReadObject[h]; inst _ NEW[CD.InstanceRep _ [trans: [location, orientation], properties: properties, ob: ob]] } }; ReadPos: PUBLIC PROC [h: TokenIO.Handle] RETURNS [p: CD.Position] = { p.x _ TokenIO.ReadInt[h]; p.y _ TokenIO.ReadInt[h]; }; ReadRect: PUBLIC PROC [h: TokenIO.Handle] RETURNS [r: CD.Rect] = { r.x1 _ TokenIO.ReadInt[h]; r.y1 _ TokenIO.ReadInt[h]; r.x2 _ TokenIO.ReadInt[h]; r.y2 _ TokenIO.ReadInt[h]; }; ReadPushRec: PROC [h: TokenIO.Handle] RETURNS [pr: CD.PushRec] = { dummy: CD.Object; token: TokenIO.Token _ TokenIO.Read[h]; WITH token SELECT FROM atom: TokenIO.Token.atom => { IF atom.value=$Nil THEN pr.mightReplace_NIL ELSE { TokenIO.ReadAgain[h, token]; pr.mightReplace _ ReadInstance[h]; } }; ENDCASE =>{ TokenIO.ReadAgain[h, token]; pr.mightReplace _ ReadInstance[h]; }; dummy _ ReadObjectDefinition[h, TRUE]; pr.specific _ NARROW[dummy.specific, CD.CellSpecific]; pr.specific.changed _ TRUE; ToListMode[pr.specific]; pr.specific.dummyCell _ TRUE; IF Version[h]<=15 AND Version[h]>=11 THEN { pr.specific.ir _ ReadRect[h]; }; pr.dummyCell _ CDInstances.NewInst[ob: dummy]; }; ToListMode: PROC [cp: CD.CellSpecific] = { old: CD.InstanceSequence _ cp.sequence; cp.sequence _ NIL; IF old#NIL THEN FOR n: NAT IN [0..old.length) DO cp.contents _ CONS[old[n], cp.contents] ENDLOOP; }; ReadLayer: PUBLIC PROC [h: TokenIO.Handle] RETURNS [CD.Layer] = { key: ATOM _ TokenIO.ReadAtom[h]; IF Version[h]<=12 THEN { SELECT key FROM $combined => key _ $undefLayer; $highLightShade => key _ $shadeLayer; $highLightError => key _ $errorLayer; $backGround => key _ $backGround; ENDCASE => NULL; }; RETURN [CD.FetchLayer[InlineDesignInReadOperation[h].technology, key]]; }; ReadSubObjects: PROC [h: TokenIO.Handle] = { obj: CD.Object; DO token: TokenIO.Token _ TokenIO.Read[h]; TokenIO.ReadAgain[h, token]; WITH token SELECT FROM push: TokenIO.Token.push => obj _ ReadObject[h]; int: TokenIO.Token.int => obj _ ReadObject[h]; ENDCASE => EXIT; ENDLOOP; }; ReadDesignData: PROC [h: TokenIO.Handle, design: CD.Design] = { versionKey: INT _ Version[h]; index, directoryCount: INT; obj: CD.Object; directoryCount _ TokenIO.ReadInt[h]; AllocateTables[h, directoryCount+1]; IF versionKey>=15 THEN ReadSubObjects[h] ELSE { FOR n: INT IN [1..directoryCount] DO index _ TokenIO.ReadInt[h]; obj _ ReadObject[h]; SetTableEntry[h, index, obj]; IF versionKey=0 THEN { DO token: TokenIO.Token _ TokenIO.Read[h]; WITH token SELECT FROM rope: TokenIO.Token.rope => { obx: INT = TokenIO.ReadInt[h]; [] _ CDDirectory.Include[design, GetTableEntry[h, obx], rope.value]; } ENDCASE => {TokenIO.ReadAgain[h, token]; EXIT}; ENDLOOP } ELSE IF obj.class.inDirectory THEN { IF ~CDDirectory.IsOwner[design, obj] THEN { name: Rope.ROPE = CDDirectory.Name[obj]; [] _ CDDirectory.Include[design, obj, name]; } } ENDLOOP; }; design.properties _ NEW[CD.PropList_ReadProperties[h]]; CDProperties.PutDesignProp[design, $FileVersion, CDProperties.GetProp[h.properties, $FileVersion]]; design.actual _ NIL; DO token: TokenIO.Token _ TokenIO.Read[h]; WITH token SELECT FROM atom: TokenIO.Token.atom => IF atom.value=$Push THEN {design.actual _ CONS[ReadPushRec[h], design.actual]} ELSE {TokenIO.ReadAgain[h, token]; EXIT}; ENDCASE => {TokenIO.ReadAgain[h, token]; EXIT}; ENDLOOP; IF TokenIO.ReadAtom[h]#$EndOfDesign THEN SIGNAL TokenIO.EncodingError; }; ReadDesign: PUBLIC PROC [from: REF_NIL, check: PROC [h: TokenIO.Handle] RETURNS [BOOL] _ NIL, wDir: Rope.ROPE _ NIL, stop: REF BOOL _ NIL] RETURNS [design: CD.Design_NIL] = { wDirUsed: Rope.ROPE _ NIL; DoInner: PROC [h: TokenIO.Handle] RETURNS [design: CD.Design_NIL] = { ENABLE { TokenIO.EncodingError => { TerminalIO.PutRope["** TokenIO encoding problem\n"]; REJECT; }; RuntimeError.UNCAUGHT => { TerminalIO.PutRope["** problem while reading; abort or proceed\n"]; REJECT }; UNWIND => { TokenIO.Close[h, iDidTheOpen]; }; }; TechnologyCheck: PROC [h: TokenIO.Handle] = { ENABLE UNWIND => design _ NIL; dont: BOOL _ CDEvents.ProcessEvent[ev: readEvent, design: design, x: h, listenToDont: TRUE].dont; IF dont THEN { design _ NIL; TerminalIO.PutRope["**technology rejects read\n"]; } }; VersionAndSealCheck: PROC [h: TokenIO.Handle] = { versionKey: INT; IF TokenIO.ReadInt[h]#xChipndaleFile THEN { TerminalIO.PutRope["File is not a ChipNDale design\n"]; ERROR TokenIO.EncodingError; }; versionKey _ TokenIO.ReadInt[h]; CDProperties.PutProp[h.properties, $VersionKey, NEW[INT_versionKey]]; IF versionKey#xVersion THEN { OldMsg: PROC [versionKey: INT, bar: BOOL_FALSE, conv: BOOL_FALSE, extra: Rope.ROPE_NIL] = { IF bar THEN TerminalIO.PutRope["****\n"]; TerminalIO.PutF1["design was written with old ChipNDale version; filekey = %g\n", [integer[versionKey]]]; IF conv THEN TerminalIO.PutRope["please convert all your designs (by reading and subsequent writing)\n"]; IF extra#NIL THEN TerminalIO.PutRope[extra]; IF bar THEN TerminalIO.PutRope["****\n"]; }; h.oldVersion _ TRUE; IF versionKey>xVersion THEN { -- too new TerminalIO.PutRope["design has newer file format version\n; bringover ChipNDale !!\n"]; ERROR TokenIO.EncodingError; } ELSE IF versionKey IN [13..xVersion] THEN { -- not new but dont tell it NULL } ELSE IF versionKey IN [6..xVersion] THEN { -- not new but everything ok OldMsg[versionKey]; } ELSE IF versionKey=4 THEN { -- known problem versions OldMsg[versionKey, TRUE, TRUE, "check carefully the alignment of cells which have n-well; if you have troubles, try CD18InputToggle and repeat the input\n"]; } ELSE IF versionKey=3 THEN { -- known problem versions OldMsg[versionKey, TRUE, TRUE, "check carefully the alignment of cells which have n-well\n"]; } ELSE IF versionKey IN [0..xVersion] THEN { -- not new but please convert OldMsg[versionKey, TRUE, TRUE]; } ELSE { -- too old OldMsg[versionKey, TRUE, FALSE, "sorry this version is no more supported\n"]; ERROR TokenIO.EncodingError; }; }; IF versionKey>0 THEN { IF TokenIO.ReadInt[h]#-1 THEN { TerminalIO.PutRope["**file had not been properly closed\n"]; ERROR TokenIO.EncodingError; }; }; }; ReadDesignVersion: PROC [h: TokenIO.Handle, design: CD.Design] = { designVersionKey: Rope.ROPE_NIL; IF Version[h]>=7 THEN designVersionKey _ TokenIO.ReadRope[h]; IF Rope.IsEmpty[designVersionKey] THEN designVersionKey _ Convert.RopeFromTime[from: BasicTime.Now[], end: seconds]; CDProperties.PutDesignProp[design, $FileVersion, designVersionKey]; CDProperties.PutProp[h.properties, $FileVersion, designVersionKey]; }; ReadDesignName: PROC [h: TokenIO.Handle] RETURNS [name: Rope.ROPE] = { name _ TokenIO.ReadRope[h]; IF Rope.IsEmpty[name] THEN { name _ FileNames.GetShortName[fileName, TRUE]; name _ Rope.Substr[name, 0, Rope.Index[name, 0, ".dale", FALSE]] } }; VersionAndSealCheck[h]; technologyKey _ TokenIO.ReadAtom[h]; technologyName _ TokenIO.ReadRope[h]; technology _ CDEnvironment.LoadTechnology[technologyKey, technologyName]; IF technology=NIL THEN GOTO NotDone; h.clientData _ design _ CDOps.CreateDesign[technology]; TechnologyCheck[h]; IF design=NIL THEN GOTO NotDone; design.name _ ReadDesignName[h]; ReadDesignVersion[h, design]; --read before check, fixed again later IF check#NIL THEN IF NOT check[h] THEN GOTO NotDone; ReadDesignData[h, design]; CDEnvironment.SetWorkingDirectory[design, wDirUsed]; CDValue.Store[boundTo: design, key: $CDxFromFile, value: fileName]; CDValue.Store[boundTo: design, key: $CDxLastFile, value: fileName]; TokenIO.Close[h, FALSE]; EXITS NotDone => RETURN [design_NIL]; }; h: TokenIO.Handle; technology: CD.Technology; technologyKey: ATOM; technologyName: Rope.ROPE; binfile: IO.STREAM; fileName: Rope.ROPE; iDidTheOpen: BOOL _ FALSE; name: Rope.ROPE; streamOptions: FS.StreamOptions _ ALL[TRUE]; streamOptions[tiogaRead] _ FALSE; streamOptions[commitAndReopenTransOnFlush] _ FALSE; streamOptions[truncatePagesOnClose] _ TRUE; streamOptions[finishTransOnClose] _ TRUE; streamOptions[closeFSOpenFileOnClose] _ TRUE; IF wDir=NIL THEN wDir _ FileNames.CurrentWorkingDirectory[]; IF from#NIL AND ISTYPE[from, IO.STREAM] THEN { fileName _ NIL; binfile _ NARROW[from, IO.STREAM] } ELSE { ReadName: PROC [wDir: Rope.ROPE] RETURNS [name: Rope.ROPE] = { TerminalIO.PutRopes[" input file (", wDir, ")"]; name _ TerminalIO.RequestRope[" > "]; }; IF from=NIL THEN name _ ReadName[wDir] ELSE IF ISTYPE[from, Rope.ROPE] THEN { name _ NARROW[from, Rope.ROPE]; IF Rope.IsEmpty[name] THEN name _ ReadName[wDir]; } ELSE { TerminalIO.PutRope["ReadDesign: bad parameter\n"]; GOTO NotOpened; }; fileName _ CDEnvironment.MakeName[name, "dale", wDir]; binfile _ FS.StreamOpen[fileName, $read, streamOptions ! FS.Error => IF error.group # bug THEN { TerminalIO.PutRope[Rope.Cat[fileName, " not opened: ", error.explanation, "\n"]]; GOTO NotOpened; }]; fileName _ RealFileName[binfile, fileName]; wDirUsed _ FileNames.Directory[fileName]; iDidTheOpen _ TRUE; TerminalIO.PutRopes[fileName, " opened \n"]; }; IF stop=NIL THEN stop _ NEW[BOOL_FALSE]; h _ TokenIO.CreateReader[stream: binfile, stop: stop ! TokenIO.EncodingError => { TerminalIO.PutRope["**TokenIO says file not ok; maybe not a ChipNDale file\n"]; GOTO NotOpened }; ]; design _ DoInner[h]; IF design#NIL THEN [] _ CDEvents.ProcessEvent[ev: afterInputEvent, design: design, x: h, listenToDont: FALSE]; TokenIO.Close[h, iDidTheOpen]; EXITS NotOpened => RETURN [NIL]; }; RealFileName: PROC [s: IO.STREAM, default: Rope.ROPE_NIL] RETURNS [n: Rope.ROPE] = { file: FS.OpenFile; n _ default; file _ FS.OpenFileFromStream[s ! IO.Error => GOTO Oops]; n _ FS.GetName[file! FS.Error => GOTO Oops].fullFName; EXITS Oops => n _ default }; ReadOrientation: PUBLIC PROC [h: TokenIO.Handle] RETURNS [orientation: CD.Orientation] = { i: NAT _ TokenIO.ReadInt[h]; IF Version[h]<=3 THEN { IF i IN [0..15] THEN orientation _ VAL[i/4*2 + i MOD 2] ELSE SIGNAL TokenIO.EncodingError; } ELSE IF i IN [0..7] THEN orientation _ VAL[i] ELSE SIGNAL TokenIO.EncodingError }; MakeName: PUBLIC PROC [base: Rope.ROPE, ext: Rope.ROPE_NIL, wDir: Rope.ROPE_NIL, modifier: Rope.ROPE_NIL] RETURNS [Rope.ROPE] = { RETURN [CDEnvironment.MakeName[base, ext, wDir, modifier]]; }; SetWorkingDirectory: PUBLIC PROC [design: REF, wDir: Rope.ROPE] = { CDEnvironment.SetWorkingDirectory[design, wDir]; }; GetWorkingDirectory: PUBLIC PROC [design: REF] RETURNS [wDir: Rope.ROPE_NIL] = { RETURN [CDEnvironment.GetWorkingDirectory[design]]; }; MakeShortName: PUBLIC PROC [design: CD.Design] RETURNS [name: Rope.ROPE _ NIL] = { TrailingDot: PROC [base: Rope.ROPE] RETURNS [INT] = { len: INT _ Rope.Length[base]; pos: INT _ len; WHILE pos > 0 DO SELECT Rope.Fetch[base, pos _ pos - 1] FROM '. => RETURN [pos]; '!, '], '>, '/ => EXIT; ENDCASE; ENDLOOP; RETURN [len]; }; SuggestedModule: PROC [base: Rope.ROPE] RETURNS [Rope.ROPE] = { len, dot: INT; base _ FileNames.GetShortName[base]; len _ Rope.Length[base]; dot _ TrailingDot[base]; IF len>dot AND Rope.Equal[Rope.Substr[base, dot+1], "dale", FALSE] THEN base _ Rope.Substr[base, 0, dot]; RETURN [base] }; WITH CDValue.Fetch[boundTo: design, key: $CDxFromFile] SELECT FROM r: Rope.ROPE => name _ SuggestedModule[r]; ENDCASE => NULL; IF name=NIL THEN name _ design.name; IF name=NIL THEN name _ "noname" }; CD18Input: Commander.CommandProc = { specialForVersion4 _ ~specialForVersion4; IF specialForVersion4 THEN cmd.out.PutRope["Fileformat: switch to old version of cd18\n"] ELSE cmd.out.PutRope["Fileformat: switch to last version of cd18\n"]; }; InlineDesignInReadOperation: PUBLIC PROC [h: TokenIO.Handle] RETURNS [CD.Design] = INLINE { RETURN [NARROW[h.clientData]] }; VersionKey: PUBLIC PROC [h: TokenIO.Handle] RETURNS [INT] = { WITH CDProperties.GetProp[h.properties, $VersionKey] SELECT FROM i: REF INT => RETURN [i^]; ENDCASE => RETURN [0]; }; readEvent: CDEvents.EventRegistration = CDEvents.RegisterEventType[$ReadTechnologyPrivate]; afterInputEvent: CDEvents.EventRegistration = CDEvents.RegisterEventType[$AfterInput]; Commander.Register["///Commands/CD18InputToggle", CD18Input, "toggle input mode of cd18"]; END. ‚CDIn.mesa Copyright c 1983, 1986 by Xerox Corporation. All rights reserved. Last Edited by: Kimr, November 28, 1983 10:22 am Last Edited by: Jacobi, February 8, 1984 9:41 am Last Edited by: Christian Jacobi, January 10, 1987 11:24:34 am PST --ok means NOT registered --only old version may use that ! --for the conversion from cd2.3 to cd2.4 use bbox with interest rect excluded WITH ob.specific SELECT FROM cp: CD.CellSpecific => IF cp.specifiedIr THEN oldR _ CDCellsBackdoor.Bounds[list: cp.contents, seq: cp.sequence, doIr: FALSE, doBb: TRUE].bbox; ENDCASE => NULL; ??? better instead of I: CDOldInterestRects.InsideRect[ob] --The layer keys have changed from ChipNDale 2.2 to ChipNDale 2.3. --hack to simplify some read procedures... --this overwrites an previous $FileVersion property read in the normal (wrong) way --Side-effect: if bad, design is set to NIL --ChipNDale check --version check --seal check -- DoInner -- begin ReadDesign -- open file; assign fileName and binfile -- do the actual work --position of last dot --given a filename, suggests a modulename --MakeShortName --fix an old old problem Version history versionKey 0 versionKey 1: objects with children carry names versionKey 2: versionKey 3: June 15, 1984 3:46:13 pm PDT; instances position is its innerrect; this allows to shrink or grow the nwell from cmos versionKey 4: October 20, 1984 9:36:34 am PDT; orientation changed probably while lifetime of 4: properties which are propertylists are automatically included versionKey 5: December 14, 1984 10:07:59 am PST; insiderect for cells no more done with properties; key is removed versionKey 6: February 1, 1985 4:43:29 pm PST; properties which are layers are automatically included versionKey 7: March 26, 1985 12:33:22 pm PST; file versionkey property included versionKey 8: April 15, 1985 3:26:35 pm PST; cd-coords base to file again... cells get origin and interestrect imports get interestrect versionKey 9: May 29, 1985 7:51:45 pm PDT; CD21 versionKey 10: May 29, 1985 7:51:45 pm PDT; CD22 Atomicobject have the interest rect on the file versionKey 11: May 29, 1985 7:51:45 pm PDT; (CD22) pushed records get the default interest rect versionKey 12: January 28, 1986 2:23:27 pm PST; (CD22) default properties get $DefaultProperty key versionKey 13: March 11, 1986 4:17:16 pm PST; (CD23) cells may have drawBorder field gbb April 4, 1986 3:19:31 pm PST The atoms for the keys of the technology independent layers have changed. changes to: ReadLayer: if versionKey[]<=12 translate atoms. versionKey 15: June 20, 1986 9:53:19 am PDT; Global changes Number of object for object table is now inside object definition Directory include is performed for all objects in directory, independent of source. Objects not in directory have special option to be put in table. versionKey 16: September 11, 1986 11:40:52 am PDT; CD2.4. New TokenIO New object r instead of size ส!๕– "cedar" style˜code™ Kšœ ฯmœ7™BK™0K™0KšœB™BK™—šฯk ˜ Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšžœ˜Kšœ ˜ Kšœ˜Kšœ ˜ Kšœ˜Kšœ ˜ K˜ Kšžœ˜Kšœ žœ˜!Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšžœ˜Kšžœ˜K˜Kšœ˜Kšœ˜Kšœžœžœ˜Kšœ ˜ Kšœ˜Kšœ˜—K˜šฯnœžœž˜Kš žœ&žœHžœLžœžœT˜กKšžœž˜ Kšžœžœ˜—Kšž˜K™Kšœžœ ˜Kšœ žœ˜K˜š Ÿœžœžœžœžœ˜:Kšžœžœžœžœ ˜:K˜K˜—Kš œ žœžœžœžœžœžœ ˜FKš œ žœžœžœžœžœžœ ˜HK˜Kšœžœ ˜K˜Kšœžœžœฯc˜BKšœ žœ ˜3Kšœžœžœ˜!K˜šŸ œžœžœžœžœžœžœ˜Ušžœžœ˜Kšœ žœžœ4˜WKšœ˜K˜—šžœ˜Kšœ žœžœ4˜WKšœ-žœ˜?K˜—Kšžœžœžœ0˜>Kšœ˜—K˜š Ÿ œžœžœžœ žœ˜Hšžœžœ˜Kšœ žœžœ6˜YKšœ˜K˜—šžœ˜Kšœ žœžœ6˜YKšœ(žœ˜?K˜—Kšœ˜—K˜šŸœžœžœ˜3Kšœ žœžœ žœ˜DKšœ@˜@šžœžœ˜Kšœ žœžœ˜=Kšœ@˜@š žœžœžœžœ 2˜XKšœžœ˜0Kšž˜—Kšœ˜—Kšœ˜K˜—š Ÿœžœžœžœ žœ žœ˜TK˜š Ÿœžœžœžœžœžœ˜NKšœ1˜1šžœžœžœ˜Kšœ7˜7K˜—Kšœ˜Kšžœžœžœ˜=Kšžœžœ˜K˜—K˜š Ÿœžœžœžœžœ˜:Kš ™KšœC˜CKšœžœžœžœ˜2šžœžœ˜ Kšœ@˜@Kšœ˜K˜—K˜—K˜šŸœžœ˜.Kšœžœ(˜1Kšœ'˜'šžœžœž˜Kšœ0˜0šœ˜Kš !™!Kšžœžœžœ˜4Kšœ˜K˜—Kšžœžœ˜(—Kšœ)˜)š žœ žœžœžœžœ˜6KšœJ˜JK˜—šžœžœžœ˜Kšœžœ˜"Kšœ>˜>Kšœžœ&˜IK˜)š žœ žœžœžœžœ˜6KšœJ˜JK˜—šžœ˜Kšœ˜Kšžœžœžœ˜=K˜—K˜—Kšžœ˜KšœEžœ˜LK˜K˜—šŸœžœ˜-K˜šŸœžœžœ˜šžœžœ˜"šžœž˜šœ˜Kšœžœ˜0Kšœ:˜:K˜—šœ ˜ Kšœžœ˜KšœB˜BK˜—šœ˜Kš œžœžœžœžœ˜šž˜Kšœ'˜'šžœžœž˜Kšœ$žœ˜<šžœ˜ Kšœ˜Kšœ1˜1Kšžœ˜K˜——Kšž˜—K˜—Kšžœžœ˜*—KšœEžœ˜LK˜—K˜—K˜Kšœ'˜'šžœžœž˜šœ˜šžœ!žœ˜)Kšœ'˜'šžœžœž˜šœ˜Kšœ>˜>—šœ˜Kšœ>˜>—šœ˜Kšœ1žœžœ˜F—Kšžœ#˜*—Kšœ˜——Kšœ4˜4šœ˜Kšžœžœžœ˜4Kšœ˜K˜—Kšžœžœ˜#—K˜—K˜šŸœžœžœ˜(Kšœ'˜'šžœžœž˜šœ˜Kšœ6˜6—šœ˜Kšœ6˜6—šœ˜Kšœ*žœžœ ˜>—šœ˜Kšœ˜Kšœ.˜.K˜—šœ˜šžœ žœžœžœ˜2Kšœžœ˜0Kšœ:˜:K˜—šžœžœžœ˜ Kšœžœ˜KšœB˜BK˜—Kšžœ˜KšœF˜FK˜—Kšžœ˜#—K˜—K˜šž˜Kšœ'˜'šžœžœž˜šœ˜šžœ ž˜Kšœ!˜!Kšœ'˜'Kšžœ"žœ˜1——Kšžœ"žœ˜1—Kšžœ˜—Kšœ˜—K˜šŸ œžœžœžœžœ+žœ žœžœ˜‘šžœžœ˜&KšœO˜OKšžœžœžœ)˜7K˜—K˜K˜—šŸœžœžœžœžœžœžœ˜fKšœžœ˜Kšœ žœ˜Kšœ žœ˜Kšœžœ˜!Kšœžœ)˜3Kšœžœžœ+˜EKšœ!˜!š žœžœžœžœžœ˜-Kšžœžœžœ4žœ˜Mšžœ˜Kšœžœ˜#Kšœ=˜=Kšœ2˜2Kšœžœ+˜5K˜—K˜—š žœžœžœžœžœ˜-KšœC˜CKšœ˜Kšœ'žœ˜7Kšž˜K˜—šžœžœ˜šžœžœ˜Kšœ˜K˜—šžœ˜K˜'šžœžœž˜˜Kšžœžœ˜;Kšžœ˜!—Kšžœ ˜'—K˜—K˜—Kšœ"˜"š žœžœžœ žœžœ˜!Kšœžœžœ*žœ˜G—Kšžœ žœ˜-šžœžœ˜šžœžœ˜Kšœ˜Kšžœžœ "˜RK˜—K˜—šž˜Kšœ'˜'šžœžœž˜Kšœžœ˜šžœ˜ Kšœ˜Kšœ#˜#Kšœ˜Kšžœžœ+˜?K˜——Kšžœ˜—šžœžœ˜Kšœžœ˜)šžœžœ˜šžœ#žœ žœ˜7Kšœ,˜,—Kšœ˜—Kšœ˜—Kšœ˜—K˜š Ÿ œžœžœžœžœžœ˜KK˜#šžœžœž˜Kšœ;˜;šœ˜Kšœ6˜6K˜—Kšžœžœ˜*—Kšœ˜K˜—K˜šŸ œžœžœ žœ˜AKšœ˜šžœ2žœž˜AKšœ˜šžœ˜ Kšœ˜KšœD˜DK˜——Kšžœ˜ K˜—K˜š Ÿœžœžœžœžœ ˜KKšœ ˜ šžœž˜šžœ%žœž˜4Kšœžœžœ žœ˜Kšžœž˜——Kšœ˜K˜—šŸ œžœžœžœ!žœžœ+žœ žœ˜ณJ™MJšœžœ˜Jšžœžœ˜0šžœ žœž™šœžœžœžœ™.JšœIžœžœ™a—Jšžœžœ™—Kšœ˜Kšœm˜mK˜—K˜šŸ œžœžœžœ!žœžœžœ žœ˜ŸKšœ˜Kšœp˜pK˜—K˜šŸœžœžœžœ˜IKšœ žœ˜#Kšœ žœžœ˜6Kšœ žœ˜,Kšœžœ˜Kšœ žœ˜šžœžœ˜Kšœžœžœb˜oK˜—šžœ˜šžœžœ˜KšœŸœ#™:Kšœžœžœd˜qK˜—šžœ ˜Kšœžœžœ˜Kšžœžœžœ˜'šžœžœžœ˜šžœžœ˜Kš žœžœžœžœž˜F—Kšžœž˜K˜—šžœžœžœ˜Kš žœžœžœžœž˜FK˜—Kšžœžœž˜'Kšžœžœžœž˜-Kšžœžœžœ#˜=šžœžœ˜Kšœžœžœ^˜k—šžœ˜Kšœžœžœd˜q—K˜—K˜—K˜—K˜š Ÿ œžœžœžœžœ˜MKšžœžœžœ˜2šžœ˜Kšœ žœ˜#Kšœ žœ"˜1Kšœ žœ˜,Kšœžœ˜KšœžœžœP˜]K˜—Kšœ˜K˜—š Ÿœžœžœžœžœ˜EKšœ˜Kšœ˜Kšœ˜—K˜š Ÿœžœžœžœžœ ˜BKšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—K˜šŸ œžœžœžœ ˜BKšœžœ˜Kšœ'˜'šžœžœž˜˜Kšžœžœž˜+šžœ˜Kšœ˜Kšœ"˜"K˜—K˜—šžœ˜ Kšœ˜Kšœ"˜"K˜——Kšœ žœ˜&Kšœžœžœ˜6Kšœžœ˜Kšœ˜Kšœžœ˜šžœžœžœ˜+Kšœ˜Kšœ˜—Kšœ.˜.Kšœ˜—K˜šŸ œžœžœ˜*Kšœžœ ˜'Kšœžœ˜šžœžœžœ˜šžœžœžœžœ˜!Kšœžœ˜(Kšžœ˜——K˜—K˜š Ÿ œžœžœžœžœ ˜AKšœžœ˜ šžœžœ˜Kš D™Dšžœž˜Kšœ˜Kšœ%˜%Kšœ%˜%Kšœ!˜!Kšžœžœ˜—K˜—Kšžœžœ=˜GKšœ˜—K˜šŸœžœ˜,Kšœžœ ˜šž˜Kšœ'˜'Kšœ˜šžœžœž˜Kšœ0˜0Kšœ.˜.Kšžœžœ˜—Kšžœ˜—Kšœ˜—K˜šŸœžœžœ ˜?Kšœ žœ˜Kšœžœ˜Kšœžœ˜Kšœ$˜$Kšœ%˜%Kšžœžœ˜(šžœ˜šžœžœžœž˜$Kšœ˜Kšœ˜Kšœ˜šžœžœ˜šž˜Kšœ'˜'šžœžœž˜˜Kšœžœ˜KšœD˜DK˜—Kšžœ"žœ˜/—Kšž˜—K˜—šžœžœžœ˜%Kš +™+šžœ#žœ˜+Kšœ žœ˜(Kšœ,˜,K˜—K˜—Kšžœ˜—K˜—Kšœžœžœ˜7Kš R™RKšœc˜cKšœžœ˜šž˜Kšœ'˜'šžœžœž˜šœ˜Kšžœžœžœ ˜NKšžœžœ˜)—Kšžœ"žœ˜0—Kšžœ˜—Kšžœ"žœžœ˜FKšœ˜—K˜š"Ÿ œžœžœžœžœ žœžœžœžœ žœžœžœžœžœžœ žœžœ˜ฎKšœžœžœ˜K˜š Ÿœžœžœ žœžœ˜Ešžœ˜šœ˜Kšœ4˜4Kšžœ˜Kšœ˜—šœ žœ˜KšœC˜CKšž˜Kšœ˜—šžœ˜ Kšœ˜K˜—K˜K˜—šŸœžœ˜-Kš +™+Kšžœžœ žœ˜KšœžœLžœ˜bšžœžœ˜Kšœ žœ˜ Kšœ2˜2K˜—Kšœ˜—K˜šŸœžœ˜1Kš ™Kšœ žœ˜šžœ#žœ˜+Kšœ7˜7Kšžœ˜Kšœ˜—Kš ™Kšœ ˜ Kšœ0žœžœ˜Ešžœžœ˜šŸœžœžœžœžœžœžœžœžœ˜[Kšžœžœ˜)Kšœi˜išžœžœ˜ Kšœ\˜\—Kšžœžœžœ˜,Kšžœžœ˜)K˜—Kšœžœ˜šžœžœ  ˜(KšœW˜WKšžœ˜Kšœ˜—š žœžœ žœžœ ˜GKšž˜K˜—š žœžœ žœžœ ˜GKšœ˜K˜—šžœžœžœ ˜5Kšœžœžœ€˜K˜—šžœžœžœ ˜5Kšœžœžœ@˜]K˜—š žœžœ žœžœ ˜HKšœžœžœ˜K˜—šžœ  ˜Kšœžœžœ/˜MKšžœ˜K˜—Kšœ˜—Kš  ™ šžœžœ˜šžœžœ˜Kšœ<˜Kšœ0˜0Kšœ&˜&Kšœ˜—K˜Kšžœžœžœ˜&š žœžœžœ žœžœ˜&Kšœžœ žœ˜Kšžœžœ˜1K˜—šžœ˜Kšœ2˜2Kšžœ ˜K˜—Kšœ6˜6šœ žœ-žœ ˜Ešžœžœ˜KšœQ˜QKšžœ ˜Kšœ˜——Kšœ+˜+Kšœ)˜)Kšœžœ˜Kšœ,˜,K˜—K˜Kš ™Kš žœžœžœžœžœžœ˜(šœ6˜6šœ˜KšœP˜PKšžœ ˜K˜—Kšœ˜—K˜Kšœ˜K˜šžœžœž˜KšœTžœ˜\—Kšœ˜Kšžœžœžœ˜ Kšœ˜—K˜šŸ œžœžœžœžœžœžœ žœ˜TKšœžœ ˜Kšœ ˜ Kšœžœžœ žœ˜8Kšœžœžœ žœ˜6Kšžœ˜Kšœ˜—K˜š Ÿœžœžœžœžœ˜ZKšœžœ˜šžœžœ˜Kš žœžœ žœžœ žœ˜8Kšžœžœ˜#K˜—šžœ˜Kšžœžœžœžœ˜)Kšžœžœ˜!—Kšœ˜—K™šŸœžœžœ žœ žœžœ žœžœžœžœžœžœ˜Kšžœ5˜;Kšœ˜—K˜š Ÿœžœžœ žœ žœ˜CKšœ0˜0Kšœ˜—K˜šŸœžœžœ žœžœ žœžœ˜PKšžœ-˜3Kšœ˜—K˜šŸ œžœžœ žœ žœ žœžœ˜RK˜š Ÿ œžœ žœžœžœ˜5Kš ™Kšœžœ˜Kšœžœ˜šžœ ž˜šžœ!ž˜+Kšœžœ˜Kšœžœ˜Kšžœ˜—Kšžœ˜—Kšžœ˜ K˜K˜—š Ÿœžœ žœžœžœ˜?Kš )™)Kšœ žœ˜Kšœ$˜$Kšœ˜Kšœ˜šžœ žœ.žœžœ˜HKšœ!˜!—Kšžœ˜ K˜—K˜Kš ™šžœ3žœžœ˜CKšœžœ˜*Kšžœžœ˜—Kšžœžœžœ˜$Kšžœžœžœ˜ Kšœ˜K˜—K™šะbn œ˜$Kš ™Kšœ)˜)šžœž˜Kšœ>˜>—šž˜Kšœ@˜@—Kšœ˜—K˜š Ÿœžœžœžœžœ žœ˜[Kšžœžœ˜Kšœ˜K˜—š Ÿ œžœžœžœžœ˜=šžœ1žœž˜@Kšœžœžœžœ˜Kšžœžœ˜—K˜—K˜Kšœ[˜[KšœV˜VKšœZ˜ZKšžœ˜K˜šฯb™K™Kšœ ™ šœ™Kšœ!™!—Kšœ™šœ(žœ™.KšœV™V—šœ+žœ™0Kšœ™—šœ™Kšœ=™=—šœ-žœ™2KšœA™A—šœ+žœ™0Kšœ6™6—šœ*žœ™/K™!—šœ)žœ™.K™K™!K™—šœ'žœ™,K™—šœ(žœ™-K™K™/—šœ(žœ™-K™K™,—šœ,žœ™1K™Kšœ+™+—šœ*žœ™/K™K™—šœž™ K™IKšœ ฯr œฯeœ™;—šœ)žœ™.K™K™AK™TK™A—šœ/žœ™4K™K™ K™——K™K™—…—`$›