unit Utilities;

{Miscellaneous utility routines used by NIH Image}

interface

   uses
        Memory, QuickDraw, Packages, Devices, Menus, Events, Fonts, Scrap, TextEdit, ToolUtils, Dialogs,
        Controls, Palettes, ColorPicker, Printing, SegLoad, globals, AppleEvents;



	procedure SetDlogItem (TheDialog: DialogPtr; item, value: integer);
	procedure OutlineButton (theDialog: DialogPtr; itemNo, CornerRad: integer);
	function GetDNum (TheDialog: DialogPtr; item: integer): LongInt;
	function GetDString (TheDialog: DialogPtr; item: integer): str255;
	procedure SetDNum (TheDialog: DialogPtr; item: integer; n: LongInt);
	procedure GetWindowRect (w: WindowPtr; var wrect: rect);
	procedure SetDReal (TheDialog: DialogPtr; item: integer; n: extended; fwidth: integer);
	procedure SetDString (TheDialog: DialogPtr; item: integer; str: str255);
	procedure DrawSItem (itemnum, fontrqst, sizerqst: integer; d: dialogptr; s: str255);
	function StringToReal (str: str255): extended;
	function GetDReal (TheDialog: DialogPtr; item: integer): extended;
	procedure RealToString (Val: extended; width, fwidth: integer; var Str: Str255);
	procedure DrawReal (Val: extended; width, fwidth: integer);
	procedure DrawJReal (hloc, vloc: integer; Val: extended; fwidth: integer);
	procedure DrawLong (i: LongInt);
	function GetInt (message: str255; default: integer; var Canceled: boolean): integer;
	function GetReal (message: str255; default: extended; precision: integer; var Canceled: boolean): extended;
	function OptionKeyDown: boolean;
	function ShiftKeyDown: boolean;
	function ControlKeyDown: boolean;
	function CommandPeriod: boolean;
	function SpaceBarDown: boolean;

	procedure SysResume;
	procedure beep;
	procedure PutMessage (str: str255);
	procedure PutError (str: str255);
	procedure UnprotectLUT;
	procedure LoadLUT (table: MyCSpecArray);
	procedure SetupLutUndo;
	procedure UndoLutChange;
	procedure DisableDensitySlice;
	procedure LoadInputLUT (address: ptr);
	procedure ResetQuickCapture;
	procedure ResetScionLG3;
	procedure ResetScionAG5;
	procedure ResetScionVG5f;
	procedure ResetFrameGrabber;
	procedure wait (ticks: LongInt);
	function GetScrapCount: integer;
	procedure DisplayText (update: boolean);
	procedure ScreenToOffscreen (var loc: point);
	procedure OffscreenToScreen (var loc: point);
	procedure OffScreenToScreenRect (var r: rect);
	procedure UpdateScreen (MaskRect: rect);
	procedure RestoreRoi;
	procedure Undo;
	procedure CheckOnOffItem (MenuH: MenuHandle; item, fst, lst: Integer);
	procedure SetMenuItem (menuh: menuhandle; itemnum: integer; on: boolean);
	function GetFontSize (item: integer): integer;
	function MyGetPixel (h, v: LongInt): integer;
	procedure PutPixel (h, v: LongInt; value: integer);
	procedure GetLine (h, v, count: LongInt; var line: LineType);
	procedure GetColumn (h, v, count: LongInt; var data: LineType);
	procedure PutColumn (hstart, vstart, count: LongInt; var data: LineType);
	procedure PutLine (h, v, count: LongInt; var line: LineType);
	procedure Show1Value (rvalue, CalibratedValue: extended);
	procedure Show2PlotValues (x, y: extended);
	procedure Show2Values (current, total: LongInt);
	procedure DrawXDimension (x: extended; digits: integer);
	procedure DrawYDimension (y: extended; digits: integer);
	procedure DrawRGB (index: integer);
	procedure Show3Values (hloc, vloc, ivalue: LongInt);
	procedure ShowDxDy (X, Y: extended);
	procedure PutChar (c: char);
	procedure PutTab;
	procedure PutString (str: str255);
	procedure PutReal (n: extended; width, fwidth: integer);
	procedure PutLong (n: LongInt; FieldWidth: integer);
	procedure CopyResultsToBuffer (FirstCount, LastCount: integer; Headings: boolean);
	procedure ShowWatch;
	procedure ShowAnimatedWatch;
	procedure UpdatePicWindow;
	procedure DoOperation (Operation: OpType);
	procedure SaveRoi;
	procedure KillRoi;
	procedure ShowRoi;
	procedure SetupUndo;
	procedure SetupUndoFromClip;
	procedure GetLoi (var x1, y1, x2, y2: extended);
	function NotRectangular: boolean;
	function NotInBounds: boolean;
	function NoSelection: boolean;
	function NoUndo: boolean;
	procedure CloneInfo (var OldInfo, NewInfo: PicInfo);
	function NewPicWindow (name: str255; width, height: integer): boolean;
	function GetAngle (dx, dy: extended):extended;
	procedure MakeRegion;
	procedure SelectAll (visible: boolean);
	procedure EraseScreen;
	procedure RestoreScreen;
	procedure UpdateTitleBar;
	procedure Unzoom;
	procedure DrawBString (str: string);
	procedure DrawMyGrowIcon (w: WindowPtr);
	procedure PutMemoryAlert;
	function GetBigHandle (NeededSize: LongInt): handle;
	function GetImageMemory (SaveInfo: infoPtr): ptr;
	procedure UpdateAnalysisMenu;
	procedure ExtendWindowsMenu (fname: str255; size: LongInt; wptr: WindowPtr);
	procedure MakeNewWindow (name: str255);
	function long2str (num: LongInt): str255;
	procedure PutWarning;
	procedure ScaleToFit;
	procedure SetupRoiRect;
	procedure SetForegroundColor (color: integer);
	procedure SetBackgroundColor (color: integer);
	procedure GetForegroundColor (event: EventRecord);
	procedure GetBackgroundColor (event: EventRecord);
	procedure GenerateValues;
	procedure KillOperation;
	procedure ScaleImageWindow (var trect: rect);
	procedure InvertGrayLevels;
	function TooWide: boolean;
	procedure DrawTextString (str: str255; loc: point; just: integer);
	procedure IncrementCounter;
	procedure ClearResults (i: integer);
	procedure UpdateFitEllipse;
	procedure UpdateTextItems;
	procedure MakeLowerCase (var str: str255);
	function PutMessageWithCancel (str: str255): integer;
	function CurrentWindow: integer;
	procedure FindMonitors (NewScreenDepth: integer);
	function ScreenDepth: integer;
	procedure SetFColor (index: integer);
	procedure SetBColor (index: integer);
	function DoubleToReal(d:FakeDouble):extended; {68k-bug}
	procedure RealToDouble(rr: extended; var d:FakeDouble);
	function MakeStackFromWindow: boolean;
	procedure SelectSlice (i: integer);
	procedure UpdateWindowsMenuItem;
	function AddSlice (update: boolean): boolean;
	procedure AbortMacro;
	procedure TruncateString(var str: str255; length: integer);
	procedure RemovePath(var str: str255);
	function	ForceToFront: OSErr;  {AE -RMD 2/10/95 }

	

implementation


	type
		KeyPtrType = ^KeyMap;



	{procedure MacsBug (str: str255);
	inline
		$abff;}


	procedure ShowMessage (str: str255);
		var
			vloc, hloc: integer;
			tPort: GrafPtr;
			trect: rect;
			SaveGDevice: GDHandle;
	begin
		SaveGDevice := GetGDevice;
		SetGDevice(GetMainDevice);
	  InfoMessage := str;
		GetPort(tPort);
		vloc := 35;
		hloc := 4;
		SetPort(InfoWindow);
		TextFont(Geneva);
		TextSize(9);
		Setrect(trect, hloc, vloc + 15, rwidth - 10, rheight);
		TETextBox(pointer(ord(@InfoMessage) + 1), length(InfoMessage), trect, teJustLeft);
		SetPort(tPort);
		SetGDevice(SaveGDevice);
		wait(120);
	end;


	procedure SetDlogItem (TheDialog: DialogPtr; item, value: integer);
		var
			ItemType: integer;
			ItemBox: rect;
			ItemHdl: handle;
	begin
		GetDialogItem(TheDialog, item, ItemType, ItemHdl, ItemBox);
		SetControlValue(ControlHandle(ItemHdl),value)
	end;


	procedure OutlineButton (theDialog: DialogPtr; itemNo, CornerRad: integer);
  {Draws a border around a button. 16 is the normal}
  {corner radius for small buttons }
		var
			itemType: Integer;
			itemBox: Rect;
			itemHdl: Handle;
			tempPort: GrafPtr;
	begin
		GetPort(tempPort);
		SetPort(GrafPtr(theDialog));
		GetDialogItem(theDialog, itemNo, itemType, itemHdl, itemBox);
		PenSize(3, 3);
		InSetRect(itemBox, -4, -4);
		FrameRoundRect(itemBox, cornerRad, cornerRad);
		PenSize(1, 1);
		SetPort(tempPort);
	end;


	function GetDNum (TheDialog: DialogPtr; item: integer): LongInt;
		var
			ItemType: integer;
			ItemBox: rect;
			ItemHdl: handle;
			str: str255;
			n: LongInt;
	begin
		GetDialogItem(TheDialog, item, ItemType, ItemHdl, ItemBox);
		GetDialogItemText(ItemHdl, str);
		StringToNum(str, n);
		GetDNum := n;
	end;


	function GetDString (TheDialog: DialogPtr; item: integer): str255;
		var
			ItemType: integer;
			ItemBox: rect;
			ItemHdl: handle;
			str: str255;
	begin
		GetDialogItem(TheDialog, item, ItemType, ItemHdl, ItemBox);
		GetDialogItemText(ItemHdl, str);
		GetDString := str;
	end;


	procedure SetDNum (TheDialog: DialogPtr; item: integer; n: LongInt);
		var
			ItemType: integer;
			ItemBox: rect;
			ItemHdl: handle;
			str: str255;
	begin
		GetDialogItem(TheDialog, item, ItemType, ItemHdl, ItemBox);
		NumToString(n, str);
		SetDialogItemText(ItemHdl, str)
	end;


	procedure GetWindowRect (w: WindowPtr; var wrect: rect);
  {Returns global coordinates of specified window.}
	begin
		if w <> nil then
			wrect := WindowPeek(w)^.contRgn^^.rgnBBox
		else
			SetRect(wrect, 0, 0, 0, 0);
	end;


	procedure SetDReal (TheDialog: DialogPtr; item: integer; n: extended; fwidth: integer);
		var
			ItemType: integer;
			ItemBox: rect;
			ItemHdl: handle;
			str: str255;
	begin
		GetDialogItem(TheDialog, item, ItemType, ItemHdl, ItemBox);
		RealToString(n, 1, fwidth, str);
		SetDialogItemText(ItemHdl, str)
	end;

	procedure SetDString (TheDialog: DialogPtr; item: integer; str: str255);
		var
			ItemType: integer;
			ItemBox: rect;
			ItemHdl: handle;
	begin
		GetDialogItem(TheDialog, item, ItemType, ItemHdl, ItemBox);
		SetDialogItemText(ItemHdl, str)
	end;


	function GetDReal (TheDialog: DialogPtr; item: integer): extended;
		var
			str: str255;
	begin
		str := GetDString(TheDialog, item);
		GetDReal := StringToReal(str);
	end;


	procedure DrawLong (i: LongInt);
		var
			str: str255;
	begin
		NumToString(i, str);
		DrawString(str);
	end;


	procedure RealToString (Val: extended; width, fwidth: integer; var Str: Str255);
  {Does number to string conversion equivalent to write(val:width:fwidth).}
  var
  	i:integer;
	begin
		if width<1 then width:=1;
		if (fwidth<0) or (fwidth>8) then fwidth:=0;
		str:=StringOf(val:width:fwidth);
	end;


	procedure DrawReal (Val: extended; width, fwidth: integer);
  {Displays a real(or integer) number at the current location in}
  {a form equivalent to write(val:width:fwidth) }
		var
			str: str255;
	begin
		RealToString(val, width, fwidth, str);
		DrawString(str);
	end;


	procedure DrawJReal (hloc, vloc: integer; val: extended; fwidth: integer);
  {Draws right justified real number.}
		var
			str: str255;
	begin
		if (val >= 1000.0) or (val <= -1000.0) then
			fwidth := 0;
		RealToString(val, 1, fwidth, str);
		MoveTo(hloc - StringWidth(str) - 2, vloc);
		DrawString(str);
	end;


	function GetInt (message: str255; default: integer; var Canceled: boolean): integer;
		const
			NumberID = 3;
		var
			mylog: DialogPtr;
			item: integer;
			temp: LongInt;
	begin
		if ForceToFront <> noErr then exit(GetInt);	{ AE - RMD 1/10/95 }
		ParamText(message, '', '', '');
		mylog := GetNewDialog(3000, nil, pointer(-1));
		SetDNum(MyLog, NumberID, default);
		SelectdialogItemText(MyLog, NumberID, 0, 32767);
		OutlineButton(MyLog, ok, 16);
		repeat
			ModalDialog(nil, item);
		until (item = ok) or (item = cancel);
		if item = ok then begin
				Canceled := false;
				temp := GetDNum(MyLog, NumberID);
				if (temp > -MaxInt) and (temp <= MaxInt) then
					GetInt := temp
				else begin
						SysBeep(1);
						GetInt := default
					end;
			end {item=ok}
		else begin
				Canceled := true;
				GetInt := default;
			end;
		DisposeDialog(mylog);
	end;


	function GetReal (message: str255; default: extended; precision: integer; var Canceled: boolean): extended;
		const
			NumberID = 3;
		var
			mylog: DialogPtr;
			item: integer;
	begin
		InitCursor;
		ParamText(message, '', '', '');
		mylog := GetNewDialog(3000, nil, pointer(-1));
		SetDReal(MyLog, NumberID, default, precision);
		SelectdialogItemText(MyLog, NumberID, 0, 32767);
		OutlineButton(MyLog, ok, 16);
		repeat
			ModalDialog(nil, item);
		until (item = ok) or (item = cancel);
		if item = ok then begin
				GetReal := GetDReal(MyLog, NumberID);
				Canceled := false;
			end
		else begin
				GetReal := default;
				Canceled := true;
			end;
		DisposeDialog(mylog);
	end;


	function OptionKeyDown: boolean;
		var
			KeyPtr: KeyPtrType;
			keys: array[0..3] of LongInt;
	begin
		KeyPtr := KeyPtrType(@keys);
		GetKeys(KeyPtr^);
		OptionKeyDown := (BAND(keys[1], 4)) <> 0;
	end;


	function ShiftKeyDown: boolean;
		var
			KeyPtr: KeyPtrType;
			keys: array[0..3] of LongInt;
	begin
		KeyPtr := KeyPtrType(@keys);
		GetKeys(KeyPtr^);
		ShiftKeyDown := (BAND(keys[1], 1)) <> 0;
	end;


	function ControlKeyDown: boolean;
		type
			KeyPtrType = ^KeyMap;
		var
			KeyPtr: KeyPtrType;
			keys: array[0..3] of LongInt;
	begin
		KeyPtr := KeyPtrType(@keys);
		GetKeys(KeyPtr^);
		ControlKeyDown := (BAND(keys[1], 8)) <> 0;
	end;


	function CommandPeriod: boolean;
		type
			KeyPtrType = ^KeyMap;
		var
			KeyPtr: KeyPtrType;
			keys: array[0..3] of LongInt;
	begin
		KeyPtr := KeyPtrType(@keys);
		GetKeys(KeyPtr^);
		CommandPeriod := (BAND(keys[1], $808000)) = $808000;
	end;


	function SpaceBarDown: boolean;
		var
			KeyPtr: KeyPtrType;
			keys: array[0..3] of LongInt;
	begin
		KeyPtr := KeyPtrType(@keys);
		GetKeys(KeyPtr^);
		SpaceBarDown := (BAND(keys[1], 512)) <> 0;
	end;


	procedure DrawSItem (itemnum, fontrqst, sizerqst: integer; d: dialogptr; s: str255);
 {Draw a string item in a dialog box.}
		var
			r: rect;
			iType: integer;
			ignore: handle;
	begin
		GetDialogItem(d, ItemNum, iType, ignore, r);
		TextFont(fontrqst);
		TextSize(sizerqst);
		TETextBox(pointer(ord(@s) + 1), length(s), r, TEJustRight);
	end;


	procedure SysResume;
	begin
		FlushEvents(EveryEvent, 0);
		ExitToShell;
	end;


	procedure beep;
	begin
		SysBeep(1)
	end;


	procedure PutMessage (str: str255);
		var
			ignore: integer;
			SaveGDevice: GDHandle;
	begin
		if ForceToFront <> noErr then exit(PutMessage);	{ AE - RMD 1/10/95 }
		SaveGDevice := GetGDevice;
		SetGDevice(GetMainDevice);
		InitCursor;
		ParamText(str, '', '', '');
		Ignore := Alert(300, nil);
		SetGDevice(SaveGDevice);
	end;
	

	procedure PutError (str: str255);
		var
			ignore: integer;
			SaveGDevice: GDHandle;
	begin
		if ForceToFront <> noErr then exit(PutError);	{ AE - RMD 1/10/95 }
		SaveGDevice := GetGDevice;
		SetGDevice(GetMainDevice);
		InitCursor;
		ParamText(str, '', '', '');
		Ignore := Alert(310, nil);
		SetGDevice(SaveGDevice);
	end;


	function GetFontSize (item: integer): integer;
		var
			TempSize: integer;
			Canceled: boolean;
	begin
		case item of
			1: 
				GetFontSize := 9;
			2: 
				GetFontSize := 10;
			3: 
				GetFontSize := 12;
			4: 
				GetFontSize := 14;
			5: 
				GetFontSize := 18;
			6: 
				GetFontSize := 24;
			7: 
				GetFontSize := 36;
			8: 
				GetFontSize := 48;
			9: 
				GetFontSize := 56;
			10: 
				GetFontSize := 72;
			12:  begin
					TempSize := GetInt('Font Size:', CurrentSize, Canceled);
					if TempSize < 1 then
						TempSize := 1;
					if TempSize > 1000 then
						TempSize := 1000;
					if not canceled then
						GetFontSize := TempSize
					else
						GetFontSize := CurrentSize;
				end;
		end;
	end;


	procedure SetMenuItem (menuh: menuhandle; itemnum: integer; on: boolean);
{Enable or disable menuh's itemnum. }
	begin
		if on then
			EnableItem(menuh, itemnum)
		else
			DisableItem(menuh, itemnum);
		if ItemNum = 0 then
			DrawMenuBar;
	end;


	procedure CheckOnOffItem (MenuH: MenuHandle; item, fst, lst: Integer);
		var
			i: integer;
	begin
		for i := fst to lst do
			if i = item then
				CheckItem(MenuH, i, true)
			else
				CheckItem(MenuH, i, false);
	end;


	procedure UpdateTextItems;
		var
			size, i, MenuItem, FontID, item: integer;
			FontName: str255;
			FontFound, FoundIt: boolean;
			str: str255;
	begin
		FontFound := false;
		for item := 1 to NumFontItems do begin
				GetMenuItemText(FontMenuH, Item, FontName);
				GetFNum(FontName, FontID);
				if FontID = CurrentFontID then begin
						FontFound := true;
						CheckItem(FontMenuH, Item, True)
					end
				else
					CheckItem(FontMenuH, Item, false);
			end;
		if not FontFound then begin
				FoundIt := False;
				Item := 1;
				repeat
					GetMenuItemText(FontMenuH, Item, FontName);
					GetFNum(FontName, FontID);
					if FontID = Geneva then begin
							CheckItem(FontMenuH, Item, True);
							CurrentFontID := FontID;
							FoundIt := true;
						end;
					Item := Item + 1;
				until (Item > NumFontItems) or FoundIt;
			end;

		for i := 1 to 10 do begin
				size := GetFontSize(i);
				if RealFont(CurrentFontID, size) then
					SetItemStyle(SizeMenuH, i, [outline])
				else
					SetItemStyle(SizeMenuH, i, [])
			end;
		NumToString(CurrentSize, str);
		str := concat('Other[', str, ']É');
		SetMenuItemText(SizeMenuH, 12, str);

		for i := TxPlain to TxShadow do
			CheckItem(StyleMenuH, i, false);
		if CurrentStyle = [] then
			CheckItem(StyleMenuH, TxPlain, true)
		else begin
				if Bold in CurrentStyle then
					CheckItem(StyleMenuH, TxBold, true);
				if Italic in CurrentStyle then
					CheckItem(StyleMenuH, TxItalic, true);
				if Underline in CurrentStyle then
					CheckItem(StyleMenuH, TxUnderline, true);
				if Outline in CurrentStyle then
					CheckItem(StyleMenuH, TxOutline, true);
				if Shadow in CurrentStyle then
					CheckItem(StyleMenuH, Txshadow, true);
			end;

		case CurrentSize of
			9: 
				MenuItem := 1;
			10: 
				MenuItem := 2;
			12: 
				MenuItem := 3;
			14: 
				MenuItem := 4;
			18: 
				MenuItem := 5;
			24: 
				MenuItem := 6;
			36: 
				MenuItem := 7;
			48: 
				MenuItem := 8;
			56: 
				MenuItem := 9;
			72: 
				MenuItem := 10;
			otherwise
				MenuItem := 12;
		end;
		CheckOnOffItem(SizeMenuH, MenuItem, 1, 12);

		case TextJust of
			teJustLeft: 
				MenuItem := LeftItem;
			teJustCenter: 
				MenuItem := CenterItem;
			teJustRight: 
				MenuItem := RightItem;
		end;
		CheckOnOffItem(StyleMenuH, MenuItem, LeftItem, RightItem);

		if TextBack = NoBack then
			MenuItem := NoBackgroundItem
		else
			MenuItem := WithBackgroundItem;
		CheckOnOffItem(StyleMenuH, MenuItem, NoBackgroundItem, WithBackgroundItem);
	end;


	procedure LoadLUT (table: MyCSpecArray);
		var
			i, entry, screen: integer;
			cPtr: ^cSpecArray;
			SaveDevice: GDHandle;
	begin
		if nExtraColors > 0 then begin
				entry := FirstExtraColorsEntry;
				for i := 1 to nExtraColors do begin
						table[entry].rgb := ExtraColors[i];
						entry := entry + 1;
					end;
			end;
		if HighLightMode then begin
				table[1].rgb := Highlight1;
				table[254].rgb := Highlight254;
			end;
		for i := 1 to 254 do {Work around needed for 32-bit QuickDraw}
			with table[i].rgb do
				if (red = 0) and (green = 0) and (blue = 0) then begin
						red := 256;
						green := 256;
						blue := 256;
					end;
		cPtr := @table[1];
		SaveDevice := GetGDevice;
		for screen := 1 to nMonitors do begin
				SetGDevice(Monitors[screen]);
				for i := 1 to 254 do begin
						ProtectEntry(i, false);
						ReserveEntry(i, false);
					end;
				SetEntries(1, 253, cPtr^);
			end;
		SetGDevice(SaveDevice);
		table[0].rgb := WhiteRGB;
		table[255].rgb := BlackRGB;
		BlockMove(@table, @osGDevice^^.gdPMap^^.pmTable^^.ctTable, SizeOf(table));
		with osGDevice^^.gdPMap^^.pmTable^^ do
			if ScreenDepth = 8 then
				ctSeed := ScreenPixMap^^.pmTable^^.ctSeed
			else
				ctSeed := GetCtSeed;
	end;


	procedure SetupLutUndo;
	begin
		with info^ do begin
				UndoInfo^.RedLut := RedLut;
				UndoInfo^.GreenLut := GreenLut;
				UndoInfo^.BlueLut := BlueLut;
				UndoInfo^.nColors := nColors;
				UndoInfo^.ColorStart := ColorStart;
				UndoInfo^.ColorEnd := ColorEnd;
				UndoInfo^.FillColor1 := FillColor1;
				UndoInfo^.FillColor2 := FillColor2;
				UndoInfo^.LutMode := LutMode;
				UndoInfo^.ColorTable := ColorTable;
				UndoInfo^.IdentityFunction := IdentityFunction;
				UndoInfo^.cTable := cTable;
				WhatToUndo := UndoLUT;
			end;
	end;


	procedure UndoLutChange;
	begin
		with info^ do begin
				RedLut := UndoInfo^.RedLut;
				GreenLut := UndoInfo^.GreenLut;
				BlueLut := UndoInfo^.BlueLut;
				nColors := UndoInfo^.nColors;
				ColorStart := UndoInfo^.ColorStart;
				ColorEnd := UndoInfo^.ColorEnd;
				FillColor1 := UndoInfo^.FillColor1;
				FillColor2 := UndoInfo^.FillColor2;
				LutMode := UndoInfo^.LutMode;
				LutMode := UndoInfo^.LutMode;
				ColorTable := UndoInfo^.ColorTable;
				cTable := UndoInfo^.cTable;
				LoadLut(cTable);
				Thresholding := false;
				WhatToUndo := NothingToUndo;
			end;
	end;


	procedure UpdatePicWindow;
		var
			tPort: GrafPtr;
			SaveGDevice: GDHandle;
	begin
		if (info <> NoInfo) and (info^.wptr <> nil) then
			with Info^ do begin
					SaveGDevice := GetGDevice;
					SetGDevice(GetMainDevice);
					getPort(tPort);
					SetPort(wptr);
					SetFColor(BlackIndex);
					SetBColor(WhiteIndex);
					CopyBits(BitMapHandle(osPort^.portPixMap)^^, BitMapHandle(CGrafPtr(wptr)^.PortPixMap)^^, SrcRect, wrect, gCopyMode, nil);
					SetPort(tPort);
					SetGDevice(SaveGDevice);
					RoiUpdateTime := 0;
				end;
	end;


	procedure DisableDensitySlice;
		var
			tPort: GrafPtr;
	begin
		if DensitySlicing then begin
				DensitySlicing := false;
				UndoLutChange;
				if ScreenDepth <> 8 then begin
						UpdatePicWindow;
						GetPort(tPort);
						SetPort(LUTWindow);
						InvalRect(LutWindow^.PortRect);
						SetPort(tPort);
					end;
			end;
	end;


	procedure LoadInputLUT (address: ptr);
		type
			ilutType = packed array[0..1023] of byte;
			ilutPtr = ^ilutType;
		var
			ilut: ilutPtr;
			i: integer;
	begin
		ilut := ilutPtr(address);
		if InvertVideo then begin
				for i := 0 to 255 do
					ilut^[i * 4] := i;
				ilut^[0] := 1;
				ilut^[255 * 4] := 254
			end
		else begin
				for i := 0 to 255 do
					ilut^[i * 4] := 255 - i;
				ilut^[0] := 254;
				ilut^[255 * 4] := 1
			end;
	end;


	procedure ResetQuickCapture;
		const
			ilutOffset = $90000;
	begin
		ControlReg^ := 1; {reset}
		while BitAnd(ControlReg^, $80) = $80 do
			;
		ChannelReg^ := VideoChannel * 64;
		while BitAnd(ControlReg^, $80) = $80 do
			;
		LoadInputLUT(Ptr(fgSlotBase + ilutOffset));
	end;


	procedure ResetScionLG3;
		const
			ilutOffset = $80000;
		var
			SyncChannel, t: integer;
	begin
		ControlReg^ := 0;
		BufferReg^ := 0;
		if SyncMode = SeparateSync then
			SyncChannel := 3
		else
			SyncChannel := VideoChannel;
		t := band(bsl(VideoChannel, 4), bsl(SyncChannel, 6));
		ChannelReg^ := bor(LG3DataOut, bor(bsl(VideoChannel, 4), bsl(SyncChannel, 6)));
		DacHighReg^ := DacHigh;
		DacLowReg^ := DacLow;
		DacAReg^ := LG3DacA;
		DacBReg^ := LG3DacB;
		LoadInputLUT(Ptr(fgSlotBase + ilutOffset));
	end;


	procedure ResetScionAG5;
		const
			ilutOffset = $E0000;
		var
			SyncChannel: integer;
	begin
		ControlReg^ := 0;
		if SyncMode = SeparateSync then
			SyncChannel := 3
		else
			SyncChannel := VideoChannel;
		ChannelReg^ := bor(ord(AG5BufferMode), bor(bsl(VideoChannel, 4), bsl(SyncChannel, 6)));
		DacHighReg^ := DacHigh;
		DacLowReg^ := DacLow;
		LoadInputLUT(Ptr(fgSlotBase + ilutOffset));
	end;


	procedure ResetScionVG5f;
		const
			ilutOffset = $80000;
		var
			SyncChannel, t: integer;
	begin
		ControlReg^ := 0;
		if SyncMode = SeparateSync then
			SyncChannel := 3
		else
			SyncChannel := VideoChannel;
		t := band(bsl(VideoChannel, 4), bsl(SyncChannel, 6));
		ChannelReg^ := bor(bsl(VideoChannel, 4), bsl(SyncChannel, 6));
		DacHighReg^ := DacHigh;
		DacLowReg^ := DacLow;
		LoadInputLUT(Ptr(fgSlotBase + ilutOffset));
	end;


	procedure ResetFrameGrabber;
	begin
		case FrameGrabber of
			QuickCapture: 
				ResetQuickCapture;
			ScionLG3: 
				ResetScionLG3;
			ScionAG5: 
				ResetScionAG5;
			ScionVG5f:
				ResetScionVG5f;
			otherwise
				;
		end;
	end;


	procedure wait (ticks: LongInt);
		var
			SaveTicks: LongInt;
	begin
		SaveTicks := TickCount + ticks;
		repeat
		until TickCount > SaveTicks;
	end;


	function GetScrapCount: integer;
		var
			ScrapInfo: PScrapStuff;
	begin
		ScrapInfo := InfoScrap;
		GetScrapCount := ScrapInfo^.ScrapCount;
	end;


	procedure DisplayText (update: boolean);
		var
			tPort: GrafPtr;
			i, hstart, width, ff: integer;
			MaskRect: rect;
			p1, p2: point;
			SaveGDevice: GDHandle;
	begin
		if (info = NoInfo) or (not IsInsertionPoint) then
			exit(DisplayText);
		if update then
			Undo;
		SaveGDevice := GetGDevice;
		SetGDevice(osGDevice);
		GetPort(tPort);
		SetPort(GrafPtr(Info^.osPort));
		pmForeColor(ForegroundIndex);
		pmBackColor(BackgroundIndex);
		TextFont(CurrentFontID);
		TextFace(CurrentStyle);
		TextSize(CurrentSize);
		if TextBack = NoBack then
			TextMode(SrcOr)
		else
			TextMode(SrcCopy);
		width := StringWidth(TextStr);
		case TextJust of
			teJustLeft: 
				hstart := TextStart.h;
			teJustCenter: 
				hstart := TextStart.h - width div 2;
			teJustRight: 
				hstart := TextStart.h - width;
		end;
		if hstart < 0 then
			hstart := 0;
		MoveTo(hstart, TextStart.v);
		DrawString(TextStr);
		GetPen(InsertionPoint);
		ff := CurrentSize * 2;
		p1.h := hstart - ff;
		p1.v := TextStart.v - CurrentSize;
		p2.h := TextStart.h + width + ff;
		p2.v := TextStart.v + CurrentSize div 3;
		Pt2Rect(p1, p2, MaskRect);
		UpdateScreen(MaskRect);
		SetPort(tPort);
		SetGDevice(SaveGDevice);
		Info^.changes := true;
	end;


	procedure OffScreenToScreenRect (var r: rect);
		var
			p1, p2: point;
	begin
		with r do begin
				p1.h := left;
				p1.v := top;
				p2.h := right;
				p2.v := bottom;
				OffScreenToScreen(p1);
				OffScreenToScreen(p2);
				Pt2Rect(p1, p2, r);
			end;
	end;


	procedure ScreenToOffscreen (var loc: point);
	begin
		with loc, Info^ do begin
				h := SrcRect.left + trunc(h / magnification);
				v := SrcRect.top + trunc(v / magnification);
			end;
	end;


	procedure OffscreenToScreen (var loc: point);
	begin
		with loc, Info^ do begin
				h := trunc((h - SrcRect.left) * magnification);
				v := trunc((v - SrcRect.top) * magnification);
			end;
	end;



	procedure UpdateScreen (MaskRect: rect);
 {Refreshes the portion of the screen defined by}
  {MaskRect, where MaskRect is defined in offscreen coordinates.}
		var
			tPort: GrafPtr;
			imag: integer;
			SaveGDevice: GDHandle;i:integer;
	begin
		OffScreenToScreenRect(MaskRect);
		with Info^ do
			if info <> NoInfo then begin
					SaveGDevice := GetGDevice;
					SetGDevice(GetMainDevice);
					getPort(tPort);
					SetPort(wptr);
					SetFColor(BlackIndex);
					SetBColor(WhiteIndex);
					imag := trunc(magnification);
					InsetRect(MaskRect, -imag * 2 * LineWidth, -imag * 2 * LineWidth);
					InsetRect(MaskRect, 0, 0);
					RectRgn(MaskRgn, MaskRect);
					CopyBits(BitMapHandle(osPort^.PortPixMap)^^, BitMapHandle(CGrafPtr(wptr)^.PortPixMap)^^, SrcRect, wrect, gCopyMode, MaskRgn);
					SetPort(tPort);
					SetGDevice(SaveGDevice);
				end;
	end;


	procedure RestoreRoi;
	begin
		with Info^ do begin
				SetupUndo;
				if RoiShowing then
					UpdateScreen(RoiRect);
				roiType := NoInfo^.roiType;
				RoiRect := NoInfo^.RoiRect;
				CopyRgn(NoInfo^.roiRgn, roiRgn);
				LX1 := NoInfo^.LX1;
				LY1 := NoInfo^.LY1;
				LX2 := NoInfo^.LX2;
				LY2 := NoInfo^.LY2;
				LAngle := NoInfo^.LAngle;
				RoiShowing := true;
				measuring := false;
			end;
	end;


	procedure Undo;
		var
			SrcPtr: ptr;
			line: integer;
	begin
		if info^.PixMapSize <> CurrentUndoSize then
			exit(Undo);
		if UndoFromClip then begin
				if info^.PixMapSize > ClipBufSize then
					exit(Undo);
				SrcPtr := ClipBuf;
			end
		else
			SrcPtr := UndoBuf;
		with info^ do
			BlockMove(SrcPtr, PicBaseAddr, PixMapSize);
		if UndoFromClip and RestoreUndoBuf then
			with info^ do
				BlockMove(SrcPtr, UndoBuf, PixMapSize);
		if RedoSelection then
			RestoreRoi;
	end;


	function MyGetPixel (h, v: LongInt): integer;
	begin
		MyGetPixel := BackgroundIndex;
		with Info^ do
			if h >= 0 then
				if v >= 0 then
					if h < PixelsPerLine then
						if v < nlines then
							MyGetPixel := ImageP(PicBaseAddr)^[v * BytesPerRow + h];
               {MyGetPixel := band(ptr(Ord4(PicBaseAddr) + v * BytesPerRow + h)^, 255);}
	end;


	procedure PutPixel (h, v: LongInt; value: integer);
		var
			addr: Ptr;
	begin
		with Info^ do
			if h >= 0 then
				if v >= 0 then
					if h < PixelsPerLine then
						if v < nlines then begin
								addr := Ptr(Ord4(PicBaseAddr) + v * BytesPerRow + h);
								addr^ := value;
							end;
	end;


	procedure GetLine (h, v, count: LongInt; var line: LineType);
		var
			offset: LongInt;
			p: ptr;
			i: integer;
	begin
		if count > MaxLine then
			count := MaxLine;
		with Info^ do begin
				if (h < 0) or (v < 0) or ((h + count) > PixelsPerLine) or (v >= nlines) then begin
						for i := 0 to count - 1 do
							line[i] := MyGetPixel(h + i, v);
						exit(GetLine);
					end;
				offset := v * BytesPerRow + h;
				p := ptr(ord4(PicBaseAddr) + offset);
				BlockMove(p, @line, count);
			end;
	end;


	procedure GetColumn (h, v, count: LongInt; var data: LineType);
		var
			col, pic, bpr: LongInt;
			i: integer;
	begin
		if count > MaxLine then
			count := MaxLine;
		with Info^ do begin
				if (h < 0) or (v < 0) or (h >= PixelsPerLine) or ((v + count) > nlines) then begin
						for i := 0 to count - 1 do
							data[i] := MyGetPixel(h, v + i);
						exit(GetColumn);
					end;
				col := Ord4(@data);
				bpr := BytesPerRow;
				pic := Ord4(PicBaseAddr) + v * bpr + h;
				while count > 0 do begin
						Ptr(col)^ := Ptr(pic)^;
						pic := pic + bpr;
						col := col + 1;
						count := count - 1;
					end;
			end;
	end;


	procedure PutColumn (hstart, vstart, count: LongInt; var data: LineType);
		var
			col, pic, bpr: LongInt;
	begin
		col := Ord4(@data);
		with Info^ do begin
				bpr := BytesPerRow;
				if count > 0 then
					if hstart >= 0 then
						if vstart >= 0 then
							if hstart < PixelsPerLine then begin
									if vstart > nlines - count then
										count := nlines - vstart;
									pic := Ord4(PicBaseAddr) + vstart * bpr + hstart;
									while count > 0 do begin
											Ptr(pic)^ := Ptr(col)^;
											pic := pic + bpr;
											col := col + 1;
											count := count - 1;
										end;
								end;
			end;
	end;


	procedure PutLine (h, v, count: LongInt; var line: LineType);
		var
			offset: LongInt;
			p: ptr;
	begin
		with Info^ do begin
				if (h < 0) or (v < 0) or (v >= nlines) then
					exit(PutLine);
				if (h + count) > PixelsPerLine then
					count := PixelsPerLine - h;
				offset := v * BytesPerRow + h;
				p := ptr(ord4(PicBaseAddr) + offset);
				BlocKMove(@line, p, count);
			end;
	end;


	procedure Show1Value (rvalue, CalibratedValue: extended);
		var
			tPort: GrafPtr;
			hstart, vstart, ivalue: integer;
	begin
		hstart := InfoHStart;
		vstart := InfoVStart;
		GetPort(tPort);
		SetPort(InfoWindow);
		TextSize(9);
		TextFont(Monaco);
		TextMode(SrcCopy);
		MoveTo(xValueLoc, vstart);
		if CalibratedValue <> NoValue then begin
				DrawReal(CalibratedValue, 5, 2);
				DrawString(' (');
				DrawReal(rvalue, 3, 0);
				DrawString(')');
			end
		else
			DrawReal(rvalue, 6, 2);
		DrawString('    ');
		SetPort(tPort);
	end;


	procedure Show2PlotValues (x, y: extended);
		var
			tPort: GrafPtr;
			hstart, vstart, ivalue: integer;
	begin
		with info^ do begin
				hstart := InfoHStart;
				vstart := InfoVStart;
				GetPort(tPort);
				SetPort(InfoWindow);
				TextSize(9);
				TextFont(Monaco);
				TextMode(SrcCopy);
				MoveTo(xValueLoc, vstart);
				DrawXDimension(round(x), 0);
				MoveTo(yValueLoc, vstart + 10);
				DrawReal(y, 6, 2);
				SetPort(tPort);
			end;
	end;


	procedure Show2Values (current, total: LongInt);
		var
			tPort: GrafPtr;
			hstart, vstart, ivalue: integer;
	begin
		hstart := InfoHStart;
		vstart := InfoVStart;
		GetPort(tPort);
		SetPort(InfoWindow);
		TextSize(9);
		TextFont(Monaco);
		TextMode(SrcCopy);
		MoveTo(xValueLoc, vstart);
		DrawLong(current);
		DrawString('     ');
		MoveTo(yValueLoc, vstart + 10);
		DrawLong(total);
		DrawString('     ');
		SetPort(tPort);
	end;


	procedure DrawXDimension (x: extended; digits: integer);
	begin
		with info^ do begin
				if SpatiallyCalibrated then begin
						DrawReal(x / xScale, 5, 2);
						DrawChar(xUnit[1]);
						DrawChar(xUnit[2]);
						DrawString(' (');
						DrawReal(x, 3, digits);
						DrawString(')')
					end
				else
					DrawReal(x, 1, digits);
				DrawString('      ');
			end;
	end;


	procedure DrawYDimension (y: extended; digits: integer);
	begin
		with info^ do begin
				if SpatiallyCalibrated then begin
						DrawReal(y / yScale, 5, 2);
						DrawChar(xUnit[1]);
						DrawChar(xUnit[2]);
						DrawString(' (');
						DrawReal(y, 3, digits);
						DrawString(')')
					end
				else
					DrawReal(y, 1, digits);
				DrawString('      ');
			end;
	end;


	procedure DrawRGB (index: integer);
		var
			rStr, gStr, bStr: str255;
			TempRGB: rgbColor;
			i, entry: integer;

		procedure Convert (n: integer; var str: str255);
			var
				i: integer;
		begin
			RealToString(n, 3, 0, str);
			for i := 1 to 3 do
				if str[i] = ' ' then
					str[i] := '0';
		end;

	begin
		TempRGB := cScreenPort^.portPixMap^^.pmTable^^.ctTable[index].rgb;
		with TempRGB do begin
				Convert(band(bsr(red, 8), 255), rStr);
				Convert(band(bsr(green, 8), 255), gStr);
				Convert(band(bsr(blue, 8), 255), bStr);
				DrawString(concat(rStr, ' ', gStr, ' ', bStr));
			end;
	end;


	procedure Show3Values (hloc, vloc, ivalue: LongInt);
		var
			tPort: GrafPtr;
			hstart, vstart: integer;
	begin
		with info^ do begin
				hstart := InfoHStart;
				vstart := InfoVStart;
				GetPort(tPort);
				SetPort(InfoWindow);
				TextSize(9);
				TextFont(Monaco);
				TextMode(SrcCopy);
				if hloc < 0 then
					hloc := -hloc;
				MoveTo(xValueLoc, vstart);
				DrawXDimension(hloc, 0);
				if InvertYCoordinates and (ivalue >= 0) then
					vloc := PicRect.bottom - vloc - 1;
				if vloc < 0 then
					vloc := -vloc;
				MoveTo(yValueLoc, vstart + 10);
				DrawYDimension(vloc, 0);
				DrawString('    ');
				if ivalue >= 0 then begin
						MoveTo(zValueLoc, vstart + 20);
						if (fit <> uncalibrated) or (CurrentTool = PickerTool) then begin
								if CurrentTool = PickerTool then
									DrawRGB(ivalue)
								else
									DrawReal(cvalue[ivalue], 5, precision);
								DrawString(' (');
								DrawLong(ivalue);
								DrawString(')');
							end
						else
							DrawLong(ivalue);
					end;
				DrawString('    ');
				SetPort(tPort);
			end;
	end;


	procedure ShowDxDy (X, Y: extended);
		var
			tPort: GrafPtr;
			hstart, vstart, ivalue: integer;
	begin
		with info^ do begin
				hstart := InfoHStart;
				vstart := InfoVStart;
				GetPort(tPort);
				SetPort(InfoWindow);
				TextSize(9);
				TextFont(Monaco);
				TextMode(SrcCopy);
				MoveTo(xValueLoc, vstart);
				DrawXDimension(x, 2);
				MoveTo(yValueLoc, vstart + 10);
				DrawYDimension(y, 2);
				MoveTo(zValueLoc, vstart + 20);
				if SpatiallyCalibrated then begin
						DrawReal(sqrt(sqr(x / xScale) + sqr(y / yScale)), 5, 2);
						DrawChar(xUnit[1]);
						DrawChar(xUnit[2]);
						DrawString(' (');
						DrawReal(sqrt(sqr(x) + sqr(y)), 1, 2);
						DrawString(')')
					end
				else
					DrawReal(sqrt(sqr(x) + sqr(y)), 1, 2);
				DrawString('    ');
				SetPort(tPort);
			end;
	end;


	procedure PutChar (c: char);
	begin
		if TextBufSize < MaxTextBufSize then begin
				TextBufSize := TextBufSize + 1;
				TextBufP^[TextBufSize] := c;
				if c = cr then begin
						TextBufColumn := 0;
						TextBufLineCount := TextBufLineCount + 1
					end
				else
					TextBufColumn := TextBufColumn + 1;
			end;
	end;


	procedure PutTab;
	begin
		if not printing then
			PutChar(tab)
	end;


	procedure PutString (str: str255);
		var
			i: integer;
	begin
		for i := 1 to length(str) do begin
				if TextBufSize < MaxTextBufSize then
					TextBufSize := TextBufSize + 1;
				TextBufP^[TextBufSize] := str[i];
				TextBufColumn := TextBufColumn + 1;
			end;
	end;


	procedure PutFString (str: str255; FieldWidth: integer);
		var
			LeadingSpaces: integer;
	begin
		LeadingSpaces := FieldWidth - length(str);
		if LeadingSpaces > 0 then
			str := concat(copy('            ', 1, LeadingSpaces), str);
		PutString(str);
	end;


	procedure PutReal (n: extended; width, fwidth: integer);
		var
			str: str255;
	begin
		RealToString(n, width, fwidth, str);
		PutString(str);
	end;


	procedure PutLong (n: LongInt; FieldWidth: integer);
		var
			str: str255;
			LeadingSpaces: integer;
	begin
		NumToString(n, str);
		LeadingSpaces := FieldWidth - length(str);
		if LeadingSpaces > 0 then
			str := concat(copy('            ', 1, LeadingSpaces), str);
		PutString(str);
	end;


	procedure CopyResultsToBuffer (FirstCount, LastCount: integer; Headings: boolean);
		var
			i, column, fwidth: integer;
			m: MeasurementTypes;

		procedure PutSequenceNumber;
		begin
			PutLong(i, 4);
			PutChar('.');
			PutTab;
		end;

		procedure PutUnits;
		begin
			if info^.SpatiallyCalibrated then begin
					PutString('  (');
					DrawChar(info^.xUnit[1]);
					DrawChar(info^.xUnit[2]);
					PutString(')')
				end
			else
				PutString('(Pixels)');
			PutChar(cr);
			PutChar(cr);
		end;

		procedure PutTabDelimeter;
		begin
			Column := Column + 1;
			if Column <> nListColumns then
				PutTab;
		end;

	begin
		if mCount < 1 then begin
				TextBufSize := 0;
				TextBufLineCount := 0;
				exit(CopyResultsToBuffer);
			end;
		ShowWatch;
		Headings := Headings or OptionKeyWasDown;
		TextBufSize := 0;
		TextBufColumn := 0;
		TextBufLineCount := 0;
		nListColumns := 0;
		for m := AreaM to StdDevM do
			if m in Measurements then
				nListColumns := nListColumns + 1;
		if (xyLocM in measurements) or (nPoints > 0) then
			nListColumns := nListColumns + 2;
		if ModeM in measurements then
			nListColumns := nListColumns + 1;
		if (LengthM in measurements) or (nLengths > 0) then
			nListColumns := nListColumns + 1;
		if MajorAxisM in measurements then
			nListColumns := nListColumns + 1;
		if MinorAxisM in measurements then
			nListColumns := nListColumns + 1;
		if (AngleM in measurements) or (nAngles > 0) then
			nListColumns := nListColumns + 1;
		if IntDenM in measurements then
			nListColumns := nListColumns + 2;
		if MinMaxM in measurements then
			nListColumns := nListColumns + 2;
		if User1M in measurements then
			nListColumns := nListColumns + 1;
		if User2M in measurements then
			nListColumns := nListColumns + 1;
		with info^ do begin
				fwidth := FieldWidth;
				if Headings and (FirstCount = 1) then begin
						PutFString(' ', 5);
						PutTabDelimeter;
						if AreaM in measurements then begin
								PutFString('Area', fwidth);
								PutTabDelimeter;
							end;
						if MeanM in measurements then begin
								PutFString('Mean', fwidth);
								PutTabDelimeter;
							end;
						if StdDevM in measurements then begin
								PutFString('S.D.', fwidth);
								PutTabDelimeter;
							end;
						if (xyLocM in measurements) or (nPoints > 0) then begin
								PutFString('X', fwidth);
								PutTabDelimeter;
								PutFString('Y', fwidth);
								PutTabDelimeter;
							end;
						if ModeM in measurements then begin
								PutFString('Mode', fwidth);
								PutTabDelimeter;
							end;
						if (LengthM in measurements) or (nLengths > 0) then begin
								PutFString('Length', fwidth);
								PutTabDelimeter;
							end;
						if MajorAxisM in measurements then begin
								PutFString(MajorLabel, fwidth);
								PutTabDelimeter;
							end;
						if MinorAxisM in measurements then begin
								PutFString(MinorLabel, fwidth);
								PutTabDelimeter;
							end;
						if (AngleM in measurements) or (nAngles > 0) then begin
								PutFString('Angle', fwidth);
								PutTabDelimeter;
							end;
						if IntDenM in measurements then begin
								PutFString('Int.Den.', fwidth + 2);
								PutTabDelimeter;
								PutFString('Back.', fwidth);
								PutTabDelimeter;
							end;
						if MinMaxM in measurements then begin
								PutFString('Min', fwidth);
								PutTabDelimeter;
								PutFString('Max', fwidth);
								PutTabDelimeter;
							end;
						if User1M in measurements then begin
								PutFString(User1Label, fwidth);
								PutTabDelimeter;
							end;
						if User2M in measurements then begin
								PutFString(User2Label, fwidth);
								PutTabDelimeter;
							end;
						PutChar(cr);
						PutChar(cr);
					end;
				for i := FirstCount to LastCount do begin
						column := 0;
						if Headings then
							PutSequenceNumber;
						if AreaM in measurements then begin
								PutReal(mArea^[i], fwidth, precision);
								PutTabDelimeter;
							end;
						if MeanM in measurements then begin
								PutReal(mean^[i], fwidth, precision);
								PutTabDelimeter;
							end;
						if StdDevM in measurements then begin
								PutReal(sd^[i], fwidth, precision);
								PutTabDelimeter;
							end;
						if (xyLocM in measurements) or (nPoints > 0) then begin
								PutReal(xcenter^[i], fwidth, precision);
								PutTab;
								PutReal(ycenter^[i], fwidth, precision);
								PutTabDelimeter;
							end;
						if ModeM in measurements then begin
								PutReal(mode^[i], fwidth, precision);
								PutTabDelimeter;
							end;
						if (LengthM in measurements) or (nLengths > 0) then begin
								PutReal(plength^[i], fwidth, precision);
								PutTabDelimeter;
							end;
						if MajorAxisM in measurements then begin
								PutReal(MajorAxis^[i], fwidth, precision);
								PutTabDelimeter;
							end;
						if MinorAxisM in measurements then begin
								PutReal(MinorAxis^[i], fwidth, precision);
								PutTabDelimeter;
							end;
						if (AngleM in measurements) or (nAngles > 0) then begin
								PutReal(orientation^[i], fwidth, precision);
								PutTabDelimeter;
							end;
						if IntDenM in measurements then begin
								PutReal(IntegratedDensity^[i], fwidth + 2, precision);
								PutTabDelimeter;
								PutReal(idBackground^[i], fwidth, precision);
								PutTabDelimeter;
							end;
						if MinMaxM in measurements then begin
								PutReal(mMin^[i], fwidth, precision);
								PutTabDelimeter;
								PutReal(mMax^[i], fwidth, precision);
								PutTabDelimeter;
							end;
						if User1M in measurements then begin
								PutReal(User1^[i], fwidth, precision);
								PutTabDelimeter;
							end;
						if User2M in measurements then begin
								PutReal(User2^[i], fwidth, precision);
								PutTabDelimeter;
							end;
						PutChar(cr);
					end; {for}
			end; {with}
	end;


	procedure ShowWatch;
	begin
		SetCursor(watch);
	end;


	procedure ShowAnimatedWatch;
	begin
		SetCursor(AnimatedWatch[WatchIndex]);
		WatchIndex := WatchIndex + 1;
		if WatchIndex > 8 then
			WatchIndex := 1;
	end;


	procedure CaptureImage;
		var
			Timeout: LongInt;
	begin
		case FrameGrabber of
			QuickCapture:  begin
					ControlReg^ := BitAnd($80, 255); {Start frame capture}
					while BitAnd(ControlReg^, $80) = $80 do
						;       {Wait for it to complete}
				end;
			ScionLG3, ScionAG5, ScionVG5f:  begin
					TimeOut := TickCount + 30;  {1/2sec. timeout}
					ControlReg^ := $80; {Start frame capture}
					while BitAnd(ControlReg^, $80) = $00 do begin    {Wait for it to complete}
							if TickCount > TimeOut then begin
									ControlReg^ := $00;
									leave
								end;
						end;
					ControlReg^ := $00;
				end;
		end; {case}
	end;


	procedure Paste;
		var
			srcPort: cGrafPtr;
	begin
		if info = NoInfo then begin
				beep;
				exit(Paste)
			end;
		with Info^ do begin
				if not RoiShowing then
					exit(Paste);
				if PasteTransferMode = SrcCopy then begin
						pmForeColor(BlackIndex);
						pmBackColor(WhiteIndex);
					end;
				srcPort := ClipBufInfo^.osPort;
				if LivePasteMode then
					if ((WhatsOnClip = CameraPic) or (WhatsOnClip = LivePic)) and (PictureType <> FrameGrabberType) then begin
							CaptureImage;
							srcPort := fgPort;
						end;
				CopyBits(BitMapHandle(srcPort^.portPixMap)^^, BitMapHandle(osPort^.PortPixMap)^^, ClipBufInfo^.RoiRect, RoiRect, PasteTransferMode, roiRgn);
				if PasteTransferMode = SrcCopy then begin
						pmForeColor(ForegroundIndex);
						pmBackColor(BackgroundIndex);
					end;
			end;
	end;


	procedure DoOperation (Operation: OpType);
		var
			tPort: GrafPtr;
			loc: point;
			width, height, SaveWidth: integer;
			tRect: rect;
			SaveGDevice: GDHandle;
	begin
		SaveGDevice := GetGDevice;
		GetPort(tPort);
		with Info^ do begin
				changes := true;
				SetGDevice(osGDevice);
				SetPort(GrafPtr(osPort));
				pmForeColor(ForegroundIndex);
				pmBackColor(BackgroundIndex);
				PenNormal;
				case Operation of
					InvertOp: 
						InvertRgn(roiRgn);
					PaintOp: 
						PaintRgn(roiRgn);
					FrameOp:  begin
							if (RoiType = LineRoi) or (RoiType = FreeLineRoi) or (RoiTYpe = SegLineRoi) then
								PenSize(1, 1)
							else
								PenSize(LineWidth, LineWidth);
							FrameRgn(roiRgn);
						end;
					EraseOp:begin 
							EraseRgn(roiRgn);
						end;
					PasteOp: 
						Paste;
					otherwise
				end;
				if not RoiShowing then begin
					UpdateScreen(RoiRect);
					end;
				if PixMapSize > UndoBufSize then
					OpPending := false;
			end;
		SetPort(tPort);
		SetGDevice(SaveGDevice);
	end;


	procedure SaveRoi;
	begin
		with info^ do
			if RoiType <> noRoi then begin
					NoInfo^.roiType := roiType;
					NoInfo^.RoiRect := RoiRect;
					CopyRgn(roiRgn, NoInfo^.roiRgn);
					NoInfo^.LX1 := LX1;
					NoInfo^.LY1 := LY1;
					NoInfo^.LX2 := LX2;
					NoInfo^.LY2 := LY2;
					NoInfo^.LAngle := LAngle;
				end;
	end;


	procedure KillRoi;
		var
			trect: rect;
	begin
		with info^ do begin
				if RoiShowing then begin
						if OpPending then begin
								OpPending := false;
								DoOperation(CurrentOp);
							end;
						SaveRoi;
						RoiShowing := false;
						trect := RoiRect;
						if RoiType = LineRoi then
							InsetRect(trect, -RoiHandleSize, -RoiHandleSize);
						UpdateScreen(trect);
					end;
				RoiType := NoRoi;
				RoiUpdateTime := 0;
			end;
	end;


	procedure ShowRoi;
	begin
		with info^ do
			if RoiType <> NoRoi then begin
					SetupUndo;
					RoiShowing := true;
				end;
	end;


	procedure SetupUndo;
		var
			line: integer;
	begin
		WhatToUndo := NothingToUndo;
		if info = NoInfo then begin
				CurrentUndoSize := 0;
				exit(SetupUndo)
			end;
		with info^ do begin
				if PixMapSize > UndoBufSize then begin
						CurrentUndoSize := 0;
						exit(SetupUndo)
					end;
				if OpPending then begin
						DoOperation(CurrentOp);
						OpPending := false;
					end;
				CurrentUndoSize := PixMapSize;
				BlockMove(PicBaseAddr, UndoBuf, PixMapSize);
				UndoFromClip := false;
				RedoSelection := false;
			end;
	end;


	procedure SetupUndoFromClip;
		var
			line: integer;
	begin
		WhatToUndo := NothingToUndo;
		if info = NoInfo then begin
				CurrentUndoSize := 0;
				exit(SetupUndoFromClip)
			end;
		with info^ do begin
				if PixMapSize > ClipBufSize then begin
						CurrentUndoSize := 0;
						exit(SetupUndoFromClip)
					end;
				if OpPending then begin
						DoOperation(CurrentOp);
						OpPending := false;
					end;
				CurrentUndoSize := PixMapSize;
				BlockMove(PicBaseAddr, ClipBuf, PixMapSize);
			end;
		WhatsOnClip := NothingOnClip;
		UndofromClip := true;
		RedoSelection := false;
	end;


	function NoSelection: boolean;
	begin
		if Info = NoInfo then begin
				beep;
				NoSelection := true;
				exit(NoSelection);
			end;
		if not Info^.RoiShowing then begin
				PutError('Please use a selection tool to make a selection or use the Select All command.');
				AbortMacro;
			end;
		NoSelection := not Info^.RoiShowing;
	end;


	function NotRectangular;{:boolean}
	begin
		with info^ do
			if RoiShowing and (RoiType <> RectRoi) then begin
					PutError('This operation requires a rectangular selection.');
					NotRectangular := true;
					AbortMacro;
				end
			else
				NotRectangular := false;
	end;


	procedure GetLoi (var x1, y1, x2, y2: extended);
	begin
		with info^, info^.RoiRect do begin
				x1 := left + LX1;
				y1 := top + LY1;
				x2 := left + LX2;
				y2 := top + LY2;
			end;
	end;


	function NotInBounds: boolean;
		var
			x1, y1, x2, y2: extended;
	begin
		NotInBounds := false;
		with info^, info^.RoiRect do
			if RoiShowing then begin
					if RoiType = LineRoi then begin
							GetLoi(x1, y1, x2, y2);
							if (x1 >= 0.0) and (y1 >= 0.0) and (x2 <= right) and (y2 <= bottom) then
								exit(NotInBounds);
						end;
					if (left < 0) or (top < 0) or (right > PicRect.right) or (bottom > PicRect.bottom) then begin
							PutError('This operation requires the selection to be entirely within the image.');
							NotInBounds := true;
							AbortMacro;
						end;
				end;
	end;


	function NoUndo: boolean;
		var
			ImageTooLarge: boolean;
	begin
		with info^ do
			ImageTooLarge := (PixMapSize > ClipBufSize) or (PixMapSize > UndoBufSize);
		if ImageTooLarge then
			PutError('This operation requires that the Undo and Clipboard buffers be at least as large as the image.');
		NoUndo := ImageTooLarge;
	end;



	procedure PutMemoryAlert;
	begin
		if not OpeningFinderFiles then
			PutError('There is not enough free memory to open this image. Try closing some windows or allocating more memory to NIH Image.');
		AbortMacro;
	end;


	procedure CompactMemory;
		var
			size: LongInt;
			TempInfo: InfoPtr;
			i: integer;
	begin
		for i := 1 to nPics do begin
				TempInfo := pointer(WindowPeek(PicWindow[i])^.RefCon);
				hunlock(TempInfo^.PicBaseHandle)
			end;
		size := MaxSize;
		size := MaxMem(size);
		for i := 1 to nPics do begin
				TempInfo := pointer(WindowPeek(PicWindow[i])^.RefCon);
				with TempInfo^ do begin
						hlock(PicBaseHandle);
						{$ifc PowerPC}
						PicBaseAddr := PicBaseHandle^;
						{$elsec}
						PicBaseAddr := StripAddress(PicBaseHandle^);
						{$endc}
						osPort^.PortPixMap^^.BaseAddr := PicBaseAddr;
					end;
			end;
	end;



	function GetBigHandle (NeededSize: LongInt): handle;
{Allocates a handle and guarantees MinFree contiguous free bytes after allocation . }
{Does NOT arrange for the new handle to be unlocked during CompactMemory. }
{GetBigHandle returns nil if CompactMemory fails to obtain enough contiguous free space . }
		var
			h: handle;
			FreeMem: LongInt;
	begin
		h := NewHandle(NeededSize);
		FreeMem := MaxBlock;
		if (h = nil) or (FreeMem < MinFree) then begin
				if h <> nil then
					DisposeHandle(h);
				if FreeMem > 0 then {Why does FreeMem get set to 0 sometimes and MaxMem}
					CompactMemory       {crash, but only when using the Modern Memory Manager?}
				else
					beep;
				h := NewHandle(NeededSize);
				FreeMem := MaxBlock;
			end;
		if (h = nil) or (FreeMem < MinFree) then begin
				if h <> nil then
					DisposeHandle(h);
				h := nil;
			end;
		GetBigHandle := h;
	end;


	function GetImageMemory (SaveInfo: infoPtr): ptr;
{Allocates memory for the PixMap of new image windows. SaveInfo points to the InfoRec of the previous window.}
{A handle is used, rather than a pointer, since NewPtr(particularly on the ci and fx) is rediculously slow.}
		var
			h: handle;
			NeededSize: LongInt;
	begin
		with info^ do begin
				if odd(PixelsPerLine) then
					BytesPerRow := PixelsPerLine + 1
				else
					BytesPerRow := PixelsPerLine;
				PixMapSize := nlines * BytesPerRow;
				ImageSize := nlines * PixelsPerLine;
				NeededSize := PixMapSize;
			end;
		h := GetBigHandle(NeededSize);
		if h = nil then begin
				DisposePtr(pointer(Info));
				PutMemoryAlert;
				Info := SaveInfo;
				GetImageMemory := nil;
				exit(GetImageMemory);
			end;
		with info^ do begin
				PicBaseHandle := h;
				hlock(PicBaseHandle);
				{$ifc PowerPC}
				GetImageMemory := PicBaseHandle^;
				{$elsec}
				GetImageMemory := StripAddress(PicBaseHandle^);
				{$endc}
			end;
	end;


	procedure UpdateAnalysisMenu;
		var
			ShowItems: boolean;
			i: integer;
	begin
		ShowItems := Info <> NoInfo;
		SetMenuItem(AnalyzemenuH, MeasureItem, ShowItems);
		SetMenuItem(AnalyzemenuH, AnalyzeItem, ShowItems);
		SetMenuItem(AnalyzemenuH, HistogramItem, ShowItems);
		SetMenuItem(AnalyzemenuH, PlotItem, ShowItems);
		SetMenuItem(AnalyzemenuH, PlotSurfaceItem, ShowItems);
		SetMenuItem(AnalyzemenuH, SetScaleItem, ShowItems);
		SetMenuItem(AnalyzemenuH, CalibrateItem, ShowItems);
		SetMenuItem(AnalyzemenuH, RedoItem, mCount > 0);
		SetMenuItem(AnalyzemenuH, DeleteItem, mCount > 0);
		SetMenuItem(AnalyzemenuH, RestoreItem, ShowItems and (NoInfo^.RoiType <> NoRoi));
		SetMenuItem(AnalyzemenuH, MarkItem, info^.RoiShowing);
	end;


	procedure ExtendWindowsMenu (fname: str255; size: LongInt; wptr: WindowPtr);
		var
			str, SizeStr: str255;
	begin
		if nPics < MaxPics then begin
				nPics := nPics + 1;
				PicWindow[nPics] := wptr;
				NumToString((size + 511) div 1024, SizeStr);
				str := concat(fname, '  ', SizeStr, 'K');
				AppendMenu(WindowsMenuH, ' ');
				SetMenuItemText(WindowsMenuH, nPics + WindowsMenuItems + nTextWindows, str);
				InsertMenu(WindowsMenuH, 0);
			end;
	end;


	procedure InvertGrayLevels;
	begin
		with info^ do begin
				fit := StraightLine;
				nCoefficients := 2;
				Coefficient[1] := 255.0;
				Coefficient[2] := -1.0;
				ZeroClip := false;
				UnitOfMeasure := '';
				nKnownValues := 0;
				NoInfo^.fit := StraightLine;
				NoInfo^.nCoefficients := 2;
				NoInfo^.Coefficient := Coefficient;
				NoInfo^.ZeroClip := false;
				NoInfo^.UnitOfMeasure := '';
				GenerateValues;
				UpdateTitleBar;
			end;
	end;


	function GetAngle (dx, dy: extended):extended;
		var
			angle:extended;
			quadrant: (q1, q2orq3, q4);
	begin
		if dx <> 0.0 then
			angle := arctan(dy / dx)
		else begin
				if dy >= 0.0 then
					angle := pi / 2.0
				else
					angle := -pi / 2.0
			end;
		angle := (180.0 / pi) * angle;
		if (dx >= 0.0) and (dy >= 0.0) then
			quadrant := q1
		else if dx < 0.0 then
			quadrant := q2orq3
		else
			quadrant := q4;
		case quadrant of
			q1: 
				;
			q2orq3: 
				angle := angle + 180.0;
			q4: 
				angle := angle + 360.0;
		end;
		GetAngle:=angle; {ppc-bug}
	end;


	procedure MakeRegion;
		var
			deltax, deltay, x1, y1, x2, y2, xt, yt: integer;
			dx, dy, pAngle: extended;
			add: boolean;
			tPort: GrafPtr;
	begin
		with info^ do begin
				GetPort(tPort);
				SetPort(wptr);
				OpenRgn;
				case RoiType of
					LineRoi:  begin
							LAngle:=GetAngle(LX2 - LX1, LY1 - LY2);
							x1 := round(LX1);
							y1 := round(LY1);
							x2 := round(LX2);
							y2 := round(LY2);
							if (x1 = x2) and (y1 = y2) then begin
									MoveTo(x1, y1);
									LineTo(x1 + 1, y1);
									LineTo(x1 + 1, y1 + 1);
									LineTo(x1, y1 + 1);
									LineTo(x1, y1);
								end
							else begin
									add := (LAngle > 90.0) and (LAngle <= 270.0);
									pAngle := (LAngle / 180.0) * pi;
									if add then
										pAngle := pAngle + pi / 2.0
									else
										pAngle := pAngle - pi / 2.0;
									dx := cos(pAngle) * LineWidth;
									dy := -sin(pAngle) * LineWidth;
									MoveTo(x1, y1);
									LineTo(round(x1 + dx), round(y1 + dy));
									LineTo(round(x2 + dx), round(y2 + dy));
									LineTo(x2, y2);
									LineTo(x1, y1);
								end;
						end;
					OvalRoi: 
						FrameOval(RoiRect);
					RectRoi: 
						FrameRect(RoiRect);
					otherwise
				end;
				CloseRgn(roiRgn);
				if RoiType = LineRoi then begin
						RoiRect := roiRgn^^.rgnBBox;
						with RoiRect do begin
								LX1 := LX1 - left;
								LY1 := LY1 - top;
								LX2 := LX2 - left;
								LY2 := LY2 - top;
							end;
					end;
			end;
		SetPort(tPort);
	end;


	procedure SelectAll (visible: boolean);
		var
			loc: point;
			tPort: GrafPtr;
	begin
		if info <> NoInfo then
			with Info^ do begin
					KillRoi;
					RoiType := RectRoi;
					RoiRect := PicRect;
					MakeRegion;
					if visible then begin
							SetupUndo;
							RoiShowing := true;
							if (magnification > 1.0) and not ScaleToFitWindow then
								Unzoom;
							if not macro then begin
									PreviousTool := CurrentTool;
									CurrentTool := SelectionTool;
									isSelectionTool := true;
									GetPort(tPort);
									SetPort(ToolWindow);
									EraseRect(ToolRect[PreviousTool]);
									EraseRect(ToolRect[CurrentTool]);
									InvalRect(ToolRect[PreviousTool]);
									InvalRect(ToolRect[CurrentTool]);
									SetPort(tPort);
								end;
						end;
					IsInsertionPoint := false;
					measuring := false;
				end; {with}
	end;


	procedure KillOperation;
	begin
		if OpPending then
			with info^ do
				if info <> NoInfo then begin
						DoOperation(CurrentOp);
						RoiShowing := false;
						UpdateScreen(RoiRect);
						OpPending := false;
					end;
	end;


	procedure CloneInfo (var OldInfo, NewInfo: PicInfo);
	begin
		NewInfo := OldInfo;
		with NewInfo do begin
				PicBaseAddr := nil;
				PicBaseHandle := nil;
				osPort := nil;
				roiRgn := nil;
				RoiType := NoRoi;
				RoiShowing := false;
				Magnification := 1.0;
				vref := 0;
				wPtr := nil;
				ScaleToFitWindow := false;
				WindowState := NormalWindow;
				StackInfo := nil;
				fileVersion := 0;
				PictureType := NewPicture;
				DataType := EightBits;
				changes := false;
				DataH := nil;
				LittleEndian := false;
				InvertedImage := false;
				if (not SpatiallyCalibrated and (fit=uncalibrated)) or (nPics=0) then begin
					if NoInfo^.SpatiallyCalibrated then begin
						SpatiallyCalibrated:=true;
						xUnit := NoInfo^.xUnit;
						xScale := NoInfo^.xScale;
						PixelAspectRatio := NoInfo^.PixelAspectRatio;
						yScale := xScale / PixelAspectRatio;
					end;
					if NoInfo^.fit<>uncalibrated then begin
						fit := NoInfo^.fit;
						nCoefficients := NoInfo^.nCoefficients;
						Coefficient := NoInfo^.Coefficient;
						ZeroClip := NoInfo^.ZeroClip;
						UnitOfMeasure := NoInfo^.UnitOfMeasure;
					end;
				end;
			end;
	end;


	function NewPicWindow (name: str255; width, height: integer): boolean;
		var
			iptr, p: ptr;
			lptr: ^LongInt;
			SaveInfo: InfoPtr;
			NeededSize: LongInt;
			trect: rect;
	begin
		NewPicWindow := false;
		PicLeft := PicLeftBase;
		PicTop := PicTopBase;
		if (info <> noInfo) then begin
				with info^ do begin
						GetWindowRect(wptr, trect);
						if trect.left = PicLeftBase then
							if pos('Camera', name) = 0 then begin
									PicLeft := trect.left + hPicOffset;
									PicTop := trect.top + vPicOffset;
								end;
					end;
			end;
		if nPics = MaxPics then
			exit(NewPicWindow);
		KillOperation;
		DisableDensitySlice;
		SaveInfo := Info;
		iptr := NewPtr(SizeOf(PicInfo));
		if iptr = nil then begin
				PutMemoryAlert;
				AbortMacro;
				exit(NewPicWindow);
			end;
		Info := pointer(iptr);
		CloneInfo(SaveInfo^, Info^);
		with Info^ do begin
				nlines := height;
				PixelsPerLine := width;
				p := GetImageMemory(SaveInfo);
				if p = nil then
					exit(NewPicWindow);
				PicBaseAddr := p;
				MakeNewWindow(name);
				SelectAll(false);
				if not OptionKeyDown then DoOperation(EraseOp);
				KillRoi;
				Changes := false;
				BinaryPic := false;
			end;
		UpdateTitleBar;
		NewPicWindow := true;
	end;


	procedure EraseScreen;
	begin
		SetPort(GrafPtr(CScreenPort));
		with CScreenPort^ do begin
				HideCursor;
				pmBackColor(BackgroundIndex);
				EraseRect(portPixMap^^.Bounds);
				pmBackColor(WhiteIndex);
			end;
	end;


	procedure RestoreScreen;
		var
			GrayRgn: RgnHandle;
			rptr: rhptr;
			wp: ^WindowPtr;
	begin
		rptr := rhptr(GrayRgnGlobal);
		GrayRgn := rptr^;
		wp := pointer(GhostWindow);
		wp^ := WindowPtr(nil);
		PaintBehind(WindowRef(FrontWindow), GrayRgn);
		wp^ := PasteControl;
		DrawMenuBar;
		InitCursor;
	end;


	procedure UpdateTitleBar;
    {Updates the window title bar to show the current magnification or the current frame within a stack.}
		var
			str, str2, str3: str255;
	begin
		with info^ do begin
				str := title;
				if SpatiallyCalibrated then
					str := concat(str, chr($13)); {Black Diamond}
				if fit <> uncalibrated then
					str := concat(str, '×');
				if StackInfo <> nil then
					with StackInfo^ do
						if (nSlices = 3) and (StackType = rgbStack) then begin
								case CurrentSlice of
									1: str2 := 'Red';
									2: str2 := 'Green';
									3: str2 := 'Blue';
								end;
								str := concat(str, ' (', str2, ')');
						end else begin
								NumToString(CurrentSlice, str2);
								NumToString(nSlices, str3);
								str := concat(str, ' (', str2, '/', str3, ')');
						end
				else if (magnification <> 1.0) or ScaleToFitWindow then begin
						if ScaleToFitWindow then begin
								RealToString(magnification, 1, 2, str2);
								str := concat(str, ' (', str2, ')');
							end
						else begin
								RealToString(magnification, 1, 0, str2);
								str := concat(str, ' (', str2, ':1)');
							end;
					end;
				if Digitizing then begin
						if ExternalTrigger then
							str := concat(str, ' (Waiting for Trigger)')
						else
							str := concat(str, ' (Live)');
					end;
				if wptr <> nil then
					SetWTitle(wptr, str);
			end; {with}
	end;


	procedure ScaleToFit;
		var
			trect: rect;
	begin
		if digitizing then
			exit(ScaleToFit);
		if info <> NoInfo then
			with info^ do begin
					ScaleToFitWindow := not ScaleToFitWindow;
					KillRoi;
					if ScaleToFitWindow then begin
							savewrect := wrect;
							SaveSrcRect := SrcRect;
							SaveMagnification := magnification;
							GetWindowRect(wptr, trect);
							savehloc := trect.left;
							savevloc := trect.top;
							wrect := wptr^.PortRect;
							SrcRect := PicRect;
							ScaleImageWindow(wrect);
							SizeWindow(wptr, wrect.right, wrect.bottom, true);
						end
					else begin
							if WindowState = TiledBigScaled then begin
									wrect := initwrect;
									SrcRect := wrect;
									magnification := 1.0;
									WindowState := NormalWindow;
								end
							else begin
									wrect := savewrect;
									SrcRect := SaveSrcRect;
									magnification := SaveMagnification;
								end;
							HideWindow(wptr);
							SizeWindow(wptr, wrect.right, wrect.bottom, true);
							MoveWindow(wptr, savehloc, savevloc, true);
							ShowWindow(wptr);
							UpdateTitleBar;
						end;
					SetPort(wptr);
					InvalRect(wrect);
					WindowState := NormalWindow;
				end;
	end;


	procedure DrawMyGrowIcon (w: WindowPtr);
		var
			tPort: GrafPtr;
			tRect: rect;
	begin
		GetPort(tPort);
		SetPort(w);
		PenNormal;
		with w^.PortRect do begin
				SetRect(tRect, right - 12, bottom - 12, right - 5, bottom - 5);
				FrameRect(tRect);
				MoveTo(right - 6, bottom - 10);
				LineTo(right - 2, bottom - 10);
				LineTo(right - 2, bottom - 2);
				LineTo(right - 10, bottom - 2);
				LineTo(right - 10, bottom - 6);
			end;
		SetPort(tPort);
	end;


	procedure Unzoom;
	begin
		if Info <> NoInfo then
			with Info^ do begin
					ScaleToFitWindow:=false;
					wrect := initwrect;
					SrcRect := wrect;
					SizeWindow(wptr, wrect.right, wrect.bottom, true);
					LoadLUT(info^.cTable);
					UpdatePicWindow;
					magnification := 1.0;
					DrawMyGrowIcon(wptr);
					UpdateTitleBar;
					WindowState:=NormalWindow;
					if WhatToUndo = UndoZoom then
						WhatToUndo := NothingToUndo;
					ShowRoi;
				end;
	end;


	procedure DrawBString(str:string);
	var
		s:style;
	begin
		TextFace([bold]);
		DrawString(str);
		s:=[];  {ppc-bug}
		TextFace(s);
	end;


	function long2str (num: LongInt): str255;
		var
			str: str255;
	begin
		NumToString(num, str);
		long2str := str;
	end;


	procedure PutWarning;
	begin
		PutError(concat('This ', long2str((info^.PixmapSize + 511) div 1024), 'K image is larger than the ', long2str(UndoBufSize div 1024), 'K Undo buffer. Many operations may fail or be Undoable.'));
	end;


	procedure SetupRoiRect;
{Copies the current image to Undo buffer so it can be used for drawing}
{the "marching ants". The copy of the previous image in the Clipboard buffer}
{ buffer will be used for Undo.}
		var
			SaveWhatToUndo: WhatToUndoType;
	begin
		SaveWhatToUndo := WhatToUndo;
		SetupUndo;
		UndoFromClip := true;
		info^.RoiShowing := true;
		WhatToUndo := SaveWhatToUndo;
	end;


	procedure SetForegroundColor (color: integer);
		var
			tPort: GrafPtr;
			SaveGDevice: GDHandle;
	begin
		if (color >= 0) and (color <= 255) then
			with info^ do begin
					ForegroundIndex := color;
					GetPort(tPort);
					SetPort(ToolWindow);
					InvalRect(ToolRect[brush]);
					SaveGDevice := GetGDevice;
					SetGDevice(osGDevice);
					if osPort <> nil then begin
							SetPort(GrafPtr(osPort));
							pmForeColor(ForegroundIndex);
						end;
					SetPort(tPort);
					SetGDevice(SaveGDevice);
					if isInsertionPoint then
						DisplayText(true);
				end;
	end;


	procedure SetBackgroundColor (color: integer);
		var
			tPort: GrafPtr;
			SaveGDevice: GDHandle;
	begin
		if (color >= 0) and (color <= 255) then
			with info^ do begin
					BackgroundIndex := color;
					GetPort(tPort);
					SetPort(ToolWindow);
					InvalRect(ToolRect[eraser]);
					SaveGDevice := GetGDevice;
					SetGDevice(osGDevice);
					if osPort <> nil then begin
							SetPort(GrafPtr(osPort));
							pmBackColor(BackgroundIndex);
						end;
					SetPort(tPort);
					SetGDevice(SaveGDevice);
					if isInsertionPoint then
						DisplayText(true);
				end;
	end;


	procedure GetForegroundColor (event: EventRecord);
		var
			loc: point;
			color: integer;
	begin
		loc := event.where;
		ScreenToOffScreen(loc);
		Color := MyGetPixel(loc.h, loc.v);
		SetForegroundColor(color);
	end;


	procedure GetBackgroundColor; {(event: EventRecord)}
		var
			loc: point;
			color: integer;
	begin
		loc := event.where;
		ScreenToOffScreen(loc);
		Color := MyGetPixel(loc.h, loc.v);
		SetBackgroundColor(color);
	end;


procedure GenerateValues;
		var
			a, b, c, d, e, f, x, y: extended;
			i: integer;
	begin
		with info^ do begin
				if fit = uncalibrated then begin
						for i := 0 to 255 do
							cvalue[i] := i;
						minCValue := 0.0;
						maxCValue := 255.0;
						exit(GenerateValues);
					end;
				a := Coefficient[1];
				b := Coefficient[2];
				c := Coefficient[3];
				d := Coefficient[4];
				e := Coefficient[5];
				f := Coefficient[6];
				minCValue := 10e+12;
				maxCValue := -minCValue;
				for i := 0 to 255 do begin
						x := i;
						case fit of
							StraightLine: 
								y := a + b * x;
							Poly2: 
								y := a + b * x + c * x * x;
							Poly3: 
								y := a + b * x + c * x * x + d * x * x * x;
							Poly4: 
								y := a + b * x + c * x * x + d * x * x * x + e * x * x * x * x;
							Poly5: 
								y := a + b * x + c * x * x + d * x * x * x + e * x * x * x * x + f * x * x * x * x * x;
							ExpoFit: 
								y := a * exp(b * x);
							PowerFit: 
								if x = 0.0 then
									y := 0.0
								else
									y := a * exp(b * ln(x)); {y=ax^b}
							LogFit:  begin
									if x = 0.0 then
										x := 0.5;
									y := a * ln(b * x)
								end;
							RodbardFit:  begin
									if x <= a then
										y := 0
									else begin
											y := (a - x) / (x - d);
											y := exp(ln(y) * (1 / b));  {y:=y**(1/b)}
											y := y * c;
										end;
								end;
							UncalibratedOD:  begin
									if x = 255.0 then
										x := 254.5;
									y := 0.434294481 * ln(255.0 / (255.0 - x))  {log10}
								end;
							otherwise
								y := x;
						end; {case}
						cvalue[i] := y;
						if y > maxCValue then
							maxCValue := y;
						if y < minCValue then
							minCValue := y;
					end; {for}
				if minCValue >= 0.0 then
					ZeroClip := false;
				if ZeroClip then begin
						for i := 0 to 255 do
							if cvalue[i] < 0.0 then
								cvalue[i] := 0.0;
						minCValue := 0.0;
					end;
			end;
	end;


	procedure ScaleImageWindow (var trect: rect);
		var
			WindowLeft, WindowTop: integer;
			PicAspectRatio, TempMagnification: extended;
	begin
		with info^ do begin
				SrcRect := PicRect;
				with CGrafPtr(wptr)^.PortPixMap^^.bounds do begin
						WindowLeft := -left;
						WindowTop := -top;
					end;
	with PicRect do
					PicAspectRatio := right / bottom;
				with trect do begin
						if (WindowLeft + right) > (ScreenWidth - 5) then
							right := ScreenWidth - 5 - WindowLeft;
						bottom := round(right / PicAspectRatio);
						if (WindowTop + bottom) > (ScreenHeight - 5) then
							bottom := ScreenHeight - 5 - WindowTop;
						right := round(bottom * PicAspectRatio);
						magnification := right / PicRect.right;
					end;
				UpdateTitleBar;
			end; {with}
	end;


	function TooWide: boolean;
		var
			SelectionTooWide: boolean;
			MaxWidth: str255;
	begin
		with info^.RoiRect do
			SelectionTooWide := (right - left) > MaxLine;
		if SelectionTooWide then begin
				NumToString(MaxLine, MaxWidth);
				PutError(concat('This operation does not support selections wider than ', MaxWidth, ' pixels.'));
				AbortMacro;
			end;
		TooWide := SelectionTooWide;
	end;


	procedure DrawTextString (str: str255; loc: point; just: integer);
		var
			SaveJust: integer;
	begin
		TextStr := str;
		IsInsertionPoint := true;
		TextStart := loc;
		SaveJust := TextJust;
		TextJust := just;
		DisplayText(false);
		TextJust := SaveJust;
		IsInsertionPoint := false;
	end;


	procedure IncrementCounter;
	begin
		if mCount < MaxMeasurements then begin
				mCount := mCount + 1;
				UnsavedResults := true;
			end
		else
			beep;
	end;


	procedure ClearResults (i: integer);
	begin
		mean^[i] := 0.0;
		sd^[i] := 0.0;
		PixelCount^[i] := 0;
		mArea^[i] := 0.0;
		mode^[i] := 0.0;
		IntegratedDensity^[i] := 0.0;
		idBackground^[i] := 0.0;
		xcenter^[i] := 0.0;
		ycenter^[i] := 0.0;
		MajorAxis^[i] := 0.0;
		MinorAxis^[i] := 0.0;
		orientation^[i] := 0.0;
		mMin^[i] := 0.0;
		mMax^[i] := 0.0;
		plength^[i] := 0.0;
	end;

	procedure UpdateFitEllipse;
	begin
		FitEllipse :=(xyLocM in measurements) or (MajorAxisM in measurements) or (MinorAxisM in measurements) or (AngleM in measurements);
	end;



	function StringToReal (str: str255): extended;
		var
			i, ndigits, StringLength: integer;
			c: char;
			n, m: extended;
			negative, LeftOfPoint, NegExp: boolean;
			exponent: LongInt;
	begin
		negative := false;
		n := 0.0;
		LeftOfPoint := true;
		m := 0.1;
		ndigits := 0;
		StringLength := length(str);
		i := 0;
		repeat
			i := i + 1;
		until (str[i] in ['0'..'9', '-', '.']) or (i >= StringLength);
		c := str[i];
		repeat
			if c = '-' then
				negative := true
			else if c = '.' then
				LeftOfPoint := false
			else if (c >= '0') and (c <= '9') then begin
					ndigits := ndigits + 1;
					if LeftOfPoint then
						n := n * 10.0 + ord(c) - ord('0')
					else begin
							n := n + (ord(c) - ord('0')) * m;
							m := m * 0.1;
						end;
				end;
			i := i + 1;
			if i <= StringLength then
				c := str[i];
		until not (c in ['0'..'9', '-', '.']) or (i > StringLength);
		if (c = 'e') or (c = 'E') then begin
				NegExp := false;
				exponent := 0;
				i := i + 1;
				if i <= StringLength then
					c := str[i];
				if (c = '+') or (c = '-') then begin
						if c = '-' then
							NegExp := true;
						i := i + 1;
						if i <= StringLength then
							c := str[i];
					end;
				repeat
					if (c >= '0') and (c <= '9') then
						exponent := exponent * 10 + ord(c) - ord('0');
					i := i + 1;
					if i <= StringLength then
						c := str[i];
				until not (c in ['0'..'9']) or (i > StringLength);
				if negExp then
					exponent := -exponent;
				if exponent <> 0 then
					n := n * exp(exponent * ln(10));
			end; {if c='e'}
		if ndigits = 0 then
			n := BadReal
		else if negative then
			n := -n;
		StringToReal := n;
	end;


	procedure RemovePath(var str: str255);
	var
		loc: integer;
	begin
		repeat
			loc := pos(':', str);
			if loc > 0 then
				delete(str, 1, loc);
		until loc = 0;
	end;


	procedure MakeNewWindow (name: str255);
		var
			wwidth, wheight, wleft, wtop, i: integer;
			tPort: GrafPtr;
			rgb: RGBColor;
			err: OSErr;
			str: str255;
			SaveGDevice: GDHandle;
	begin
		with Info^ do begin
				RemovePath(name);
				wleft := PicLeft;
				wtop := PicTop;
				PicLeft := PicLeft + hPicOffset;
				PicTop := PicTop + vPicOffset;
				if ((PicLeft + round(0.75 * PixelsPerLine)) > ScreenWidth) or ((PicTop + round(0.75 * nlines)) > ScreenHeight) then begin
						PicLeft := PicLeftBase;
						PicTop := PicTopBase;
					end;
				wwidth := PixelsPerLine;
				if (wleft + wwidth) > ScreenWidth then
					wwidth := ScreenWidth - wleft - 4;
				wheight := nlines;
				if (wtop + wheight) > ScreenHeight then
					wheight := ScreenHeight - wtop - 4;
				if OpeningPlugInWindow then
					SetRect(wrect, -10000, wtop, -10000 + wwidth, wtop + wheight)
				else
					SetRect(wrect, wleft, wtop, wleft + wwidth, wtop + wheight);
				str := name;
				if SpatiallyCalibrated then
					str := concat(str, chr($13)); {Black Diamond}
				if fit <> uncalibrated then
					str := concat(str, '×');
				wptr := NewCWindow(nil, wrect, str, true, DocumentProc + ZoomDocProc, nil, true, 0);
				GetPort(tPort);
				SetPort(wptr);
				SetPalette(wptr, ExplicitPalette, false);
				pmForeColor(BlackIndex);
				pmBackColor(WhiteIndex);
				SetRect(wrect, 0, 0, wwidth, wheight);
				SetRect(PicRect, 0, 0, PixelsPerLine, nlines);
				SelectWindow(wptr);
				WindowPeek(wptr)^.WindowKind := PicKind;
				WindowPeek(wptr)^.RefCon := ord4(Info);
				TruncateString(name, maxTitle);
				title := name;
				ExtendWindowsMenu(name, PixMapSize, wptr);
				PicNum := nPics;
				PidNum := nextPid;
				nextPid := nextPid - 1;
				osPort := CGrafPtr(NewPtr(SizeOf(CGrafPort)));
				SaveGDevice := GetGDevice;
				SetGDevice(osGDevice);
				OpenCPort(osPort);
				with osPort^ do begin
						with PortPixMap^^ do begin
								BaseAddr := PicBaseAddr;
								bounds := PicRect;
								pixelType := 0;
								if PixelSize > 8 then
									PixelSize := 8;
								cmpCount := 1;
							end;
						PortRect := PicRect;
						RectRgn(visRgn, PicRect);
						PortPixMap^^.RowBytes := BitOr(BytesPerRow, $8000);
					end;
				SetPalette(WindowPtr(osPort), ExplicitPalette, false);
				pmForeColor(ForegroundIndex);
				pmBackColor(BackgroundIndex);
				SetGDevice(SaveGDevice);
				SetPort(tPort);
				SrcRect := wrect;
				magnification := 1.0;
				RoiShowing := false;
				roiType := NoRoi;
				initwrect := wrect;
				savewrect := wrect;
				SaveSrcRect := SrcRect;
				SaveMagnification := magnification;
				savehloc := wleft;
				savevloc := wtop;
				roiRgn := NewRgn;
				NewPic := true;
				ScaleToFitWindow := false;
				OpPending := false;
				Changes := false;
				WindowState := NormalWindow;
				if (fit = uncalibrated) and InvertPixelValues then
					InvertGrayLevels;
				Revertable := false;
			end;
		WhatToUndo := NothingToUndo;
	end;


	procedure MakeLowerCase (var str: str255);
		var
			i: integer;
			c: char;
	begin
		for i := 1 to length(str) do begin
				c := str[i];
				if (c >= 'A') and (c <= 'Z') then
					str[i] := chr(ord(c) + 32);
			end;
	end;


	function PutMessageWithCancel (str: str255): integer;
	begin
		InitCursor;
		ParamText(str, '', '', '');
		PutMessageWithCancel := Alert(800, nil);
	end;


	function CurrentWindow: integer;
	begin
		if AEisActive then			{ AE - RMD 5/10/95 Allow AE to specify current window }
			begin
				CurrentWindow := CurrentKind;
				exit(CurrentWindow);
			end;
		CurrentWPtr := FrontWindow;
		if CurrentWPtr <> nil then begin
				CurrentKind := WindowPeek(CurrentWPtr)^.WindowKind;
				if CurrentKind = TextKind then
					TextInfo := TextInfoPtr(WindowPeek(CurrentWPtr)^.RefCon);
				CurrentWindow := CurrentKind;
			end
		else begin
				CurrentWindow := 0;
				CurrentKind := 0;
			end;
	end;


	procedure FindMonitors (NewScreenDepth: integer);
  {Generate a list of 8-bit monitors so we can update their LUTs.}
  {This wouldn't be necessary if we were using the Palette Manager.}
		var
			nextDevice: GDHandle;
	begin
		nMonitors := 0;
		nextDevice := GetDeviceList;
		while nextDevice <> nil do begin
				if TestDeviceAttribute(nextDevice, screenDevice) and TestDeviceAttribute(nextDevice, screenActive) then
					if nextDevice^^.gdPmap^^.PixelSize = 8 then begin
							nMonitors := nMonitors + 1;
							Monitors[nMonitors] := nextDevice;
						end;
				nextDevice := GetNextDevice(nextDevice);
			end; {while}
		if NewScreenDepth < 4 then
			gCopyMode := DitherCopy
		else
			gCopyMode := SrcCopy;
		SaveScreenDepth := NewScreenDepth;
	end;


	function ScreenDepth: integer;
		var
			depth: integer;
	begin
		depth := ScreenPixMap^^.PixelSize;
		if depth <> SaveScreenDepth then
			FindMonitors(depth);
		ScreenDepth := depth;
	end;


	procedure SetFColor (index: integer);
  {Sets the screen foreground color. Use pmForeColor to set the offscreen color.}
	begin
		if ScreenDepth = 8 then
			pmForeColor(index)
		else
			RGBForeColor(osGDevice^^.gdPMap^^.pmTable^^.ctTable[index].rgb);
	end;

	procedure SetBColor (index: integer);
  {Sets the screen background color.}
	begin
		if ScreenDepth = 8 then
			pmBackColor(index)
		else
			RGBBackColor(osGDevice^^.gdPMap^^.pmTable^^.ctTable[index].rgb);
	end;
	
	
	function DoubleToReal(d:FakeDouble):extended;
	{Converts an IEEE double to an IEEE float. Will not be needed
	when "8 Byte Doubles" work in the Metrowerks 68k compiler.}
	var
	  s, f, r:extended;
	  e:LongInt;
	  dd:double;
	begin
		{$ifc PowerPC}
		dd:=double(d);
		r:=dd;
		{$elsec PowerPC}
		if band(d[1],$80000000)=0 then
			s:=1
		else
			s:=-1;
		e:=band(d[1],$7ff00000);
		e:=bsr(e,20);
		f:=band(d[1],$fffff);
		f:=f / 1048576.0;
		f:=f + bsr(d[2],24)/268435456.0;
		{ShowMessage(StringOf('s=',s , ' e=', e, ' f=', f));}
		if (e > 0) and (e < 2047) then 
			r:=s * exp((e-1023)*ln(2.0)) * (1.0 + f)
		else if (e = 0) and (f <> 0) then 
			r:=s * f * exp(-1022.0*ln(2.0)) * f
		else if (e = 0) and (e = 0) then
			r:=0.0
		else if (e = 255) and (f = 0) then
			r:=0.0 {inf}
		else {if e=255 and f<>0}
			r:=0.0; {nan}
		{$endc PowerPC}
		DoubleToReal:=r;
	end;


	procedure RealToDouble(rr: extended; var d:FakeDouble);
	{Converts an IEEE float to an IEEE double. Will not be needed
	when "8 Byte Doubles" work in the Metrowerks 68k compiler.}
	var
	  i, s, e, f:LongInt;
	  r:real;
	  dd:double;
	begin
		{$ifc PowerPC}
		dd:=rr;
		d:=FakeDouble(dd);
		{$elsec PowerPC}
		r:=rr;
		i:=LongInt(r);
	  s:=band(i,$80000000);
	  e:=band(i,$7f800000);
		e:=bsr(e, 23);
		if e>255 then
			e:=255;
		e:=e-127+1023;
		e:=bsl(e, 20);
		f:=band(i, $7fffff);
		f:=bsr(f, 3);
		d[1]:=bor(s,bor(e,f));
		d[2]:=0;
		{if r<>0.0 then begin
			ShowMessage(StringOf(' e=', e,' f=', f)); wait(60);
		end;}
		{$endc PowerPC}
	end;
	
	
{$S Utilities2}
{Routines from here to the end of the file go in the Utilities2 segment}

	function MakeStackFromWindow: boolean;
	begin
		with info^ do begin
				StackInfo := StackInfoPtr(NewPtr(SizeOf(StackInfoRec)));
				if StackInfo = nil then begin
						MakeStackFromWindow := false;
						exit(MakeStackFromWindow);
					end;
				with StackInfo^ do begin
						nSlices := 1;
						CurrentSlice := 1;
						PicBaseH[1] := PicBaseHandle;
						SliceSpacing := 0.0;
						FrameInterval := 0.0;
						StackType := VolumeStack;
					end;
				PictureType := NewPicture;
				MakeStackFromWindow := true;
			end;
	end;

	
	procedure SelectSlice (i: integer);
	begin
		with info^, info^.StackInfo^ do
			if i <= nSlices then begin
					hunlock(PicBaseHandle);
					PicBaseHandle := PicBaseH[i];
					hlock(PicBaseHandle);
					{$ifc PowerPC}
					PicBaseAddr := PicBaseHandle^;
					{$elsec}
					PicBaseAddr := StripAddress(PicBaseHandle^);
					{$endc}
					osPort^.PortPixMap^^.BaseAddr := PicBaseAddr;
				end;
	end;


	procedure UpdateWindowsMenuItem;
		var
			str: str255;
			picSize: LongInt;
	begin
		with info^ do begin
			PicSize := PixMapSize;
			if StackInfo <> nil then
				PicSize := PicSize * StackInfo^.nSlices;
			NumToString((PicSize + 511) div 1024, str);
			str := concat(title, '  ', str, 'K');
			SetMenuItemText(WindowsMenuH, PicNum + WindowsMenuItems + nTextWindows, str);
		end;
	end;


	function AddSlice (update: boolean): boolean;
		var
			i: integer;
			h: handle;
			isRoi: boolean;
	begin
		with info^, info^.StackInfo^ do begin
				AddSlice := false;
				if nSlices = MaxSlices then
					exit(AddSlice);
				isRoi := RoiShowing;
				if isRoi then
					KillRoi;
				h := GetBigHandle(PixMapSize);
				if h = nil then begin
						PutError('Not enough memory available to add a slice to this stack.');
						AbortMacro;
						exit(AddSlice);
					end;
				for i := nSlices downto CurrentSlice + 1 do
					PicBaseH[i + 1] := PicBaseH[i];
				nSlices := nSlices + 1;
				CurrentSlice := CurrentSlice + 1;
				PicBaseH[CurrentSlice] := h;
				SelectSlice(CurrentSlice);
				if Update then begin
						SelectAll(false);
						DoOperation(EraseOp);
						UpdatePicWindow;
					end;
				if (StackType = rgbStack) and (nSlices <> 3) then
					StackType := VolumeStack;
				UpdateTitleBar;
				if isRoi then
					RestoreRoi;
				WhatToUndo := NothingToUndo;
				AddSlice := true;
				changes := true;
				PictureType := NewPicture;
				UpdateWindowsMenuItem;
			end;
	end;
	
	
	procedure AbortMacro;
	{If a macro is running, abort it.}
	begin
		macro := false;
	end;
	
	
	procedure TruncateString(var str: str255; len: integer);
	begin
{if length(str) > len then
	beep;}
			if length(str) > len then
			delete(str, len + 1, length(str) - len);
	end;

{ AE - RMD 2/10/95
	This routine forces Image to the front and is called before any dialog
	that accepts user input.  This is necessary as AppleEvent processing can occur
	with when Image is in the background and the dialog might be hidden.  Some
	dialogs, expecially the StandardGetFile and StandardPutFile, will crash.
} 
	function	ForceToFront: OSErr;
	var
		reqFront:NMrec;	
	begin
			reqFront.qType := ord(nmType);
			reqFront.nmMark := 1;
			reqFront.nmIcon := nil;
			reqFront.nmSound := nil;
			reqFront.nmStr := nil;
			reqFront.nmResp := nil;
			reqFront.nmRefCon := 0;
			ForceToFront := AEInteractWithUser( 60, @reqFront, nil );
	end;
			
	end.