-- Read Griffin files and call GriffinFig procs -- borrowed liberally from GriffinFile.mesa -- M. Stone 9-Sep-81 17:52:57 DIRECTORY GFileFormatDefs, StyleDefs, SplineDefs, IOStream USING [Handle,CreateFileStream,Close,GetChar, GetBlock, SetIndex, Error], RealConvert USING [Mesa5ToIeee], Environment USING [charsPerPage,Byte], PairList, ReadGriffin, Storage USING [Node,Free], GriffinFig, Convert USING [ValueToRope], RTTypesBasic USING [NarrowFault], Inline USING [BITAND,BITOR,LongCOPY,BytePair], Cubic USING[CoeffsToBezier,Coeffs], Vector USING[Vec], Rope USING [Ref,Concat,FromString,FromChar]; ReadGriffinImpl: PROGRAM IMPORTS IOStream, Rope, PairList, Storage, GriffinFig, SplineDefs, Inline, RealConvert, Convert, RTTypesBasic, Cubic EXPORTS ReadGriffin = BEGIN OPEN GFileFormatDefs, ReadGriffin; -- --------------------------------------------------------------------------------- Allocate: PROCEDURE [nwords: CARDINAL] RETURNS [POINTER] _ Storage.Node; Free: PROCEDURE [POINTER TO UNSPECIFIED] _ Storage.Free; GriffinFileNameError: PUBLIC SIGNAL[why: Rope.Ref] = CODE; FigureNumber: TYPE = CARDINAL [1 .. 100]; fileName: Rope.Ref; diskHandle: IOStream.Handle; majorVersion: Environment.Byte = 1; minorVersion: Environment.Byte = 4; maxCPairCount: CARDINAL = 2000; -- just for safety realConvert: BOOLEAN _ FALSE; --from griffinfontdefs.mesa Rot0Degrees: CARDINAL = 0; Rot90Degrees: CARDINAL = 5400; Rot180Degrees: CARDINAL = 10800; Rot270Degrees: CARDINAL = 16200; Regular: CARDINAL = 0; Italic: CARDINAL = 1; Bold: CARDINAL = 2; BoldItalic: CARDINAL = Bold + Italic; --from controllers.mesa for ComputeTexture GreyArray: TYPE = ARRAY [0 .. 3] OF CARDINAL; grey50: GreyArray = [52525B, 125252B, 52525B, 125252B]; greyTable: ARRAY [-1 .. 16] OF GreyArray; --now our own datastructures clusterMap: PairList.Relation _ NIL; firstCluster,lastCluster: CARDINAL; minCluster: CARDINAL _ 1; SRHandle: TYPE = POINTER TO StyleRecord; CRHandle: TYPE = POINTER TO ColorRecord; Styles: SRHandle _ @StyleHead; Colors: CRHandle _ @ColorHead; StyleHead: StyleRecord; ColorHead: ColorRecord; StyleRecord: TYPE = RECORD [next: SRHandle _ NIL, fileStyle: CARDINAL _ 0, textOr: REAL _ 0, filled: BOOLEAN _ TRUE, outlined: BOOLEAN _ TRUE, anchor: GriffinFig.AnchorType _ left, text: GriffinFig.TextStyleID _ 0, fill: GriffinFig.FillStyleID _ 0, line: GriffinFig.LineStyleID _ 0]; ColorRecord: TYPE = RECORD [next: CRHandle _ NIL, id: GriffinFig.ColorID _ 0, hsb: StyleDefs.Color _ [0,0,0]]; -- -------------------------------------------------------------------------- GetReal: PROCEDURE [r: LONG UNSPECIFIED] RETURNS [out: REAL] = BEGIN IF realConvert THEN RETURN[RealConvert.Mesa5ToIeee[r]] ELSE RETURN[r]; END; ReadFile: PUBLIC PROCEDURE [filename: Rope.Ref, view: ViewType] = BEGIN ENABLE IOStream.Error => { GriffinFileNameError["file not found"]; CONTINUE}; fileName _ NIL; fileName _ Rope.Concat [fileName, filename]; diskHandle _ IOStream.CreateFileStream[fileName,read ! IOStream.Error => IF ec=FileNotFound THEN{ fileName _ Rope.Concat[fileName, ".Griffin"]; diskHandle _ IOStream.CreateFileStream[fileName,read]; CONTINUE}]; ReadFigure[1,view]; CloseFile[]; END; -- --------------------------------------------------------------------------------- CloseFile: PUBLIC PROCEDURE = BEGIN IOStream.Close [diskHandle]; END; -- --------------------------------------------------------------------------------- --all this sector moving is an artifact. When griffin files were intended to have multiple --figures, each figure was to begin on a page boundary. The sectorIndex is just a relative --page index ReadFigure: PUBLIC PROCEDURE [fignum: FigureNumber, view: ViewType] = BEGIN OPEN PairList; fileheader: GFileHeader; hcontrol: GFileHardcopyController; dcontrol: GFileDisplayController; font: GFileFont; figurename: GFileFigureName; stylecount, fontcount, objectcount, slen, i, f, s: CARDINAL; refID,refFont: REF CARDINAL; fontName,face: Rope.Ref; fontOr: REAL; fontMap: Relation; ReadHeader [@fileheader]; MoveToSector [fileheader.figure [fignum]]; -- go to the right sector ReadStructure [@figurename, lGFileFigureName]; ReadStructure [@hcontrol, lGFileHardcopyController]; ReadStructure [@dcontrol, lGFileDisplayController]; BEGIN OPEN hcontrol; hxcenter: REAL _ GetReal[centerx]; hycenter: REAL _ GetReal[centery]; hwidth: REAL _ GetReal[width]; hheight: REAL _ GetReal[height]; pressxcenter: CARDINAL _ presscenterx; pressycenter: CARDINAL _ presscentery; hscale: REAL _ GetReal[scale]; --we never did make the general mechanism work. These numbers are empirical --GriffinFig.PressController[[1,1],[1067,407]]; END; BEGIN OPEN dcontrol; dxcenter: CARDINAL _ centerx; dycenter: CARDINAL _ centery; dwidth: CARDINAL _ width; dheight: CARDINAL _ height; dxscale: REAL _ GetReal[xscale]; dyscale: REAL _ GetReal[yscale]; dxorigin: REAL _ GetReal[gridxo]; dyorigin: REAL _ GetReal[gridyo]; dgridsize: CARDINAL _ gridsize; --not really a general computation... --GriffinFig.DisplayController[[dxscale,dyscale],[0,-dheight]]; END; --control pairs not implemented IF dcontrol.numcontrolpairs > maxCPairCount THEN SIGNAL GriffinFileNameError["too many control pairs"]; fontcount _ ReadWord []; fontMap _ CreateRelation[]; FOR f IN [1 .. fontcount] DO ReadStructure [@font, lGFileFont]; slen _ LOOPHOLE[font.char[0],CARDINAL]; fontName _ NIL; FOR i IN [1 .. slen] DO fontName _ Rope.Concat[fontName,Rope.FromChar[font.char [i]]]; ENDLOOP; fontOr _ (SELECT font.rotation FROM Rot0Degrees => 0, Rot90Degrees => 90, Rot180Degrees => 180, Rot270Degrees => 270, ENDCASE => 0); fontName _ Rope.Concat[fontName,Convert.ValueToRope[[signed[font.points]]]]; face _ (SELECT font.face FROM Regular => "", Bold => "B", Italic => "I", BoldItalic => "BI", ENDCASE => ""); fontName _ Rope.Concat[fontName,face]; refID _ NEW[CARDINAL _ f]; refFont _ NEW[CARDINAL _ GriffinFig.Font[fontName,fontOr]]; AddPair[fontMap, refID, refFont]; ENDLOOP; stylecount _ ReadWord []; FOR s IN [1 .. stylecount] DO ReadStyle[s,fontMap]; ENDLOOP; clusterMap _ CreateRelation[]; objectcount _ ReadWord []; THROUGH [1 .. objectcount] DO ReadObject[view]; ENDLOOP; PutClusters[]; DestroyRelation[fontMap]; DestroyRelation[clusterMap]; FreeStyles[]; FreeColors[]; END; -- --------------------------------------------------------------------------------- ReadHeader: PROCEDURE [h: POINTER TO GFileHeader] = BEGIN IOStream.SetIndex [diskHandle,0]; ReadStructure [h, lGFileHeader]; realConvert _ FALSE; IF h.majversion#majorVersion OR h.minversion#minorVersion THEN BEGIN --version 1.4 is the first with the Ieee floating point format. --we need to set up to convert the reals for older versions IF h.majversion=1 AND h.minversion IN [0..3] THEN realConvert _ TRUE ELSE {IOStream.Close[diskHandle]; GriffinFileNameError["Incorrect file format."]; }; END; END; -- --------------------------------------------------------------------------------- ------ -- --------------------------------------------------------------------------------- EqualCardinals: PairList.EqualProc = {ENABLE RTTypesBasic.NarrowFault => CONTINUE; l,r: CARDINAL; return _ FALSE; --if not a cardinal, will signal out l _ NARROW[left,REF CARDINAL]^; r _ NARROW[right,REF CARDINAL]^; IF l=r THEN return _ TRUE; }; ReadStyle: PROCEDURE [fileStyle: CARDINAL, fontMap: PairList.Relation] = BEGIN OPEN StyleDefs; thisstyle: Style; fstyle: GFileStyle; ReadStructure [@fstyle, lGFileStyle]; BEGIN OPEN thisstyle; refFont: REF CARDINAL _ NEW[CARDINAL _ fstyle.fontid]; next _ NIL; color _ Color[fstyle.hue, fstyle.saturation, fstyle.brightness]; width _ GetReal[fstyle.thickness]; fillcolor _ Color [fstyle.ahue, fstyle.asaturation, fstyle.abrightness]; filled _ fstyle.afilled; outlined _ fstyle.aoutlined; fontid _ NARROW[PairList.Right[fontMap, EqualCardinals, refFont],REF CARDINAL]^; backgndcolor _ Color [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 orientation _ SELECT fstyle.torient FROM typeRot0 => or0, typeRot90 => or90, typeRot180 => or180, typeRot270 => or270, ENDCASE => or0; -- should be an error END; AddStyle[fileStyle,@thisstyle]; END; -- --------------------------------------------------------------------------------- -- --------------------------------------------------------------------------------- ReadObject: PROCEDURE[view: ViewType] = BEGIN fileobject: GFileObject; fcaptiontrailer: GFileCaptionTrailer; splinetype: SplineDefs.SplineType; nlinks: CARDINAL; style: SRHandle; id: GriffinFig.ObjectID; path: GriffinFig.PathID; pt: Vector.Vec; captionText: Rope.Ref; refID,refCluster: REF CARDINAL; ReadStructure [@fileobject, lGFileObject]; style _ GetStyle[fileobject.style]; SELECT fileobject.objtype FROM typeCurveObject, typeAreaObject => BEGIN OPEN SplineDefs; 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 => { nlinks _ ReadWord []; GriffinFig.StartPath[]; THROUGH [1..nlinks] DO AddLink[splinetype,FALSE] ENDLOOP; path _ GriffinFig.EndPath[]; }; typeCSTraj => { nlinks _ ReadWord []; IF nlinks#1 THEN SIGNAL GriffinFileNameError["imposible cyclic spline"]; splinetype _ (SELECT splinetype FROM naturalUM => cyclicUM, naturalAL => cyclicAL, ENDCASE => splinetype); GriffinFig.StartPath[]; AddLink [splinetype,TRUE]; path _ GriffinFig.EndPath[] }; ENDCASE => SIGNAL GriffinFileNameError["invalid trajectory"]; END; typeCaptionObject => BEGIN ReadStructure [@fcaptiontrailer, lGFileCaptionTrailer]; pt.x _ GetReal[fcaptiontrailer.xanchor]; pt.y _ GetReal[fcaptiontrailer.yanchor]; captionText _ ReadString []; END; ENDCASE => SIGNAL GriffinFileNameError["bad object"]; IF view=both OR (view=main AND ~fileobject.hidewindow) OR (view=alternate AND fileobject.hidewindow) THEN { SELECT fileobject.objtype FROM typeAreaObject => { fillStyle: GriffinFig.FillStyleID _ (IF style.filled THEN style.fill ELSE GriffinFig.NullStyle); lineStyle: GriffinFig.LineStyleID _ (IF style.outlined THEN style.line ELSE GriffinFig.NullStyle); id _ GriffinFig.AreaObject[fillStyle,lineStyle,path]; }; typeCurveObject => id _ GriffinFig.LineObject[style.line,path]; typeCaptionObject => id _ GriffinFig.TextObject[style.text,captionText,style.anchor,pt,style.textOr]; ENDCASE => SIGNAL GriffinFileNameError["invalid object"]; refCluster _ NEW[CARDINAL _ fileobject.cluster]; refID _ NEW[CARDINAL _ id]; PairList.AddPair[clusterMap,refCluster,refID]; }; END; -- --------------------------------------------------------------------------------- -- --------------------------------------------------------------------------------- AddLink: PROCEDURE[splinetype: SplineDefs.SplineType,cyclic: BOOLEAN] = BEGIN OPEN SplineDefs; knotword: GFileKnotWord; knots: DESCRIPTOR FOR ARRAY OF SplineDefs.FPCoords; coeffs: DESCRIPTOR FOR ARRAY OF SplineDefs.Coeffs; num, j: CARDINAL; fpoint: GFilePoint; ReadStructure [@knotword, lGFileKnotWord]; num _ knotword.knotcount; IF num=0 THEN SIGNAL GriffinFileNameError["bad link"]; SELECT knotword.knottype FROM GFileFormatDefs.typeFD3Knot => { knots _ DESCRIPTOR [Allocate[num*SIZE[SplineDefs.FPCoords]], num]; FOR j IN [0 .. num) DO ReadStructure [@fpoint, lGFilePoint]; knots [j] _ SplineDefs.FPCoords[GetReal[fpoint.x], GetReal[fpoint.y]]; ENDLOOP; IF cyclic THEN knots _ MakeCyclicKnots[knots,splinetype]; coeffs _ SplineDefs.MakeSpline[knots,splinetype]; FOR j IN [0..LENGTH[coeffs]) DO c: Cubic.Coeffs; c.c0 _ [coeffs[j].t0[X],coeffs[j].t0[Y]]; c.c1 _ [coeffs[j].t1[X],coeffs[j].t1[Y]]; c.c2 _ [coeffs[j].t2[X],coeffs[j].t2[Y]]; c.c3 _ [coeffs[j].t3[X],coeffs[j].t3[Y]]; GriffinFig.EnterCubic[Cubic.CoeffsToBezier[c]]; ENDLOOP; SplineDefs.FreeCoeffs[coeffs]; Free[BASE[knots]]; }; GFileFormatDefs.typeFD0Knot, GFileFormatDefs.typeFD1Knot, GFileFormatDefs.typeFD2Knot => FOR j IN [0 .. num) DO ReadStructure [@fpoint, lGFilePoint]; GriffinFig.EnterPoint[[GetReal[fpoint.x], GetReal[fpoint.y]]]; ENDLOOP; ENDCASE => SIGNAL GriffinFileNameError["bad link"]; END; MakeCyclicKnots: PROCEDURE[knots: DESCRIPTOR FOR ARRAY OF SplineDefs.FPCoords, type: SplineDefs.SplineType] RETURNS[DESCRIPTOR FOR ARRAY OF SplineDefs.FPCoords]= BEGIN cycknots: DESCRIPTOR FOR ARRAY OF SplineDefs.FPCoords; numknots: INTEGER _ LENGTH[knots]; newLength,i: INTEGER; IF numknots <= 0 THEN RETURN[DESCRIPTOR[NIL,0]]; SELECT type FROM cyclicUM, cyclicAL,bezier=> newLength _ numknots+1; bspline, crspline=> newLength _ numknots+3; ENDCASE; cycknots _ DESCRIPTOR[Allocate[newLength*SIZE[SplineDefs.FPCoords]],newLength]; FOR i IN [0..numknots) DO cycknots[i] _ knots[i]; ENDLOOP; cycknots[numknots] _ cycknots[0]; SELECT type FROM naturalUM=> type _ cyclicUM; naturalAL=> type _ cyclicAL; bspline=> BEGIN cycknots[numknots+1] _ cycknots[1]; cycknots[numknots+2] _ cycknots[2]; END; crspline=> BEGIN cycknots[numknots+1] _ cycknots[1]; cycknots[numknots+2] _ cycknots[2]; END; ENDCASE; Free[BASE[knots]]; RETURN[cycknots]; END; -- --------------------------------------------------------------------------------- --style, color and object mapping stuff --this maps a Griffin Style into calls on GriffinFig, and saves the IDs AddStyle: PROC[fileStyle: CARDINAL, style: StyleDefs.StyleHandle] = { sr: SRHandle _ Allocate[SIZE[StyleRecord]]; ptr: SRHandle; color,fillcolor: GriffinFig.ColorID; anchor: GriffinFig.AnchorType _ (SELECT style.anchor FROM left => left, right => right, center => center, ENDCASE => ERROR); color _ GetColor[style.color]; fillcolor _ GetColor[style.fillcolor]; sr.line _ GriffinFig.LineStyle[color,style.width]; sr.fill _ GriffinFig.FillStyle[fillcolor]; sr.text _ GriffinFig.TextStyle[color,style.fontid]; sr.fileStyle _ fileStyle; sr.filled _ style.filled; sr.outlined _ style.outlined; sr.next _ NIL; sr.textOr _ (SELECT style.orientation FROM or0 => 0, or90 => 90, or180 => 180, or270 => 270, ENDCASE => 0); sr.anchor _ (SELECT style.anchor FROM left => left, right => right, center => center, ENDCASE => left); FOR ptr _ Styles, ptr.next UNTIL ptr.next=NIL DO ENDLOOP; ptr.next _ sr; }; GetStyle: PROC[fileStyle: CARDINAL] RETURNS[SRHandle] = { style: SRHandle; FOR style _ Styles.next, style.next UNTIL style=NIL DO IF style.fileStyle=fileStyle THEN EXIT ENDLOOP; IF style=NIL THEN ERROR; RETURN[style]; }; GetColor: PROC[hsb: StyleDefs.Color] RETURNS[GriffinFig.ColorID] = { color: CRHandle; FOR color _ Colors.next, color.next UNTIL color=NIL DO IF color.hsb=hsb THEN EXIT ENDLOOP; IF color=NIL THEN RETURN[AddColor[hsb]]; RETURN[color.id]; }; --this maps a Griffin Color into calls on GriffinFig, and saves the IDs AddColor: PROC[hsb: StyleDefs.Color] RETURNS[GriffinFig.ColorID] = { cr: CRHandle _ Allocate[SIZE[ColorRecord]]; ptr: CRHandle; cr.next _ NIL; cr.id _ GriffinFig.Color[hsb.hue,hsb.saturation,hsb.brightness,ComputeTexture[hsb]]; cr.hsb _ hsb; FOR ptr _ Colors, ptr.next UNTIL ptr.next=NIL DO ENDLOOP; ptr.next _ cr; RETURN[cr.id]; }; FreeStyles: PROC = { temp: SRHandle; ptr: SRHandle _ Styles.next; UNTIL ptr=NIL DO temp _ ptr.next; Free[ptr]; ptr _ temp; ENDLOOP; Styles.next _ NIL; }; FreeColors: PROC = { temp: CRHandle; ptr: CRHandle _ Colors.next; UNTIL ptr=NIL DO temp _ ptr.next; Free[ptr]; ptr _ temp; ENDLOOP; Colors.next _ NIL; }; --cluster numbers run from firstCluster to lastCluster, but may not be --contiguous PutClusters: PROC = { cluster: CARDINAL; first: BOOLEAN _ TRUE; do: PROC[leftPart,rightPart: REF ANY] = { IF NARROW[leftPart,REF CARDINAL]^=cluster THEN { IF first THEN {GriffinFig.StartCluster[]; first _ FALSE}; GriffinFig.EnterObject[NARROW[rightPart,REF CARDINAL]^]; }; }; FOR cluster IN [firstCluster..lastCluster] DO first _ TRUE; PairList.ForAllPairs[clusterMap,do]; IF ~first THEN [] _ GriffinFig.Cluster[]; ENDLOOP; }; -- --------------------------------------------------------------------------------- -- private low-level disk access procedures -- --------------------------------------------------------------------------------- ReadWord: PROCEDURE RETURNS [CARDINAL] = BEGIN high,low: CHARACTER; word: Inline.BytePair; high _ IOStream.GetChar [diskHandle]; low _ IOStream.GetChar [diskHandle]; word.high _ LOOPHOLE[high]; word.low _ LOOPHOLE[low]; RETURN [LOOPHOLE[word]]; END; -- --------------------------------------------------------------------------------- ReadString: PROCEDURE RETURNS [r: Rope.Ref] = BEGIN t: REF TEXT; length: CARDINAL; length _ LOOPHOLE[IOStream.GetChar[diskHandle], CARDINAL]; t _ NEW[TEXT[length]]; IF IOStream.GetBlock[diskHandle,t,0,length] # length THEN SIGNAL GriffinFileNameError["Possible disk problem"]; r _ Rope.FromString[t]; --always read an even number of bytes: string length + string chars MOD 2 = 0 IF (length+1) MOD 2 # 0 THEN [] _ IOStream.GetChar[diskHandle]; END; -- --------------------------------------------------------------------------------- MoveToSector: PROCEDURE [si: SectorIndex] = BEGIN IOStream.SetIndex [diskHandle, INTEGER[si*Environment.charsPerPage]]; END; -- --------------------------------------------------------------------------------- ReadStructure: PROCEDURE [p: LONG POINTER, l: CARDINAL] = BEGIN from: LONG POINTER; b: REF TEXT _ NEW[TEXT[l*2]]; IF IOStream.GetBlock [diskHandle, b, 0, 2*l] # 2*l THEN SIGNAL GriffinFileNameError["Possible disk problem"]; from _ LOOPHOLE[b,LONG POINTER]+2; --start of bytes Inline.LongCOPY[from,l,p]; END; -- --------------------------------------------------------------------------------- --compute cedargraphics texture from Griffin greys ComputeTexture: PROC[color: StyleDefs.Color] RETURNS[texture: CARDINAL] = {OPEN Inline; grey: INTEGER _ SELECT color FROM --from controllers.mesa --black-- [0,0,0] => 16, --dk brown-- [7,255,59] => 14, --brown-- [7,255,118] => 12, --tan-- [0,131,217] => 4, --maroon-- [234,255,79] => 13, --dk red-- [0,255,160] => 11, --red-- [0,255,255] => 8, --orange-- [10,255,255] => 6, --dk yellow-- [25,255,255] => 7, --yellow-- [40,255,255] => 3, --lt yellow-- [40,190,255] => 2, --dk green-- [71,255,59] => 11, --green-- [76,255,255] => 7, --lt green-- [71,193,255] => 5, --dk blue-- [150,255,170] => 10, --blue-- [148,255,255] => 7, --lt blue-- [141,150,255] => 4, --dk aqua-- [107,255,98] => 9, --aqua-- [107,224,255] => 5, --cyan-- [120,255,255] => 5, --dk purple-- [178,255,178] => 10, --purple-- [170,224,255] => 8, --violet-- [170,131,255] => 4, --magenta-- [200,255,255] => 8, --pink-- [206,170,255] => 4, --dk grey-- [0,0,40] => 13, --grey-- [0,0,120] => 8, --lt grey-- [0,0,200] => 4, --pale grey-- [0,0,230] => 1, --white-- [0,0,255] => 0, ENDCASE => -1; texture _ BITAND[greyTable[grey][0],170000B]; texture _ BITOR[texture,BITAND[greyTable[grey][1],007400B]]; texture _ BITOR[texture,BITAND[greyTable[grey][2],000360B]]; texture _ BITOR[texture,BITAND[greyTable[grey][3],000017B]]; }; -- ----------------------------------------------------------------- --module code SplineDefs.InitSplines[Allocate,Free]; greyTable [-1] _ grey50; greyTable [0] _ [0B, 0B, 0B, 0B]; greyTable [1] _ [0B, 40100B, 0B, 2004B]; greyTable [2] _ [2004B, 40100B, 40100B, 2004B]; greyTable [3] _ [3006B, 40100B, 60140B, 2004B]; greyTable [4] _ [3006B, 60140B, 60140B, 3006B]; greyTable [5] _ [3407B, 60140B, 70160B, 3006B]; greyTable [6] _ [3407B, 160340B, 70160B, 7016B]; greyTable [7] _ [23447B, 160340B, 71162B, 7016B]; greyTable [8] _ [23447B, 162344B, 71162B, 47116B]; greyTable [9] _ [23447B, 172364B, 71162B, 47517B]; greyTable [10] _ [27475B, 172364B, 171362B, 47517B]; greyTable [11] _ [67557B, 172364B, 173366B, 47517B]; greyTable [12] _ [67557B, 173366B, 173366B, 67557B]; greyTable [13] _ [77577B, 173366B, 173767B, 67557B]; greyTable [14] _ [77577B, 177376B, 173767B, 167757B]; greyTable [15] _ [177777B, 177376B, 177777B, 167757B]; greyTable [16] _ [177777B, 177777B, 177777B, 177777B]; END. (896)