DIRECTORY GriffinFileDefs: FROM "GriffinFileDefs", GFileFormatDefs: FROM "GFileFormatDefs", GriffinDefs: FROM "GriffinDefs" USING [UserMessage], GriffinMemoryDefs: FROM "GriffinMemoryDefs", ControllerDefs: FROM "ControllerDefs", StyleDefs USING [Style, StyleHandle, Color], GriffinStyle, GriffinText USING [GetBoundingBox], GriffinColor USING [FileColor, ColorFromFileColor, FileColorFromColor], ObjectDefs USING [StartObject, ObjectHandle, Object, Link, Trajectory, ObjectType, ForAllObjects, ObjectProc, OpenCluster, GetNextClusterID, View, GetCurrentView, EncodeObject], PointDefs USING [ObjPt, ScrPt, X, Y, ObjPtSequence, ObjPtSequenceRec], PrincOpsUtils USING [LongCopy], CubicSplines USING [SplineType], IO, FS, UserCredentials USING [Get], RealConvert: FROM "RealConvert" USING [Mesa5ToIeee], BasicTime USING [Now], GriffinFontDefs USING [FontDescriptor, FontDescriptorHandle], RelationDefs: FROM "RelationDefs", Rope USING [ROPE, Length, FromProc, Fetch, Flatten, FromRefText, ToRefText]; GriffinFile: PROGRAM IMPORTS IO, FS, UserCredentials, Rope, BasicTime, GriffinMemoryDefs, ControllerDefs, ObjectDefs, GriffinDefs, RelationDefs, RealConvert, PrincOpsUtils, GriffinStyle, GriffinColor, GriffinText EXPORTS GriffinFileDefs = BEGIN OPEN GFileFormatDefs, GriffinFileDefs, GriffinMemoryDefs; GriffinFileError: PUBLIC SIGNAL = CODE; ROPE: TYPE = Rope.ROPE; diskHandle: IO.STREAM; GFileState: TYPE = {notopen, open}; gfileState: GFileState _ notopen; majorVersion: BYTE = 3; minorVersion: BYTE = 0; maxCPairCount: CARDINAL = 2000; -- just for safety realConvert: BOOLEAN _ FALSE; GetReal: PROCEDURE [r: REAL] RETURNS [out: REAL] = BEGIN IF realConvert THEN RETURN[RealConvert.Mesa5ToIeee[LOOPHOLE[r]]] ELSE RETURN[r]; END; OpenFile: PUBLIC PROCEDURE [filename: ROPE, write: BOOLEAN _ FALSE] RETURNS [BOOLEAN] = BEGIN newfile: BOOLEAN _FALSE; username: ROPE; header: GFileHeader; j: INTEGER; -- just a loop control variable IF gfileState # notopen THEN SIGNAL GriffinFileError; IF write THEN BEGIN OPEN header; len: INTEGER; diskHandle _ FS.StreamOpen[fileName: filename, accessOptions: $create, keep: 2 ! FS.Error => { IF error.group=user AND error.code=$unknownFile THEN SIGNAL GriffinDefs.UserMessage["unknown file"] ELSE IF error.group=user AND error.code=$globalCreation THEN SIGNAL GriffinDefs.UserMessage["can't write on remote file"] ELSE SIGNAL GriffinFileError} ]; Zero [@header, lGFileHeader]; majversion _ majorVersion; minversion _ minorVersion; createtime _ LOOPHOLE[BasicTime.Now[], LONG CARDINAL];--don't change the interface numfigs _ 0; nextsector _ SectorIndex [1]; Reset[diskHandle]; FOR j IN ValidFigRange DO header.figure [j] _ SectorIndex [0]; ENDLOOP; [username,] _ UserCredentials.Get[]; len _ Rope.Length[username]; creatorname [0] _ LOOPHOLE [len, CHARACTER]; FOR j IN [1 .. cNameChars] DO creatorname [j] _ IF j > len THEN 0C ELSE Rope.Fetch[username,j-1]; ENDLOOP; len _ Rope.Length[filename]; portfolioname [0] _ LOOPHOLE [len, CHARACTER]; FOR j IN [1 .. pNameChars] DO portfolioname[j] _ IF j > len THEN 0C ELSE Rope.Fetch[filename,j-1]; ENDLOOP; WriteHeaderAndFlush [@header]; END ELSE diskHandle _ FS.StreamOpen[fileName: filename, accessOptions: $read ! FS.Error => { IF error.group=user AND error.code=$unknownFile THEN SIGNAL GriffinDefs.UserMessage["unknown file"] ELSE SIGNAL GriffinFileError}]; gfileState _ open; RETURN [TRUE]; END; CloseFile: PUBLIC PROCEDURE = BEGIN fileheader: GFileHeader; IF gfileState = notopen THEN RETURN; ReadHeader [@fileheader]; MoveToSector [fileheader.nextsector]; IO.Close [diskHandle]; gfileState _ notopen; END; ReadFigure: PUBLIC PROCEDURE = BEGIN OPEN RelationDefs; fileheader: GFileHeader; hcontrol: GFileHardcopyController; dcontrol: GFileDisplayController; controlpair: GFileControlPair; font: GFileFont; figurename: GFileFigureName; stylecount, fontcount, objectcount, i, slen, f, s: CARDINAL; color: StyleDefs.Color; fd: GriffinFontDefs.FontDescriptorHandle _ CZone.NEW[GriffinFontDefs.FontDescriptor]; clusterMap: Relation; newStyles, oldStyles: GriffinStyle.StyleSequence; fontList: GriffinStyle.FontSequence; fignum: CARDINAL=1; --original plan involved multiple figures in a portfolio. Never used more than 1 IF gfileState # open THEN SIGNAL GriffinFileError; ReadHeader [@fileheader]; IF fignum > fileheader.numfigs OR fignum = 0 THEN SIGNAL GriffinFileError; MoveToSector [fileheader.figure [fignum]]; -- go to the right sector ReadStructure [@figurename, lGFileFigureName]; ReadStructure [@hcontrol, lGFileHardcopyController]; ReadStructure [@dcontrol, lGFileDisplayController]; BEGIN OPEN hcontrol; ControllerDefs.SetHardcopyController [[hxcenter: GetReal[centerx], hycenter: GetReal[centery], hwidth: GetReal[width], hheight: GetReal[height], pressxcenter: presscenterx, pressycenter: presscentery, hscale: GetReal[scale]]]; END; BEGIN OPEN dcontrol; ControllerDefs.SetDisplayController [[dxcenter: centerx, dycenter: centery, dwidth: width, dheight: height, dxscale: GetReal[xscale], dyscale: GetReal[yscale], dxorigin: GetReal[gridxo], dyorigin: GetReal[gridyo], dgridsize: gridsize]]; END; IF dcontrol.numcontrolpairs > maxCPairCount THEN SIGNAL GriffinFileError; THROUGH [1 .. dcontrol.numcontrolpairs] DO OPEN controlpair; ReadStructure [@controlpair, lGFileControlPair]; color _ [H: hue, V: brightness, S: saturation]; ENDLOOP; fontcount _ ReadWord []; fontList _ CZone.NEW[GriffinStyle.FontSequenceRec[fontcount]]; FOR f IN [0 .. fontcount) DO fromProc: SAFE PROC RETURNS [CHAR] = CHECKED {i _ i+1; RETURN[ font.char [i]]}; ReadStructure [@font, lGFileFont]; slen _ LOOPHOLE [font.char [0], BYTE]; -- just a temp i _ 0; fd.name _ Rope.FromProc[slen,fromProc]; fd.rotation _ font.rotation; fd.face _ font.face; fd.points _ font.points; fontList[f] _ GriffinStyle.FontFromInternalFont[fd]; ENDLOOP; stylecount _ ReadWord []; oldStyles _ GriffinStyle.CreateStyleList[]; newStyles _ CZone.NEW[GriffinStyle.StyleSequenceRec[stylecount]]; FOR s IN [0 .. stylecount) DO newStyles[s] _ ReadStyle [fontList, oldStyles]; --returns a style, reusing duplicates ENDLOOP; objectcount _ ReadWord []; clusterMap _ CreateRelation[]; THROUGH [1 .. objectcount] DO ReadObject [newStyles, clusterMap]; ENDLOOP; DestroyRelation[clusterMap]; END; WriteFigure: PUBLIC PROCEDURE = BEGIN figbegin: SectorIndex; i, figlength: CARDINAL; header: GFileHeader; fignum: CARDINAL=1; --was a plan involving multiple figures, now canceled IF gfileState # open THEN SIGNAL GriffinFileError; ReadHeader [@header]; IF fignum > header.numfigs + 1 THEN SIGNAL GriffinDefs.UserMessage["Invalid file."]; figbegin _ header.figure [fignum]; IF figbegin = 0 THEN figbegin _ header.figure [fignum] _ SectorIndex [1]; MoveToSector [header.nextsector]; figlength _ WriteFigureContents [] - header.nextsector; FOR i DECREASING IN [fignum .. header.numfigs] DO header.figure [i+1] _ SectorIndex [header.figure [i] +figlength]; ENDLOOP; MoveSectors [figbegin, figlength, header.nextsector]; header.nextsector _ SectorIndex [header.nextsector + figlength]; IF header.numfigs >= fignum THEN BEGIN -- wasn't last fig, write it again MoveToSector [figbegin]; [] _ WriteFigureContents []; END; header.numfigs _ header.numfigs + 1; WriteHeaderAndFlush [@header]; END; ReadHeader: PROCEDURE [h: LONG POINTER TO GFileHeader] = BEGIN version,currentVersion: CARDINAL; Reset[diskHandle]; ReadStructure [h, lGFileHeader]; realConvert _ FALSE; version _ h.majversion*10+h.minversion; currentVersion _ majorVersion*10+minorVersion; IF version < 14 THEN realConvert _ TRUE; IF version NOT IN [10..currentVersion] THEN { IO.Close[diskHandle]; gfileState _ notopen; GriffinDefs.UserMessage["Incorrect file format."]; }; END; WriteHeaderAndFlush: PROCEDURE [h: LONG POINTER TO GFileHeader] = BEGIN Reset[diskHandle]; WriteStructure [h, lGFileHeader]; IO.Flush [diskHandle]; END; WriteFigureContents: PROCEDURE RETURNS [nextfree: SectorIndex] = BEGIN hcontroller: GFileHardcopyController; dcontroller: GFileDisplayController; figname: GFileFigureName; hc: ControllerDefs.HardcopyController; -- temp dc: ControllerDefs.DisplayController; -- temp count: CARDINAL; fonts: GriffinStyle.FontSequence; styles: GriffinStyle.StyleSequence; doWrite: ObjectDefs.ObjectProc = TRUSTED {WriteObject[obj, styles]}; CountObject: ObjectDefs.ObjectProc = TRUSTED BEGIN SELECT obj.objectType FROM shape,caption => count _ count+1; ENDCASE; END; CountPair: SAFE PROC [h, s, v: [0 .. 255], grey: [0 .. 255]] = TRUSTED { count _ count+1 }; Zero [@figname, lGFileFigureName]; WriteStructure [@figname, lGFileFigureName]; Zero [@hcontroller, lGFileHardcopyController]; BEGIN OPEN ControllerDefs, hcontroller; [hxcenter: centerx, hycenter: centery, hwidth: width, hheight: height, pressxcenter: presscenterx, pressycenter: presscentery, hscale: scale] _ hc _ ReadHardcopyController []; END; Zero [@dcontroller, lGFileDisplayController]; BEGIN OPEN ControllerDefs, dcontroller; [dxcenter: centerx, dycenter: centery, dwidth: width, dheight: height, dxscale: xscale, dyscale: yscale, dxorigin: gridxo, dyorigin: gridyo, dgridsize: gridsize] _ dc _ ReadDisplayController []; END; WriteStructure [@hcontroller, lGFileHardcopyController]; count _ 0; ControllerDefs.ForAllControlPairs [CountPair]; dcontroller.numcontrolpairs _ count; WriteStructure [@dcontroller, lGFileDisplayController]; ControllerDefs.ForAllControlPairs [WriteControlPair]; styles _ GriffinStyle.CreateStyleList[]; IF styles#NIL THEN { --empty file if styles=NIL fonts _ GriffinStyle.CreateFontList[styles]; WriteWord[fonts.length]; FOR i: NAT IN [0..fonts.length) DO WriteFont[GriffinStyle.InternalFontFromFont[fonts[i]]]; ENDLOOP; WriteWord[styles.length]; FOR i: NAT IN [0..styles.length) DO WriteStyle[styles[i], fonts]; ENDLOOP; count _ 0; ObjectDefs.ForAllObjects [CountObject]; WriteWord [count]; ObjectDefs.ForAllObjects [doWrite]; }; nextfree _ ZeroRestOfSector [] END; WriteControlPair: SAFE PROCEDURE [h, s, v: [0 .. 255], grey: CARDINAL [0 .. 255]] = TRUSTED BEGIN cp: GFileControlPair; Zero [@cp, lGFileControlPair]; cp.hue _ h; cp.saturation _ s; cp.brightness _ v; cp.greytouse _ grey; WriteStructure [@cp, lGFileControlPair]; END; WriteFont: PROCEDURE [fd: GriffinFontDefs.FontDescriptorHandle] = BEGIN j,len: INTEGER; font: GFileFont; Zero [@font, lGFileFont]; font.points _ fd.points; font.face _ fd.face; font.rotation _ fd.rotation; len _ Rope.Length[fd.name]; font.char [0] _ LOOPHOLE [len, CHARACTER]; FOR j IN [1.. fontChars] DO font.char[j] _ IF j<=len THEN Rope.Fetch[fd.name,j-1] ELSE 0C; ENDLOOP; WriteStructure [@font, lGFileFont]; END; WriteStyle: PROCEDURE [style: StyleDefs.StyleHandle, fonts: GriffinStyle.FontSequence] = BEGIN OPEN StyleDefs, style; fstyle: GFileStyle; fcolor: GriffinColor.FileColor; j,len: INTEGER; Zero [@fstyle, lGFileStyle]; fcolor _ GriffinColor.FileColorFromColor[style.color]; fstyle.hue _ fcolor.hue; fstyle.saturation _ fcolor.saturation; fstyle.brightness _ fcolor.brightness; fstyle.dashedness _ SELECT dashed FROM undashed => typeUnDashed, dash1 => typeDash1, dash2 => typeDash2, dash3 => typeDash3, dash4 => typeDash4, dash5 => typeDash5, ENDCASE => typeUnDashed; fstyle.send _ SELECT firstend.type FROM round => typeRoundEnd, cyclic => typeCyclicEnd, flat => typeFlatEnd, angled => typeAngledEnd, ENDCASE => typeRoundEnd; fstyle.eend _ SELECT lastend.type FROM round => typeRoundEnd, cyclic => typeCyclicEnd, flat => typeFlatEnd, angled => typeAngledEnd, ENDCASE => typeRoundEnd; fstyle.bdx _ firstend.dx; fstyle.bdy _ firstend.dy; fstyle.ba _ firstend.a; fstyle.bb _ firstend.b; fstyle.bc _ firstend.c; fstyle.edx _ lastend.dx; fstyle.edy _ lastend.dy; fstyle.ea _ lastend.a; fstyle.eb _ lastend.b; fstyle.ec _ lastend.c; fstyle.thickness _ width; fstyle.junction _ SELECT junctiontype FROM round => typeRoundJunction, square => typeSquareJunction, angled => typeAngledJunction, ENDCASE => typeRoundJunction; fcolor _ GriffinColor.FileColorFromColor[style.fillcolor]; fstyle.ahue _ fcolor.hue; fstyle.asaturation _ fcolor.saturation; fstyle.abrightness _ fcolor.brightness; fstyle.afilled _ filled; fstyle.aoutlined _ outlined; fstyle.fontid _ GriffinStyle.NumberOfFont[style.font, fonts]; fcolor _ GriffinColor.FileColorFromColor[style.backgndcolor]; fstyle.bhue _ fcolor.hue; fstyle.bsaturation _ fcolor.saturation; fstyle.bbrightness _ fcolor.brightness; fstyle.background _ fillbackgnd; fstyle.anchor _ SELECT anchor FROM left => typeLeftAnchor, center => typeCenterAnchor, right => typeRightAnchor, ENDCASE => typeLeftAnchor; fstyle.torient _ SELECT stringRotation FROM or0 => typeRot0, or90 => typeRot90, or180 => typeRot180, or270 => typeRot270, ENDCASE => typeRot0; len _ Rope.Length[name]; fstyle.stylename [0] _ LOOPHOLE [len, CHARACTER]; FOR j IN [1 .. sNameChars] DO fstyle.stylename [j] _ IF j > len THEN 0C ELSE Rope.Fetch[name, j-1]; ENDLOOP; WriteStructure [@fstyle, lGFileStyle]; END; WriteObject: PROCEDURE [obj: ObjectDefs.ObjectHandle, styles: GriffinStyle.StyleSequence] = BEGIN OPEN ObjectDefs; fobject: GFileObject; fcaptiontrailer: GFileCaptionTrailer; flinks: REF Link; fakelink: REF Link _ CZone.NEW[Link _ [link: NIL, degree: D3, knots: NIL]]; flinkcount: CARDINAL; SELECT obj.objectType FROM shape,caption => NULL; --do these ENDCASE => RETURN; --ignore the rest Zero [@fobject, lGFileObject]; Zero [@fcaptiontrailer, lGFileCaptionTrailer]; fobject.hidewindow _ obj.view # ObjectDefs.GetCurrentView[]; fobject.visible _ SELECT obj.cull FROM inside => typeWhollyVisible, outside => typeNotVisible, partial => typePartiallyVisible, ENDCASE => typePartiallyVisible; fobject.style _ GriffinStyle.NumberOfStyle [obj.style, styles]; fobject.cluster _ obj.cluster; fobject.bleft _ obj.tl [PointDefs.X]; fobject.bbottom _ obj.br [PointDefs.Y]; fobject.bright _ obj.br [PointDefs.X]; fobject.btop _ obj.tl [PointDefs.Y]; WITH object: obj SELECT FROM shape => BEGIN OPEN CubicSplines; fobject.objtype _ IF object.closed THEN typeAreaObject ELSE typeCurveObject; fobject.splinetype _ SELECT object.trajectory.splineType FROM SplineType [naturalUM] => typeNUMSpline, SplineType [cyclicUM] => typeCUMSpline, SplineType [naturalAL] => typeNALSpline, SplineType [cyclicAL] => typeCALSpline, SplineType [bezier] => typeBEZSpline, SplineType [bsplineInterp] => typeBSISpline, SplineType [bspline] => typeBSpline, SplineType [crspline] => typeCRSpline, ENDCASE => typeCRSpline; WITH traj: object.trajectory SELECT FROM linked => BEGIN fobject.trajtype _ typeLinkedTraj; flinkcount _ CountLinks [traj.links]; flinks _ traj.links; END; cyclic => BEGIN fobject.trajtype _ typeCSTraj; flinkcount _ 1; flinks _ fakelink; fakelink.knots _ traj.knots; END; ENDCASE => SIGNAL GriffinFileError; WriteStructure [@fobject, lGFileObject]; WriteWord [flinkcount]; UNTIL flinks = NIL DO WriteLink [flinks]; flinks _ flinks.link; ENDLOOP; END; caption => BEGIN fobject.objtype _ typeCaptionObject; WriteStructure [@fobject, lGFileObject]; fcaptiontrailer.xanchor _ object.p0 [PointDefs.X]; fcaptiontrailer.yanchor _ object.p0 [PointDefs.Y]; WriteStructure [@fcaptiontrailer, lGFileCaptionTrailer]; WriteString [object.text]; END; ENDCASE => ERROR; END; CountLinks: PROCEDURE [links: REF ObjectDefs.Link] RETURNS [count: CARDINAL] = BEGIN count _ 0; UNTIL links = NIL DO links _ links.link; count _ count + 1; ENDLOOP; RETURN; END; WriteLink: PROCEDURE [link: REF ObjectDefs.Link] = BEGIN knotword: GFileKnotWord; fpoint: GFilePoint; freal: GFileReal; j: CARDINAL; Zero [@knotword, lGFileKnotWord]; Zero [@fpoint, lGFilePoint]; Zero [@freal, lGFileReal]; knotword.knotcount _ link.knots.length; knotword.knottype _ SELECT link.degree FROM D0 => typeFD0Knot, D1 => typeFD1Knot, D2 => typeFD2Knot, D3 => typeFD3Knot, ENDCASE => typeFD3Knot; WriteStructure [@knotword, lGFileKnotWord]; FOR j IN [0 .. knotword.knotcount) DO fpoint.x _ link.knots [j] [PointDefs.X]; fpoint.y _ link.knots [j] [PointDefs.Y]; WriteStructure [@fpoint, lGFilePoint]; ENDLOOP; END; ReadStyle: PROCEDURE [fonts: GriffinStyle.FontSequence, styles: GriffinStyle.StyleSequence] RETURNS [StyleDefs.StyleHandle] = BEGIN OPEN StyleDefs; thisstyle: StyleHandle _ CZone.NEW[Style]; fstyle: GFileStyle; ReadStructure [@fstyle, lGFileStyle]; BEGIN OPEN thisstyle; color _ GriffinColor.ColorFromFileColor[[fstyle.hue, fstyle.saturation, fstyle.brightness]]; dashed _ SELECT fstyle.dashedness FROM typeUnDashed => undashed, ENDCASE => undashed; firstend.type _ SELECT fstyle.send FROM typeRoundEnd => round, typeCyclicEnd => cyclic, typeFlatEnd => flat, typeAngledEnd => angled, ENDCASE => round; -- should be an error lastend.type _ SELECT fstyle.eend FROM typeRoundEnd => round, typeCyclicEnd => cyclic, typeFlatEnd => flat, typeAngledEnd => angled, ENDCASE => round; -- should be an error firstend.dx _ GetReal[fstyle.bdx]; firstend.dy _ GetReal[fstyle.bdy]; firstend.a _ GetReal[fstyle.ba]; firstend.b _ GetReal[fstyle.bb]; firstend.c _ GetReal[fstyle.bc]; lastend.dx _ GetReal[fstyle.edx]; lastend.dy _ GetReal[fstyle.edy]; lastend.a _ GetReal[fstyle.ea]; lastend.b _ GetReal[fstyle.eb]; lastend.c _ GetReal[fstyle.ec]; width _ GetReal[fstyle.thickness]; junctiontype _ SELECT fstyle.junction FROM typeRoundJunction => round, typeSquareJunction => square, typeAngledJunction => angled, ENDCASE => round; fillcolor _ GriffinColor.ColorFromFileColor[[fstyle.ahue, fstyle.asaturation, fstyle.abrightness]]; filled _ fstyle.afilled; outlined _ fstyle.aoutlined; font _ fonts[fstyle.fontid-1]; --the first font is font number 1 backgndcolor _ GriffinColor.ColorFromFileColor[[fstyle.bhue, fstyle.bsaturation, fstyle.bbrightness]]; fillbackgnd _ fstyle.background; anchor _ SELECT fstyle.anchor FROM typeLeftAnchor => left, typeCenterAnchor => center, typeRightAnchor => right, ENDCASE => left; -- should be an error stringRotation _ SELECT fstyle.torient FROM typeRot0 => or0, typeRot90 => or90, typeRot180 => or180, typeRot270 => or270, ENDCASE => or0; -- should be an error stringType _ GriffinStyle.ComputeStringType[stringRotation, font]; END; { --an attempt here to avoid the proliferation of identical styles test: StyleHandle _ GriffinStyle.FindEquivalentStyle[thisstyle, styles]; IF test#NIL THEN thisstyle _ test ELSE thisstyle.name _ GriffinStyle.NextName[]; --change the name to reflect current scope }; RETURN[thisstyle]; END; ReadObject: PROCEDURE[styles: GriffinStyle.StyleSequence, clusterMap: RelationDefs.Relation] = BEGIN OPEN ObjectDefs; newobject: ObjectHandle; fileobject: GFileObject; fcaptiontrailer: GFileCaptionTrailer; tl, br: PointDefs.ScrPt; splinetype: CubicSplines.SplineType; nlinks: CARDINAL; ptr: REF Link; xptr: REF Link; currentView: ObjectDefs.View _ ObjectDefs.GetCurrentView[]; otherView: ObjectDefs.View _ IF currentView=main THEN alternate ELSE main; ReadStructure [@fileobject, lGFileObject]; SELECT fileobject.objtype FROM typeAreaObject, typeCurveObject => newobject_ StartObject[shape]; typeCaptionObject => newobject_ StartObject[caption]; typeTokenObject => newobject_ StartObject[token]; ENDCASE => SIGNAL GriffinFileError; newobject.style _ styles[fileobject.style-1]; --the first style is number 1 IF fileobject.cluster <= ObjectDefs.OpenCluster THEN newobject.cluster _ fileobject.cluster ELSE BEGIN cluster: CARDINAL _ RelationDefs.Right[clusterMap, fileobject.cluster]; IF cluster = RelationDefs.notFound THEN BEGIN cluster _ ObjectDefs.GetNextClusterID[]; RelationDefs.AddPair[clusterMap, fileobject.cluster, cluster]; END; newobject.cluster _ cluster; END; newobject.view _ IF fileobject.hidewindow THEN otherView ELSE currentView; newobject.cull _ SELECT fileobject.visible FROM typeNotVisible => outside, typePartiallyVisible => partial, typeWhollyVisible => inside, ENDCASE => partial; tl [PointDefs.X] _ fileobject.bleft; tl [PointDefs.Y] _ fileobject.btop; br [PointDefs.X] _ fileobject.bright; br [PointDefs.Y] _ fileobject.bbottom; newobject.tl _ tl; newobject.br _ br; WITH newobject SELECT FROM object: REF shape ObjectDefs.Object => BEGIN OPEN CubicSplines; object.closed _ fileobject.objtype = typeAreaObject; splinetype _ SELECT fileobject.splinetype FROM typeNUMSpline => SplineType [naturalUM], typeCUMSpline => SplineType [cyclicUM], typeNALSpline => SplineType [naturalAL], typeCALSpline => SplineType [cyclicAL], typeBEZSpline => SplineType [bezier], typeBSISpline => SplineType [bsplineInterp], typeBSpline => SplineType [bspline], typeCRSpline => SplineType [crspline], ENDCASE => SplineType [bspline]; SELECT fileobject.trajtype FROM typeLinkedTraj => BEGIN nlinks _ ReadWord []; IF nlinks =0 THEN object.trajectory _ CZone.NEW[Trajectory _ [splinetype, linked [NIL]]] ELSE BEGIN ptr _ NewLink []; object.trajectory _ CZone.NEW[Trajectory _ [splinetype, linked [ptr]]]; THROUGH (1..nlinks] DO ptr_ptr.link_NewLink[] ENDLOOP; END; END; typeCSTraj => BEGIN IF ReadWord [] # 1 THEN SIGNAL GriffinFileError; xptr _ NewLink []; object.trajectory _ CZone.NEW[Trajectory _ [splinetype, cyclic [xptr.knots]]]; END; ENDCASE => SIGNAL GriffinFileError; ObjectDefs.EncodeObject[object]; END; object: REF caption ObjectDefs.Object => BEGIN ReadStructure [@fcaptiontrailer, lGFileCaptionTrailer]; object.p0 [PointDefs.X] _ GetReal[fcaptiontrailer.xanchor]; object.p0 [PointDefs.Y] _ GetReal[fcaptiontrailer.yanchor]; object.text _ ReadString []; [object.tl, object.br] _ GriffinText.GetBoundingBox[object.text, object.style, object.p0]; END; ENDCASE; newobject.validEncoding _ TRUE; END; NewLink: PROCEDURE RETURNS [lin: REF ObjectDefs.Link] = BEGIN OPEN ObjectDefs; knotword: GFileKnotWord; knots: PointDefs.ObjPtSequence; num, j: CARDINAL; fpoint: GFilePoint; lin _ CZone.NEW [Link]; ReadStructure [@knotword, lGFileKnotWord]; num _ knotword.knotcount; SELECT knotword.knottype FROM typeFD0Knot, typeFD1Knot, typeFD2Knot, typeFD3Knot => BEGIN knots _ CZone.NEW[PointDefs.ObjPtSequenceRec[num]]; lin^ _ Link [NIL, (SELECT knotword.knottype FROM typeFD0Knot => D0, typeFD1Knot => D1, typeFD2Knot => D2, typeFD3Knot => D3, ENDCASE => D1), knots]; FOR j IN [0 .. num) DO ReadStructure [@fpoint, lGFilePoint]; knots [j] _ PointDefs.ObjPt[GetReal[fpoint.x], GetReal[fpoint.y]]; ENDLOOP; END; ENDCASE => SIGNAL GriffinFileError; END; WriteWord: PROCEDURE [word: CARDINAL] = BEGIN bytes: TWOBYTES _ LOOPHOLE[word]; IO.PutChar[diskHandle,bytes.high]; IO.PutChar[diskHandle,bytes.low]; END; ReadWord: PROCEDURE RETURNS [CARDINAL] = BEGIN word: TWOBYTES; word.high _ IO.GetChar[diskHandle]; word.low _ IO.GetChar[diskHandle]; RETURN[LOOPHOLE[word]]; END; TWOBYTES: TYPE = MACHINE DEPENDENT RECORD [high: CHARACTER, low: CHARACTER]; WriteString: PROCEDURE [s: ROPE] = BEGIN len: CARDINAL _ Rope.Length[s]; IO.PutChar[diskHandle,LOOPHOLE [len, CHARACTER]]; IO.PutBlock[diskHandle,Rope.ToRefText[Rope.Flatten[s]]]; IF (len+1) MOD 2 # 0 THEN IO.PutChar[diskHandle,0C]; END; stringHack: BOOLEAN _ FALSE; --for the old bug in WriteString ReadString: PROCEDURE RETURNS [s: ROPE] = BEGIN t: REF TEXT; length: CARDINAL; length _ LOOPHOLE[IO.GetChar[diskHandle], CARDINAL]; t _ NEW[TEXT[length]]; IF IO.GetBlock[diskHandle,t,0,length] # length THEN SIGNAL GriffinFileError; s _ Rope.FromRefText[t]; IF (length+1) MOD 2 # 0 THEN IF ~stringHack THEN [] _ IO.GetChar[diskHandle]; END; ZeroRestOfSector: PROCEDURE RETURNS [SectorIndex] = BEGIN UNTIL IO.GetIndex [diskHandle] MOD 512 = 0 DO WriteWord [0] ENDLOOP; RETURN [SectorIndex [IO.GetIndex [diskHandle]/512]]; END; MoveToSector: PROCEDURE [si: SectorIndex] = BEGIN IO.SetIndex [diskHandle, LONG[si.sector]*512]; END; Reset: PROCEDURE [d: IO.STREAM] = BEGIN IO.SetIndex [d, 0]; END; ReadStructure: PROCEDURE [p: LONG POINTER, l: CARDINAL] = BEGIN block: IO.UnsafeBlock _ [base: LOOPHOLE[p], startIndex: 0, count: l*2]; IF IO.UnsafeGetBlock [diskHandle, block] # l*2 THEN SIGNAL GriffinFileError; END; WriteStructure: PROCEDURE [p: LONG POINTER, l: CARDINAL] = BEGIN block: IO.UnsafeBlock _ [base: LOOPHOLE[p], startIndex: 0, count: l*2]; IO.UnsafePutBlock [diskHandle, block]; END; MoveSectors: PROCEDURE [source: SectorIndex, dist: INTEGER, oldfileend: SectorIndex] = BEGIN j: CARDINAL; sector: GFileSector; p: LONG POINTER TO GFileSector = @sector; block: IO.UnsafeBlock _ [base: LOOPHOLE[p], startIndex: 0, count: 512]; IF dist < 0 THEN FOR j DECREASING IN [source .. oldfileend) DO MoveToSector [SectorIndex [j]]; IF IO.UnsafeGetBlock[diskHandle, block] # 512 THEN SIGNAL GriffinFileError; MoveToSector [SectorIndex [j+dist]]; IO.UnsafePutBlock[diskHandle, block]; ENDLOOP ELSE FOR j IN [source .. oldfileend) DO MoveToSector [SectorIndex [j]]; IF IO.UnsafeGetBlock[diskHandle, block] # 512 THEN SIGNAL GriffinFileError; MoveToSector [SectorIndex [j+dist]]; IO.UnsafePutBlock[diskHandle, block]; ENDLOOP; END; Zero: PROC [block: LONG POINTER, length: CARDINAL] = { block^ _ 0; PrincOpsUtils.LongCopy[from: block, to: block+1, nwords: length-1]; }; END. „GriffinFile Stone April 30, 1981 1:51 PM Stone Changed minor version September 30, 1980 1:40 PM Tiberi January 20, 1980 7:38 PM implementing module for griffin file creation NOTE: Strange patch in ReplaceFigure to "cleanup" files with multiple figures Last Edited by: Stone, March 20, 1984 10:52:10 am PST Last Edited by: Pier, February 14, 1984 10:18:47 am PST --------------------------------------------------------------------------------- version 2.0 is Cedar version 2.1 is after string fix version 2.2 is Cedar 5 ? version 3.0 is cedar 6.0 -------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- DeletePortfolio: PUBLIC PROCEDURE = BEGIN IF gfileState = notopen THEN RETURN; this procedure should really delete the file, not just truncate it gfileState _ notopen; IO.Close[diskHandle]; END; --------------------------------------------------------------------------------- allocate global string for figure name name.length _ LOOPHOLE [figurename [0], BYTE]; FOR i IN [1 .. name.length] DO name [i] _ figurename.char [i] ENDLOOP; colorpairs are not used but must be read out of the file. --------------------------------------------------------------------------------- ReplaceFigure: PUBLIC PROCEDURE [fignum: FigureNumber] RETURNS [BOOLEAN] = BEGIN Stone April 16, 1980 9:38 PM figbegin, oldfigend: SectorIndex; j: CARDINAL; sectorsadded: INTEGER; header: GFileHeader; IF gfileState # open THEN SIGNAL GriffinFileError; ReadHeader [@header]; IF header.numfigs = 0 THEN RETURN[AddFigure[fignum]]; IF fignum = 0 OR fignum > header.numfigs THEN SIGNAL GriffinFileError; this is a cleanup proc for the bug that was adding figures instead of replacing them it assumes there is no correct way to have multiple figures in a portfolio IF header.numfigs > 1 THEN BEGIN fig: FigureNumber _ header.numfigs; UNTIL fig = 1 DO DeleteFigure[fig]; fig _ fig-1; ENDLOOP; ReadHeader [@header]; END; header.minversion _ minorVersion; header.createtime _ LOOPHOLE[BasicTime.Now[], LONG CARDINAL];--don't change the interface figbegin _ header.figure [fignum]; -- where figure begins oldfigend _ header.figure [fignum+1]; --where figure ends, or 0 IF oldfigend = 0 THEN BEGIN -- last fig in file, no problem MoveToSector [figbegin]; header.nextsector _ WriteFigureContents []; END ELSE BEGIN MoveToSector [header.nextsector]; sectorsadded _ WriteFigureContents [] - header.nextsector - (oldfigend - figbegin); MoveSectors [oldfigend, sectorsadded, header.nextsector]; MoveToSector [figbegin]; [] _ WriteFigureContents []; header.nextsector _ SectorIndex [header.nextsector + sectorsadded]; FOR j IN (fignum .. header.numfigs] DO header.figure [j] _ SectorIndex [header.figure [j] + sectorsadded]; ENDLOOP; END; WriteHeaderAndFlush [@header]; RETURN [TRUE]; END; --------------------------------------------------------------------------------- DeleteFigure: PUBLIC PROCEDURE [fignum: FigureNumber] = BEGIN figbegin, nextfigbegin: SectorIndex; sectordelta: INTEGER; i: CARDINAL; header: GFileHeader; IF gfileState # open THEN SIGNAL GriffinFileError; ReadHeader [@header]; figbegin _ header.figure [fignum]; nextfigbegin _ header.figure [fignum+1]; IF fignum = 0 OR fignum > header.numfigs THEN SIGNAL GriffinFileError; IF nextfigbegin = 0 THEN header.nextsector _ figbegin ELSE BEGIN -- wasn't last fig in file sectordelta _ figbegin - header.figure [fignum+1]; MoveSectors [nextfigbegin, sectordelta, header.nextsector]; header.nextsector _ SectorIndex [header.nextsector + sectordelta]; FOR i IN [fignum .. header.numfigs) DO header.figure [i] _ SectorIndex [header.figure [i+1] + sectordelta]; ENDLOOP; header.figure [header.numfigs] _ SectorIndex [0]; END; header.numfigs _ header.numfigs - 1; WriteHeaderAndFlush [@header]; END; --------------------------------------------------------------------------------- Stone April 16, 1980 9:38 PM --------------------------------------------------------------------------------- version 1.4 is the first with the Ieee floating point format. we need to set up to convert the reals for older versions --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- This information is never really used --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- namelength _ LOOPHOLE [fstyle.stylename [0], BYTE]; BEGIN fromProc: PROC RETURNS [CHAR] = CHECKED {j _ j+1; RETURN[fstyle.stylename[j]]}; j _ 0; name _ Rope.FromProc[namelength,fromProc]; END; --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- private low-level disk access procedures --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- always read an even number of bytes: string length + string chars MOD 2 = 0 --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- ----------------------------------------------------------------- Κž˜J˜Jšœ ™ Jšœ™Jšœ7™7Jšœ ™ Jšœ-™-JšœN™NJšœ5™5Jšœ7™7J˜šΟk ˜ Jšœœ˜(Jšœœ˜(Jšœ œœ˜4Jšœœ˜,Jšœœ˜&Jšœ œ˜,Icodešœ ˜ Kšœ œ˜#Kšœ œ5˜Gšœ œ6˜FJ˜3J˜6—Jšœ œœœ#˜FJšœœ ˜Jšœ œ˜ Jšœ˜Jšœ˜Jšœœ˜Jšœ œœ˜4Jšœ œ˜Jšœœ(˜=Jšœœ˜"Jšœœœ<˜LJ˜J˜—š œœœœœ$˜HJšœ˜šœ˜J˜——Jšœœ5˜?J˜JšœQ™QJ˜J˜Jšœœœœ˜)Jšœœœ˜J˜Jšœ œœ˜Jšœ œ˜#J˜!Jšœœ˜Jšœœ˜Jšœœ Οc˜2Jšœ œœ˜Jšœ™Jšœ™J™J™J˜JšœJ™JJ˜Jš Οnœ œœœœ˜2Jš˜Jšœ œœœ˜@Jšœœ˜Jšœ˜J˜šŸœœ œ œ œœœœ˜XJš˜Jšœ œœ˜Jšœ œ˜J˜Jšœœž˜+Jšœœœ˜5šœ œœ˜ Jšœœ˜ šœ œM˜\šœ˜šœœ˜/Jšœœ(˜3—šœœ˜7Jšœœ6˜A—Jšœœ˜—Jšœ˜—J˜J˜J˜Jšœ œœœž˜RJ˜ J˜J˜Jšœœœ&œ˜GJ˜$J˜Jšœœ œ˜,šœœ˜Jšœœ œœ˜CJšœ˜—J˜Jšœœ œ˜.šœœ˜Jšœœ œœ˜DJšœ˜—J˜Jš˜—šœœ7œ ˜Všœ˜šœœ˜/Jšœœ(˜3—Jšœœ˜——J˜Jšœœ˜Jšœ˜J˜J˜J˜—JšœQ™QJ˜J˜šŸ œœ œ˜Jš˜J˜Jšœœœ˜$J˜J˜%Jšœ˜J˜Jšœ˜J˜J˜—JšœQ™QJ˜šŸœœ œ™)Jšœœœ™$JšœB™BJ™Jšœ™Jšœ™J™J™J™—JšœQ™QJ˜J˜šŸ œœ œ˜Jšœœ˜J˜J˜"J˜!J˜J˜J˜Jšœ3œ˜šœœ˜Jš œ  œœœœ œ˜PJ˜"Jšœœœž˜5J˜J˜'J˜J˜J˜Jšœ4˜4Jšœ˜—J˜Jšœ+˜+Jšœœ,˜Ašœœ˜Jšœ0ž%˜UJšœ˜—J˜J˜šœ˜Jšœ%œ˜/—J˜Jšœ˜J˜J˜—JšœQ™QJ˜J˜Jš Ÿ œœ œœœ™Pšœ™J™!Jšœœ™ Jšœœ™J™Jšœœœ™2J™Jšœœœ™5Jšœ œœœ™FJ™—JšœT™TšœJ™Jšœœ™ J™#šœ ™J™J™ Jšœ™—J™Jšœ™J™—J™!Jšœœœœž™YJšœ#ž™9Jšœ&ž™?šœœœž™;J™J™+Jš™—šœ™ J™!™;J™—J™9J™J™J™Cšœœ™&J™4J™Jšœ™—Jšœ™—J™Jšœœ™Jšœ™J˜J˜J˜—JšœQ™QJ˜šŸ œœ œ™=J™$Jšœ œ™Jšœœ™ J™Jšœœœ™2J™J™"J™(Jšœ œœœ™Fšœœ™:Jšœž™ J™2J™;J™Bšœœœ™:J™0Jšœ™—J™1Jšœ™—J™$J™Jšœ™J™J™J™—JšœQ™QJ˜J˜JšŸ œœ œ˜'šœ™J˜Jšœœ˜J˜Jšœœž5˜JJšœœœ˜2J˜Jšœœœ*˜TJ˜"Jšœœ5˜IJ˜!J˜7šœ œœ˜1J˜AJšœ˜—J˜5J˜@šœœœž"˜IJ˜J˜Jšœ˜—J˜$J˜Jšœ˜J˜J˜J˜—JšœQ™Qš Ÿ œ œœœœ˜8Jš˜Jšœœ˜!J˜J˜ Jšœœ˜J˜'J˜.Jšœ=™=—šœ9™9Jšœœœ˜(šœ œœœ˜-Jšœ˜J˜J˜2J˜—Jšœ˜—JšœQ™Qš Ÿœ œœœœ˜AJš˜J˜J˜!Jšœ˜Jšœ˜J˜—JšœQ™QJ˜šŸœ œœ˜FJ˜%J˜$J˜Jšœ'ž˜.Jšœ&ž˜-Jšœœ˜Jšœ!˜!J˜#Jšœ"œ˜E˜$šœœœœ˜)Jšœ"œ˜*—Jšœ˜—JšŸ œœœ,œ˜]J˜"J˜,J˜.šœœ˜'J˜5J˜HJ˜0—Jšœ˜J˜-šœœ˜'J˜5˜D˜-J˜———Jšœ˜J˜8J˜ J˜TJ˜7J˜6Jšœ(˜(šœœœž˜/Jšœ,˜,J˜šœœœœ˜#Jšœ7˜7Jšœ˜—J˜Jš œœœœœ˜JJ˜EJ˜#J˜—J˜Jšœ˜—JšœQ™QJ˜J˜šŸœœœœ˜dJ™%J˜J˜Jšœ ˜ J˜J˜J˜J˜(Jšœ˜J˜—JšœQ™QJ˜J˜šŸ œ œ.˜GJšœœ˜J˜J˜J˜J˜J˜J˜Jšœœ œ˜*šœœ˜Jš˜Jšœœœœ˜>Jšœ˜—J˜#Jšœ˜J˜—JšœQ™QJ˜JšœQ™QšŸ œ œDœœ˜uJ˜J˜Jšœœ˜J˜J˜6J˜J˜&J˜&šœœ˜&J˜J˜J˜J˜J˜J˜Jšœ˜—šœœ˜'J˜J˜J˜J˜Jšœ˜—šœœ˜&J˜J˜J˜J˜Jšœ˜—J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜šœœ˜*J˜J˜J˜Jšœ˜—J˜:J˜J˜'J˜'J˜J˜Jšœ=˜=J˜=J˜J˜(J˜'J˜ šœœ˜"J˜J˜J˜Jšœ˜—šœœ˜+J˜J˜J˜J˜Jšœ ˜—J˜Jšœœ œ˜1šœœ˜Jšœœ œœ˜EJšœ˜—J˜&Jšœ˜J˜—JšœQ™QJ˜J˜JšŸ œ œE˜[Jšœœ ˜J˜J˜%Jšœœ˜Jš œ œœœœ˜KJšœ œ˜šœ˜Jšœœž ˜!Jšœœž˜$—J˜J˜.J˜<šœœ ˜&J˜J˜J˜ Jšœ˜ —J˜?J˜Jšœ"œ˜%Jšœ$œ˜'Jšœ#œ˜&Jšœ!œ˜$Jšœ œ˜˜Jšœœ˜Jšœœœœ˜Lšœœ˜=J˜(J˜'J˜(J˜'J˜%J˜,J˜$J˜&Jšœ˜—šœœ˜(˜ Jš˜J˜"J˜%J˜Jšœ˜—˜ Jš˜J˜J˜J˜J˜Jšœ˜—Jšœœ˜#—J˜(J˜Jšœ œœ+œ˜HJšœ˜—˜ Jš˜J˜$J˜(Jšœ/œ˜2Jšœ/œ˜2J˜8J˜Jšœ˜—Jšœœ˜Jšœ˜JšœQ™QJ˜JšœQ™QJ˜J˜Jš Ÿ œ œ œœ œ˜TJ˜ Jšœ œœ(œ˜DJšœ˜Jšœ˜J˜JšœQ™QJ˜J˜JšŸ œ œœ˜8J˜J˜J˜Jšœœ˜ J˜!J˜J˜J˜'šœœ ˜+J˜J˜J˜J˜Jšœ˜—J˜+šœœ˜"Jš˜Jšœ%œ˜(Jšœ%œ˜(J˜&Jšœ˜—Jšœ˜JšœQ™QJ˜J˜J˜JšœQ™QJ˜JšŸ œ œHœ˜}Jšœœ ˜Jšœœ˜*J˜˜%Jšœœ ˜J˜\šœ œ˜&J˜Jšœ ˜—šœœ ˜'J˜J˜J˜J˜Jšœ ž˜'—šœœ ˜&J˜J˜J˜J˜Jšœ ž˜'—J˜"J˜"J˜ J˜ J˜ J˜!J˜!J˜J˜J˜J˜"šœœ˜*J˜J˜J˜Jšœ ˜—J˜cJ˜J˜Jšœž!˜@J˜fJ˜ šœ œ˜"J˜J˜J˜Jšœ ž˜&—šœœ˜+J˜J˜J˜J˜Jšœ ž˜%—JšœB˜BJšœ˜šœž@˜BJ˜HJšœœœ˜!Jšœ,ž*˜ZJ˜—Jšœ œœ™3š™Jš œ œœœœ œ™PJ™J™+Jšœ™——Jšœ ˜Jšœ˜JšœQ™QJ˜JšœQ™QJšŸ œ œI˜^Jšœœ ˜J˜J˜J˜%J˜J˜$Jšœœ˜Jšœœ˜Jšœœ˜J˜;˜Jšœœœ œ˜/J˜—J˜*šœ˜˜#J˜—˜J˜ —˜J˜—Jšœœ˜#—Jšœ.ž˜Kšœ-˜/Jšœ'˜+šœ˜ Jšœ œ6˜Gšœ!œ˜-J˜(J˜>Jšœ˜—J˜Jšœ˜——šœœ˜)Jšœ ˜Jšœ ˜—šœœ˜/J˜J˜ J˜Jšœ ˜—Jšœœ$œ˜HJšœœ%œ˜LJ˜%šœ œ˜šœœ˜&Jšœœ˜—J˜4šœ œ˜.J˜(J˜'J˜(J˜'J˜%J˜,J˜$J˜&Jšœ˜ —šœ˜˜Jš˜J˜Jšœ œœ#œ˜Yšœ˜ J˜Jšœœ*˜GJšœ œœ˜6Jšœ˜—Jšœ˜—˜Jš˜Jšœœœ˜0J˜Jšœœ1˜NJšœ˜—Jšœœ˜#—J˜ Jšœ˜šœœ˜.J˜7Jšœœ%˜;Jšœœ%˜;J˜J˜ZJšœ˜—Jšœ˜—Jšœœ˜Jšœ˜JšœQ™QJ˜J˜JšœQ™QJ˜J˜J˜J˜š Ÿœ œœœœœ ˜NJ˜J˜Jšœœ˜J˜Jšœ œ˜J˜*J˜Jšœ˜˜6Jš˜Jšœœ"˜3šœ œœ˜0J˜J˜J˜J˜Jšœ˜—šœœ ˜J˜%J˜BJšœ˜—Jšœ˜—Jšœœ˜#Jšœ˜J˜J˜—JšœQ™QJ˜J˜Jšœ(™(JšœQ™QšŸ œ œœ˜-Jšœœœ˜!Jšœ ˜"Jšœ˜!Jšœ˜—JšœQ™Qš Ÿœ œœœ˜.Jšœœ˜Jšœ œ˜#Jšœ œ˜"Jšœœ˜Jšœ˜—JšœQ™QJ˜Jšœœœ œœ œ œ˜LJ˜šŸ œ œœ˜(Jšœœ˜Jšœœ œ˜1Jšœ6˜8Jšœ œœœ˜4Jšœ˜—JšœQ™QJšœ œœž ˜>š Ÿ œ œœœ˜0Jšœœœ˜ Jšœœ˜Jšœ œœœ˜4Jšœœœ ˜šœœ)˜.Jšœœ˜—J˜JšœK™KJš œ œœœ œœ˜MJšœ˜—JšœQ™QJ˜J˜šŸœ œœ˜9Jš œœœ œœ˜DJšœœ˜4Jšœ˜J˜—JšœQ™QšŸ œ œ˜1Jšœœ˜.Jšœ˜J˜J˜—š Ÿœ œœœ˜'Jšœ˜Jšœ˜J˜J˜—JšœQ™Qš Ÿ œ œœœœ˜?Jšœœœ ˜GJšœœ*œœ˜LJšœ˜—JšœQ™Qš Ÿœ œœœœ˜@Jšœœœ ˜GJšœ$˜&Jšœ˜J˜—JšœQ™QšŸ œ œœ˜VJš˜Jšœœ˜ J˜Jšœœœœ˜)Jšœœœ ˜Hš œ œœ œœ˜>J˜Jšœœ)œœ˜KJ˜$Jšœ#˜%Jš˜—šœœœ˜'J˜Jšœœ)œœ˜KJ˜$Jšœ#˜%Jšœ˜—Jšœ˜J˜—JšœA™AJ˜š Ÿœœ œœ œ˜6J˜ JšœC˜CJ˜—Jšœ˜J˜J˜J˜—…—a(˜J