DIRECTORY Atom, Ascii, BasicTime, Commander, CD, CDBasics, CDCells, CDDirectory, CDEnvironment, CDEvents, CDInstances, CDImports, CDIO, CDRepetitions, CDSequencer USING [CheckAborted], CDOps, CDPrivate, CDProperties, CDRects, CDValue, Convert, FileNames, FS, IO, Properties, RefTab, Rope, RuntimeError USING [UNCAUGHT], TerminalIO, TokenIO; CDIn: CEDAR PROGRAM IMPORTS Atom, BasicTime, Convert, CD, CDBasics, CDCells, CDDirectory, CDEnvironment, CDEvents, CDInstances, CDIO, CDOps, CDPrivate, CDProperties, CDRects, CDSequencer, CDValue, FileNames, FS, IO, Properties, RefTab, Rope, RuntimeError, TerminalIO, TokenIO EXPORTS CDIO SHARES CD, CDDirectory = BEGIN xChipndaleFile: INT = 12121983; xVersion: INT = 18; 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 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 }; }; NoteError: PROC [h: TokenIO.Handle, x: REF] = { IF x=NIL THEN x _ $TRUE; CDProperties.PutPRefProp[h.properties, $errorObject, x]; }; 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 _ Properties.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 _ Properties.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 _ Properties.PutProp[props, key, propertieProps]; }; $layer => { layer: CD.Layer _ ReadLayer[h]; props _ Properties.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 _ Properties.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 _ Properties.PutProp[props, atom.value, ropex.value]; atomx: TokenIO.Token.atom => props _ Properties.PutProp[props, atom.value, atomx.value]; intx: TokenIO.Token.int => props _ Properties.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 _ Properties.PutProp[props, key, rope.value]; atom: TokenIO.Token.atom => props _ Properties.PutProp[props, key, atom.value]; int: TokenIO.Token.int => props _ Properties.PutProp[props, key, NEW[INT_int.value]]; pop: TokenIO.Token.pop => { TokenIO.ReadAgain[h, token]; props _ Properties.PutProp[props, key, key] }; push: TokenIO.Token.push => { IF push.value=NIL OR push.value=$properties THEN { propertieProps: CD.PropList _ ReadProperties[h]; props _ Properties.PutProp[props, key, propertieProps]; } ELSE IF push.value=$layer THEN { layer: CD.Layer _ ReadLayer[h]; props _ Properties.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; }; ReadObjectDefinition: PROC [h: TokenIO.Handle, pushRec: BOOL _ FALSE] RETURNS [obj: CD.Object_NIL] = { index: INT _ -1; name: Rope.ROPE _ NIL; 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]; NoteError[h, obj]; RETURN }; IF versionKey>=15 THEN { IF class.composed THEN { token: TokenIO.Token _ TokenIO.Read[h]; WITH token SELECT FROM r: TokenIO.Token.rope => { name _ r.value; index _ TokenIO.ReadInt[h]; }; i: TokenIO.Token.int => index _ i.value; ENDCASE => TokenIO.EncodingError; } ELSE { token: TokenIO.Token _ TokenIO.Read[h]; WITH token SELECT FROM atom: TokenIO.Token.atom => IF atom.value=$CDIOUseDir THEN { name _ TokenIO.ReadRope[h]; index _ TokenIO.ReadInt[h] } ELSE 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<17 AND versionKey>0 THEN { IF class.composed 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 => { props: CD.PropList; TokenIO.ReadAgain[h, token]; props _ ReadProperties[h]; FOR pl: Properties.PropList _ obj.properties, pl.rest WHILE pl#NIL DO IF Properties.GetProp[props, pl.first.key]=NIL THEN props _ Properties.PutProp[props, pl.first.key, pl.first.val]; ENDLOOP; obj.properties _ props; TokenIO.ReadPop[h]; IF versionKey<8 THEN OldAdjustInterest[h, obj]; }; END; IF versionKey>=17 THEN { IF name#NIL THEN [] _ CDDirectory.Include[design, obj, name] ELSE IF obj.class.composed THEN CDDirectory.SetOwner[design, obj]; } ELSE --old version-- { IF obj.class.composed THEN { DirectoryOp: PROC [me: CD.Object, design: CD.Design, name: Rope.ROPE, function: CDDirectory.DirectoryFunction] ~ { IF me.class.composed THEN { dp: CDDirectory.DirectoryProc _ CDDirectory.ObToDirectoryProcs[me].directoryOp; IF dp#NIL THEN dp[me, design, name, function] } }; DirectoryOp[obj, NIL, name, rename]; IF versionKey>=15 THEN { IF ~CDDirectory.IsIncluded[design, obj] AND ~pushRec THEN [] _ CDDirectory.Include[design, obj, name]; }; } }; IF obj.layer=CD.errorLayer THEN NoteError[h, obj]; }; 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[]; }; 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; IF ~Version[h]<17 THEN { atom: ATOM _ TokenIO.ReadAtom[h]; pr.specific.changed _ atom=$T; IF atom=$EndOfDesign THEN { TokenIO.ReadAgain[h, [atom[atom]]]; TerminalIO.PutRope["****THIS FILE SHOULD BE CONVERTED AGAIN !!!"]; }; }; 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 } 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; }; GetFile: PROC [from: REF_NIL, wDir: Rope.ROPE _ NIL] RETURNS [stream: IO.STREAM_NIL, iDidTheOpen: BOOL _ FALSE] = { ReadName: PROC [wDir: Rope.ROPE] RETURNS [name: Rope.ROPE] = { IF Rope.IsEmpty[wDir] THEN TerminalIO.PutRope[" input file"] ELSE TerminalIO.PutRopes[" input file (", wDir, ")"]; name _ TerminalIO.RequestRope[" > "]; }; name, fullName: Rope.ROPE_NIL; IF from#NIL AND ISTYPE[from, IO.STREAM] THEN { RETURN [NARROW[from, IO.STREAM], FALSE]; }; 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[(IF wDir#NIL THEN wDir ELSE FileNames.CurrentWorkingDirectory[])]; } ELSE {TerminalIO.PutRope["ReadDesign: bad parameter\n"]; GOTO NotOpened}; fullName _ CDEnvironment.FindFile[name, ".dale", wDir]; IF Rope.IsEmpty[fullName] THEN { TerminalIO.PutRopes[name, " not found\n"]; GOTO NotOpened; }; stream _ FS.StreamOpen[fullName, $read, FS.binaryStreamOptions ! FS.Error => IF error.group # bug THEN { TerminalIO.PutF["%g not opened: %g\n", [rope[fullName]], [rope[error.explanation]]]; GOTO NotOpened; }]; iDidTheOpen _ TRUE; TerminalIO.PutRopes[fullName, " opened \n"]; EXITS NotOpened => {} }; 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, iDidTheOpen: BOOL] 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[eventRegistration: 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]; IF versionKey<0 THEN { TerminalIO.PutF["****design was written with a ChipNDale version which was NOT released; dont expect any help if problems occur; [filekey = %g]\n", [integer[versionKey]]]; versionKey _ -versionKey; }; 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 { SELECT TokenIO.ReadInt[h] FROM -1 => {}; -2 => {TerminalIO.PutRope["file is cached; not the truth\n"]; h.truth _ FALSE; }; ENDCASE => { 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[fullName, 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 Oops; h.clientData _ design _ CDOps.CreateDesign[technology]; TechnologyCheck[h]; IF design=NIL THEN GOTO Oops; design.name _ ReadDesignName[h]; ReadDesignVersion[h, design]; --read before check, fixed again later IF iDidTheOpen THEN { fullFName: Rope.ROPE; created: BasicTime.GMT; [fullFName, created] _ FileIdentification[stream]; CDValue.Store[boundTo: design, key: $CDxFromFile, value: fullFName]; CDValue.Store[boundTo: design, key: $CDxLastFile, value: fullFName]; CDEnvironment.SetWorkingDirectory[design, FileNames.Directory[fullName]]; IF created#BasicTime.nullGMT THEN CDValue.Store[boundTo: design, key: $CDxFileCreated, value: NEW[INT_LOOPHOLE[created]]]; }; IF check#NIL THEN IF NOT check[h] THEN GOTO Oops; ReadDesignData[h, design]; EXITS Oops => RETURN [design_NIL]; }; h: TokenIO.Handle; iDidTheOpen: BOOL; technology: CD.Technology; technologyKey: ATOM; technologyName: Rope.ROPE; stream: IO.STREAM; fullName: Rope.ROPE_NIL; [stream, iDidTheOpen] _ GetFile[from, wDir]; IF stream=NIL THEN RETURN; IF stop=NIL THEN stop _ NEW[BOOL_FALSE]; h _ TokenIO.CreateReader[stream: stream, stop: stop ! TokenIO.EncodingError => { TerminalIO.PutRope["**TokenIO says file not ok; maybe not a ChipNDale file\n"]; GOTO Oops }; ]; design _ DoInner[h, iDidTheOpen]; IF design#NIL THEN { IF CDProperties.GetPRefProp[h.properties, $errorObject]#NIL THEN { TerminalIO.PutRope[" **design includes some error message(s)\n"]; }; [] _ CDEvents.ProcessEvent[eventRegistration: afterInputEvent, design: design, x: h, listenToDont: FALSE]; }; TokenIO.Close[h, iDidTheOpen]; EXITS Oops => RETURN [NIL]; }; FileIdentification: PROC [s: IO.STREAM] RETURNS [fullFName: Rope.ROPE _ NIL, created: BasicTime.GMT _ BasicTime.nullGMT] = { file: FS.OpenFile; file _ FS.OpenFileFromStream[s ! IO.Error => GOTO Oops]; fullFName _ FS.GetName[file! FS.Error => GOTO Oops].fullFName; fullFName _ FileNames.ConvertToSlashFormat[fullFName]; created _ FS.GetInfo[file! FS.Error => GOTO Oops].created; EXITS Oops => {fullFName _ NIL; created _ BasicTime.nullGMT} }; 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] = { Translator: PROC [old: CHAR] RETURNS [new: CHAR] = { SELECT TRUE FROM old IN ['0..'9] => RETURN [old]; old IN ['a..'z] => RETURN [old]; old IN ['A..'Z] => RETURN [old]; ENDCASE => RETURN ['x]; }; name _ Rope.Translate[base: CD.DesignName[design], translator: Translator]; }; 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]; }; setManually: INT _ 0; --used for saving old designs specialForVersion4: BOOL _ FALSE; 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.composed THEN absoluteMode_TRUE ELSE absoluteMode_FALSE ELSE absoluteMode_FALSE } ELSE IF versionKey=3 THEN { IF ob.class.composed 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.composed; 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]] }; }; }; Get23Table: PROC [h: TokenIO.Handle] RETURNS [RefTab.Ref_NIL] = { rt: RefTab.Ref; WITH Properties.GetProp[h.properties^, $convert23] SELECT FROM tab: RefTab.Ref => rt _ tab; ENDCASE => { rt _ RefTab.Create[201]; h.properties^ _ Properties.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.composed 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]]]]; }; OldCD18Input: Commander.CommandProc = { specialForVersion4 _ ~specialForVersion4; IF specialForVersion4 THEN cmd.out.PutRope["Fileformat: switch to first versions of cd18\n"] ELSE cmd.out.PutRope["Fileformat: switch to last versions of cd18\n"]; }; OldAdjustInterest: PROC [h: TokenIO.Handle, ob: CD.Object] = { OldSetInterest: PROC [ob: CD.Object, r: CD.Rect] = { WITH ob.specific SELECT FROM s: CDRepetitions.RepSpecific => s.ir _ r; s: CDImports.ImportSpecific => s.ir _ r; s: CDRepetitions.RepSpecific => s.ir _ r; ENDCASE => NULL; }; IF ob.class.composed AND CDIO.VersionKey[h]<8 THEN { WITH CDProperties.GetObjectProp[from: ob, prop: oldInterestRectProperty] SELECT FROM pp: REF CD.Rect => { IF CDBasics.NonEmpty[pp^] THEN OldSetInterest[ob, pp^]; CDProperties.PutProp[ob, oldInterestRectProperty, NIL]; }; ENDCASE => NULL; }; }; OldInternalReadOrigin: PROC [h: TokenIO.Handle, prop: ATOM] RETURNS [val: REF_NIL] = { [] _ ReadPos[h]; }; OldInternalReadRProperty: PROC [h: TokenIO.Handle, prop: ATOM] RETURNS [val: REF] = { val _ NEW[CD.Rect_ReadRect[h]] }; oldOriginProperty: ATOM = $origin; oldInterestRectProperty: ATOM = $interestRect; OldInit: PROC [] = { [] _ CDProperties.RegisterProperty[oldInterestRectProperty]; CDProperties.InstallProcs[prop: oldInterestRectProperty, procs: CDProperties.PropertyProcsRec[ makeCopy: CDProperties.DontCopy, internalRead: OldInternalReadRProperty, exclusive: TRUE ] ]; [] _ CDProperties.RegisterProperty[oldOriginProperty]; CDProperties.InstallProcs[prop: oldOriginProperty, procs: CDProperties.PropertyProcsRec[ makeCopy: CDProperties.DontCopy, internalRead: OldInternalReadOrigin, exclusive: TRUE ] ]; CDEnvironment.RegisterCommander["CD18InputToggle", OldCD18Input, "Toggle input mode of old ChipNDale version CD18"]; }; readEvent: CDEvents.EventRegistration = CDEvents.RegisterEventType[$ReadTechnologyPrivate]; afterInputEvent: CDEvents.EventRegistration = CDEvents.RegisterEventType[$AfterInput]; OldInit[]; END. CDIn.mesa Copyright c 1983, 1984, 1985, 1986, 1987 by Xerox Corporation. All rights reserved. Last Edited by: Kimr, November 28, 1983 10:22 am Last Edited by: Christian Jacobi, February 8, 1984 9:41 am Last Edited by: Christian Jacobi, April 1, 1987 10:55:37 am PST --ok means NOT registered --only old version may use that ! --read in explicite properties --save the properties put on the object by the class, but only if not explicitely read --explicite PutProp is ok since props is not yet available to any forked process --put back the combined properties FixePushedNames: PROC [design: CD.Design] = { FOR pl: LIST OF CD.PushRec _ design.actual, pl.rest WHILE pl#NIL DO pl.first.desc _ IF pl.first.mightReplace=NIL THEN "top level" ELSE CD.Describe[pl.first.mightReplace.ob, pl.first.mightReplace.properties, design, 0] ENDLOOP; }; --old --The layer keys have changed from ChipNDale 2.2 to ChipNDale 2.3. --this overwrites an previous $FileVersion property read in the normal (wrong) way IF versionKey>=17 THEN { ReadDirectory[design, h]; FixePushedNames[design]; }; ReadDirectory: PROC [design: CD.Design, h: TokenIO.Handle] = { num: INT; IF TokenIO.ReadAtom[h]#$Directory THEN ERROR TokenIO.EncodingError; num _ TokenIO.ReadInt[h]; FOR i: INT IN [0..num) DO name: Rope.ROPE _ TokenIO.ReadRope[h]; ob: CD.Object _ ReadObject[h]; IF ob#NIL THEN [] _ CDDirectory.Include[design, ob, name, TRUE]; ENDLOOP; }; --Side-effect: if bad, design is set to NIL --ChipNDale check --version check --seal check -- DoInner -- begin ReadDesign -- do the actual work --================================================================ -- old stuff ??? better instead of I: CDOldInterestRects.InsideRect[ob] --for the conversion from cd2.3 to cd2.4 use bbox with interest rect excluded --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 versionKey 17: January 12, 1987 4:02:28 pm PST CD2.5. Directory is treated differently versionKey 18: April 20, 1987 9:08:40 pm PDT Atomic objects write actual rectangles Ê%Ù– "cedar" style˜code™ Kšœ ÏmœI™TK™0Kšœ:™: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šœžœžœ˜Kšœ ˜ Kšœ˜—K˜šÏnœžœž˜Kš žœžœHžœLžœžœ=˜ÿKšžœž˜ Kšžœžœ˜—Kšž˜K™Kšœžœ ˜Kšœ žœ˜K˜š Ÿœžœžœžœžœ˜:Kšžœžœžœžœ ˜:K˜K˜—Kš œ žœžœžœžœžœžœ ˜FKš œ žœžœžœžœžœžœ ˜HK˜Kšœžœ ˜K˜KšœžœžœÏc˜BK˜šŸ œžœžœžœžœžœžœ˜Ušžœžœ˜Kšœ žœžœ1˜TKšœ˜K˜—šžœ˜Kšœ žœžœ1˜TKšœ-žœ˜?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˜—šŸ œžœžœ˜/Kšžœžœžœ ˜Kšœ8˜8K˜—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šœG˜GK˜—šžœžœžœ˜Kšœžœ˜"Kšœ>˜>Kšœžœ&˜IK˜)š žœ žœžœžœžœ˜6KšœG˜GK˜—šžœ˜Kšœ˜Kšžœžœžœ˜=K˜—K˜—Kšžœ˜KšœEžœ˜LK˜K˜—šŸœžœ˜-K˜šŸœžœžœ˜šžœžœ˜"šžœž˜šœ˜Kšœžœ˜0Kšœ7˜7K˜—šœ ˜ Kšœžœ˜Kšœ?˜?K˜—šœ˜Kš œžœžœžœžœ˜šž˜Kšœ'˜'šžœžœž˜Kšœ$žœ˜<šžœ˜ Kšœ˜Kšœ.˜.Kšžœ˜K˜——Kšž˜—K˜—Kšžœžœ˜*—KšœEžœ˜LK˜—K˜—K˜Kšœ'˜'šžœžœž˜šœ˜šžœ!žœ˜)Kšœ'˜'šžœžœž˜šœ˜Kšœ;˜;—šœ˜Kšœ;˜;—šœ˜Kšœ.žœžœ˜C—Kšžœ#˜*—Kšœ˜——Kšœ4˜4šœ˜Kšžœžœžœ˜4Kšœ˜K˜—Kšžœžœ˜#—K˜—K˜šŸœžœžœ˜(Kšœ'˜'šžœžœž˜šœ˜Kšœ3˜3—šœ˜Kšœ3˜3—šœ˜Kšœ'žœžœ ˜;—šœ˜Kšœ˜Kšœ+˜+K˜—šœ˜šžœ žœžœžœ˜2Kšœžœ˜0Kšœ7˜7K˜—šžœžœžœ˜ Kšœžœ˜Kšœ?˜?K˜—Kšžœ˜KšœF˜FK˜—Kšžœ˜#—K˜—K˜šž˜Kšœ'˜'šžœžœž˜šœ˜šžœ ž˜Kšœ!˜!Kšœ'˜'Kšžœ"žœ˜1——Kšžœ"žœ˜1—Kšžœ˜—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šœ˜Kšœ˜K˜—Kšžœžœ˜@Kšžœ˜!—Kšžœ ˜'—K˜—K˜—Kšœ"˜"š žœžœžœ žœžœ˜#Kšœžœžœ*žœ˜GKšœ˜—Kšžœ žœ˜-šžœžœžœ˜(šžœžœ˜Kšœ˜Kšžœžœ "˜RK˜—K˜—šž˜Kšœ'˜'šžœžœž˜Kšœžœ˜šžœ˜ Kšœžœ ˜Kšœ˜K™Kšœ˜K™Všžœ3žœžœž˜Ešžœ)žœž˜3Kšœ>˜>KšœP™P—Kšžœ˜—K™"Kšœ˜Kšœ˜Kšžœžœ˜/K˜——Kšžœ˜—šžœžœ˜šžœžœ˜ Kšžœ,˜0Kšžœžœžœ$˜C—K˜—šžœ œ˜šžœžœ˜š Ÿ œžœžœžœžœ.˜ršžœžœ˜KšœO˜OKšžœžœžœ˜-K˜—K˜—Kšœžœ˜$šžœžœ˜šžœ&žœ žœ˜:Kšœ,˜,—Kšœ˜—K˜—K˜—Kšžœ žœ žœ˜2Kšœ˜—K˜š Ÿ œžœžœžœžœžœ˜KK˜#šžœžœž˜Kšœ;˜;šœ˜Kšœ6˜6K˜—Kšžœžœ˜*—Kšœ˜—K˜š Ÿ œžœžœžœžœ˜MKšžœžœžœ˜2šžœ˜Kšœ žœ˜#Kšœ žœ"˜1Kšœ žœ˜,Kšœžœ˜KšœžœžœP˜]K˜—Kšœ˜K˜—š Ÿœžœžœžœžœ˜EKšœ˜Kšœ˜Kšœ˜—K˜š Ÿœžœžœžœžœ ˜BKšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—K˜šŸœžœ žœ ™-š žœžœžœžœ"žœžœž™Cšœ™Kšžœžœžœ ™-KšžœžœP™W—Kšžœ™—K™—K˜šŸ œžœžœžœ ˜BKšœžœ˜Kšœ'˜'šžœžœž˜˜Kšžœžœž˜+šžœ˜Kšœ™Kšœ˜Kšœ"˜"K˜—K˜—šžœ˜ Kšœ˜Kšœ"˜"K˜——Kšœ žœ˜&Kšœžœžœ˜6Kšœžœ˜šžœžœ˜Kšœžœ˜!Kšœ˜šžœžœ˜Kšœ#˜#K˜BK˜—K˜—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šœžœžœ˜7Kš R™RKšœc˜cKšœžœ˜šž˜Kšœ'˜'šžœžœž˜šœ˜Kšžœžœžœ ˜NKšžœžœ˜)—Kšžœ"žœ˜0—Kšžœ˜—šžœžœ™Kšœ™K™K™—Kšžœ"žœžœ˜FKšœ˜—K˜šŸ œžœ žœ™>Kšœžœ™ Kšžœ žœžœ™DKšœ™šžœžœžœ ž™Kšœ žœ™&Kšœžœ™Kšžœžœžœ,žœ™@Kšžœ™—K™—K˜šŸœžœžœžœ žœžœžœ žœžœžœžœžœ˜sš Ÿœžœ žœžœ žœ˜>šžœ˜Kšžœ"˜&Kšžœ1˜5—Kšœ&˜&K˜—Kšœžœžœ˜šžœžœžœžœžœžœžœ˜.Kš žœžœžœžœžœ˜(K˜—Kšžœžœžœ˜&š žœžœžœ žœžœ˜&Kšœžœ žœ˜šžœžœ˜Kš œžœžœžœžœ'˜R—K˜—Kšžœ5žœ ˜IKšœ8˜8šžœžœ˜ Kšœ+žœ ˜;K˜—šœ žœžœžœ ˜Mšžœžœ˜KšœT˜TKšžœ ˜Kšœ˜——Kšœžœ˜Kšœ,˜,Kšžœ˜Kšœ˜—K˜š"Ÿ œžœžœžœžœ žœžœžœžœ žœžœžœžœžœžœ žœžœ˜®Kšœžœžœ˜K˜š Ÿœžœ"žœžœ žœžœ˜Xšžœ˜šœ˜Kšœ4˜4Kšžœ˜Kšœ˜—šœ žœ˜KšœC˜CKšž˜Kšœ˜—šžœ˜ Kšœ˜K˜—K˜K˜—šŸœžœ˜-Kš +™+Kšžœžœ žœ˜Kšœžœ[žœ˜qšžœžœ˜Kšœ žœ˜ Kšœ2˜2K˜—Kšœ˜—K˜šŸœžœ˜1Kš ™Kšœ žœ˜šžœ#žœ˜+Kšœ7˜7Kšžœ˜Kšœ˜—Kš ™Kšœ ˜ šžœžœ˜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šœ žœ˜K˜—šžœ˜ Kšœ<˜Kšœ6˜6Kšœ žœžœ žœ˜:Kšžœžœ˜Kšœ˜šžœ˜ Kšœ˜KšœA˜AK˜——Kšžœ˜ K˜—K˜š Ÿœžœžœžœžœ ˜KKšœ ˜ šžœž˜šžœ%žœž˜4Kšœžœžœ žœ˜Kšžœž˜——Kšœ˜K˜—šŸ œžœžœžœ!žœžœ+žœ žœ˜³J™MJšœžœ˜Jšžœžœ˜0Kšœ˜Kšœm˜mK˜—K˜šÐbn œ˜'Kš ™Kšœ)˜)šžœž˜KšœA˜A—šž˜KšœA˜A—Kšœ˜—J˜šŸœžœžœ ˜>šÏbœžœžœ žœ ˜4šžœ žœž˜Jšœ)˜)Jšœ(˜(Jšœ)˜)Jšžœžœ˜—Jšœ˜—šžœžœžœžœ˜4šžœEžœž˜Tšœžœžœ ˜Jšžœžœ˜7Jšœ2žœ˜7J˜—Jšžœžœ˜—J˜—Jšœ˜—š Ÿœžœžœžœžœ˜VJšœ˜Jšœ˜—J˜š Ÿœžœžœžœžœ˜UJšœžœžœ˜Jšœ˜—K˜Jšœžœ ˜"Jšœžœ˜.J˜šŸœžœ˜Jšœ<˜<šœ9˜9šœ%˜%Jšœ ˜ Jšœ'˜'Jšœ ž˜Jšœ˜—Jšœ˜—Jšœ6˜6šœ3˜3šœ%˜%Jšœ!˜!Jšœ$˜$Jšœ ž˜Jšœ˜—Jšœ˜—Kšœt˜tJ˜—K˜KšœB™BK˜K˜Kšœ[˜[KšœV˜VKšœ ˜ Kšžœ˜K˜š¢™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™ —šœ-™-K™&——K™—…—jòŸé