DIRECTORY AISFileFormat, AISIO, Basics, CommanderOps, Convert, CtBasic, CtDispatch, CtMap, CtViewer, FileNames, FS, ImagerSample, IO, PFS, PreDebug, Process, Rope, TiogaExtraOps, TiogaOps, TypeScript, ViewerClasses, ViewerIO, ViewerOps; CtInfoCommandImpl: CEDAR PROGRAM IMPORTS AISIO, Basics, CommanderOps, Convert, CtBasic, CtDispatch, CtMap, CtViewer, FileNames, FS, ImagerSample, IO, PFS, PreDebug, Process, Rope, TiogaExtraOps, TiogaOps, TypeScript, ViewerIO, ViewerOps ~ BEGIN SampleMaps: TYPE ~ CtBasic.SampleMaps; Box: TYPE ~ CtBasic.Box; RGB: TYPE ~ CtBasic.RGB; CtProc: TYPE ~ CtDispatch.CtProc; Cmap: TYPE ~ CtMap.Cmap; STREAM: TYPE ~ IO.STREAM; ROPE: TYPE ~ Rope.ROPE; Viewer: TYPE ~ ViewerClasses.Viewer; ViewerClassRec: TYPE ~ ViewerClasses.ViewerClassRec; BytesForAISWords: PROC [aisWords: INT] RETURNS [INT] ~ INLINE { RETURN[LONG[AISFileFormat.bytesPerAISWord]*aisWords]; }; ReadBytes: UNSAFE PROC [stream: STREAM, base: LONG POINTER, bytes: INT] ~ UNCHECKED { actualBytes: INT ~ IO.UnsafeGetBlock[stream, [base: LOOPHOLE[base], count: bytes]]; IF actualBytes # bytes THEN ERROR IO.EndOfStream[stream]; -- file too short }; AISError: ERROR = CODE; PrintAIS: PROC [s: STREAM, fileName: ROPE, verbose: BOOL] ~ { ENABLE AISError => GOTO Bad; PrintInfo: PROC [i: AISIO.Info] ~ { V: PROC [c: AISFileFormat.Card16] RETURNS [CARD] ~ {RETURN[Basics.Card16FromH[c]]}; IO.PutFL[s, "%g:\n\t%g x %g x %g bits", LIST[ IO.rope[name], IO.int[V[i.raster.scanLength]], IO.int[V[i.raster.scanCount]], IO.int[V[i.uca.bitsPerSample]]]]; IF i.placement # NIL THEN IO.PutF[s, ", origin: (%g, %g)", IO.int[V[i.placement.xLeft]], IO.int[V[i.placement.yBottom]]]; IO.PutRope[s, "\n"]; FOR l: LIST OF ROPE ¬ i.comments, l.rest WHILE l # NIL DO IF NOT Rope.IsEmpty[l.first] THEN IO.PutF1[s, "\t\t%g\n", IO.rope[l.first]]; ENDLOOP; IF verbose THEN { IO.PutF1[s, "\traster offset: %g\n", IO.int[i.rasterOffset]]; IO.PutF1[s, "\traster direction: %g\n", IO.rope[SELECT V[i.raster.scanDirection] FROM 3 => "scan right towards bottom", 0, 8 => "scan right towards top", ENDCASE => "undefined"]]; IO.PutF1[s, "\t%g sample(s) per pixel\n", IO.int[V[i.raster.samplesPerPixel]]]; IO.PutF1[s, "\tcoding type: %g\n", IO.rope[SELECT i.raster.codingType FROM nil => "nil", uca => "uca", ENDCASE => "undefined"]]; IO.PutF1[s, "\t%g wordsPerScanLine\n", IO.int[V[i.uca.wordsPerScanLine]]]; IO.PutF[s, "\t%g scanLinesPerBlock, %g paddingPerBlock\n", IO.int[V[i.uca.scanLinesPerBlock]], IO.int[V[i.uca.paddingPerBlock]]]; }; }; info: AISIO.Info ¬ NIL; name: ROPE ¬ FileNames.ResolveRelativePath[fileName]; info ¬ AISIO.ReadInfo[name ! FS.Error => { IO.PutF[s, "Bad AIS file: %g\n(%g)\n", IO.rope[fileName], IO.rope[error.explanation]]; GOTO Bad; }; AISIO.Error => CONTINUE ]; IF info # NIL THEN PrintInfo[info] ELSE { -- rolling our own Int16: TYPE ~ Basics.HWORD; Card16: TYPE ~ Basics.HWORD; AttributeHeader: TYPE ~ AISFileFormat.AttributeHeader; PartHeader: TYPE ~ AISFileFormat.PartHeader; RasterPart: TYPE ~ AISFileFormat.RasterPart; UCACoding: TYPE ~ AISFileFormat.UCACoding; PlacementPart: TYPE ~ AISFileFormat.PlacementPart; PhotometryPart: TYPE ~ AISFileFormat.PhotometryPart; CommentPart: TYPE ~ AISFileFormat.CommentPart; IOrd: PROC [h: Int16] RETURNS [INT16] ~ {RETURN[Basics.Int16FromH[h]]}; COrd: PROC [h: Card16] RETURNS [CARD16] ~ {RETURN[Basics.Card16FromH[h]]}; Assert: PROC [title: ROPE, assertion: BOOL] ~ { IF assertion THEN RETURN; PrintInfo[info]; IO.PutF1[s, "\tAIS file structure is inconsistent (%g)\n", IO.rope[title]]; IO.Close[in]; AISError[]; }; in: IO.STREAM ~ PFS.StreamOpen[PFS.PathFromRope[name], read]; header: MACHINE DEPENDENT RECORD [ c: AttributeHeader, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[AttributeHeader] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1]]; partHeader: MACHINE DEPENDENT RECORD [ c: PartHeader, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[PartHeader] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1]]; raster: MACHINE DEPENDENT RECORD [ c: RasterPart, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[RasterPart] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1]]; uca: MACHINE DEPENDENT RECORD [ c: UCACoding, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[UCACoding] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1]]; placement: MACHINE DEPENDENT RECORD [ c: PlacementPart, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[PlacementPart] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1]]; photometry: MACHINE DEPENDENT RECORD [ c: PhotometryPart, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[PhotometryPart] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1]]; comment: MACHINE DEPENDENT RECORD [ c: CommentPart, p: PACKED ARRAY [0..(BITS[WORD]-(BITS[CommentPart] MOD BITS[WORD])) MOD BITS[WORD]) OF [0..1]]; info ¬ NEW[AISIO.InfoRep]; TRUSTED {ReadBytes[in, @header, AISFileFormat.byteSizeAttributeHeader]}; IF header.c.password # AISFileFormat.passwordValue THEN Assert["bad password", FALSE]; Assert["bad header size", COrd[header.c.length]>0 AND (COrd[header.c.length] MOD AISFileFormat.wordsPerAISPage)=0]; info.rasterOffset ¬ BytesForAISWords[COrd[header.c.length]]; FOR firstPart: BOOL ¬ TRUE, FALSE DO startIndex, stopIndex: INT ¬ IO.GetIndex[in]; TRUSTED {ReadBytes[in, @partHeader, AISFileFormat.byteSizePartHeader]}; stopIndex ¬ startIndex+BytesForAISWords[256*partHeader.c.lengthHi+partHeader.c.lengthLo]; Assert["header bigger than rasterOffset", stopIndex <= info.rasterOffset]; SELECT partHeader.c.type FROM nil => { Assert["bad length for nil part", partHeader.c.lengthHi = 0 AND partHeader.c.lengthLo = 0]; EXIT; -- only correct way out }; -- should be a zero word raster => { Assert["raster not first", firstPart]; -- raster part must be first TRUSTED {ReadBytes[in, @raster, AISFileFormat.byteSizeRasterPart]}; Assert["part size too large", IO.GetIndex[in] <= stopIndex]; Assert["bad raster part size", COrd[raster.c.scanCount]>0 AND COrd[raster.c.scanLength]>0 AND COrd[raster.c.samplesPerPixel]>0]; SELECT raster.c.codingType FROM uca => { byteSizeCoding: INT ~ stopIndex-IO.GetIndex[in]; Assert["bad byteSizeCoding", byteSizeCoding <= AISFileFormat.byteSizeUCACoding]; TRUSTED {ReadBytes[in, @uca, byteSizeCoding]}; IF COrd[uca.c.bitsPerSample] = 0 THEN uca.c.bitsPerSample.lo ¬ 1; -- kludge Assert["bad scans part", INT[COrd[uca.c.bitsPerSample]]*INT[COrd[raster.c.samplesPerPixel]]*INT[COrd[raster.c.scanLength]]<=INT[Basics.bitsPerByte]*BytesForAISWords[COrd[uca.c.wordsPerScanLine]]]; IF byteSizeCoding < AISFileFormat.byteSizeUCACoding THEN { Assert["bad scanLinesPerBlock", uca.c.scanLinesPerBlock = AISFileFormat.nil]; uca.c.paddingPerBlock ¬ AISFileFormat.nil; }; info.uca ¬ NEW[UCACoding ¬ uca.c]; }; ENDCASE => Assert["Unknown AIS coding type", FALSE]; info.raster ¬ NEW[RasterPart ¬ raster.c]; }; placement => { TRUSTED {ReadBytes[in, @placement, AISFileFormat.byteSizePlacementPart]}; Assert["bad placement part size", IO.GetIndex[in] = stopIndex]; IF IOrd[placement.c.xLeft] = -1 AND IOrd[placement.c.yBottom] = -1 AND IOrd[placement.c.xWidth] = -1 AND IOrd[placement.c.yHeight] = -1 THEN NULL ELSE Assert["bad place coordinates", IOrd[placement.c.xWidth]>0 AND IOrd[placement.c.yHeight]>0]; info.placement ¬ NEW[PlacementPart ¬ placement.c]; }; photometry => { TRUSTED {ReadBytes[in, @photometry, AISFileFormat.byteSizePhotometryPart]}; Assert["bad photometry part size", IO.GetIndex[in] <= stopIndex]; IO.SetIndex[in, stopIndex]; -- Ignore histogram, if any info.photometry ¬ NEW[PhotometryPart ¬ photometry.c]; }; comment => { byteSizeComment: INT ~ stopIndex-IO.GetIndex[in]; length: NAT ¬ 0; -- number of characters in the string Assert["bad comment part size", byteSizeComment IN [1..AISFileFormat.byteSizeCommentPart]]; TRUSTED {ReadBytes[in, @comment, byteSizeComment]}; length ¬ ORD[comment.c[0]]; Assert["bad comment part size", byteSizeComment >= INT[length+1]]; { -- turn the comment into a ROPE i: NAT ¬ 0; p: PROC RETURNS [CHAR] ~ {RETURN[comment.c[i ¬ i+1]]}; rope: ROPE ¬ Rope.FromProc[len: length, p: p]; info.comments ¬ CONS[rope, info.comments]; }; }; ENDCASE => Assert["unknown part", TRUE]; IF IO.GetIndex[in] # stopIndex THEN Assert["header # sum of parts", FALSE]; ENDLOOP; IO.Close[in]; PrintInfo[info]; }; EXITS Bad => NULL; }; ctAISInfoUsage: ROPE ~ "Ct AISInfo [-verbose]: Print the AIS header info."; CtAISInfo: CtProc ~ { verbose: BOOL ¬ FALSE; argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd]; IF argv.argc <= 1 THEN RETURN [error: ctAISInfoUsage]; FOR i: INT IN [1..argv.argc) DO IF Rope.Equal[argv[i], "-verbose", FALSE] THEN verbose ¬ TRUE; ENDLOOP; FOR i: INT IN [1..argv.argc) DO NameProc: PROC [file: ROPE] RETURNS [continue: BOOL ¬ TRUE] ~ { Inner: PROC ~ {PrintAIS[cmd.out, file, verbose]}; Reject: PROC [reason: ROPE] RETURNS [reject: BOOL ¬ FALSE] ~ { IO.PutF1[cmd.out, "%g\n", IO.rope[reason]]; }; once ¬ TRUE; Process.CheckForAbort[]; [] ¬ PreDebug.Protect[Inner, Reject]; }; once: BOOL ¬ FALSE; IF Rope.Equal[argv[i], "-verbose", FALSE] THEN LOOP; IF Rope.Find[argv[i], "!"] = -1 THEN argv[i] ¬ Rope.Concat[argv[i], "!h"]; FS.EnumerateForNames[FileNames.ResolveRelativePath[argv[i]], NameProc ! FS.Error => GOTO Bad]; IF NOT once THEN IO.PutF1[cmd.out, "No such files: %g\n", IO.rope[argv[i]]]; ENDLOOP; EXITS Bad => NULL; }; Info: TYPE ~ REF InfoRec; InfoRec: TYPE ~ RECORD [ts, image: Viewer, out: STREAM, maps: SampleMaps, cmap: Cmap]; PixelInfo: TYPE ~ RECORD [valid: BOOL ¬ TRUE, pval: CARDINAL ¬ 0, rgb: RGB]; InfoTrack: CtViewer.MouseProc ~ { info: Info ~ NARROW[clientData]; IF mouse.state = up THEN SELECT mouse.button FROM left => APixel[info.out, info.maps, info.cmap, mouse.pos.x, mouse.pos.y]; middle => ManyPixels[info.out, info.maps, info.cmap, mouse.pos.x, mouse.pos.y, info.ts]; ENDCASE; }; InfoDestroy: ViewerClasses.DestroyProc ~ { CtViewer.UnregisterMouse[NARROW[self.data, Info].image, InfoTrack]; }; ctInfoUsage: ROPE ~ "Ct Info [x, y: INT]: Print the pixel value at (x, y)."; CtInfo: CtProc ~ { ENABLE Convert.Error => GOTO ConvertError; args: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd]; affect ¬ [[0, 0], [0, 0]]; SELECT args.argc FROM 1 => { info: Info ¬ NEW[InfoRec]; TRUSTED {Process.Detach[FORK MakeViewer[info]]}; info.image ¬ viewer; info.maps ¬ maps; info.cmap ¬ CtMap.Read[]; CtViewer.RegisterMouse[info.image, InfoTrack, info]; }; 3 => { x: INTEGER ¬ Convert.IntFromRope[args[1]]; y: INTEGER ¬ Convert.IntFromRope[args[2]]; cmap: Cmap ¬ IF maps.bpp = 8 THEN CtMap.Read[] ELSE NIL; IF NOT CoordinatesOK[maps, x, y] THEN RETURN[error: IO.PutFR["(x, y) must be ([0..%g), [0..%g))", IO.int[maps.w], IO.int[maps.h]]]; APixel[cmd.out, maps, cmap, x, y]; }; ENDCASE => RETURN[error: "bad arguments"]; EXITS ConvertError => RETURN[error: "conversion error"]; }; MakeViewer: PROC [info: Info] ~ { r: Rope.ROPE ~ "0 pt restIndent"; v: Viewer ¬ ViewerOps.CreateViewer[ flavor: $CtInfo, info: [openHeight: 400, name: "Ct Info", data: info, column: right, iconic: TRUE]]; ViewerOps.OpenIcon[v]; info.ts ¬ TypeScript.Create[[parent: v, ww: v.cw, wh: v.ch, border: FALSE]]; TiogaExtraOps.PutProp[TiogaOps.LastWithin[TiogaOps.ViewerDoc[info.ts]], $Postfix, r]; info.out ¬ ViewerIO.CreateViewerStreams[NIL, info.ts].out; }; APixel: PROC [out: STREAM, maps: SampleMaps, cmap: Cmap, x, y: NAT] ~ { pix: PixelInfo ¬ GetPixelInfo[maps, cmap, x, y]; SELECT TRUE FROM pix.valid = FALSE => IO.PutRope[out, "Pixel off screen\n"]; maps.bpp = 8 => IO.PutRope[out, Rope.Concat[ IO.PutFR["8 bit pixel at (%g, %g): %g ", IO.int[x], IO.int[y], IO.card[pix.pval]], IO.PutFR["(r: %g, g: %g, b: %g)\n", IO.int[cmap[0][pix.pval]], IO.int[cmap[1][pix.pval]], IO.int[cmap[2][pix.pval]]]]]; maps.bpp = 24 => IO.PutRope[out, IO.PutFLR["24 bit pixel at (%g, %g), r: %g, g: %g, b: %g\n", LIST[ IO.int[x], IO.int[y], IO.card[pix.rgb.r], IO.card[pix.rgb.g], IO.card[pix.rgb.b]]]]; ENDCASE; }; ManyPixels: PROC [out: STREAM, maps: SampleMaps, cmap: Cmap, x, y: NAT, v: Viewer] ~ { pixs: ARRAY [0..5) OF ARRAY [0..5) OF PixelInfo; Bar: PROC ~ { IF maps.bpp = 8 THEN IO.PutRope[out, "\n"] ELSE IO.PutRope[out, "\n"] }; PrintLine: PROC [j: INTEGER, proc: PROC [i, j: INTEGER], reportY: BOOL ¬ FALSE] ~ { IF proc # PrintX THEN IO.PutRope[out, "| "]; FOR i: NAT IN [0..5) DO proc[i, j]; ENDLOOP; IF reportY THEN IO.PutF1[out, " %g", IO.int[y-2+j]]; IO.PutRope[out, "\n"]; }; PrintX: PROC [i, j: INTEGER] ~ { IF maps.bpp = 8 THEN IO.PutF1[out, " %3g\t", IO.int[x-2+i]] ELSE IO.PutF1[out, " %3g\t", IO.int[x-2+i]]; }; PrintPval: PROC [i, j: INTEGER] ~ {IO.PutF1[out, " %-3g\t\t|", IO.card[pixs[i][j].pval]]}; PrintRed: PROC [i, j: INTEGER] ~ {PrintCard["r", pixs[i][j].rgb.r]}; PrintGrn: PROC [i, j: INTEGER] ~ {PrintCard["g", pixs[i][j].rgb.g]}; PrintBlu: PROC [i, j: INTEGER] ~ {PrintCard["b", pixs[i][j].rgb.b]}; PrintCard: PROC [rope: Rope.ROPE, card: CARDINAL] ~ { IF maps.bpp = 8 THEN IO.PutF[out, " %g: %3g\t|", IO.rope[rope], IO.card[card]] ELSE IO.PutF1[out, " %3g\t|", IO.card[card]]; }; FOR j: NAT IN [0..5) DO yy: INTEGER ¬ y-2+j; FOR i: NAT IN [0..5) DO pixs[i][j] ¬ GetPixelInfo[maps, cmap, x-2+i, yy]; ENDLOOP; ENDLOOP; IO.PutF[out, "\n%g bit pixels centered at (%g, %g):\n", IO.int[maps.bpp], IO.int[x], IO.int[y]]; Process.Pause[Process.MsecToTicks[100]]; [] ¬ v.class.scroll[v, thumb, 100]; PrintLine[0, PrintX]; Bar[]; FOR line: NAT IN [0..5) DO IF maps.bpp = 8 THEN PrintLine[line, PrintPval]; PrintLine[line, PrintRed]; PrintLine[line, PrintGrn, TRUE]; PrintLine[line, PrintBlu]; Bar[]; ENDLOOP }; CoordinatesOK: PROC [maps: SampleMaps, x, y: INTEGER] RETURNS [BOOL] ~ { RETURN[x IN [0..maps.w) AND y IN [0..maps.h)]; }; GetPixelInfo: PROC [maps: SampleMaps, cmap: Cmap, x, y: INTEGER] RETURNS [p: PixelInfo] ~ { IF CoordinatesOK[maps, x, y] THEN SELECT maps.bpp FROM 8 => { p.pval ¬ ImagerSample.Get[maps[0].map, [y, x]]; p.rgb ¬ [cmap[0][p.pval], cmap[1][p.pval], cmap[2][p.pval]]; }; 24 => p.rgb ¬ CtBasic.GetRGBPixel[maps, x, y]; ENDCASE ELSE p.valid ¬ FALSE; }; ctViewerSizeUsage: ROPE ~ "Ct ViewerSize: Print size of current ColorTrix viewer."; CtViewerSize: CtProc ~ { affect ¬ [[0, 0], [0, 0]]; IO.PutFL[cmd.out, "%g %g %g %g (xywh)\n", LIST[IO.int[maps.x], IO.int[maps.y], IO.int[maps.w], IO.int[maps.h]]]; }; ctBBoxUsage: ROPE ~ "Ct BBox [-w ]: Print non-background xywh."; CtBBox: CtProc ~ { box: Box ¬ BBox[maps]; affect ¬ [[0, 0], [0, 0]]; IO.PutFL[cmd.out, "%g %g %g %g\n", LIST[ IO.int[box.min.f], IO.int[box.min.s], IO.int[box.max.f-box.min.f], IO.int[box.max.s-box.min.s]]]; }; BBox: PROC [maps: SampleMaps] RETURNS [Box] ~ { xmin: INT16 ¬ maps.x+maps.w; ymin: INT16 ¬ maps.y+maps.h; xmax: INT16 ¬ maps.x-1; ymax: INT16 ¬ maps.y-1; line: ImagerSample.SampleBuffer ~ ImagerSample.ObtainScratchSamples[maps.w]; bgbuf: ImagerSample.SampleBuffer ~ ImagerSample.ObtainScratchSamples[1]; bg: ImagerSample.Sample; FOR chan: NAT IN [0..maps.nChannels) DO ImagerSample.GetSamples[map: maps[chan].map, initIndex: [maps.y+maps.h-1, maps.x+maps.w-1], buffer: bgbuf, count: 1]; bg ¬ bgbuf[0]; FOR y: NAT IN [0..maps.h) DO ImagerSample.GetSamples[map: maps[chan].map, initIndex: [maps.y+y, maps.x], buffer: line, count: maps.w]; FOR x: NAT IN [0..maps.w) DO IF line[x] # bg THEN { IF x < xmin THEN xmin ¬ x; IF x > xmax THEN xmax ¬ x; IF y < ymin THEN ymin ¬ y; IF y > ymax THEN ymax ¬ y; }; ENDLOOP; ENDLOOP; ENDLOOP; ImagerSample.ReleaseScratchSamples[bgbuf]; ImagerSample.ReleaseScratchSamples[line]; RETURN[IF xmin <= xmax THEN [[ymin, xmin], [ymax-ymin+1, xmax-xmin+1]] ELSE [[0,0], [0,0]]]; }; ViewerOps.RegisterViewerClass[$CtInfo, NEW[ViewerClassRec ¬ [destroy: InfoDestroy]]]; CtDispatch.RegisterCtOp["Information:", NIL, NIL]; CtDispatch.RegisterCtOp["Info", CtInfo, ctInfoUsage, TRUE, FALSE]; CtDispatch.RegisterCtOp["AISInfo", CtAISInfo, ctAISInfoUsage, FALSE]; CtDispatch.RegisterCtOp["BBox", CtBBox, ctBBoxUsage, TRUE, FALSE]; CtDispatch.RegisterCtOp["ViewerSize", CtViewerSize, ctViewerSizeUsage, TRUE, FALSE]; END. κ CtInfoCommandImpl.mesa Copyright Σ 1985, 1992 by Xerox Corporation. All rights reserved. Bloomenthal, October 13, 1992 3:15 pm PDT Heckbert, June 23, 1988 8:42:17 pm PDT Types AIS Info Paul Heckbert, 30 May 1988 IF i.photometry # NIL THEN IO.PutF[s, ", photometry present"]; Pixel Info Tool Viewer Size Command Bounding Box Command find the bounding box of the foreground (non-background) area of the maps read lower right pixel and regard that as the background color Start Code Κf•NewlineDelimiter –"cedarcode" style™™Jšœ Οeœ6™BJ™)J™&—J˜JšΟk œyžœh˜μJ˜šΠblœžœž˜ JšžœjžœX˜Λ—J˜Jšœž˜headšΟl™Jšœ žœ˜'Jšœžœ˜Jšžœžœ žœ˜Jšœ žœ˜#Jšœ žœ˜Jšžœžœžœžœ˜Jšžœžœžœ˜Jšœ žœ˜&Jšœžœ ˜4—š ™š Οnœžœ žœžœžœžœ˜?Jšžœžœ*˜5J˜J˜—š‘ œžœžœ žœžœžœ žœž œ˜UJšœ žœžœžœ˜SJš žœžœžœžœΟc˜KJ˜J˜—š‘œžœžœ˜J˜—š ‘œžœžœ žœ žœ˜=J™Jšžœ žœ˜š‘ œžœžœ ˜#Jš‘œΟsž£œ£œ£ž£œžœžœ˜Sšžœ&žœ˜-Jšžœ žœ˜.Jšžœ˜Jšžœ˜!—šž£œ £œ£ž œ£œ£œ£œ£œ˜:Jšžœ£žœ˜>—Jšžœžœžœžœ!™>Jšžœ˜š žœžœžœžœžœžœž˜9Jšžœžœžœžœ˜LJšžœ˜—šžœ žœ˜Jšžœ"žœ˜=šžœ%žœžœž˜UJ˜!J˜!Jšžœ˜—Jšžœ(žœ#˜Ošžœ žœžœž˜JJšœžœ˜5—Jšžœ%žœ!˜Jšžœ8˜:Jšžœ"žœ ˜F—J˜—J˜—Jšœžœžœ˜Jšœžœ+˜5šœžœ˜šžœ ˜ Jšžœ%žœžœ˜VJšžœ˜ Jšœ˜—Jšžœ ž˜J˜—šžœž˜ Jšžœ˜šžœ’˜Jšœžœ žœ˜Jšœžœ žœ˜Jšœžœ!˜6Jšœ žœ˜-Jšœ žœ˜-Jšœ žœ˜+Jšœžœ˜2Jšœžœ ˜4Jšœ žœ˜.Jš ‘œžœ žœžœžœ˜GJš ‘œžœ Πksžœžœžœ˜Jš‘œžœ žœ žœ˜/Jšžœ žœžœ˜J˜Jšžœ9žœ˜KJšžœ ˜ Jšœ ˜ Jšœ˜—Jš œžœžœžœ žœ˜=šœžœž œžœ˜"Jšœžœžœžœžœžœžœžœžœžœžœžœžœ ˜w—šœ žœž œžœ˜&Jšœžœžœžœžœžœ žœžœžœžœžœžœžœ ˜m—šœžœž œžœ˜"Jšœžœžœžœžœžœ žœžœžœžœžœžœžœ ˜m—šœžœž œžœ˜Jšœžœžœžœžœžœ žœžœžœžœžœžœžœ ˜k—šœ žœž œžœ˜%Jšœžœžœžœžœžœžœžœžœžœžœžœžœ ˜s—šœ žœž œžœ˜&Jšœžœžœžœžœžœžœžœžœžœžœžœžœ ˜u—šœ žœž œžœ˜#Jšœžœžœžœžœžœžœžœžœžœžœžœžœ ˜o—Jšœžœžœ ˜JšžœA˜HJšžœ1žœžœ˜VJš œ£œ£ž£œ£ž£œ"˜sJ˜<š žœ žœžœžœž˜$Jšœžœžœ˜-Jšžœ@˜GJšœ £œO˜YJšœJ˜Jšžœž˜šœ˜Jšœ<žœ˜[Jšžœ’˜Jšœ’˜—šœ ˜ Jšœ'’˜CJšžœ<˜CJšœžœ˜Jšžœ˜—šžœžœžœž˜š ‘œžœžœžœ žœžœ˜?Jš‘œžœ&˜1š ‘œžœ žœžœ žœžœ˜>Jšžœžœ˜+J˜—Jšœžœ˜ J˜J˜%J˜—Jšœžœžœ˜Jšžœ!žœžœžœ˜4Jšžœžœ&˜JšžœC˜EJšœžœ žœ˜—Jš žœžœžœžœ'žœ˜LJšžœ˜—Jšžœžœ˜J˜——š ™Jšœžœžœ ˜Jšœ žœžœžœ ˜Vš œ žœžœ žœžœžœ žœ˜LJ˜—š‘ œ˜!Jšœ žœ ˜ šžœžœžœž˜1J˜IJ˜XJšžœ˜—J˜J˜—š‘ œ˜*Jšœžœ$˜CJ˜J˜—šœ žœ£œ%˜LJ˜—š‘œ ˜Jšžœžœ˜*J˜J˜uJ˜šžœžœžœ ž˜J–Έ[map: ImagerSample.SampleMap, initIndex: SF.Vec _ [s: 0, f: 0], delta: SF.Vec _ [s: 0, f: 1], buffer: ImagerSample.SampleBuffer, start: NAT _ 0, count: NAT _ 32767]˜išžœžœžœ ž˜šžœžœ˜Jšžœ žœ ˜Jšžœ žœ ˜Jšžœ žœ ˜Jšžœ žœ ˜J˜—Jšžœ˜—Jšžœ˜—Jšžœ˜—J˜*J˜)šžœžœ ˜Jšžœ+˜/Jšžœ˜—J˜——š  ™ šœ'žœ+˜UJ˜—Jšœ(žœžœ˜5Jšœ:žœžœ˜GJšœAžœ˜HJšœ:žœžœ˜GJšœHžœžœ˜UJ˜—Jšž˜J™J˜J˜—…—>BT’