#pragma rtGlobals=1		// Use modern global access method.
#pragma IgorVersion = 6.2
#pragma version = 4.2.2
#include <Scatter Plot Matrix 2>
#include <All Gizmo Procedures>
#include <Autosize Images>
#include <Wave Arithmetic Panel>
#include <Multi-peak fitting 2.0>
#include <Global Fit 2>

// written by Matt Sfeir, Brookhaven National Laboratory
// msfeir@bnl.gov
// v.4.2 January 17. 2012

//  Build menu items

Menu "Load Waves"
	"Load Transient Absorption Data", OpenTA()
End

Menu "TA Analysis"
	"Load Transient Absorption Data", OpenTA()
	"-"
	"Inspect Image Data", ImageHookGen()
//	"Kill Data Inspector", KillHookGen()
//	"-"	
	"Extract Kinetics", ExtractKin()
	"Extract Spectra", ExtractSpec()
	"-"
	"Time Zero Correction", T0ImCorr()
	"Scattered Light Correction", DisplayIntBkgdControlPanel()
	"Extract Region of Interest", ImageROI()
	"-"
	"Import SX Pro Solvent Fit Coeffs", ImportCC()
	"Generate Fit Coeffs from Solvent Response",FitSolvFC()
	"-"
	"Generate t0 wave from Fit Coeffs", t0WaveGen()
	"Chirp Correction from t0 Wave", ChirpCorrect()
	"-"
	"Singular Value Decomposition", AutoSVG()
	"Rank SVD Matrices", RankSVD()
	"Global Fit", WM_NewGlobalFit1#InitNewGlobalFitPanel()
	"-"
	"Generate Progressive Time Axis", ExpTimeAxis()

End

///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////

//  For debugging.  Remove Later.
Function KillHookGen()
	//DoWindow/K kinetics0
	//DoWindow/K spectra0
	DoWindow/K kinetics
	DoWindow/K spectra
	KillDataFolder root:Packages:InspectData
	return 0
End


///////////////////////////////////////////////////////////////////////////////////////////////

// Modify Open File Dialog to break if cancelled

Function OpenTA()
	Variable refNum
	String message = "Select a file" 
	String outputPath, fileHandle, wName, wName2
	String fileFilters = "Transient Absorption Data Files (*.csv):.csv;" 
	fileFilters += "All Files:.*;" 
	Open /D /R /F=fileFilters /M=message refNum 
	outputPath = S_fileName
	printf "%s\r" outputPath
	fileHandle = ParseFilePath(5, outputPath, ":", 0,0)
	fileHandle = ParseFilePath(3, outputPath, ":", 0,0)
	printf "%s\r" fileHandle
	Variable lengthTest = strlen(fileHandle)
//  shorten string to 22 characters to satisfy Igor constraints on wave name length
//  max is 31.  start with 22 so that we can append suffix.
	fileHandle = CleanUpName(fileHandle, 0)
	if(lengthTest >= 22)
		Variable i = lengthTest - 22
		Variable j=0
		do
			fileHandle = RemoveEnding(fileHandle)
			j+=1
		while(j <= i)
	else
		fileHandle = fileHandle
	endif

	LoadWave/J/M/U={0,2,0,2}/D/A=$fileHandle/K=0 outputPath
	
	// WaveExists  1 valid 0 invalid
	wName = fileHandle +"0"
	Variable b=0

	if (WaveExists ($wName) == 1)
		do
			b += 1
			wName2 = fileHandle + num2str(b)
		while(WaveExists ($wName2) == 1)
		// write b-1 since loop runs one more time than we want
		wName = fileHandle + num2str(b-1)
	endif	
	
	
	Print wName
	Variable cancelTest = cmpstr(outputPath, "")
	if (cancelTest == 0)
		Print "Open file cancelled."
	else
		ProcessTA(wName, outputPath)
	endif
End

// Loads waves and processes them for plotting
// Called by OpenTA()
Function ProcessTA(wName, outputPath)  // CMD - . aborts the procedure
	String wName, outputPath

	Duplicate $wName w
	String RPName = "RP_" + wName
	String CPName = "CP_" + wName
	Wave RP =RPName
	Wave CP =CPName
	Duplicate $RPName RP
	Duplicate $CPName CP

//	Wave w,RP,CP	
	Variable m, n, pp, qq, r
	
// remove NaNs and Infs.  Replace with zeros.

	m = Dimsize(w,0) // numer of rows
//	printf "%f\r" m
	n = Dimsize(w,1) // number of columns	
	
	Make/N=(m,n) /D/O Zmat
	Zmat= (numtype(w) == 1) ? 0  : w
	Zmat= (numtype(Zmat) == 2) ? 0  : Zmat
	
	Make/N=(m) /D/O ContX
	ContX= (numtype(RP) == 1) ? 0  : RP
	ContX= (numtype(ContX) == 2) ? 0  : ContX

// remove extra rows - often contain bad data
// re-write to handle arbitrary sized wavelength dimension while scaling is monotonic, increasing

	qq = Dimsize(ContX,0)
	Variable aa = qq
	Do
		Redimension /N=(aa) ContX
		Redimension /N=(aa,-1) Zmat
		aa-=1
	While(ContX[aa] <= ContX [aa-1])
	qq = Dimsize(ContX,0)
//	Print qq

// use new length information to import footer text
// needs to be handled after extra rows are removed so we know where to start importing
// without resorting to regular expressions
	Variable refNum2
	String buffer
	Variable linenumber, len
	linenumber = 0
	Open/R refNum2 outputPath
	do
		FReadLine refNum2, buffer
		len = strlen(buffer)
		if(len == 0)
			break
		endif
		if(linenumber > qq)
			Print buffer
			Note/NOCR Zmat, buffer
		endif
		linenumber +=1
	while(1)
	Close refNum2

// continue with formatting
	
	m = Dimsize(Zmat,0) // numer of rows
	n = Dimsize(Zmat,1) // number of columns
	pp = m*n
			
	Make/N=(n) /D/O ContY
	ContY= (numtype(CP) == 1) ? 0  : CP
	ContY= (numtype(ContY) == 2) ? 0  : ContY

	Make/N=(pp) /D/O tempXwave
	Make/N=(pp) /D/O tempYwave
	Make/N=(pp) /D/O tempZwave
	
	Make/N=(m+1) /D/O ImageX
	Make/N=(n+1) /D/O ImageY
	
	Make/N=(M,N,3) /O ParametricWave

// create new processed row, column positions and z matrix
// can be used to generate contour plot
	
	Variable i,j
	
	i=0
	do
		j=0
		do	
			tempXwave[j+m*i]=ContX[j]
			tempYwave[j+m*i]=ContY[floor((j+m*i)/m)]
			tempZwave[j+m*i]=Zmat[j][i]
			j +=1
		while (j <=m)
	i +=1	
	while (i <= n)
	
	Concatenate/O {tempXwave, tempYwave, tempZwave}, wScatterMatrix
	KillWaves tempXwave, tempYwave, tempZwave
	
// Format for Image Plot
// Create x and y wave for image.  Points define start and end of pixel positions, not center 
// so need to generate N+1 points from N.
// Add point at [-1] at same distance from [0] as [1]
// and shift by [0] - [1] distance OR pick midpoint between consecutive points
// assuming smallest increment at start of wave


// this needs to be modifed to ensure that data is monotonic
//  bug in 
	Variable g, h
	
	ImageX[0]= ContX[0]-((ContX[1]-ContX[0])/2)
//	g = 0
//	do
//		ImageX[g+1]=ContX[g]+((ContX[1]-ContX[0])/2)
//		g += 1
//	while (g <= m)
	g=1
	do
		ImageX[g] = (ContX[g] + ContX[g-1])/2
		g += 1
	while (g < m)
	ImageX[m] = ContX[m-1] + ((ContX[m-1] - ContX[m-2])/2)


	ImageY[0]= ContY[0]-((ContY[1]-ContY[0])/2)
//	h=0
//	do
//		ImageY[h+1]=ContY[h]+((ContY[1]-ContY[0])/2)
//		h += 1
//	while (h <= n)
	h=1
	do
		ImageY[h] = (ContY[h] + ContY[h-1])/2
		h+= 1
	while (h < n)
	ImageY[n] = ContY[n-1] + ((ContY[n-1] - ContY[n-2])/2)

	// start looking for non-monotonic behavior at point 1 not point 0
	// assume first 2 points are good
	Variable h2 = 1
	Variable deltaNM
	Variable ipts, jpts
	//Variable h2orig
	do
		ipts = 2
		// first find 2 consecutive equal points
		if (ImageY[h2] == ImageY[h2+1])
			// now check for more using ipts as a counting variable
			//Print "non-monotonic"
			do
				if(ImageY[h2] == ImageY[h2+ipts])
					ipts+=1
				else
					//Print "breaking . . ."
					break
				endif
			while(ipts<100)
			// use ipts and previous non-equal point to define spacing
			deltaNM = Abs((ImageY[h2+ipts]-ImageY[h2] ))/ipts
			//print deltaNM
			jpts = 0
			do
				ImageY[h2+jpts] = ImageY[h2+jpts] + (jpts)*deltaNM
				jpts +=1
			while(jpts < ipts)
		endif
		//Print h2
		h2 +=1
	// stop one point before the end	
	while(h2 < n -1)
	

// generate Parametic data.
// used for uneven spacings in surface plots

	Variable k,l
	
	k=0
	do
		l=0
		do
			ParametricWave[k][l][0]=ContX[k]
			ParametricWave[k][l][1]=ContY[l] 
			ParametricWave[k][l][2]=Zmat[k][l]
			l +=1
		while (l <= n)
	k +=1
	while (k <= m)

// clean up wave names
	
//	String ZmatName = NameOfWave(w) + "_zmat"
	String ZmatName = wName + "_zmat"
	Duplicate/O Zmat, $ZmatName
	KillWaves Zmat
	
//	String ContXName = NameOfWave(w) + "_xc"
	String ContXName = wName + "_xc"
	Duplicate/O ContX, $ContXName
	KillWaves ContX
	
//	String ContYName = NameOfWave(w) + "_yc"
	String ContYName = wName + "_yc"
	Duplicate/O ContY, $ContYName
	KillWaves ContY
	
//	String ImageXName = NameOfWave(w) + "_xim"
	String ImageXName = wName + "_xim"
	Duplicate/O ImageX, $ImageXName
	KillWaves ImageX
	
//	String ImageYName = NameOfWave(w) + "_yim"
	String ImageYName = wName + "_yim"
	Duplicate/O ImageY, $ImageYName
	KillWaves ImageY
	
//	String ScatMatName = NameOfWave(w) + "_sca"
	String ScatMatName = wName + "_sca"
	Duplicate/O wScatterMatrix, $ScatMatName
	KillWaves wScatterMatrix
	
//	String ParaName = NameOfWave(w) + "_par"
	String ParaName = wName + "_par"
	Duplicate/O ParametricWave, $ParaName
	KillWaves ParametricWave, w, RP, CP

// kill orignal waves generated by LoadFile before processing
	KillWaves $wName, $RPName, $CPName

// Generate default image	

	Display;AppendImage $ZmatName vs {$ImageXName,$ImageYName};DelayUpdate
	ModifyImage $ZmatName ctab= {*,*,Rainbow,0}
	ModifyImage $ZmatName ctabAutoscale=3,lookup= $""
	ShowInfo
	
	GetWindow kwTopWin wtitle
	String imTitle = S_Value
	imTitle = RemoveEnding(imTitle, ":")
	Cursor/I/H=1 /W=$imTitle A $ZmatName 1,1
	Cursor/M/H=1 B
	
	// if inspector is already enabled on other images
	// enable by default on subsequent images
	//DoWindow kinetics0
//	DoWindow kinetics
//	if (V_Flag == 1)
//		SetWindow $imTitle, hook(MyHook)=MyWindowHook
//	else
//		return 0
//	endif
//	DoUpdate

	ImageHookGen()
	
	return 0
	
End

/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

//  Inspect Image Data section
// Apply Window Hook Calls to existing image

Function ImageHookGen()

//  No need to build new image
//  Just apply window hook function to top window
//  first make sure this is an image

	String ImTest = ImageInfo("","",0)
	//  make this only applicable to images
	if(cmpstr(Imtest,"",0) == 0)
		Print "Not an image."
		return 0
	else
		String info= ImageInfo("","",0)
		String zmatName = StringByKey("ZWAVE",info)
		String xwName = StringByKey("XWAVE",info)
		String ywName = StringByKey("YWAVE",info)
		// figure out which one is z
		String Zregex = "(.*?)(zmat|zibg|zroi|zccm|A.sv)"
		Print "Z = " + zmatName

		GetWindow kwTopWin, wtitle
		String imTitle = S_Value
	//	Cursor/I A $ZMatName 1,1
	
	//  add call for Window Hook - testing phase

		SetWindow kwTopWin, hook(MyHook)=MyWindowHook

	// build window for displaying kinetics
		String base, xybase
		String suffix, xysuffix
		String regex = "(.*?)(zmat|zibg|zroi|zccm|A.sv)"
		SplitString /E=(regex) ZMatName, base, suffix
		
		String XYregex = "(.*?)(ximr|xim|xcim)"
		SplitString /E=(XYregex) xwName, xybase, xysuffix
		Print xysuffix
		if(CmpStr(xysuffix,"")==0)
			xwName = "NewXwave"
			ywName = "NewYWave"
		elseif(CmpStr(xysuffix,"ximr")==0)
			ywName = xybase + "yroi"
			xwName = xybase + "xroi"
		elseif(CmpStr(xysuffix,"xcim")==0)
			ywName = xybase + "ycc"
			xwName = xybase + "xcc"
		elseif(CmpStr(xysuffix,"xim")==0)
			ywName = xybase + "yc"
			xwName = xybase + "xc"	
		endif
		
		
	endif
	
	//  first data to display for kinetics
	Variable xpos, lambda
	xpos = pcsr(A)
	lambda = hcsr(A)
	//  first data to display for spectra
	Variable ypos, stime	
	ypos = qcsr(A)
	stime = vcsr(A)
	
	// build kinetics graph
	Wave kM = $ZMatName
		
	//	Wave lM = $xwName
	
	// generate target wave for kinetic information
	// named appropriately with the wavelength
	
	Variable m,n
	m = Dimsize(kM,0) // numer of rows
	n = Dimsize(kM,1) // number of columns

	// name with generic name so it can be continuously overwritten
	// can be copied later with appropriate command	
	// String kWaveName = "kinetics"
	// String sWaveName = "spectra"
	String kWaveName = "kineticsA"
	String sWaveName = "spectraA"

	// why do we change names here?
	String tWave = ywName
	//  . . . and lambda wave
	String sWave = xwName
	
	Make/D/O/N=(n) $kWaveName
	Wave w = $kWaveName
	
	Make/D/O/N=(m) $sWaveName
	Wave v = $sWaveName
	
	// replace with MatrixOp 

	//w = kM[xpos] [p]
	MatrixOp/O w = row(kM,xpos)^t
	//v = kM[p][ypos]
	MatrixOp/O v = col(kM, ypos)

	// break out graphing function so that the panel can be modified
	
	//  first create global variables if they don't exist
	if(DataFolderExists("root:Packages:InspectData") == 0)
		NewDataFolder/O root:Packages:InspectData
	endif
	String/G root:Packages:InspectData:gMessagek= ""
	String/G root:Packages:InspectData:gMessagekB= ""		
	String/G root:Packages:InspectData:gMessageki= ""
	String/G root:Packages:InspectData:gMessageXSck= ""
	String/G root:Packages:InspectData:gMessageYSck= ""
		
	Variable/G root:Packages:InspectData:gCursB= 0
		
	String/G root:Packages:InspectData:gMessages= ""
	String/G root:Packages:InspectData:gMessagesB= ""
	String/G root:Packages:InspectData:gMessagesi= ""
	String/G root:Packages:InspectData:gMessageXScs= ""
	String/G root:Packages:InspectData:gMessageYScs= ""
		
	// next fill in string values
	SVAR gMessagek = root:Packages:InspectData:gMessagek
	SVAR gMessagekB = root:Packages:InspectData:gMessagekB
	SVAR gMessageki = root:Packages:InspectData:gMessageki
	gMessagek = num2str(lambda)
	gMessageki = ZMatName
		
	NVAR gCursB = root:Packages:InspectData:gCursB
		
	SVAR gMessages = root:Packages:InspectData:gMessages
	SVAR gMessagesB = root:Packages:InspectData:gMessagesB
	SVAR gMessagesi = root:Packages:InspectData:gMessagesi
	gMessages = num2str(stime)
	gMessagesi = ZMatName
		
	//  make waves for cursor B anyway
	//  same size as A
	String kWaveNameB = "kineticsB"
	String sWaveNameB = "spectraB"
			
	Make/D/O/N=(n) $kWaveNameB
	Make/D/O/N=(m) $sWaveNameB
		
	Wave wB = $kWaveNameB
	Wave vB = $sWaveNameB
		
	Variable xposB, lambdaB	
	Variable yposB, stimeB	
		
	// initialize properly if B is on graph
		
	Variable bExists= strlen(CsrInfo(B)) > 0
	if (bExists == 1)
		gCursB = 1
		//  first data to display for kinetics			
		xposB = pcsr(B)
		lambdaB = hcsr(B)
		gMessagekB= num2str(lambdaB)
			
		//  first data to display for spectra
		yposB = qcsr(B)
		stimeB = vcsr(B)
		gMessagesB = num2str(stimeB)
			
		//wB = kM[xposB] [p]
		MatrixOp/O wB = row(kM, xposB)^t
		//vB = kM[p][yposB]
		MatrixOp/O vB = col(kM, yposB)
	else
		gCursB = 0
		gMessagekB = ""
		gMessagesB = ""
	endif
		
	//  now build graphs
	InspectGraphK(kWaveName, tWave, "kinetics")
	InspectGraphS(sWaveName, sWave, "spectra")
		
	// do these only if cursor B is already on the graph
	if (bExists == 1)
		InspectGraphK(kWaveNameB, tWave, "kinetics")
		InspectGraphS(sWaveNameB, sWave, "spectra")
	endif
	return 0
		
End



Function InspectGraphK(ywave, xwave, wvname)
	String ywave, xwave, wvname
	//String wwname = wvname + "0"
	String wwname = wvname 
//	Print wwname
	// make sure proper folder exists for global variables
	// do not switch to this folder

	SVAR gMessagek = root:Packages:InspectData:gMessagek
	SVAR gMessageki = root:Packages:InspectData:gMessageki

	SVAR gMessagekB = root:Packages:InspectData:gMessagekB
	NVAR gCursB = root:Packages:InspectData:gCursB

	SVAR gMessageXSck = root:Packages:InspectData:gMessageXSck
	SVAR gMessageYSck = root:Packages:InspectData:gMessageYSck
	
	String grState
		
// create new graph if it doesn't exist
// this will only add the first trace that is called (A cursor)
// we need to incorporate logic that will add the second trace under the right conditions
	DoWindow/F $wwname
	if (V_Flag == 0)
		Display/W=(505,42,1068,414)/K=2/N=$wvname $ywave vs $xwave as wvname
		ControlBar 50
		SetVariable msg,pos={12,10},size={120,17},title="A Wavelength "
		SetVariable msg,limits={-Inf,Inf,1},value= root:Packages:InspectData:gMessagek
		SetVariable msg5,pos={142,10},size={120,17},fcolor=(65535,0,0),title="B Wavelength "
		SetVariable msg5,limits={-Inf,Inf,1},value= gMessagekB		
		SetVariable msg2,pos={280,10},size={230,17},title="Image     "
		SetVariable msg2,limits={-Inf,Inf,1},value= root:Packages:InspectData:gMessageki
		SetVariable msg3,pos={12,30},size={250,17},title="X Scaling        "
		SetVariable msg3,limits={-Inf,Inf,1},value= root:Packages:InspectData:gMessageXSck
		SetVariable msg4,pos={280,30},size={230,17},title="Y Scaling "
		SetVariable msg4,limits={-Inf,Inf,1},value= root:Packages:InspectData:gMessageYSck	
		ModifyGraph/Z rgb[0] = (0,0,0)
		ModifyGraph/Z rgb[1] = (65535,0,0)
	else
		grState = TraceNameList("",":",1)
		// first ask if both traces are already on the graph
		// then we do nothing
		if(CmpStr(grState, "kineticsA:kineticsB:")== 0)
			return 0
		// next ask if the wave on which we are running this function already exists on the graph
		elseif(CmpStr(grState, ywave + ":") == 0)
			return 0
		// if not, append to graph
		else
			Print xwave
			AppendToGraph $ywave vs $xwave
		endif
	endif
//	SetWindow kwTopWin,hook(MyHook)=MyWindowHook //hook=SimpleInfoHook,hookevents=3
	SetWindow $wwname,hook(MyHook)=MyWindowHook //hook=SimpleInfoHook,hookevents=3
//	SetWindow kwTopWin,hook=MyWindowHook 
	DoUpdate
End

Function InspectGraphS(ywave, xwave, wvname)
	String ywave, xwave, wvname
	//String wwname = wvname + "0"
	String wwname = wvname 
	// make sure proper folder exists for global variables
	// do not switch to this folder
	if(DataFolderExists("root:Packages:InspectData") == 0)
		NewDataFolder/O root:Packages:InspectData
	endif
	SVAR gMessages = root:Packages:InspectData:gMessages
	SVAR gMessagesi = root:Packages:InspectData:gMessagesi
	SVAR gMessageXScs = root:Packages:InspectData:gMessageXScs
	SVAR gMessageYScs = root:Packages:InspectData:gMessageYScs
	
	String grState
	
// create new graph if it doesn't exist
	DoWindow/F $wwname
	if (V_Flag == 0)
		Display/W=(505,442,1068,814)/K=2/N=$wvname $ywave vs $xwave as wvname
		ControlBar 50
		SetVariable msg,pos={12,10},size={120,17},title="A Time        "
		SetVariable msg,limits={-Inf,Inf,1},value= root:Packages:InspectData:gMessages
		SetVariable msg5,pos={142,10},size={120,17},fcolor=(65535,0,0),title="B Time       "
		SetVariable msg5,limits={-Inf,Inf,1},value= root:Packages:InspectData:gMessagesB
		SetVariable msg2,pos={280,10},size={230,17},title="Image     "
		SetVariable msg2,limits={-Inf,Inf,1},value= root:Packages:InspectData:gMessagesi
		SetVariable msg3,pos={12,30},size={250,17},title="X Scaling     "
		SetVariable msg3,limits={-Inf,Inf,1},value= root:Packages:InspectData:gMessageXScs
		SetVariable msg4,pos={280,30},size={230,17},title="Y Scaling "
		SetVariable msg4,limits={-Inf,Inf,1},value= root:Packages:InspectData:gMessageYScs	
		ModifyGraph/Z rgb[0] = (0,0,0)
		ModifyGraph/Z rgb[1] = (65535,0,0)
	else
		grState = TraceNameList("",":",1)
		if(CmpStr(grState, "spectraA:spectraB:")== 0)
			return 0
		elseif(CmpStr(grState, ywave + ":") == 0)
			return 0
		else
			AppendToGraph $ywave vs $xwave
		endif
	endif		
	SetWindow $wwname,hook(MyHook)=MyWindowHook 
	DoUpdate
	
End

// begin Window Hook implementation
// testing phase

Function MyWindowHook(s)
	STRUCT WMWinHookStruct &s
	
	Variable hookResult = 0
//	Wave wk = kinetics
//	Wave ws = spectra
	Wave wk = kineticsA
	Wave ws = spectraA
	
	Wave wkB = kineticsB
	Wave wsB = spectraB

// do this when procedure is called

	String ImTest = ImageInfo("","",0)
	//  make this only applicable to images
	if(cmpstr(Imtest,"",0) == 0)
		//Print "Not an image."
		return 0
	else
		String info= ImageInfo("","",0)
		String zmatName = StringByKey("ZWAVE",info)
		String xwName = StringByKey("XWAVE",info)
		String ywName = StringByKey("YWAVE",info)
		//String Zregex = "(.*?)(zmat|zibg|zroi|zccm|A.sv)"
		Wave kM = $zmatName
	endif
	
// initalize variables for case 0, image window get activated
	String grtitle
	String base, xybase
	String suffix, xysuffix
	String regex = "(.*?)(zmat|zibg|zroi|zccm|A.sv)"
	SplitString /E=(regex) ZMatName, base, suffix
	
	String XYregex = "(.*?)(ximr|xim|xcim)"
	SplitString /E=(XYregex) xwName, xybase, xysuffix
	String tWave, sWave
	if(CmpStr(xysuffix,"")==0)
		tWave = "EmptyTimeWave"
		sWave = "EmptyLamWave"
	elseif(CmpStr(xysuffix,"ximr")==0)
		tWave = xybase + "yroi"
		sWave = xybase + "xroi"
	elseif(CmpStr(xysuffix,"xcim")==0)
		tWave = xybase + "ycc"
		sWave = xybase + "xcc"
	elseif(CmpStr(xysuffix,"xim")==0)
		tWave = xybase + "yc"
		sWave = xybase + "xc"	
	endif
	
	Variable colsize, rowsize, xpos, ypos, lambda, stime

	Variable xposB, lambdaB	
	Variable yposB, stimeB	
	Variable bExists
	
	//  add global variable references for the PreserveGraphScaling function
	PreserveGraphScaling("kinetics","k")
	PreserveGraphScaling("spectra","s")
	
	//  what is happening here?
	// are we resetting the values somehow???
	NVAR gvaslk = root:Packages:InspectData:gvaslk
	NVAR gvasbk = root:Packages:InspectData:gvasbk
	NVAR gvlmink = root:Packages:InspectData:gvlmink
	NVAR gvlmaxk = root:Packages:InspectData:gvlmaxk
	NVAR gvbmink = root:Packages:InspectData:gvbmink
	NVAR gvbmaxk = root:Packages:InspectData:gvbmaxk
	//PreserveGraphScaling("spectra0","s")
	
	//  add global variable references for the PreserveGraphScaling function
	NVAR gvasls = root:Packages:InspectData:gvasls
	NVAR gvasbs = root:Packages:InspectData:gvasbs
	NVAR gvlmins = root:Packages:InspectData:gvlmins
	NVAR gvlmaxs = root:Packages:InspectData:gvlmaxs
	NVAR gvbmins = root:Packages:InspectData:gvbmins
	NVAR gvbmaxs = root:Packages:InspectData:gvbmaxs
	// global variables for graph messages
	SVAR gMessagek = root:Packages:InspectData:gMessagek
	SVAR gMessageki = root:Packages:InspectData:gMessageki
	SVAR gMessageXSck = root:Packages:InspectData:gMessageXSck
	SVAR gMessageYSck = root:Packages:InspectData:gMessageYSck
		
	SVAR gMessagekB = root:Packages:InspectData:gMessagekB
	SVAR gMessagesB = root:Packages:InspectData:gMessagesB
	NVAR gCursB = root:Packages:InspectData:gCursB
		
	SVAR gMessages = root:Packages:InspectData:gMessages
	SVAR gMessagesi = root:Packages:InspectData:gMessagesi
	SVAR gMessageXScs = root:Packages:InspectData:gMessageXScs
	SVAR gMessageYScs = root:Packages:InspectData:gMessageYScs

//	Print gvaslk

	switch(s.eventcode)
		// activate window
		case 0:
			//Print "case 0"
			//Print gvaslk
			//PreserveGraphScaling("kinetics0","k")
			PreserveGraphScaling("kinetics","k")
			
			
			// update for window hook calls on kinetics or spectra window
			// just updates control bar fields
			GetWindow kwTopWin, wtitle
			grTitle = S_Value
//			Print grTitle
			
			if(CmpStr(grTitle,"kinetics",0) == 0)
				
				PreserveGraphScaling("kinetics","k")	
				if(gvaslk == 1)
					gMessageYSck = num2str(gvlmink) +", "+ num2str(gvlmaxk)
				else
					gMessageYSck = "Auto"
				endif
				
				if(gvasbk == 1)
					gMessageXSck = num2str(gvbmink) +", "+ num2str(gvbmaxk)
				else
					gMessageXSck = "Auto"
				endif
				
				hookresult = 1
				break			
			endif
			
			// do the same for the spectra graph
			GetWindow kwTopWin, wtitle
			grTitle = S_Value
//			Print grTitle
			if(CmpStr(grTitle,"spectra",0) == 0)
				
				PreserveGraphScaling("spectra","s")	
				if(gvasls == 1)
					gMessageYScs = num2str(gvlmins) +", "+ num2str(gvlmaxs)
				else
					gMessageYScs = "Auto"
				endif
				
				if(gvasbs == 1)
					gMessageXScs = num2str(gvbmins) +", "+ num2str(gvbmaxs)
				else
					gMessageXScs = "Auto"
				endif
				
				hookresult = 1
				break			
			endif
			

			// may need to plot against new time wave if we have switched windows
			

			// update dimensions of the kinetics wave
			colsize = Dimsize(kM,1) // numer of columns
			rowsize = DimSize(kM,0) // number of rows
			Redimension/N=(colsize) kineticsA
			Redimension/N=(rowsize) spectraA
				
			// re-initialize graph
			//DoWindow kinetics0
			DoWindow kinetics
			if (V_Flag == 0)
				return 0
			else
				// RemoveFromGraph/W=kinetics0 kinetics
				// AppendToGraph/W=kinetics0 kinetics vs $tWave
				RemoveFromGraph/W=kinetics kineticsA
				AppendToGraph/W=kinetics kineticsA vs $tWave
			endif
				
			//DoWindow spectra0
			DoWindow spectra
			if (V_Flag == 0)
				return 0
			else				
				// RemoveFromGraph/W=spectra0 spectra
				// AppendToGraph/W=spectra0 spectra vs $sWave
				RemoveFromGraph/W=spectra spectraA
				AppendToGraph/W=spectra spectraA vs $sWave
			endif
								
			xpos = pcsr(A)
			ypos = qcsr(A)
			lambda = hcsr(A)
			stime = vcsr(A)
				
			gMessagek = num2str(lambda)
			gMessageki = ZMatName
				
			gMessages = num2str(stime)
			gMessagesi = ZMatName
				
			//wk = kM[xpos] [p]
			MatrixOp/O wk = row(kM, xpos)^t
			//ws = kM[p] [ypos]
			MatrixOp/O ws = col(kM, ypos)
				
			// the cursor calls reset the graph scaling need to fix it here
			// include temp variable to reset axes back to default
			Variable gvaslktemp = gvaslk
			Variable gvasbktemp = gvasbk
				
			Variable gvaslstemp = gvasls
			Variable gvasbstemp = gvasbs
				
			Cursor/H=2/W=kinetics A kineticsA ypos
			Cursor/H=2/W=spectra A spectraA xpos
				
			gvaslk = gvaslktemp
			gvasbk = gvasbktemp
				
			gvasls = gvaslstemp
			gvasbs = gvasbstemp
				
			// this is repeated during image operations
			// also calls setaxis so state of graph is preseved if not autoscaled
			if(gvaslk == 1)
				//SetAxis/W=kinetics0 left, gvlmink, gvlmaxk
				SetAxis/W=kinetics left, gvlmink, gvlmaxk
				gMessageYSck = num2str(gvlmink) +", "+ num2str(gvlmaxk)
			else
					gMessageYSck = "Auto"
			endif
				
			if(gvasbk == 1)
				//SetAxis/W=kinetics0 bottom, gvbmink, gvbmaxk
				SetAxis/W=kinetics bottom, gvbmink, gvbmaxk
				gMessageXSck = num2str(gvbmink) +", "+ num2str(gvbmaxk)
			else
				gMessageXSck = "Auto"
			endif
				
			if(gvasls == 1)
				//SetAxis/W=spectra0 left, gvlmins, gvlmaxs
				SetAxis/W=spectra left, gvlmins, gvlmaxs
				gMessageYScs = num2str(gvlmins) +", "+ num2str(gvlmaxs)
			else
				gMessageYScs = "Auto"
			endif
				
			if(gvasbs == 1)
				//SetAxis/W=spectra0 bottom, gvbmins, gvbmaxs
				SetAxis/W=spectra bottom, gvbmins, gvbmaxs
				gMessageXScs = num2str(gvbmins) +", "+ num2str(gvbmaxs)
			else
				gMessageXScs = "Auto"
			endif				
				
				
				// updates for cursor B
			bExists= strlen(CsrInfo(B)) > 0
			if (bExists == 1)
				gCursB = 1
				Redimension/N=(colsize) kineticsB
				Redimension/N=(rowsize) spectraB
				DoWindow kinetics
				if (V_Flag == 0)
					return 0
				else
					RemoveFromGraph/Z/W=kinetics kineticsB
					AppendToGraph/W=kinetics kineticsB vs $tWave
				endif
				
				DoWindow spectra
				if (V_Flag == 0)
					return 0
				else				
					RemoveFromGraph/Z/W=spectra spectraB
					AppendToGraph/W=spectra spectraB vs $sWave
				endif
				
				//  first data to display for kinetics			
				xposB = pcsr(B)
				lambdaB = hcsr(B)
				gMessagekB= num2str(lambdaB)
			
				//  first data to display for spectra
				yposB = qcsr(B)
				stimeB = vcsr(B)
				gMessagesB = num2str(stimeB)
			
				//wkB = kM[xposB] [p]
				MatrixOp/O wkB = row(kM, xposB)^t			
				//wsB = kM[p][yposB]
				MatrixOp/O wsB = col(kM, yposB)
					
				Cursor/H=2/C=(65535,0,0)/W=kinetics B kineticsB yposB
				Cursor/H=2/C=(65535,0,0)/W=spectra B spectraB xposB
			else
				gCursB = 0
				gMessagekB = ""
				gMessagesB = ""
				RemoveFromGraph/Z/W=kinetics kineticsB
				RemoveFromGraph/Z/W=spectra spectraB
				Cursor/K/W=kinetics B
				Cursor/K/W=spectra B
			endif
				
			ModifyGraph/Z/W=kinetics rgb[0] = (0,0,0)
			ModifyGraph/Z/W=kinetics rgb[1] = (65535,0,0)
			ModifyGraph/Z/W=spectra rgb[0] = (0,0,0)
			ModifyGraph/Z/W=spectra rgb[1] = (65535,0,0)
				
				
				
			hookresult = 1
			break
			
			
//  implement cursor move part
		//  current problem with cursor move - activate seems ok
		//null string variable on startup
		case 7:
			//Print "case 7"
			//Print "1: " + num2str(gvaslk)
			// mouse move
//			Print s.pointnumber
//			Print s.yPointNumber	
			//PreserveGraphScaling("kinetics0","k")	
			PreserveGraphScaling("kinetics","k")
			//PreserveGraphScaling("spectra0","s")
			PreserveGraphScaling("spectra","s")
			//Print "2: " + num2str(gvaslk)
				
			xpos = pcsr(A)
			ypos = qcsr(A)
			
			//wk = kM[xpos] [p]
			MatrixOP/O wk = row(kM,xpos)^t
			//ws = kM[p][ypos]
			MatrixOp/O ws = col(kM, ypos)
			
			lambda = hcsr(A)
			gMessagek = num2str(lambda)
			gMessageki = ZMatName
			
			stime = vcsr(A)
			gMessages = num2str(stime)
			gMessagesi = ZMatName
				
			Cursor/H=2/W=kinetics A kineticsA ypos
			Cursor/H=2/W=spectra A spectraA xpos
				
			if(gvaslk == 1)
				//SetAxis/W=kinetics0 left, gvlmink, gvlmaxk
				SetAxis/W=kinetics left, gvlmink, gvlmaxk
			endif
				
			if(gvasbk == 1)
				//SetAxis/W=kinetics0 bottom, gvbmink, gvbmaxk
				SetAxis/W=kinetics bottom, gvbmink, gvbmaxk
			endif
				
			if(gvasls == 1)
				//SetAxis/W=spectra0 left, gvlmins, gvlmaxs
				SetAxis/W=spectra left, gvlmins, gvlmaxs
			endif
				
			if(gvasbs == 1)
				//SetAxis/W=spectra0 bottom, gvbmins, gvbmaxs
				SetAxis/W=spectra bottom, gvbmins, gvbmaxs
			endif
			
				// updates for cursor B
	//			Variable xposB, lambdaB	
	//			Variable yposB, stimeB	
			bExists= strlen(CsrInfo(B)) > 0
			if (bExists == 1)
				gCursB = 1
			
				//  first data to display for kinetics			
				xposB = pcsr(B)
				lambdaB = hcsr(B)
				gMessagekB= num2str(lambdaB)
			
				//  first data to display for spectra
				yposB = qcsr(B)
				stimeB = vcsr(B)
				gMessagesB = num2str(stimeB)
			
				//wkB = kM[xposB] [p]
				MatrixOp/O wkB = row(kM, xposB)^t
				//wsB = kM[p][yposB]
				MatrixOp/O wsB = col(kM, yposB)
				
				CheckDisplayed/W=kinetics kineticsB
				if(V_flag == 1)
					Cursor/H=2/C=(65535,0,0)/W=kinetics B kineticsB yposB
					// return 0
				else
					AppendToGraph/W=kinetics kineticsB vs $tWave
				endif	
				
				CheckDisplayed/W=spectra spectraB
				if(V_flag == 1)
					Cursor/H=2/C=(65535,0,0)/W=spectra B spectraB xposB
					// return 0
				else
					AppendToGraph/W=spectra spectraB vs $sWave	
				endif
					
			else
				gCursB = 0
				gMessagekB = ""
				gMessagesB = ""
				RemoveFromGraph/Z/W=kinetics kineticsB
				RemoveFromGraph/Z/W=spectra spectraB
				Cursor/K/W=kinetics B
				Cursor/K/W=spectra B
			endif			
			//Print "4: " + num2str(gvaslk)
			hookresult = 1
			break
			
		case 8:
			//Print "case 8"
			//Print gvaslk
			// update if we rescale the kinetics graph

			GetWindow kwTopWin, wtitle
			grTitle = S_Value
			
	
			if(CmpStr(grTitle,"kinetics",0) == 0)
				//Print "modified kinetics running"
				// PreserveGraphScaling("kinetics0","k")	
				PreserveGraphScaling("kinetics","k")
				if(gvaslk == 1)
					gMessageYSck = num2str(gvlmink) +", "+ num2str(gvlmaxk)
				else
					gMessageYSck = "Auto"
				endif
				
				if(gvasbk == 1)
					gMessageXSck = num2str(gvbmink) +", "+ num2str(gvbmaxk)
				else
					gMessageXSck = "Auto"
				endif
				
				hookresult = 1
				break			
			endif		
			
			if(CmpStr(grTitle,"spectra",0) == 0)
				//PreserveGraphScaling("spectra0","s")	
				PreserveGraphScaling("spectra","s")	
				if(gvasls == 1)
					gMessageYScs = num2str(gvlmins) +", "+ num2str(gvlmaxs)
				else
					gMessageYScs = "Auto"
				endif
				
				if(gvasbs == 1)
					gMessageXScs = num2str(gvbmins) +", "+ num2str(gvbmaxs)
				else
					gMessageXScs = "Auto"
				endif
		
				hookresult = 1
				break			
			endif		
			
	endswitch
	
	return hookResult
End


//  After a Window Hook call, graph axis limits automatically reset
//  We want to preserve the axis range as the window is activated
// But, we want to preserve autoscaling so that things are easy when 
//  we switch images.  Use this function in combination with SetScale

Function PreserveGraphScaling(graphname, suffix)
	// be careful that suffix is less than 25 or so characters
	String graphname
	String suffix
	DoWindow $graphname
	if (V_Flag == 0)
		//Print "Window doesn't exist"
		return 0
	else
			
		// create folder to store global variables which will be accessed
		// by our window hook functions
		DFREF saveDFR = GetDataFolderDFR()
		if(DataFolderExists("root:Packages:InspectData") == 1)
			SetDataFolder("root:Packages:InspectData")
		else
			NewDataFolder/O/S root:Packages:InspectData
		endif
	
		// create global variables for manual or auto
		// default is autoscale
	
		// left axis
		String vaslname = ":gvasl" + suffix
		Variable vasl = NumVarOrDefault(vaslname, 0) 
		Variable/G $vaslname = vasl
		NVAR gvasl = $vaslname
		
		// bottom axis
		String vasbname = ":gvasb" + suffix
		Variable vasb = NumVarOrDefault(vasbname, 0) 
		Variable/G $vasbname = vasb
		NVAR gvasb = $vasbname
		 
		// create global variables for axis limits
		// left axis
		String vlminname = ":gvlmin" + suffix
		Variable vlmin = NumVarOrDefault(vlminname, -1) 
		Variable/G $vlminname = vlmin 
		NVAR gvlmin = $vlminname

		String vlmaxname = ":gvlmax" + suffix	
		Variable vlmax = NumVarOrDefault(vlmaxname, 1) 
		Variable/G $vlmaxname = vlmax 
		NVAR gvlmax = $vlmaxname
		
		// bottom axis
		String vbminname = ":gvbmin" + suffix	
		Variable vbmin = NumVarOrDefault(vbminname, -1) 
		Variable/G $vbminname = vbmin 
		NVAR gvbmin = $vbminname
	
		String vbmaxname = ":gvbmax" + suffix	
		Variable vbmax = NumVarOrDefault(vbmaxname, 1) 
		Variable/G $vbmaxname = vbmax 
		NVAR gvbmax = $vbmaxname
		
		//NVAR gvaslk
		//Print gvaslk
		// test for autoscaling
		// variables created 1 for manual, 0 for auto
		String asl = StringByKey("SETAXISFLAGS", AxisInfo(graphname,"left"))
	//	Print asl
		if(CmpStr(asl,"",0) == 0)
	//		Print "left manual"
			gvasl = 1
		else
	//		Print "left auto"
			gvasl = 0
		endif

		String asb = StringByKey("SETAXISFLAGS", AxisInfo(graphname,"bottom"))
	//	Print asb
		if(CmpStr(asb,"",0) == 0)
	//		Print "bottom manual"
			gvasb = 1
		else
	//		Print "bottom auto"
			gvasb = 0
		endif
		
		// store min and max values if set to manual
		if(gvasl == 1)
			GetAxis/Q/W=$graphname left
			gvlmin = V_min
	//		Print V_min
	//		Print gvlmin
			gvlmax = V_max
	//		Print V_max
	//		Print gvlmax
		endif
		
		if(gvasb == 1)
			GetAxis/Q/W=$graphname bottom
			gvbmin = V_min
	//		Print V_min
	//		Print gvbmin
			gvbmax = V_max
	//		Print V_max
	//		Print gvbmax
		endif
		
		// return to default folder
		SetDataFolder saveDFR
		//Print gvaslk
	endif

End


/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

Function ExtractKin()
//	WAVE/Z w = CsrWaveRef(A)
//	if (!WaveExists(w))
//		return NaN
//	endif
//	String zmatName = NameOfWave(w)
	String ImTest = ImageInfo("","",0)
	//  make this only applicable to images
	if(cmpstr(Imtest,"",0) == 0)
		Print "Not an image."
		return 0
	else
		NVAR gCursB = root:Packages:InspectData:gCursB
		String info= ImageInfo("","",0)
		String zmatName = StringByKey("ZWAVE",info)
		String xwName = StringByKey("XWAVE",info)
		String ywName = StringByKey("YWAVE",info)
		String base, xybase
		String suffix, xysuffix
		String regex = "(.*?)(zmat|zibg|zroi|zccm|A.sv)"
		SplitString /E=(regex) zmatName, base, suffix

		String XYregex = "(.*?)(ximr|xim|xcim)"
		SplitString /E=(XYregex) xwName, xybase, xysuffix
		//String tWave, sWave
		if(CmpStr(xysuffix,"")==0)
			xwName = "NewXwave"
			ywName = "NewYWave"
		elseif(CmpStr(xysuffix,"ximr")==0)
			ywName = xybase + "yroi"
			xwName = xybase + "xroi"
		elseif(CmpStr(xysuffix,"xcim")==0)
			ywName = xybase + "xcc"
			xwName = xybase + "ycc"
		elseif(CmpStr(xysuffix,"xim")==0)
			ywName = xybase + "xc"
			xwName = xybase + "yc"	
		endif

		Variable xpos, lambda, CursName
		Variable xposB, lambdaB
		xpos = pcsr(A)
		lambda = hcsr(A)
		if(gCursB == 1)
			xposB = pcsr(B)
			lambdaB = hcsr(B)
		endif
		Prompt CursName, "Cursor used to generate plot:", popup, "Cursor A;Cursor B;ROI Cursor A/B"
		Prompt zmatName, "Enter matrix wave name: "
	//	Prompt zmatName, "Enter matrix wave name: ", popup, StringByKey("ZWAVE",ImageInfo("","",0))
		Prompt xpos, "Enter cursor A postion for desired wavelength: "
		Prompt xposB, "Enter cursor B postion for desired wavelength: "
		Prompt xwName, "Enter wavelength wave name: "
		if(gCursB == 1)
			DoPrompt "Generate Kinetics", CursName, zmatName, xpos, xposB, xwName
		else
			DoPrompt "Generate Kinetics", zmatName, xpos, xwName
			CursName = 1
		endif
		if (V_Flag)
			return -1
		endif
		if(CursName == 1)
			Print "A"
			Plot1DFromMat2(zmatName, xpos, xpos, xwName, ywName, 0)
		elseif(CursName == 2)
			Print "B"
			Plot1DFromMat2(zmatName, xposB, xposB, xwName, ywName, 0)
		elseif(CursName == 3)
			Print "A/B"
			Plot1DFromMat2(zmatName, xpos, xposB, xwName, ywName, 0)
		endif
	
	//	Print zmatName; Print xwName
	//	Variable tName = NumberByKey("RECREATION",CsrInfo(A))
	//	KineticsPlot2(zmatName,xpos,xwName)
		return 0
	endif
End

Function ExtractSpec()
//	WAVE/Z w = CsrWaveRef(A)
//	if (!WaveExists(w))
//		return NaN
//	endif
//	String zmatName = NameOfWave(w)
	String ImTest = ImageInfo("","",0)
	//  make this only applicable to images
	if(cmpstr(Imtest,"",0) == 0)
		Print "Not an image."
		return 0
	else
		NVAR gCursB = root:Packages:InspectData:gCursB
		String info= ImageInfo("","",0)
		String zmatName = StringByKey("ZWAVE",info)
		String xwName = StringByKey("XWAVE",info)
		String ywName = StringByKey("YWAVE",info)
		String base, xybase
		String suffix, xysuffix
		String regex = "(.*?)(zmat|zibg|zroi|zccm|A.sv)"
		SplitString /E=(regex) zmatName, base, suffix
		
		String XYregex = "(.*?)(ximr|xim|xcim)"
		SplitString /E=(XYregex) xwName, xybase, xysuffix
		//String tWave, sWave
		if(CmpStr(xysuffix,"")==0)
			xwName = "NewXwave"
			ywName = "NewYWave"
		elseif(CmpStr(xysuffix,"ximr")==0)
			ywName = xybase + "yroi"
			xwName = xybase + "xroi"
		elseif(CmpStr(xysuffix,"xcim")==0)
			ywName = xybase + "xcc"
			xwName = xybase + "ycc"
		elseif(CmpStr(xysuffix,"xim")==0)
			ywName = xybase + "xc"
			xwName = xybase + "yc"	
		endif
	
	
		Variable ypos, stime, CursName	
		Variable yposB, stimeB
		ypos = qcsr(A)
		stime = vcsr(A)
		if(gCursB == 1)
			yposB = qcsr(B)
			stimeB = vcsr(B)
		endif
		Prompt CursName, "Cursor used to generate plot:", popup, "Cursor A;Cursor B;ROI Cursor A/B"
		Prompt zmatName, "Enter matrix wave name: "
		Prompt ypos, "Enter cursor A postion for desired time: "
		Prompt yposB, "Enter cursor B postion for desired time: "
		Prompt ywName, "Enter time wave name: "
		if(gCursB == 1)
			DoPrompt "Generate Spectra", CursName, zmatName, ypos, yposB, ywName
		else
			DoPrompt "Generate Spectra", zmatName, ypos, ywName
			CursName = 1
		endif
		if (V_Flag)
			return -1
		endif
		if(CursName == 1)
			Print "A"
			Plot1DFromMat2(zmatName, ypos, ypos, xwName, ywName, 1)
		elseif(CursName == 2)
			Print "B"
			Plot1DFromMat2(zmatName, yposB, yposB, xwName, ywName, 1)
		elseif(CursName == 3)
			Print "A/B"
			Plot1DFromMat2(zmatName, ypos, yposB, xwName, ywName, 1)
		endif
	//	Print zmatName; Print ywName
	//	SpectraPlot2(zmatName,ypos,ywName)
		return 0
	endif

End

Function/S Plot1DFromMat2(Mat, ACurs, BCurs, sWave, twave, mode)
	// this function will average 1D slices over a range given by the 2 cursor positions
	// for extraction at a single pixel, make sure that ACurs = B Curs
	
	//  mode should be set to 0 for vertical image slice (kinetics)
	//  mode should be set to 1 for horizontal slice (spectra)
	
	// written to behave like KineticsPlot2 (found in v. 4alpha3)
	
	String Mat, sWave, twave
	Variable ACurs, BCurs, mode

	Wave ksM = $Mat
	Variable m,n
	m = Dimsize(ksM,0) // numer of rows
	n = Dimsize(ksM,1) // number of columns
	
	// get base name to append to
	// also define name of time wave to plot against
	String base
	String suffix
	// First write for kinetics plot
	String kWaveName, sWaveName
	// Name for common plot
	String kWinName, sWinName
                                      
	String dfSave
	
	String regex = "(.*?)(zmat|zibg|zroi|zccm|A.sv)"
	SplitString /E=(regex) Mat, base, suffix
	if(CmpStr(base,"")==0)
		kWaveName = "NewMatrix"
		// plot all extracted kinetics on the same graph
		// define window name to be base + kp
		kWinName = "Empty K Name"
		sWinName = "Empty S Plot"
	else
		// plot all extracted kinetics on the same graph
		// define window name to be base + kp
		kWinName = base + "kp"
		sWinName = base + "sp"
	endif
	// make sure it is not more than 31 chars

	
	if(mode == 0) // kinetics
		Wave ltM = $sWave  
	elseif(mode == 1)  // spectra
		Wave ltM = $tWave
	endif
	
	Variable DAB = abs(ACurs - BCurs)
	String IName
	
	Variable IA = ltM[ACurs]
	Variable lB = ltM[BCurs]     
	Variable lAB = abs(IA - lB)
	
	Variable minpix, maxpix
	if(ACurs <= BCurs)
//		Print "Less than or equal" 
		minpix = ACurs
		maxpix = BCurs
//		IName = num2Str(IA + ((IA - lB)/2))
		if(mode == 0)
			sprintf IName, "%3.0f", (IA + (lAB/2))
		else
			sprintf IName, "%1.3f", (IA + (lAB/2))
		endif

	else
//		Print "GT!"
		minpix = BCurs
		maxpix = ACurs
//		IName = num2Str(lB + ((lB - IA)/2))
		if(mode == 0)
			sprintf IName, "%3.0f", (lB + (lAB/2))
		else
			sprintf IName, "%1.3f", (lB + (lAB/2))
		endif
	endif
	
	kWaveName = base + "k" + IName + "_" + num2iStr(DAB)
	sWaveName = base + "s" + IName + "_" + num2iStr(DAB)
	kWaveName = CleanupName(kWaveName, 1)
	sWaveName = CleanupName(sWaveName, 1)
	
	Variable i = 0
	Variable j = 0
	if(mode == 0)
		Make/D/O/N=(n) $kWaveName
		Wave w = $kWaveName
		w = 0
		// use built-in indexing capabilities to
		// extract a row
		// I find this implementation to be partuclarly confusing
		do 
			w += ksM[minpix+i] [p]
			i+=1
		while(minpix+i <= maxpix)
		w /= i
		
		// show all extracted traces on the same graph
		// create new graph if it doesn't exist
		DoWindow/F $kWinName
		if (V_Flag == 0)
			Display/K=2/N=$kWinName w vs $tWave 
		else 
			AppendToGraph/W=$kWinName w vs $tWave 
		endif
		//	DoUpdate

	
	elseif(mode == 1)
		Make/D/O/N=(m) $sWaveName
		Wave v = $sWaveName
		v = 0
		do 
			v += ksM[p][minpix+j]
			j+=1
		while(minpix+j <= maxpix)
		v /= j
		
		// show all extracted traces on the same graph
		// create new graph if it doesn't exist
		DoWindow/F $sWinName
		if (V_Flag == 0)
			Display/K=2/N=$sWinName v vs $sWave 
		else 
			AppendToGraph/W=$sWinName v vs $sWave 
		endif
	else
		// just fail if mode set to anything else
		return ""
	endif
	
	if(mode == 0)
		return kWaveName
	elseif(mode == 1)
		return sWaveName
	endif


End



/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

//  Subtract scattered light procedures (laser + fluorescence)
//  This is not used for other background subtraction

// This is the display recreation macro, created by Igor 
// and then manually tweaked. The parts that were tweaked 
// are shown in bold. NOTE: Some lines are wrapped to fit on the page. 
Window IntBackControlPanel() : Panel
	PauseUpdate; Silent 1	// building window...
	NewPanel/W=(150,100,600,320)/K=1 as "Get Cursor Positions"
	
	SetDrawEnv fsize= 16
	DrawText 109,28,"Scattered Light Correction"

	SetVariable XSetVar,pos={40,45},size={150,15},title="Cursor A:" 
	SetVariable XSetVar,limits={0,Inf,1},value=root:Packages:IntensityBackground:cAComponent

	SetVariable YSetVar,pos={210,45},size={150,15},title="Cursor B:" 
	SetVariable YSetVar,limits={0,Inf,1},value=root:Packages:IntensityBackground:cBComponent
	Button ComputeButton,pos={110,76},size={90,20}, proc=GetCursorPositions,title="Preview"
	Button ComputeButton2,pos={227,76},size={90,20}, proc=GetCursorPositions2,title="Save"
	SetVariable setvar0 title="matrix:",size={284,15},bodyWidth=250, pos={77,115}, value=root:Packages:IntensityBackground:zWave
	SetVariable setvar0_1 title="sca_bkgd:",size={298,15},bodyWidth=250, pos={63,142}, value=root:Packages:IntensityBackground:scaWave
	SetVariable setvar0_2 title="corrected:",size={299,15},bodyWidth=250, pos={62,171}, value=root:Packages:IntensityBackground:corrWave
// embed graph
//	String IntBackPlot
//	Display/host=# /W=(50,200,400,350) as IntBackPlot
End

// This is the action procedure for the Compute button. 
// We created it using the Button dialog. 
Function GetCursorPositions(ctrlName) : ButtonControl
	String ctrlName
	// Make sure both cursors are on the same wave. 
	WAVE wA = CsrWaveRef(A) 
	WAVE wB = CsrWaveRef(B) 
	String dfA = GetWavesDataFolder(wA, 2)
	String dfB = GetWavesDataFolder(wB, 2) 
	if (CmpStr(dfA, dfB) != 0)
		Abort "Both cursors must be on the same wave."
		return -1 
	endif
	String info= ImageInfo("","",0)
	String zmatName = StringByKey("ZWAVE",info)
	Print zmatName
//	Wave wZ = $zmatName
	Variable n = Dimsize($zmatName,0) // number of columns
	String dfSave = GetDataFolder(1) 
//	SetDataFolder root:Packages:IntensityBackground
	SVAR  zWave  = root:Packages:IntensityBackground:zWave 
	zWave = zmatName
	NVAR cAComponent = root:Packages:IntensityBackground:cAComponent
	NVAR cBComponent = root:Packages:IntensityBackground:cBComponent 
	cAComponent = qcsr(A)
	Printf "Cursor A=%g\r", cAComponent
	Variable imin = cAComponent
	cBComponent = qcsr(B)
	Printf "Cursor B=%g\r", cBComponent
	Variable imax = cBComponent
//	SetDataFolder dfSave  //restore original location
//	Print imin 
//	Print imax
//	Print  n
	PreviewSLC(zmatName, imin, imax)
End

Function GetCursorPositions2(ctrlName) : ButtonControl
	String ctrlName
	DoWindow/K tempGraph
	// Make sure both cursors are on the same wave. 
	WAVE wA = CsrWaveRef(A) 
	WAVE wB = CsrWaveRef(B) 
	String dfA = GetWavesDataFolder(wA, 2)
	String dfB = GetWavesDataFolder(wB, 2) 
	if (CmpStr(dfA, dfB) != 0)
		Abort "Both cursors must be on the same wave."
		return -1 
	endif
	String info= ImageInfo("","",0)
	String zmatName = StringByKey("ZWAVE",info)
	Print zmatName
	Wave wZ = $zmatName
	Variable n = Dimsize(wZ,0) // number of columns
	String dfSave = GetDataFolder(1) 
//	SetDataFolder root:Packages:IntensityBackground
	SVAR  zWave  = root:Packages:IntensityBackground:zWave 
	zWave = zmatName
	NVAR cAComponent = root:Packages:IntensityBackground:cAComponent
	NVAR cBComponent = root:Packages:IntensityBackground:cBComponent// Access current data folder. 
	cAComponent = qcsr(A)
	Printf "Cursor A=%g\r", cAComponent
	Variable imin = cAComponent
	cBComponent = qcsr(B)
	Printf "Cursor B=%g\r", cBComponent
	Variable imax = cBComponent
//	SetDataFolder dfSave  //restore original location
//	Print imin 
//	Print imax
//	Print  n
	ApplySLC(zmatName, imin, imax)
End


Function PreviewSLC(zMat, tmin, tmax)
	String zMat
	Variable tmin, tmax
	Wave fM = $zMat
	
	String scaBName = RemoveEnding(zMat, "zmat") + "scab"
	
	Variable minSig, maxSig

	if(tmin <= tmax)
		minSig = tmin
		maxSig = tmax
	elseif(tmin > tmax)
		minSig = tmax
		maxSig = tmin
	endif
	
	Variable m,n
	m = Dimsize(fM,0) // numer of rows
	n = Dimsize(fM,1) // number of columns
	
	String dfSave = GetDataFolder(1) 
	SetDataFolder root:Packages:IntensityBackground
//	Make/O/N=(m) dummyS1
	Make/O/N=(m) dummyS_avg
	
	Display/N=tempGraph
	Variable i,j
	i=0
	do
		String dumstr =  "dummyS_" + num2str(i)
		Make/O/N=(m) $dumstr
		Wave dS = $dumstr
		j=0
		do
			dS[j] = fM[j][i+minSig]
			j+=1
		while (j<=m)
		i+=1
		dummyS_avg += dS
		AppendToGraph $dumstr
	while (i+minSig <= maxSig)
	dummyS_avg /= i
	SVAR scaWave = root:Packages:IntensityBackground:scaWave
	scaWave = scaBName
	Duplicate/O dummyS_avg, $scaBName
	KillWaves dummyS_avg
	

	SetDataFolder dfSave  //restore original location
	
return 0
end


Function ApplySLC(zMat, tmin, tmax)
	String zMat
	Variable tmin, tmax
	
	String scaBName = RemoveEnding(zMat, "zmat") + "scab"
	String zcorName = RemoveEnding(zMat, "zmat") + "zibg"
	String ImageXName = RemoveEnding(zMat, "zmat") + "xim"
	String ImageYName = RemoveEnding(zMat, "zmat") + "yim"
	
	Wave fM = $zMat
	Duplicate/O $zMat, root:Packages:IntensityBackground:zMatTemp
		
	Variable minSig, maxSig

	if(tmin <= tmax)
		minSig = tmin
		maxSig = tmax
	elseif(tmin > tmax)
		minSig = tmax
		maxSig = tmin
	endif
	
	Variable m,n
	m = Dimsize(fM,0) // numer of rows
	n = Dimsize(fM,1) // number of columns
	
	Make/O/N=(m) dummyS1
	Make/O/N=(m) dummyS_avg

	String dfSave = GetDataFolder(1) 
	SetDataFolder root:Packages:IntensityBackground
	
	Variable i,j
	i=0
	do
		j=0
		do
			dummyS1[j] = fM[j][i+minSig]
			j+=1
		while (j<=m)
		i+=1
		dummyS_avg += dummyS1
	while (i+minSig <= maxSig)
	dummyS_avg /= i
	SVAR scaWave = root:Packages:IntensityBackground:scaWave
	scaWave = scaBName
	KillWaves dummyS1
	Duplicate/O dummyS_avg, $scaBName
	Duplicate/O dummyS_avg, root:$scaBName

	Wave wcorr = zMatTemp
	Variable k,l
	k=0
	do
		l=0
			do
				wcorr[l][k] = -log(10^(-(fM[l][k])) - 10^(-(dummyS_avg[l])) +1)
//				wcorr[k][l] = -log(10^(-(fM[k][l])))
//				wcorr[k][l] = fM[k][l]
				l+=1
			while (l<=m)
		k+=1
	while(k<n)
	SVAR corrWave = root:Packages:IntensityBackground:corrWave
	corrWave = zcorName
	Duplicate/O zMatTemp, root:$zcorName
	KillWaves dummyS_avg
	SetDataFolder dfSave  //restore original location
	

	
	Display;AppendImage $zcorName vs {$ImageXName,$ImageYName}//;DelayUpdate
	ModifyImage $zcorName ctab= {*,*,Rainbow,0}
	ModifyImage $zcorName ctabAutoscale=3,lookup= $""
	ShowInfo
	
	GetWindow kwTopWin wtitle
	String imTitle = S_Value
	String imTitle2 = WinName(0,1)
	imTitle = RemoveEnding(imTitle, ":")
	Cursor/I/H=1 /W=$imTitle A $zcorName 1,1
	Cursor/M/H=1 B
	
//	ImageHookGen()
	SetWindow $imTitle2, hook(MyHook)=MyWindowHook

	DoWindow/K IntBackControlPanel
	DoWindow/F $imTitle2
	
	
return 0
end




// This is the top level routine which makes sure that the globals 
// and their enclosing data folders exist and then makes sure that 
// the control panel is displayed.
 Function DisplayIntBkgdControlPanel()
	// If the panel is already created, 
	DoWindow/F IntBackControlPanel 
	if (V_Flag != 0)
		return 0 
	endif
	String dfSave = GetDataFolder(1)
	// Create a data folder in Packages to store globals.
	NewDataFolder/O/S root:Packages 
	NewDataFolder/O/S root:Packages:IntensityBackground
	// Create global variables used by the control panel. 
//	Variable AComponent = NumVarOrDefault(":cAComponent", 10) 
	Variable AComponent = 0
	Variable/G cAComponent = AComponent 
//	Variable BComponent = NumVarOrDefault(":cBComponent", 20) 
	Variable BComponent = 0
	Variable/G cBComponent = BComponent
//	String ZWName = StrVarOrDefault(":zWave", "") 
	String ZWName = ""
	String /G zWave = ZWName
//	String ScWName = StrVarOrDefault(":scaWave", "") 
	String ScWName = ""
	String /G scaWave = ScWName
//	String CorWName = StrVarOrDefault(":corrWave", "") 
	String CorWName = ""
	String /G corrWave = CorWName
	// Create the control panel. 
	Execute "IntBackControlPanel()"
	SetDataFolder dfSave
End

///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////

Function T0ImCorr()
//	WAVE/Z w = CsrWaveRef(A)
//	if (!WaveExists(w))
//		return NaN
//	endif
//	String zmatName = NameOfWave(w)

	String info= ImageInfo("","",0)
	String yimName = StringByKey("YWAVE",info)
	// need to account for chirp corrected files which use a different time file (yicc)
	String ycName = RemoveEnding(yimName, "im") + "c"
	Variable ypos, stime, newt0	
	ypos = qcsr(A)
	stime = vcsr(A)
	newt0 = stime
	Prompt yimName, "Enter image time wave name: "
	Prompt ycName, "Enter 1D time wave name (0 to ignore): "
	Prompt newt0, "Enter new t0: "
	DoPrompt "Correct Time Zero", yimName, ycName, newt0
	if (V_Flag)
		return -1
	endif
	T0CorrDo(yimName,newt0)
	if ((stringmatch(ycName, "0") == 1))
		Print "Igoring 1D time wave in t0 correction."
	else
		T0CorrDo(ycName,newt0)
	endif
	return 0
End

Function T0CorrDo(yName,newt0)
	String yName
	Variable newt0
	Wave w = $yName
	w -= newt0
	return 0
End

/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

// Generate progressive time axis using exponential scaling
// Following modified procedure from Megerle et. al. Applied Physics B 96 215 (2009)

Function ExpTimeAxis()

	String dfSave = GetDataFolder(1)
	// Create a data folder in Packages to store globals.
	NewDataFolder/O/S root:Packages 
	NewDataFolder/O/S root:Packages:ExpTimeAxis
	
	// set local variables
//	Variable TimeZero = 200
	Variable TimeZero = NumVarOrDefault(":gTimeZero", 200) 

//	Variable ToStep = 0.02
	Variable ToStep = NumVarOrDefault(":gToStep", 0.02) 
	
//	Variable MaxTime = 3200
	Variable MaxTime = NumVarOrDefault(":gMaxTime", 3200) 
	
//	Variable PreData = 1
	Variable PreData = NumVarOrDefault(":gPreData", 1) 
	
// get values from prompt
	Prompt TimeZero, "Enter time zero value (absolute ps): "
	Prompt ToStep, "Enter t0 step size (ps): "
	Prompt MaxTime, "Enter max delay time (relative ps): "
	Prompt PreData, "Use sparse pre-points?",popup, "yes;no"
	DoPrompt "Generate Progressive TIme Axis", TimeZero, ToStep, MaxTime, PreData
	if (V_Flag)
		SetDataFolder dfSave
		return -1
	endif
	if(TimeZero < 1.5)
		Print "Not enough dynamic range!"
		return -1
	endif

// write to global variables

	Variable/G gTimeZero = TimeZero
	Variable/G gToStep = ToStep
	Variable/G gMaxTime = MaxTime
	Variable/G gPreData = PreData

// execute function
	Variable NBasePts
	Variable NewZero
	Variable pp
	String MaxTimeString
	if(PreData ==1)
		// define set of prepoints for accurate baseline determination
		Variable PreStart
		Make/D/O/N=10 PrePts
		PrePts = {100,70,50,40,30,20,10,5,2,0.5}
		pp = 0
		do
			PreStart = TimeZero - PrePts[pp]
			pp += 1
		while(TimeZero - PrePts[pp-1] < 0)
		NBasePts = Dimsize(PrePts,0) - (pp-1)
		// NewZero represents the total amount of pre-points time (relative time)
		NewZero = PrePts[pp-1]
//		Print "NewZero = " + Num2Str(NewZero)
		Print "Time Zero = " + Num2Str(TimeZero)
//		Print "Max time = " + Num2Str(MaxTime)
		// make string reflect Max time after prepoints are included
		MaxTimeString = Num2Str(NewZero + 1 + MaxTime)
		//  end baseline determination

		//	Print NptsTo
		//	Print TotNpts
	else
		NewZero = 0
		NBasePts = 0
		pp = 11
		MaxTimeString = Num2Str(MaxTime + 1)
		Print "Time Zero = " + Num2Str(TimeZero)
	endif
	Variable NptsTo = 2./ToStep
	Variable TotNpts = floor(NptsTo * (log(MaxTime)+1))+NBasePts
	String PTAwave = "PTA_start_" + num2str(TimeZero-NewZero-1) + "_end_" + MaxTimeString
	Make/D/O /N=(1,TotNpts) root:$PTAwave
	Wave w = root:$PTAwave
// insert pre-points
	if(PreData ==1)
		Variable qq = 0
		do
			w[1][qq] = PrePts[pp-1] - PrePts[pp-1+qq]
			qq+=1
		while(pp + qq <= 10)
	else
		qq=0
	endif
// insert progressive time axis
	Variable i = 0
	do
		if(i < (NptsTo+NBasePts))
			w[1][i+qq] = NewZero +(2*i)/NptsTo
		else
			w[1][i+qq] = NewZero +1 + 10^(-1+(i/NptsTo))
		endif
		i+=1
	while((i+qq)<=TotNpts)
	KillWAves PrePts
	SetDataFolder dfSave
	String message = "Choose a location to save the progressive time file"
	String outputPath
	String fileFilters = "Data Files (*.csv):.csv"
	Variable refNum
	String filenameDef = PTAwave + ".csv"
	Open /F=fileFilters /M=message refNum as filenameDef
	Print S_fileName
	if(stringmatch(S_fileName,""))
		return -1
	else
		outputPath = S_fileName
	endif
	wfprintf refNum, "%4.3f,", w
	Close/A 


	
End




////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////

Function ImageROI()
	String ImTest = ImageInfo("","",0)
	//  make this only applicable to images
	if(cmpstr(Imtest,"",0) == 0)
		Print "Not an image."
		return 0
	else
		NVAR gCursB = root:Packages:InspectData:gCursB
		String info= ImageInfo("","",0)
		String zmatName = StringByKey("ZWAVE",info)
		String xwName, ywName, ximName, yimName
		String base
		String suffix
		String regex = "(.*?)(zmat|zibg|zroi|zccm|A.sv)"
		SplitString /E=(regex) zmatName, base, suffix
		if(CmpStr(zmatName,"")==0)
			Print "Failed to get matrix name."
			return 0
		else
			xwName = base + "xc"
			ywName = base + "yc"
			ximName = base + "xim"
			yimName = base + "yim"
		endif	
	
		Variable xmin, xmax, ymin, ymax
		Variable xlength, ylength
		
		Wave wZ = $zmatName
		Wave Xw = $xwName			
		Wave XwIm = $ximName
		Wave Yw = $ywName
		Wave YwIm = $yimName		
				
		xlength = Dimsize(wZ,0) // max rows of zmat
		ylength = Dimsize(wZ,1)// max columns of zmat
		xmin = pcsr(A)
		ymin = qcsr(A)
		if(gCursB == 1)
			xmax = pcsr(B)
			ymax = qcsr(B)
		else
			xmax = xlength -1
			ymax = ylength -1
		endif
		
		Prompt zmatName, "Enter matrix wave name: "
		Prompt xmin, "Enter miminum wavelength index:"
		Prompt xmax, "Enter maximum wavelength index:"
		Prompt ymin, "Enter minimum time index:"
		Prompt ymax, "Enter maximum time index:"
		DoPrompt "Extract Matric Region of Interest", zmatName, xmin, xmax, ymin,ymax
		
		Variable xroimin = min(xmin, xmax)
		Variable xroimax = max(xmin, xmax)
		Variable yroimin = min(ymin, ymax)
		Variable yroimax = max(ymin, ymax)
		
		if (xroimin > xlength - 2)
			xroimin = xlength -2
		endif
		
		if (xroimax > xlength - 1)
			xroimax = xlength -1
		endif
		
		if (yroimin > ylength - 2)
			yroimin = ylength -2
		endif
		
		if (yroimax > ylength - 1)
			yroimax = ylength -1
		endif

		Variable irange, jrange, imax, imin
		irange = abs(xroimax-xroimin)
		jrange = abs(yroimax-yroimin)

		String ZMatROI = base + "zroi"
		
		// for 1D plotting
		String XROI = base + "xroi"
		// for image visualization
		String XIMR = base + "ximr"
		
		// for 1D plotting
		String YROI = base + "yroi"
		// for image visualization
		String YIMR = base + "yimr"
		
		Make/O/N=(irange,jrange) $ZMatROI
		Make/O/N=(irange) $XROI
		Make/O/N=(jrange) $YROI
		// image needs N+1 points
		Make/O/N=(irange+1) $XIMR
		Make/O/N=(jrange+1) $YIMR
		
		Wave ZROI = $ZMatROI

		Wave XR = $XROI
		Wave XRIm = $XIMR
		
		Wave YR = $YROI
		Wave YRIm = $YIMR

		
		// do 2 extractions, 1 for 1D plots (N), 1 for image plots (N+1)
		
		Variable i,j
		i=0
		do
			j = 0
			do
				ZROI[j][i] = wZ[j+xroimin][i+yroimin]
				XR[j] = Xw[j+xroimin]
				XRIm[j] = XwIm[j+xroimin]
				j += 1
			while (j+xroimin <= xroimax)	
			YR[i] = Yw[i+yroimin]
			YRIm[i] = YwIm[i+yroimin]
			i+=1
		while (i+yroimin <= yroimax)
		// fill in N+1 points for image labels
		XRIm[irange] = XwIm[1+xroimax]
		YRIm[jrange] = YwIm[1+yroimax]
		
		Display;AppendImage $ZMatROI vs {$XIMR,$YIMR}//;DelayUpdate
		ModifyImage $ZMatROI ctab= {*,*,Rainbow,0}
		ModifyImage $ZMatROI ctabAutoscale=3,lookup= $""
		ShowInfo
	
		GetWindow kwTopWin wtitle
		String imTitle = S_Value
		String imTitle2 = WinName(0,1)
		imTitle = RemoveEnding(imTitle, ":")
		Cursor/I/H=1 /W=$imTitle A $ZMatROI 1,1
		Cursor/M/H=1 B
	
		//	ImageHookGen()
		SetWindow $imTitle2, hook(MyHook)=MyWindowHook
		DoWindow/F $imTitle2
		
	endif
	return 0
End


////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////



Function AutoSVG()
	String ImTest = ImageInfo("","",0)
	//  make this only applicable to images
	if(cmpstr(Imtest,"",0) == 0)
		Print "Not an image."
		return 0
	else

		String info= ImageInfo("","",0)
		String zmatName = StringByKey("ZWAVE",info)
		String xwName, ywName, ximName, yimName
		String UmatName, VmatName, SwName
		String base
		String suffix
		String regex = "(.*?)(zmat|zibg|zroi|zccm|A.sv)"
		SplitString /E=(regex) zmatName, base, suffix
		if(CmpStr(zmatName,"")==0)
			Print "Failed to get matrix name."
			return 0
		else
			xwName = base + "xc"
			ywName = base + "yc"
			ximName = base + "xim"
			yimName = base + "yim"
			UmatName = base + "psU"
			VmatName = base + "pkV"
			SwName = base + "svW"
		endif	
		MatrixSVD $zmatName
		MatrixTranspose M_VT
		Duplicate/O M_U $UmatName
		Duplicate/O W_W $SwName
		Duplicate/O M_VT $VmatName
		
		KillWaves/Z M_U
		KillWaves/Z W_W
		KillWaves/Z M_VT
		
		Display $SwName
		ModifyGraph log(left)=1
		ModifyGraph mode=3,marker=16
		SetAxis bottom 0,10
		
	endif
End


////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////

Function RankSVD()

	Variable rank = 1
	Variable scale = 2
	String UmatName, VmatName, SwName, zmatName
			
	String ImTest = ImageInfo("","",0)
	if(cmpstr(Imtest,"",0) == 0)
		Prompt UmatName, "Enter U matrix wave name: ", popup, Wavelist("*",";","")
		Prompt VmatName, "Enter V matrix wave name:", popup, Wavelist("*",";","")
		Prompt SwName, "Enter singular value wave name:", popup, Wavelist("*",";","")
		Prompt zmatName, "Enter original matrix wave name:", popup, Wavelist("*",";","")
	else

		String info= ImageInfo("","",0)
		zmatName = StringByKey("ZWAVE",info)
		String xwName, ywName, ximName, yimName
		String ImName
		String base
		String suffix
		String regex = "(.*?)(zmat|zibg|zroi|zccm|A.sv)"
		SplitString /E=(regex) zmatName, base, suffix
		if(CmpStr(zmatName,"")==0)
			Print "Failed to get matrix name."
			return 0
		elseif(CmpStr(suffix,"zmat")==0 || CmpStr(suffix,"zibg")==0)
			ImName = WinName(0,1)
			xwName = base + "xc"
			ywName = base + "yc"
			ximName = base + "xim"
			yimName = base + "yim"
			UmatName = base + "psU"
			VmatName = base + "pkV"
			SwName = base + "svW"
		elseif(CmpStr(suffix,"zroi")==0)
			ImName = WinName(0,1)
			xwName = base + "xroi"
			ywName = base + "yroi"
			ximName = base + "ximr"
			yimName = base + "yimr"
			UmatName = base + "psU"
			VmatName = base + "pkV"
			SwName = base + "svW"
		endif	
		if (exists(UmatName) == 1 && exists(VmatName) == 1 && exists(SwName) == 1)
			Prompt UmatName, "Enter U matrix wave name: "
			Prompt VmatName, "Enter V matrix wave name:"
			Prompt SwName, "Enter singular value wave name:"
			Prompt zmatName, "Enter original matrix wave name:", popup, Wavelist("*",";","")
		else
			Prompt UmatName, "Enter U matrix wave name: ", popup, Wavelist("*",";","")
			Prompt VmatName, "Enter V matrix wave name: ", popup, Wavelist("*",";","")
			Prompt SwName, "Enter singular value wave name:", popup, Wavelist("*",";","")
			Prompt zmatName, "Enter original matrix wave name:", popup, Wavelist("*",";","")
		endif
		
	endif 
	Prompt rank, "Number of species in data:"
	Prompt scale, "Scale by singular value?",popup, "yes;no"

	DoPrompt "Rank SVD Matrices", UmatName, VmatName, rank, scale, SwName
	if (V_flag == 1)
		// User hit cancel button, so do nothing.
		return 0 
	endif
	Wave ZM = $zmatName
	Wave MU = $UmatName
	Make/D/O/N=(DimSize(MU,0),rank) MURtemp
	
	Wave MV = $VmatName
	Make/D/O/N=(DimSize(MV,0),rank) MVRtemp
	
	Wave SV = $SwName
	Make/D/O/N=(rank) SVtemp
	Make/D/O/N=(DimSize(MU,0),DimSize(MV,0)) ARtemp
	
	String TempPSName, TempPKName
	
	// kill any previously extracted vectors
	Variable bb = 0
	do
		TempPSName = base + "ps" + num2str(bb+1)
		TempPKName = base + "pk" + num2str(bb+1)
		KillWaves/Z $TempPSName
		KillWaves/Z $TempPKName
		bb+= 1
	while (bb < dimsize(MU,0))
	
	// need to test to see if these exist
	// otherwise, windows are created at point 0,0,0,0
	// not fixed by boolean below
	NVAR/Z V_left = root:V_left, V_right = root:V_right
	NVAR/Z V_top = root:V_top, V_bottom = root:V_bottom
	
	if (!NVAR_Exists(V_left)) 
		Variable/G V_left = 0
	endif
	
	if (!NVAR_Exists(V_right)) 
		Variable/G V_right = 0
	endif
	
	if (!NVAR_Exists(V_top)) 
		Variable/G V_top = 0
	endif
	
	if (!NVAR_Exists(V_bottom)) 
		Variable/G V_bottom = 0
	endif
	
	String cmdU0, cmdU1, cmdU2
	
	String Uwindowname = base + "PS"
	sprintf cmdU0, "GetWindow/Z %s, wsize", Uwindowname
	Execute/Q cmdU0
//	Print V_left, V_top, V_right, V_bottom
	sprintf cmdU1, "DoWindow/K %s", Uwindowname
	Execute/Q cmdU1
	if ((V_left + V_top + V_right + V_bottom) == 0)
		sprintf cmdU2, "Display/N=%s", Uwindowname
	else
		sprintf cmdU2, "Display/N=%s/W=(%d,%d,%d,%d)", Uwindowname, V_left, V_top, V_right, V_bottom
	endif
	Execute/Q cmdU2
	Legend

	String Vwindowname = base + "PK"
	String cmdV0, cmdV1, cmdV2
	sprintf cmdV0, "GetWindow/Z %s, wsize", Vwindowname
	Execute/Q cmdV0
//	Print V_left, V_top, V_right, V_bottom
	sprintf cmdV1, "DoWindow/K %s", Vwindowname
	Execute/Q cmdV1
	if ((V_left + V_top + V_right + V_bottom) == 0)
		sprintf cmdV2, "Display/N=%s", Vwindowname
	else
		sprintf cmdV2, "Display/N=%s/W=(%d,%d,%d,%d)", Vwindowname, V_left, V_top, V_right, V_bottom
	endif
	Execute/Q cmdV2
	Legend
	
	ColorTab2Wave blueredgreen
	Wave CT = M_colors
	Variable aa = 0
	Variable colorind = 0
//	Print scale
//   Generate graphs with or without scaling
	do
		TempPSName = base + "ps" + num2str(aa+1)
		if (scale == 1)
			Make/D/O/N=(dimsize(MU,0)) $TempPSName = MU[p][aa]*sqrt(SV[aa])
		else
			Make/D/O/N=(dimsize(MU,0)) $TempPSName = MU[p][aa]
		endif
		AppendToGraph/C=(CT[colorind][0],CT[colorind][1],CT[colorind][2])/W=$Uwindowname $TempPSName vs $xwName
		TempPKName = base + "pk" + num2str(aa+1)
		if (scale == 1)
			Make/D/O/N=(dimsize(MV,0)) $TempPKName = MV[p][aa]*sqrt(SV[aa])
		else
			Make/D/O/N=(dimsize(MV,0)) $TempPKName = MV[p][aa]
		endif
		AppendToGraph/C=(CT[colorind][0],CT[colorind][1],CT[colorind][2])/W=$Vwindowname $TempPKName vs $ywName
		colorind += (floor((Dimsize(CT,0))/(rank-1)))
		MURtemp[][aa] = MU[p][aa]
		MVRtemp[][aa] = MV[p][aa]
		SVtemp[aa] = SV[aa]
		aa  +=1
	while(aa < rank)
// Reconstruct matrix from significant SVD components
	MatrixOp/O ARtemp = MURtemp x DiagRC(SVtemp,rank,rank) x ((MVRtemp)^t)
	String ReconDA = base + "A" + num2str(rank) + "sv"
	Duplicate/O ARtemp $ReconDA
	Duplicate/O ARtemp DAtemp_zmat
	MatrixOp/O DAtemp_zmat = ZM - ARtemp 
	DAtemp_zmat = DAtemp_zmat^2
	String DDAname = base + "DDA" + num2str(rank)
	Duplicate/O DAtemp_zmat $DDAname
	
	String cmdZ0, cmdZ1, cmdZ2
	String DAwindowname = base + num2str(rank) + "DDA"
	sprintf cmdZ0, "GetWindow/Z %s, wsize", DAwindowname
	Execute/Q cmdZ0
//	Print V_left, V_top, V_right, V_bottom
	sprintf cmdZ1, "DoWindow/K %s", DAwindowname
	Execute/Q cmdZ1
	if ((V_left + V_top + V_right + V_bottom) == 0)
		sprintf cmdZ2, "Display/N=%s;AppendImage %s vs {%s, %s}", DAwindowname, DDAname, ximName, yimName
	else
		sprintf cmdZ2, "Display/N=%s/W=(%d,%d,%d,%d);AppendImage %s vs {%s, %s}", DAwindowname, V_left, V_top, V_right, V_bottom, DDAname, ximName, yimName
	endif
	Execute/Q cmdZ2

	String cmdZ3
	sprintf cmdZ3, "ModifyImage %s ctab={*,*,Rainbow,0}", DDAname
	Execute/Q cmdZ3

	String cmdZ4
	sprintf cmdZ4, "ModifyImage %s ctabAutoscale=3", DDAname
	Execute/Q cmdZ4
	ShowInfo
	
	String cmdZ5
	sprintf cmdZ5, "ColorScale/C/N=text0/F=0/A=RC/E image=%s", DDAname
	Execute/Q cmdZ5

	
	KillWaves/Z M_colors
	KillWaves/Z MURtemp
	KillWaves/Z MVRtemp
	KillWaves/Z SVtemp
	KillWaves/Z ARtemp
	KillWaves/Z DAtemp_zmat
	
	DoWindow/F $ImName
		
	return 0
End


////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////


Function ReconSpeciesAbs(Pmat, Umat, Smat)
	String Pmat, Umat, Smat
	Wave PM = $Pmat
	Wave UM = $Umat
	Wave SM = $Smat
	
	Variable rank = Dimsize(PM, 0)
	Variable basis = Dimsize(PM,1)
	Variable length = Dimsize(UM, 0)
	
	String Fname = "FMat"
	Make/O/D/N=(length, rank) $Fname
	Wave FM = $Fname
	FM=0
	
	Variable i,j, q
	i = 0
	do
		q=0
		do
			j=0
			do
				// mulitply by appropraite SV
				// SV0 for basis 0, 1 for basis 1, etc.
				// so, use j index
				FM[i][q] = FM[i][q] + PM[q][j]*UM[i][j]*SM[j]
				j +=1
			while(j<basis)
			q+=1
		while(q<rank)
		i+=1
	while(i<length)

	return 0
End


////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////


Function ChirpCorrect()
	String xwave, ywave, zmat, t0wave
	
	Prompt xwave, "Enter x matrix wave name (lambda): ", popup, Wavelist("*",";","")
	Prompt ywave, "Enter y matrix wave name (time):", popup, Wavelist("*",";","")
	Prompt zmat, "Enter zmat wave name:", popup, Wavelist("*",";","")
	Prompt t0wave, "Enter t0 wave name:", popup, Wavelist("*",";","")
	
	DoPrompt "Generate XYZ Wave", xwave, ywave, zmat, t0wave
	if (V_flag == 1)
		// User hit cancel button, so do nothing.
		return 0 
	else
		PWCreate(xwave, ywave, zmat, t0wave)
		// uncomment for XYZ triplet wave
		// no eneabled by default
		// XYZCreate(xwave, ywave, zmat, t0wave)
	endif
End

Function XYZCreate(xwave, ywave, zmat, t0wave)
	String xwave, ywave, zmat, t0wave
		
	Wave xw = $xwave
	Wave yw = $ywave
	Wave zw = $zmat
	Wave tw = $t0wave
	
	Variable imax, jmax
	Variable XYZLength
	
	imax = Dimsize(xw,0)
	jmax = Dimsize(yw,0)
	
	Make/D/O/N=((imax*jmax),3) XYZtemp
	
	Variable i,j
	j=0
	do
		i=0
		do
			XYZtemp[i+imax*j][0] = xw[i]
			XYZtemp[i+imax*j][1] = yw[j]-tw[i]
			XYZtemp[i+imax*j][2] = zw[i][j]
			i+=1
		while(i<imax)
		j+=1
	while(j<jmax)
	
	return 0
End

Function PWCreate(xwave, ywave, zmat, t0wave)
	String xwave, ywave, zmat, t0wave
	
	Wave xw = $xwave
	Wave yw = $ywave
	Wave zw = $zmat
	Wave tw = $t0wave
	
	Variable imax, jmax
	Variable XYZLength
	
	imax = Dimsize(xw,0)
	jmax = Dimsize(yw,0)
	
	String base
	String suffix
	String pwName, ccXName, ccYName, ccMName, ccIMx, ccIMy
	String regex = "(.*?)(zmat|zibg|zroi|A.sv)"
	SplitString /E=(regex) zmat, base, suffix
	if(CmpStr(zmat,"")==0)
		Print "Failed to get matrix name."
		pwName = "PWtemp"
		ccXName = "CCxtemp"
		ccYName = "CCytemp"
		ccMName = "CCtemp"
		ccIMx = "CCximTemp"
		ccIMy = "CCyimTemp"
		return 0
	else
		pwName = base + "ccp"
		ccXName = base + "xcc"
		ccYName = base + "ycc"
		ccMName = base + "zccm"
		ccIMx = base + "xcim"
		ccIMy = base + "ycim"
	endif	
	
	Make/D/O/N=(imax,jmax,3) $pwName
	Wave pW = $pwName
	Make/D/O/N=(imax) $ccXName
	Wave CCx = $ccXName
	Make/D/O/N=(jmax) $ccYName
	Wave CCy = $ccYName
	Make/D/O/N=(imax,jmax) $ccMName
	Wave cZ = $ccMName
	
	// for image plots
	Make/D/O/N=(imax+1) $ccIMx
	Wave CCxIm = $ccIMx
	Make/D/O/N=(jmax+1) $ccIMy
	Wave CCyIm = $ccIMy
	
	// dummy waves for interpolation
	// to be overwritten and deleted at end
	
	Make/D/O/N=(jmax) dummytime
	Make/D/O/N=(jmax) dummyA
	Make/D/O/N=(jmax) dummyAInt
	
	MatrixOp/O CCy = col(yW,0) - tW[0]
	MatrixOp/O CCx = col(xW,0)
	
	Variable i,j
	j=0
	do
		i=0
		do
			pW[i][j][0] = xw[i]
			pW[i][j][1] = yw[j]-tw[i]
			pW[i][j][2] = zw[i][j]
			i+=1
		while(i<imax)
		j+=1
	while(j<jmax)
	
	Variable k
	k=0
	do
		MatrixOp/O dummytime= row(pW[][][1],k)^t
		MatrixOp/O dummyA = row(pW[][][2],k)^t
		Interpolate2/I=3/J=0/X='CCy'/Y='dummyAInt'/T=1 'dummytime','dummyA'
		MatrixTranspose dummyAInt
		cZ[k][]=dummyAInt[q]
		k+=1
	while(k<imax)
	
	// generate pixel locations for image
	// assume monotonic data since already processed once by OpenTA
	Variable g, h
	
	CCxIm[0]= CCx[0]-((CCx[1]-CCx[0])/2)
	g=1
	do
		CCxIm[g] = (CCx[g] + CCx[g-1])/2
		g += 1
	while (g < imax)
	CCxIm[imax] = CCx[imax-1] + ((CCx[imax-1] - CCx[imax-2])/2)


	CCyIm[0]= CCy[0]-((CCy[1]-CCy[0])/2)
	h=1
	do
		CCyIm[h] = (CCy[h] + CCy[h-1])/2
		h+= 1
	while (h < jmax)
	CCyIm[jmax] = CCy[jmax-1] + ((CCy[jmax-1] - CCy[jmax-2])/2)

	KillWaves/Z dummytime, dummyAInt, dummyA
	
	Display;AppendImage $ccMName vs {$ccIMx,$ccIMy}//;DelayUpdate
	ModifyImage $ccMName ctab= {*,*,Rainbow,0}
	ModifyImage $ccMName ctabAutoscale=3,lookup= $""
	ShowInfo
	
	GetWindow kwTopWin wtitle
	String imTitle = S_Value
	String imTitle2 = WinName(0,1)
	imTitle = RemoveEnding(imTitle, ":")
	Cursor/I/H=1 /W=$imTitle A $ccMName 1,1
	Cursor/M/H=1 B
	
	//	ImageHookGen()
	SetWindow $imTitle2, hook(MyHook)=MyWindowHook
	DoWindow/F $imTitle2
	
	return 0
End

Function t0WaveGen()
	String t0s, lambdaWave
	
	Prompt t0s, "Choose 2D wave with wavelength, t0 pairs:", popup, Wavelist("*",";","")
	Prompt lambdaWave, "Choose x matrix wave name (lambda values):", popup, Wavelist("*",";","")
	
	DoPrompt "Generate t0 wave from polynomial fit", t0s, lambdaWave
	if (V_flag == 1)
		// User hit cancel button, so do nothing.
		return 0 
	else
		Wave lW = $lambdaWave
		Wave t0pairs = $t0s
		Variable t0N = Dimsize(t0pairs,0)
		// Plot extracted t0 values and fit with polynomial
		Display t0pairs[][1] vs t0pairs[][0]
		ModifyGraph mode=3,marker=19,rgb=(0,1,0)
		// Can't fit 2D wave directly
		MatrixOp/O t0tempX = col(t0pairs,0)
		MatrixOp/O t0poly = col(t0pairs,1)
		CurveFit/NTHR=0/TBOX=768 poly 3,  t0poly /X=t0tempX /D 
		AppendToGraph fit_t0poly
		KillWaves/Z t0tempX, t0poly
		// Generate new t0 wave for all lambda values
		Variable llength=Dimsize(lW,0)
		String newt0Name = RemoveEnding(RemoveEnding(lambdaWave)) + "t0"
		Make/D/O/N=(llength) $newt0Name
		Wave tnew = $newt0Name
		tnew = K0 + K1*lw + K2*(lw)^2
	endif
End

Function ImportCC()
	Variable refNum
	String message = "Select a file with Solvent Fit Coefficients" 
	String outputPath, fileHandle, wName, wName2
	String fileFilters = "Fit Coefficient File (*.txt):.txt;" 
	fileFilters += "All Files:.*;" 
	Open /D /R /F=fileFilters /M=message refNum 
	outputPath = S_fileName
	printf "%s\r" outputPath
	fileHandle = ParseFilePath(5, outputPath, ":", 0,0)
	fileHandle = ParseFilePath(3, outputPath, ":", 0,0)
	printf "%s\r" fileHandle
	Variable lengthTest = strlen(fileHandle)
//  shorten string to 22 characters to satisfy Igor constraints on wave name length
//  max is 31.  start with 22 so that we can append suffix.
	fileHandle = CleanUpName(fileHandle, 0)
	if(lengthTest >= 22)
		Variable i = lengthTest - 22
		Variable j=0
		do
			fileHandle = RemoveEnding(fileHandle)
			j+=1
		while(j <= i)
	else
		fileHandle = fileHandle 
	endif
	fileHandle += "_sxfc"
	LoadWave/J/M/D/A=$fileHandle/K=0 outputPath
	
	// WaveExists  1 valid 0 invalid
	wName = fileHandle +"0"
	Variable b=0

	if (WaveExists ($wName) == 1)
		do
			b += 1
			wName2 = fileHandle + num2str(b)
		while(WaveExists ($wName2) == 1)
		// write b-1 since loop runs one more time than we want
		wName = fileHandle + num2str(b-1)
	endif	
	
	
	Print wName
	Variable cancelTest = cmpstr(outputPath, "")
	if (cancelTest == 0)
		Print "Open file cancelled."
	else
		Redimension/N=(-1,2) $wName
	endif
End

Function FitSolvFC()
	String ImTest = ImageInfo("","",0)
	//  make this only applicable to images
	if(cmpstr(Imtest,"",0) == 0)
		Print "Not an image."
		return 0
	else
		NVAR gCursB = root:Packages:InspectData:gCursB
		String info= ImageInfo("","",0)
		String zmatName = StringByKey("ZWAVE",info)
	//	String xwName = StringByKey("XWAVE",info)
		String base
		String suffix
		String regex = "(.*?)(zmat|zibg|zroi|zccm|A.sv)"
		SplitString /E=(regex) zmatName, base, suffix
		String xwName, ywName
		if(CmpStr(zmatName,"")==0)
			xwName = "new_xc"
			ywName = "new_yc"
		else
			xwName = base + "xc"
			ywName = base + "yc"
		endif
	//	String xwName = RemoveEnding(zmatName, "zmat")
	// xwName = RemoveEnding(zmatName, "zibg")

		Variable xpos, lambda, CursName
		Variable xposB, lambdaB
		xpos = pcsr(A)
		lambda = hcsr(A)
		if(gCursB == 1)
			xposB = pcsr(B)
			lambdaB = hcsr(B)
		endif
//		Prompt CursName, "Cursor used to generate plot:", popup, "Cursor A;Cursor B;ROI Cursor A/B"
		Prompt CursName, "Cursor used to generate plot:", popup, "Cursor A;Cursor B"
		Prompt zmatName, "Enter matrix wave name: "
	//	Prompt zmatName, "Enter matrix wave name: ", popup, StringByKey("ZWAVE",ImageInfo("","",0))
		Prompt xpos, "Enter cursor A postion for desired wavelength: "
		Prompt xposB, "Enter cursor B postion for desired wavelength: "
		Prompt xwName, "Enter wavelength wave name: "
		if(gCursB == 1)
			DoPrompt "Generate Kinetics", CursName, zmatName, xpos, xposB, xwName
		else
			DoPrompt "Generate Kinetics", zmatName, xpos, xwName
			CursName = 1
		endif
		if (V_Flag)
			return -1
		endif
		String skwName
		if(CursName == 1)
			Print "A"
			skwName = Plot1DFromMat2(zmatName, xpos, xpos, xwName, ywName, 0)
		elseif(CursName == 2)
			Print "B"
			skwName = Plot1DFromMat2(zmatName, xposB, xposB, xwName, ywName, 0)
		elseif(CursName == 3)
			Print "A/B"
			skwName = Plot1DFromMat2(zmatName, xpos, xposB, xwName, ywName, 0)
		endif
	DoUpdate
	Variable t0guess, t0final
	Prompt  t0guess, "Enter guess for t0: "
	DoPrompt "Initial Guesses", t0guess
	Make/D/N=5/O W_coef
	W_coef[0] = {.001,.001,-.001,t0guess,.06}
	FuncFit/NTHR=0/TBOX=768 SolventResponse W_coef  $skwName /X=$ywName /D 
	t0final = W_coef[3]
			if(CursName == 1)
			Print num2str(lambda) + ", " num2str(t0final)
			Appendt0Wave(lambda, t0final)
		elseif(CursName == 2)
			Print num2str(lambdaB) + ", " num2str(t0final)
			Appendt0Wave(lambdaB, t0final)
		elseif(CursName == 3)
			Print num2str(lambda) + ", " num2str(t0final)
			Appendt0Wave(lambda, t0final)
		endif 
	endif
	return 0
End

Function Appendt0Wave(lambda, t0final)
	Variable lambda, t0final
	String towavename
	String newtowave = "FC_t0"
	Variable lcheck, tcheck
	Prompt towavename, "Enter target 2D t0 Fit Coefficient Wave to Append: ", popup, "New Wave;"+Wavelist("*",";","")
	Prompt newtowave, "Enter name of new FC target wave: "
	Prompt lambda, "Lambda position: "
	Prompt t0final, "Time zero position: "
	DoPrompt "Store Fit Coefficients", towavename,newtowave, lambda, t0final
	if (V_flag == 1)
		// User hit cancel button, so do nothing.
		return 0 
	endif
	Variable dummy
	If(CmpStr(towavename,"New Wave") == 0)
		If(WaveExists($newtowave) == 0)
			Make/D/O/N=(1,2) $newtowave
			Wave NT0 = $newtowave
			NT0[0][0] = lambda
			NT0[0][1] = t0final
		Else
			Print "Wave already exists.  Try Again."
			Appendt0Wave(lambda, t0final)
		Endif
	Else
		Wave TWN = $towavename
		If(Dimsize(TWN,1) == 2)
			dummy = Dimsize(TWN,0)
			Redimension/N=(dummy+1,2) TWN
			TWN[dummy][0] = lambda
			TWN[dummy][1] = t0final
		Else
			Print "Target wave does not have the proper dimensions.  Try a new wave."
			Appendt0Wave(lambda, t0final)
		Endif
	EndIf
End
