diff --git a/add_overlap.pro b/add_overlap.pro
new file mode 100644
index 0000000000000000000000000000000000000000..695969b619f9b39e6e1181e3f58e8c2825e9cdbe
--- /dev/null
+++ b/add_overlap.pro
@@ -0,0 +1,42 @@
+; $Id: add_overlap.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	ADD_OVERLAP
+;
+; PURPOSE:
+;	Find the overlap region of two 2D arrays, after ideally superposing the
+;	relative positions of a reference point, and add the overlap region of
+;	the second array to the overlap region of the first one.
+;
+; CATEGORY:
+;	Array manipulation.
+;
+; CALLING SEQUENCE:
+;	ADD_OVERLAP, Array1, Array2, R1, R2
+;
+; INPUTS:
+;	Array1, Array2:	Input arrays
+;
+;	R1:	2-components vector of coordinates of reference point in Array1
+;
+;	R2:	2-components vector of coordinates of reference point in Array2
+;
+; OUTPUTS:
+;	Array1:	Input Array1 + overlap region of Array2
+;
+; SIDE EFFECTS:
+;	Array1 is overwritten.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+PRO add_overlap, array1, array2, r1, r2
+
+	on_error, 2
+	array_overlap, size52(array1, /DIM), size52(array2, /DIM), r1, r2, $
+   				   lx1, ux1, ly1, uy1, lx2, ux2, ly2, uy2
+	array1[lx1,ly1] = array1[lx1:ux1,ly1:uy1] + array2[lx2:ux2,ly2:uy2]
+	return
+end
diff --git a/add_subscript.pro b/add_subscript.pro
new file mode 100644
index 0000000000000000000000000000000000000000..04349e04bef5a369ee66ec75c67c977f17dad661
--- /dev/null
+++ b/add_subscript.pro
@@ -0,0 +1,36 @@
+; $Id: add_subscript.pro, v 1.1 Mar 2012 e.d. $
+;
+;+
+; NAME:
+;	ADD_SUBSCRIPT
+;
+; PURPOSE:
+;	Add new subscript to subscript vector.
+;
+; CATEGORY:
+;	STARFINDER auxiliary procedures.
+;
+; CALLING SEQUENCE:
+;	Result = ADD_SUBSCRIPT(Subscripts, S)
+;
+; INPUTS:
+;	Subscripts:	1D vector of subscripts.
+;
+;	S:	new subscripts to append to Subscripts
+;
+; OUTPUTS:
+;	Return appended vector of subscripts.
+;	If input vector Subscripts is not valid, return S.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, June 2001.
+;   1) Created this file (E. D., March 2012).
+;-
+
+FUNCTION add_subscript, subscripts, s
+
+    on_error, 2
+    if  subscripts[0] lt 0  then $
+       w = s  else  w = [subscripts, s]
+    return, w
+end
diff --git a/airy_pattern.pro b/airy_pattern.pro
new file mode 100644
index 0000000000000000000000000000000000000000..215a1486edb9b879f4ec4e7e00d9acceb7bb5d36
--- /dev/null
+++ b/airy_pattern.pro
@@ -0,0 +1,52 @@
+; $Id: airy_pattern.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	AIRY_PATTERN
+;
+; PURPOSE:
+;	Compute Airy pattern.
+;
+; CATEGORY:
+;	Models.
+;
+; CALLING SEQUENCE:
+;	Result = AIRY_PATTERN(X_size, Y_size, X_center, Y_center, Sampling_factor)
+;
+; INPUTS:
+;	X_size, Y_size:	X- and y_ size of output array
+;
+;	X_center, Y_center:	Coordinates of center, not necessarily integer
+;
+; OPTIONAL INPUTS:
+;	Sampling_factor:	Ratio of actual sampling factor to critical sampling
+;		step for the optical system producing the Airy pattern.
+;		The default is Sampling_factor = 1, i.e. critical sampling
+;
+; OUTPUTS:
+;	Result:	2D array containing Airy pattern normalized to maximum = 1
+;
+; PROCEDURE:
+;	Compute Airy pattern as defined in
+;	Born, Wolf, "Principles of Optics", Pergamon Press, 2nd revised edition.
+;	Suitably adjust sampling step.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION airy_pattern, x_size, y_size, x_center, y_center, sampling_factor
+
+	if  n_elements(sampling_factor) eq 0  then $
+	   sampling_factor = 1			; critical sampling
+	scale = !pi / 2
+	; define 2D array of radial distances
+	r = radial_dist(x_size, y_size, x_center, y_center)
+	r = temporary(r) * scale * sampling_factor
+	; compute diffraction pattern
+	w = where(r ne 0)
+	d = r  &  d[w] = 2 * (beselj(r, 1))[w] / r[w]
+	w = where(r eq 0, n)  &  if  n ne 0  then  d[w] = 1
+	d = temporary(d)^2
+	return, d
+end
\ No newline at end of file
diff --git a/all_max.pro b/all_max.pro
new file mode 100644
index 0000000000000000000000000000000000000000..74ec9c53eba4c2d84111e20ea79f937534f57937
--- /dev/null
+++ b/all_max.pro
@@ -0,0 +1,61 @@
+; $Id: all_max.pro, v 1.1 Sep 2001 e.d. $
+;
+;+
+; NAME:
+;	ALL_MAX
+;
+; PURPOSE:
+;	Find relative maxima in a 2D array.
+;	A given pixel is considered a relative maximum if it is brighter
+;	than its 8-neighbors or 4-neighbors.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	ALL_MAX, Array, X, Y, N
+;
+; INPUTS:
+;	Array:	2D array to be searched
+;
+; KEYWORD PARAMETERS:
+;	BOX:	Size of sub-regions where the local maxima are defined.
+;		The default is 3, i.e. each returned peak is the relative
+;		maximum in a 3x3 sub-array.
+;
+;	FOUR:	Set this keyword to identify relative maxima as pixels
+;		brighter than their 4-neighbors. The default is to use
+;		8-neighbors.
+;
+; OUTPUTS:
+;	X, Y:	Coordinates of detected maxima
+;
+;	N:	Number of detected maxima
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;	1) Added BOX keyword (Emiliano Diolaiti, September 2001).
+;-
+
+PRO all_max, array, x, y, n, BOX = box, FOUR = four
+
+	on_error, 2
+	if  n_elements(box) eq 0  then  box  = 3
+	siz = size52(array, /DIM)  &  sx = siz[0]  &  sy = siz[1]
+	xedge = box/2  &  yedge = box/2
+	ext_array = extend_array(array, sx + 2*xedge, sy + 2*yedge)
+	m = make_array(sx + 2*xedge, sy + 2*yedge, /BYTE, VALUE = 1B)
+	for  dx = -box/2, box/2  do  for  dy = -box/2, box/2  do begin
+	   if  keyword_set(four)  then $
+	      check = abs(dx) ne abs(dy)  else $	; 4-neighbors
+	      check = dx ne 0 or dy ne 0		     	; 8-neighbors
+	   if  check  then $
+	      m = temporary(m) and ext_array gt shift(ext_array, dx, dy)
+	endfor
+   w = where(m[xedge:xedge+sx-1,yedge:yedge+sy-1] eq 1, n)
+   if  n ne 0  then  subs_to_coord, w, sx, x, y
+   if  n eq 1  then begin
+	   x = x[0]  &  y = y[0]
+	endif
+	return
+end
diff --git a/angle.pro b/angle.pro
new file mode 100644
index 0000000000000000000000000000000000000000..740c238dffc7588f729e1e8938965f2b71e5e85e
--- /dev/null
+++ b/angle.pro
@@ -0,0 +1,49 @@
+; $Id: angle.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	ANGLE
+;
+; PURPOSE:
+;	Compute the position angles of a set of points on a plane with
+;	respect to the horizontal axis of a reference frame passing through
+;	a fixed origin. The angles are measured counter-clockwise in radians
+;	and belong to the interval [0, 2*pi[.
+;	The computations are performed in floating-point arithmethic.
+;
+; CATEGORY:
+;	Mathematics.
+;
+; CALLING SEQUENCE:
+;	Result = ANGLE(X0, Y0, X, Y)
+;
+; INPUTS:
+;	X0, Y0:	Couple of scalars, representing coordinates of the origin
+;
+;	X, Y:	Coordinates of the points for which the position angle
+;		must be computed
+;
+; OUTPUTS:
+;	Result:	Array of position angles, with the same size as the input
+;		arrays X and Y.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION angle, x0, y0, x, y
+
+	on_error, 2
+	a = float(x) - x  &  dx = x - float(x0[0])  &  dy = y - float(y0[0])
+	w = where(dx eq 0 and dy ne 0, n)
+	if  n ne 0  then  a[w] = !pi/2
+	w = where(dx ne 0, n)
+	if  n ne 0  then  a[w] = atan(dy[w] / dx[w])
+	w = ((dx lt 0) or ((dx eq 0) and (dy lt 0))) and 1B
+	a = a + w * !pi
+	w = where(a lt 0, n)
+	if  n ne 0  then  a[w] = a[w] + 2*!pi
+	w = where(a eq 2*!pi, n)
+	if  n ne 0  then  a[w] = 0
+ 	return, a
+end
diff --git a/array_overlap.pro b/array_overlap.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1ac97fe0124ab00e4ee24b9c896731e057c7728d
--- /dev/null
+++ b/array_overlap.pro
@@ -0,0 +1,60 @@
+; $Id: array_overlap.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	ARRAY_OVERLAP
+;
+; PURPOSE:
+;	Find bounds of overlap region of two 2D arrays, by ideally
+;	matching the coordinates of a reference point.
+;
+; CATEGORY:
+;	Array manipulation.
+;
+; CALLING SEQUENCE:
+;	ARRAY_OVERLAP, Size1, Size2, R1, R2, $
+;   			   Lx1, Ux1, Ly1, Uy1, Lx2, Ux2, Ly2, Uy2
+;
+; INPUTS:
+;	Size1:	2-components vector, size of array 1, as returned by
+;		size52(array1, /DIM)
+;
+;	Size2:	2-components vector, size of array 2
+;
+;	R1:	2-components vector, coordinates of reference pixel in array 1
+;
+;	R2:	2-components vector, coordinates of reference pixel in array 2
+;
+; OUTPUTS:
+;	Lx1, Ux1, Ly1, Uy1:	Lower and Upper X- and Y- bounds of intersection
+;		in array 1
+;
+;	Lx2, Ux2, Ly2, Uy2:	Lower and Upper X- and Y- bounds of intersection
+;		in array 2
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+
+
+; INT_BOUNDS: auxiliary procedure.
+
+PRO int_bounds, p1, p2, size1, size2, l, u
+
+	l = (p1 - p2) > 0 < (size1 - 1)
+	u = (p1 + size2 - p2 - 1) > 0 < (size1 - 1)
+	return
+end
+
+
+PRO array_overlap, size1, size2, r1, r2, $
+   				   lx1, ux1, ly1, uy1, lx2, ux2, ly2, uy2
+
+	on_error, 2
+	int_bounds, r1[0], r2[0], size1[0], size2[0], lx1, ux1
+	int_bounds, r1[1], r2[1], size1[1], size2[1], ly1, uy1
+	int_bounds, r2[0], r1[0], size2[0], size1[0], lx2, ux2
+	int_bounds, r2[1], r1[1], size2[1], size1[1], ly2, uy2
+	return
+end
diff --git a/array_partition.pro b/array_partition.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2cb69fde95a6b528f2b006b097837b3ed77c7935
--- /dev/null
+++ b/array_partition.pro
@@ -0,0 +1,97 @@
+; $Id: array_partition.pro, v 1.2 Mar 2012 e.d. $
+;
+;+
+; NAME:
+;   ARRAY_PARTITION
+;
+; PURPOSE:
+;   Define bounds to partition an array into a pre-fixed number of
+;   parts along one dimension.
+;
+; CATEGORY:
+;   Array manipulation.
+;
+; CALLING SEQUENCE:
+;   ARRAY_PARTITION, Siz, N, L, U, S
+;
+; INPUTS:
+;   Siz:  (Long) integer, representing the array size along the
+;      dimension of interest.
+;
+;   N:    Number of parts into which the dimension must be partitioned.
+;     The size of the sub-domains may be defined using the keyword STEP.
+;     In this case, the input N may be left undefined; on output, it is
+;     set to the actual number of sub-domains.
+;
+; KEYWORD INPUTS:
+;   STEP: Set this keyword to the integer value of the desired size of each
+;     sub-domain. If STEP is set, the parameter N is set on output to
+;     the actual number of sub-domains.
+;     
+;   OVERLAP: Set this keyword to overlap sub-domains (upper boundary of 
+;     a sub-domain coincides with lower boundary of next sub-domain).
+;
+; OUTPUTS:
+;   L, U: N-element long integer vectors, defined as follows:
+;      [L[i], U[i]] are the bounds of the i-th partition, i = 0, N - 1.
+;      Notice that L[0] = 0, U[N - 1] = Siz - 1.
+;      The following relation holds:
+;      L[i + 1] = U[i] + 1, if the keyword OVERLAP is not set
+;      L[i + 1] = U[i], if the keyword OVERLAP is set
+;
+;   S:    N-element long integer vector, with the size of each sub-domain.
+;
+; EXAMPLE:
+;   Given a 512x512 array, partition it into 2x2 sub-regions. Define the
+;   bounds of the sub-arrays along one dimension:
+;   
+;   IDL> ARRAY_PARTITION, 512, 2, L, U, S
+;   IDL> PRINT, L, U
+;        0      256
+;        255    511
+;   IDL> ARRAY_PARTITION, 512, 2, L, U, S, /OVERLAP
+;   IDL> PRINT, L, U
+;        0      256
+;        256    512
+;
+; MODIFICATION HISTORY:
+;   Written by:  Emiliano Diolaiti, December 1999.
+;   1) Added keyword STEP (E.D., July 2007).
+;   2) Added keyword OVERLAP (E.D., March 2012).
+;-
+
+PRO array_partition, siz, n, l, u, s, STEP = step, OVERLAP = overlap
+
+    on_error, 2
+    if keyword_set(step) then begin
+       n = siz / step
+       if siz mod step ne 0 then n = n + 1
+    endif else $
+       step = siz / n
+    if keyword_set(overlap) then begin
+       l = lindgen(n + 1) * step
+       u = l[1: *]
+       u[n - 1] = siz
+       l = l[0: n - 1]
+    endif else begin
+       l = lindgen(n) * step
+       u = l + step - 1
+       u[n - 1] = siz - 1
+    endelse
+    s = u - l + 1
+    return
+end
+
+
+;    on_error, 2
+;    if keyword_set(step) then begin
+;       n = siz / step
+;       if siz mod step ne 0 then n = n + 1
+;    endif else $
+;       step = siz / n
+;    l = lindgen(n) * step
+;    u = l + step - 1
+;    u[n - 1] = siz - 1
+;    s = u - l + 1
+;    return
+;end
diff --git a/b_splines.pro b/b_splines.pro
new file mode 100644
index 0000000000000000000000000000000000000000..356709dd350ba665127b68abf38fe03f2ad94295
--- /dev/null
+++ b/b_splines.pro
@@ -0,0 +1,102 @@
+; $Id: b_splines.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	B_SPLINES
+;
+; PURPOSE:
+;	Compute the 1-D observation matrix to determine the coefficients
+;	of an interpolating spline in the B-splines representation.
+;
+; CATEGORY:
+;	Mathematics. Interpolation.
+;
+; CALLING SEQUENCE:
+;	B_SPLINES, Points, Knots, Degree, A, Npt
+;
+; INPUTS:
+;	Points:	1D vector of observation points
+;
+;	Knots:	Knots of the spline function
+;
+;	Degree:	Degree of the spline (integer, odd)
+;
+; KEYWORD PARAMETERS:
+;	BOUNDS:	Option used by SPLINE_INTERP (see the function SPLINE_INTERP
+;		in the file 'splie_interp.pro') to compute the observation matrix.
+;
+;	FULL:	The observation array has a band structure of width (Degree+1).
+;		Normally only the nonzero entries are returned. Set the keyword
+;		FULL to return the full observation matrix.
+;
+; OUTPUTS:
+;	A:	Observation matrix of size (Degree+1)*N, where N is the number
+;		of observation points. If the keyword FULL is set, A is returned
+;		as a N*N array.
+;
+;	Npt:	1D Vector of subscripts defining the relative position of
+;			the observation points with respect to the knots of the spline
+;
+; PROCEDURE:
+;	Apply the procedures described in
+;	Paul Dierckx, "Curve and surface fitting with splines",
+;		Clarendon Press, Oxford (1995)
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;	Adapted in IDL from the sofware FITPACK, written in FORTRAN by P.Dierckx.
+;	Complete references may be found in
+;	Paul Dierckx, "Curve and surface fitting with splines",
+;		Clarendon Press, Oxford (1995)
+;-
+
+
+;;; Auxiliary function.
+
+; SPL_BSPL: given a set of knots k and a point x, with k[s] <= x < k[s+1],
+; compute the (d + 1) non-zero B-splines of degree d at x, using
+; the recurrence relations of de Boor and Cox.
+
+FUNCTION spl_bspl, k, d, x, s
+
+	on_error, 2
+	v = fltarr(d + 1)  &  aux = fltarr(d)
+	v[0] = 1
+	for  j = 1, d  do begin
+	   aux[0:j-1] = v[0:j-1]  &  v[0] = 0
+	   for  i = 1, j  do begin
+	      si = s + i  &  sj = si - j
+	      f = aux[i-1] / (k[si] - k[sj])
+	      v[i-1] = v[i-1] + f * (k[si] - x)
+	      v[i] = f * (x - k[sj])
+	   endfor
+	endfor
+	return, v
+end
+
+;;; The main routine.
+
+PRO b_splines, points, knots, degree, a, npt, $
+   			   BOUNDS = chk_bounds, FULL = full
+
+	on_error, 2
+	npoints = n_elements(points)  &  nk = n_elements(knots)
+	if  keyword_set(full)  then $
+	   a = fltarr(nk - degree - 1, npoints)  else $
+	   a = fltarr(degree + 1, npoints)
+	npt = lonarr(npoints)
+	l = degree  &  r = l + 1  &  num = 0
+	for  n = 0L, npoints - 1  do begin
+	   point = points[n]
+	   if  keyword_set(chk_bounds)  then $
+	      point = (point > knots[degree]) < knots[nk-degree-1]
+	   while  point ge knots[r] and l lt nk - degree - 2  do begin
+	      l = r  &  r = l + 1  &  num = num + 1
+	   endwhile
+	   npt[n] = num
+	   ; knots[degree + npt[n]] <= points[n] < knots[degree + npt[n] + 1]
+	   b = spl_bspl(knots, degree, point, l)
+	   if  keyword_set(full)  then  a[num,n] = b  else  a[*,n] = b
+	endfor
+	return
+end
diff --git a/background.fits b/background.fits
new file mode 100644
index 0000000000000000000000000000000000000000..7c9b6821de69ee0a29b4782314f2c73bfc4734f9
Binary files /dev/null and b/background.fits differ
diff --git a/binary_array.pro b/binary_array.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0741ac12904a123731f23e1bae957cc2d14479a7
--- /dev/null
+++ b/binary_array.pro
@@ -0,0 +1,36 @@
+; $Id: binary_array.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	BINARY_ARRAY
+;
+; PURPOSE:
+;	Transform an array to binary by thresholding.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = BINARY_ARRAY(Array, Threshold)
+;
+; INPUTS:
+;	Array:	Input array to be thresholded
+;
+;	Threshold:	Scalar value or 2D array with the same size as Array.
+;
+; OUTPUTS:
+;	Result:	Byte array, defined as follows:
+;		Result[j,i] = 1B, if Array[j,i] >= Threshold
+;		            = 0B, otherwise
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION binary_array, array, threshold
+
+	on_error, 2
+	siz = size52(array, /DIM)  &  b = bytarr(siz[0], siz[1])
+	w = where(array ge threshold, n)  &  if  n ne 0  then  b[w] = 1
+	return, b
+end
diff --git a/center_array.pro b/center_array.pro
new file mode 100644
index 0000000000000000000000000000000000000000..92c7e90c4f8f08131fe85d0027ceb82816d9512b
--- /dev/null
+++ b/center_array.pro
@@ -0,0 +1,46 @@
+; $Id: center_array.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	CENTER_ARRAY
+;
+; PURPOSE:
+;	Shift a 2D array in order to put its maximum at the specified position.
+;
+; CATEGORY:
+;	Array manipulation.
+;
+; CALLING SEQUENCE:
+;	Result = CENTER_ARRAY(Array, X, Y)
+;
+; INPUTS:
+;	Array:	2D array to shift
+;
+;	X, Y:	X- and y- final coordinates of the Array maximum
+;
+; KEYWORD PARAMETERS:
+;	NO_EXTEND:	Set this keyword to a nonzero value to indicate that
+;		the Array must be extended before being shifted. The original
+;		size is restored after the shift. Use this keyword to prevent
+;		circular shift effects.
+;
+; OUTPUTS:
+;	Result:	Shifted array
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION center_array, image, x, y, NO_EXTEND = no_extend
+
+	on_error, 2
+	s = size52(image, /DIM)
+	if  n_elements(x) * n_elements(y) eq 0  then begin
+	   x = s[0]/2  &  y = s[1]/2
+	endif
+	m = get_max(image)  &  xs = x - m[0]  &  ys = y - m[1]
+	if  xs eq 0 and ys eq 0  then  return, image
+	if  keyword_set(no_extend)  then $
+	   return, shift(image, xs, ys)  else $
+	   return, extend_shift(image, xs, ys)
+end
diff --git a/centroid.pro b/centroid.pro
new file mode 100644
index 0000000000000000000000000000000000000000..d5f20f376255d308e9ec38207d6715a55f7f7b02
--- /dev/null
+++ b/centroid.pro
@@ -0,0 +1,41 @@
+; $Id: centroid.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	CENTROID
+;
+; PURPOSE:
+;	Compute the centroid of a 2D array, defined as the "center of mass"
+;	of a 2D intensity distribution.
+;
+; CATEGORY:
+;	Mathematics.
+;
+; CALLING SEQUENCE:
+;	Result = CENTROID(Array)
+;
+; INPUTS:
+;	Array:	2D array
+;
+; OUTPUTS:
+;	Result:	2-components floating point vector, containing the
+;		coordinates of the centroid
+;
+; RESTRICTIONS:
+;	Apply only to 2D arrays.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION centroid, array
+
+	on_error, 2
+	s = size(array, /DIM)  &  sx = s[0]  &  sy = s[1]
+	x = findgen(sx)  &  x_one = make_array(sx, VALUE = 1)
+	y = findgen(sy)  &  y_one = make_array(sy, VALUE = 1)
+	tot_array = total(array)
+	xc = total(array * (x # y_one)) / tot_array
+	yc = total(array * (x_one # y)) / tot_array
+	return, [xc, yc]
+end
diff --git a/centroider.pro b/centroider.pro
new file mode 100644
index 0000000000000000000000000000000000000000..3b5a313c920e44a84ebb44ed193048e2dbcf426b
--- /dev/null
+++ b/centroider.pro
@@ -0,0 +1,107 @@
+; $Id: centroider.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	CENTROIDER
+;
+; PURPOSE:
+;	Sub-pixel centering of an image by iterative fractional shift.
+;
+; CATEGORY:
+;	Signal processing. Interpolation.
+;
+; CALLING SEQUENCE:
+;	Result = CENTROIDER(Image)
+;
+; INPUTS:
+;	Image:	2D array to be centered
+;
+; KEYWORD PARAMETERS:
+;	XC, YC:	Reference pixel for centroid computation. The default is the
+;		Image maximum.
+;
+;	CENTROID_BOX:	Width of box centered at the reference pixel used to
+;		compute the Image centroid. The default is equal to the (rounded)
+;		FWHM of the peak at the reference position. A minimum value of
+;		3 pixels is fixed.
+;
+;	CENTROID_TOL:	This keyword defines the stopping condition for the
+;		iterative algorithm, i.e. the maximum allowed off-centering of
+;		the Image centroid. The default is  CENTROID_TOL = 0.05 pixels.
+;
+;	CENTROID_IT:	Use this keyword to fix the maximum number of
+;		iterations. The default is 20, even though centering is achieved
+;		in fewer iterations (tipically 5).
+;
+;	INTERP_TYPE:	Set this keyword to a string identifying one of the
+;		interpolation techiques supported by IMAGE_SHIFT. For more details
+;		see the function IMAGE_SHIFT in the file 'image_shift.pro'.
+;
+; OUTPUTS:
+;	Result:	Centered array
+;
+; OPTIONAL OUTPUTS:
+;	XSHIFT, YSHIFT:	Use these output keywords to retrieve the total shifts
+;		performed to center the Image, starting from the reference position.
+;		The quantities XC + X_SHIFT and YC + Y_SHIFT represent and estimate
+;		of the true centroid location in the original Image
+;
+; RESTRICTIONS:
+;	The Image is shifted by interpolation techniques, which are suited to
+;	well sampled data. This method should not applied to undersampled
+;	images.
+;
+; PROCEDURE:
+;	Compute first the offset of the image centroid and shift the array in
+;	order to cancel the off-centering. The operation is iterated until the
+;	offset is smaller than a pre-fixed tolerance.
+;	The centroid is computed on a small box centered at a reference position,
+;	which generally coincides with the image maximum.
+;	The image shift is performed by interpolation.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;	Adapted from an algorithm described in:
+;	Christou J.C., Bonaccini D., "Technical Report ESO VLT",
+;		Doc. No. GEN-TRE-ESO-11620-1261  (1996)
+;-
+
+FUNCTION centroider, image, XC = xc, YC = yc, CENTROID_BOX = box, $
+   					 CENTROID_TOL = tol, CENTROID_IT = maxit,     $
+   					 XSHIFT = xs, YSHIFT = ys, _EXTRA = extra
+
+	on_error, 2
+	; reference pixel
+	if  n_elements(xc) * n_elements(yc) eq 0  then begin
+	   m = get_max(image)  &  x = m[0]  &  y = m[1]
+	endif else begin
+	   x = xc  &  y = yc
+	endelse
+	x = round(x)  &  y = round(y)
+	; box size to compute centroid
+	if  n_elements(box) eq 0  then $
+	   b = fwhm(image, X = x, Y = y)  else  b = box
+	b = round(b)
+	if  n_elements(b) eq 1  then  b = [b, b]
+	b = b < size52(image, /DIM)  &  b = b + 1 - b mod 2  &  b = b > 3
+	; other parameters
+	if  n_elements(tol)   eq 0  then  tol = 0.05
+	if  n_elements(maxit) eq 0  then  maxit = 20
+	imag = image  &  it = 0  &  xs = 0.  &  ys = 0.
+	; iteration
+	repeat begin
+	   it = it + 1
+	   ; compute centroid
+	   c = centroid(sub_array(imag, b[0], b[1], $
+	   					REFERENCE = [x, y], LX = lx, LY = ly))
+	   dx = x - lx - c[0]  &  dy = y - ly - c[1]
+	   ; shift image to center centroid
+	   xs = xs + dx   &  ys = ys + dy
+	   imag = image_shift(imag, xs, ys, _EXTRA = extra, shift_data)
+	   convergence = abs(dx) lt tol and abs(dy) lt tol
+	endrep until  convergence or it eq maxit
+	if  it eq maxit and not convergence  then begin
+	   imag = image  &  xs = 0.  &  ys = 0.
+	endif
+	return, imag
+end
diff --git a/check_border.pro b/check_border.pro
new file mode 100644
index 0000000000000000000000000000000000000000..31c0cc44af9aa303f47de77ca21e71e2462eaf3a
--- /dev/null
+++ b/check_border.pro
@@ -0,0 +1,59 @@
+; $Id: check_border.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	CHECK_BORDER
+;
+; PURPOSE:
+;	Given two 2D arrays, ideally superpose the positions of a reference
+;	point and check if the first array is larger than the second by a
+;	pre-fixed edge of pixels. Resize the arrays if the condition is
+;	not fulfilled.
+;
+; CATEGORY:
+;	Array manipulation.
+;
+; CALLING SEQUENCE:
+;	CHECK_BORDER, Array1, Array2, Pix1, Pix2, Edge, $
+;   			  Array1_out, Array2_out, Pix1_out, Pix2_out
+;
+; INPUTS:
+;	Array1, Array2:	Input 2D arrays
+;
+;	Pix1, Pix2:	2-components vectors, coordinates of reference point in
+;		Array1 and Array2 respectively
+;
+;	Edge:	When the coordinates of the reference point have been matched,
+;		the size of Array1 must be equal to the size of Array2 plus an
+;		additional border, whose width is specified by Edge
+;
+; OUTPUTS:
+;	Array1_out, Array2_out:	Output arrays
+;
+;	Pix1_out, Pix2_out:	Positions of reference points in output arrays
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+PRO check_border, array1, array2, pix1, pix2, edge, $
+   				  array1_out, array2_out, pix1_out, pix2_out
+
+	on_error, 2
+	s1 = size52(array1, /DIM)  &  s2 = size52(array2, /DIM)
+	l1 = [0, 0]  &  u1 = s1 - 1  &  l2 = [0, 0]  &  u2 = s2 - 1
+	; resize lower bounds
+	d = pix1 - (pix2 + edge)
+	l1 = l1 + (d > 0)  &  pix1_out = pix1 - (d > 0)
+	l2 = l2 - (d < 0)  &  pix2_out = pix2 + (d < 0)
+	; resize upper bounds
+	d = (s1 - pix1) - (s2 - pix2 + edge)
+	u1 = u1 - (d > 0)  &  u2 = u2 + (d < 0)
+	; resize arrays
+	array1_out = array1  &  array2_out = array2
+	if  min(u1 - l1) ge 0 and min(u2 - l2) ge 0  then begin
+	   array1_out = array1_out[l1[0]:u1[0],l1[1]:u1[1]]
+	   array2_out = array2_out[l2[0]:u2[0],l2[1]:u2[1]]
+	endif
+    return
+end
diff --git a/circ_mask.pro b/circ_mask.pro
new file mode 100644
index 0000000000000000000000000000000000000000..57c43efd415b81593d443c13438bbe3f31d1a3db
--- /dev/null
+++ b/circ_mask.pro
@@ -0,0 +1,51 @@
+; $Id: circ_mask.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	CIRC_MASK
+;
+; PURPOSE:
+;	Apply a circular mask to a 2D array, setting to a pre-fixed value all
+;	the pixels whose distance from a reference position is either greater
+;	or smaller equal than a specified threshold.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = CIRC_MASK(Array, X0, Y0, R0)
+;
+; INPUTS:
+;	Array:	2D array to mask
+;
+;	X0, Y0:	Coordinates of center of circular mask
+;
+;	R0:	Radius of circular mask in pixels
+;
+; KEYWORD PARAMETERS:
+;	INNER:	Set this keyword to a nonzero value to mask the pixels within
+;		a distance R0 from (X0, Y0): the boundary is included (i.e. masked).
+;		The default is to mask the pixels outside that distance (in this
+;		case the boundary is excluded, i.e. not masked).
+;
+;	VALUE:	Use this value to replace masked pixels. The default is VALUE = 0
+;
+; OUTPUTS:
+;	Result:	Array with region defined by circular mask set to the value
+;		defined by the keyword VALUE.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION circ_mask, array, x0, y0, r0, INNER = inner, VALUE = v
+
+	on_error, 2
+	siz = size52(array, /DIM)
+	r = radial_dist(siz[0], siz[1], x0, y0)
+	if  keyword_set(inner)  then $
+	   w = where(r le r0, npix)  else  w = where(r gt r0, npix)
+	if  n_elements(v) eq 0  then  v = 0
+	circ = array  &  if  npix ne 0  then  circ[w] = v
+	return, circ
+end
diff --git a/click_on_max.pro b/click_on_max.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1bd8765c3eab6a11acc5ee7175f243a790ef7efa
--- /dev/null
+++ b/click_on_max.pro
@@ -0,0 +1,119 @@
+; $Id: click_on_max.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	CLICK_ON_MAX
+;
+; PURPOSE:
+;	Interactive selection of local maxima in an image by mouse click.
+;
+; CATEGORY:
+;	Data visualization.
+;
+; CALLING SEQUENCE:
+;	CLICK_ON_MAX, Image, X, Y
+;
+; INPUTS:
+;	Image:	2D data array containing local maxima to be selected
+;
+; KEYWORD PARAMETERS:
+;	MARK:	Set this keyword to a nonzero value to mark selected objects
+;		as soon as they are clicked on
+;
+;	N_SELECT:	Set this keyword to an integer (positive) number to specify
+;		the number of maxima to select. If this keyword is not used, the
+;		selection is interrupted by a right-button click.
+;
+;	BOXSIZE:	Specify the tolerance on the maximum position in pixel
+;		units: after each click, the maximum within a box having this
+;		size and centered at the click location is selected.
+;		The default is BOXSIZE = 11.
+;
+;	UPPER:	Set this keyword to a scalar value or a 2D array with the same
+;		size as the Image to specify the threshold above which the position
+;		of a click must be retained as it is, without searching for the
+;		nearest local maximum. This odd requirement is related to the
+;		selection of stars in a stellar field.
+;
+;	DARK:	Set this keyword to a nonzero value to have dark marks for the
+;		selected points. This options is available only if the keyword MARK
+;		is set (as obvious). For more details, see the procedure CROSSES
+;		in the file 'crosses.pro'.
+;
+;	SYMSIZE:	Specify the size of the symbol used by the routine CROSSES
+;			to mark the selected points.
+;
+;	SILENT:	Set this keyword to avoid printing a brief instruction message
+;
+; OUTPUTS:
+;	X, Y: x- and y- coordinates (in pixel units, data coordinates) of
+;		the selected local maxima
+;
+; OPTIONAL OUTPUTS:
+;	Mark each selected maximum if the keyword MARK is set.
+;
+; RESTRICTIONS:
+;	This procedure assumes that the image containing the objects of
+;	interest is already displayed in the currently active window.
+;	It is also assumed that the window is completely filled by the image.
+;
+; PROCEDURE:
+;	Select peaks by clicking with the left button of the mouse.
+;	The selection ends when the number of maxima specified by the input
+;	keyword N_SELECT is reached or when the right button of the mouse
+;	is pushed.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;	2) Removed call to obsolete routine APPEND_ELEMENTS
+;	   (Emiliano Diolaiti, June 2001).
+;-
+
+PRO click_on_max, image, MARK = mark, N_SELECT = n_sel, $
+   		  BOXSIZE = boxsize, UPPER = threshold, SILENT = silent, $
+   		  _EXTRA = extra, x, y
+
+	on_error, 2
+	s = float(size52(image, /DIM))
+	if  n_elements(boxsize) eq 0  then  boxsize = 11
+	if  n_elements(threshold) eq 0  then  threshold = max(image) + 1
+	fixed = n_elements(n_sel) ne 0
+	if  fixed  then  n_select = round(n_sel > 0)
+	if  not keyword_set(silent)  then begin
+	   print, 'Select by clicking with the left button of your mouse...'
+	   if  not fixed  then  print, 'Push right button to exit'
+	endif
+	!MOUSE.button = 1  &  n_click = 0
+	cursor, x_click, y_click, /NORMAL, /DOWN
+	while  !MOUSE.button eq 1  do begin
+		x_click = round(x_click * s[0])  &  y_click = round(y_click * s[1])
+		if  boxsize ge 2 and image[x_click, y_click] lt threshold  then $
+		   m = get_max(sub_array(image, boxsize, REF = [x_click, y_click], $
+		   						 LX = lx, LY = ly)) $
+		else begin
+		   m = [0, 0]  &  lx = x_click  &  ly = y_click
+		endelse
+		x_click = x_click + m[0] - (x_click - lx)
+		y_click = y_click + m[1] - (y_click - ly)
+		if  n_elements(x_saved) eq 0  then begin
+		   x_saved = x_click
+		   y_saved = y_click
+		endif else begin
+		   x_saved = [x_saved, x_click]
+		   y_saved = [y_saved, y_click]
+		endelse
+		if  keyword_set(mark)  then $
+		   crosses, tvrd(), x_click/(s[0] - 1)*!D.x_size, y_click/(s[1] - 1)*!D.y_size, $
+		   	    /EXISTING, _EXTRA = extra, /DEVICE
+		if  fixed  then begin
+		   n_click = n_click + 1
+		   if  n_click eq n_select  then  !MOUSE.button = 4
+		endif
+		if  !MOUSE.button eq 1  then  cursor, x_click, y_click, /NORMAL, /DOWN
+	endwhile
+	if  n_elements(x_saved) ne 0  then begin
+		x = x_saved  &  y = y_saved
+	endif
+	remove_coincident, x, y, x, y
+	return
+end
diff --git a/compare_lists.pro b/compare_lists.pro
new file mode 100644
index 0000000000000000000000000000000000000000..67f6f0b074f6b534af612f8a4132df030c8816db
--- /dev/null
+++ b/compare_lists.pro
@@ -0,0 +1,114 @@
+; $Id: compare_lists, v 1.1 Feb 2000 e.d. $
+;
+;+
+; NAME:
+;	COMPARE_LISTS
+;
+; PURPOSE:
+;	Given two sets of points on a plane, compare and match their
+;	coordinates to find coincidences.
+;
+; CATEGORY:
+;	Miscellaneous.
+;
+; CALLING SEQUENCE:
+;	COMPARE_LISTS, X1, Y1, X2, Y2, X1c, Y1c, X2c, Y2c
+;
+; INPUTS:
+;	X1, Y1:	Coordinates of first set of points
+;
+;	X2, Y2:	Coordinates of second set of points
+;
+; KEYWORD PARAMETERS:
+;	MAX_DISTANCE:	Two points in set 1 and 2 are considered coincident if
+;		their reciprocal distance is smaller than a pre-fixed threshold.
+;		Use the MAX_DISTANCE threshold to fix a threshold.
+;		If MAX_DISTANCE is undefined, any distance is considered acceptable.
+;		In this case, the COMPARE_LISTS procedure just sorts the second
+;		list according to the ordering of the first one.
+;
+; OUTPUTS:
+;	X1c, Y1c:	Coordinates of common points in set 1
+;
+;	X2c, Y2c:	Coordinates of common points in set 2
+;
+; OPTIONAL OUTPUTS:
+;	X_in1, Y_in1:	Coordinates of points in set 1 with no
+;		counterpart in set 2.
+;
+;	X_in2, Y_in2:	Coordinates of points in set 2 with no
+;		counterpart in set 1.
+;
+;	SUBSCRIPTS_1:	Use this output keyword to retrieve the subscripts of
+;		the common points in set 1. In other words, the outputs X1c is
+;		equal to the quantity X1[Subscripts1], where Subscripts1 is the
+;		output value of the keyword SUBSCRIPTS_1.
+;
+;	SUBSCRIPTS_2:	Use this output keyword to retrieve the subscripts of
+;		the common points in set 2. In other words, the outputs X2c is
+;		equal to the quantity X2[Subscripts2], where Subscripts2 is the
+;		output value of the keyword SUBSCRIPTS_2.
+;
+;	SUB1, SUB2:	Use these output keywords to retrieve the subscripts of
+;		the elements belonging only to set 1 and 2 respectively.
+;
+; RESTRICTIONS:
+;	The COMPARE_LISTS procedure assumes the two sets of coordinates are
+;	referred to the same reference frame. If there is an offset or a rotation
+;	between the two sets, use MATCH_COORD before (see 'match_coord.pro').
+;
+; PROCEDURE:
+;	Find coincidences between points in sets 1 and 2 by comparing their
+;	positions. For each point in the first set, the second set is searched
+;	for the still unexamined point nearest to the point under examination.
+;	If the distance between the two points is smaller than the pre-fixed
+;	threshold, a new coincidence is found and recorded.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;   Updates:
+;	1) Fixed bug on output keywords SUBSCRIPTS_1 and SUBSCRIPTS_2
+;	   (Emiliano Diolaiti, January 2000).
+;	2) Modified output keywords (Emiliano Diolaiti, February 2000).
+;-
+
+PRO compare_lists, x1, y1, x2, y2, x1c, y1c, x2c, y2c, $
+				   MAX_DISTANCE = max_distance, $
+				   SUBSCRIPTS_1 = subc1, SUBSCRIPTS_2 = subc2, $
+				   SUB1 = sub1, SUB2 = sub2
+
+	on_error, 2
+	any_dist = n_elements(max_distance) eq 0 and 1B
+	n1 = n_elements(x1)  &  n2 = n_elements(x2)  &  nc = min([n1, n2])
+	x1c = make_array(nc, TYPE = size52(x1, /TYPE))
+	y1c = make_array(nc, TYPE = size52(y1, /TYPE))
+	x2c = make_array(nc, TYPE = size52(x2, /TYPE))
+	y2c = make_array(nc, TYPE = size52(y2, /TYPE))
+	marked1 = bytarr(n1)  &  marked2 = bytarr(n2)
+	k = 0L
+	for  n = 0L, n1 - 1  do begin
+	   u = where(marked2 eq 0, n_unmarked)
+	   if  n_unmarked ne 0  then begin
+	      d = min(distance(x1[n], y1[n], x2[u], y2[u]), w)
+	      accept_it = any_dist
+	      if  not accept_it  then  accept_it = d le max_distance
+	      if  accept_it  then begin
+	         x1c[k] = x1[n]  &  y1c[k] = y1[n]
+	         x2c[k] = x2[u[w]]  &  y2c[k] = y2[u[w]]
+	         if  k eq 0  then begin
+	            subc1 = n  &  subc2 = u[w]
+	         endif else begin
+	            subc1 = [subc1, n]  &  subc2 = [subc2, u[w]]
+	         endelse
+	         marked1[n] = 1B  &  marked2[u[w]] = 1B
+	         k = k + 1
+	      endif
+	   endif
+	endfor
+	if  k ne 0  then begin
+	   x1c = x1c[0:k-1]  &  y1c = y1c[0:k-1]
+	   x2c = x2c[0:k-1]  &  y2c = y2c[0:k-1]
+	endif
+	sub1 = where(marked1 eq 0B)  &  sub2 = where(marked2 eq 0B)
+	return
+end
diff --git a/convergence.pro b/convergence.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f132a07a78c646131248a57eb92c9e44b8693e9c
--- /dev/null
+++ b/convergence.pro
@@ -0,0 +1,49 @@
+; $Id: convergence.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	CONVERGENCE
+;
+; PURPOSE:
+;	Check convergence condition between two IDL variables.
+;
+; CATEGORY:
+;	Mathematics.
+;
+; CALLING SEQUENCE:
+;	Result = CONVERGENCE(Var1, Var2, Tolerance)
+;
+; INPUTS:
+;	Var1:	First IDL variable
+;
+;	Var2:	Second IDL variable
+;
+;	Tolerance:	Tolerance for convergence check
+;
+; KEYWORD PARAMETERS:
+;	ABSOLUTE:	Set this keyword to a nonzero value to check the absolute
+;		error convergence between Var1 and Var2. The default is to check
+;		the relative error convergence
+;
+; OUTPUTS:
+;	Return the byte value 1B if the convergence condition is fulfilled
+;	and 0B otherwise.
+;
+; RESTRICTIONS:
+;	The relative error between a variable set to zero and a nonzero
+;	variable is 1 (100%) by definition. In this case the convergence
+;	condition will never be fulfilled, unless the relative Tolerance
+;	is > 1, which is rather unlikely.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION convergence, var1, var2, tolerance, ABSOLUTE = absolute
+
+	on_error, 2
+	if  keyword_set(absolute)  then $
+	   error = abs(var2 - var1)  else $
+	   error = abs(relative_error(var1, var2))
+	return, max(error) lt tolerance and 1B
+end
diff --git a/coord_to_subs.pro b/coord_to_subs.pro
new file mode 100644
index 0000000000000000000000000000000000000000..e2f690dc3abf0f4e5cbd57d8e996985c63b83fee
--- /dev/null
+++ b/coord_to_subs.pro
@@ -0,0 +1,36 @@
+; $Id: coord_to_subs.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	COORD_TO_SUBS
+;
+; PURPOSE:
+;	Convert pixel coordinates in a 2D array to array subscripts,
+;	to access the array in memory address order.
+;
+; CATEGORY:
+;	Array manipulation.
+;
+; CALLING SEQUENCE:
+;	Result = COORD_TO_SUBS(X, Y, N_columns)
+;
+; INPUTS:
+;	X, Y:	Coordinates of pixels
+;
+;	N_columns:	Number of columns in the 2D array
+;
+; OUTPUTS:
+;	Result:	Long integer vector of array subscripts
+;
+; RESTRICTIONS:
+;	Apply only to 2D arrays.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION coord_to_subs, x, y, n_columns
+
+	on_error, 2
+	return, round(y) * n_columns + round(x)
+end
\ No newline at end of file
diff --git a/correlate_max.pro b/correlate_max.pro
new file mode 100644
index 0000000000000000000000000000000000000000..13ff16f9a824affaa3fc4634979860e627cd957c
--- /dev/null
+++ b/correlate_max.pro
@@ -0,0 +1,128 @@
+; $Id: correlate_max.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	CORRELATE_MAX
+;
+; PURPOSE:
+;	Given an object, a reference template and an estimate of the object's
+;	center, obtain a better estimate of the object's position by maximizing
+;	its correlation with the template.
+;
+; CATEGORY:
+;	Image statistics.
+;
+; CALLING SEQUENCE:
+;	CORRELATE_MAX, Image, Template, X_i, Y_i, Search_box, $
+;   			   Max_correl, X_opt, Y_opt
+;
+; INPUTS:
+;	Image:	2D array containing the object to be correlated
+;
+;	Template:	reference template to compute the correlation
+;
+;	X_i, Y_i: x- and y- coordinates of the object's presumed center
+;
+;	Search_box:	width of box centered at (X-i, Y_i) inside which the template
+;		must be ideally moved to find the best match with the object
+;
+; KEYWORD PARAMETERS:
+;	XT, YT:	reference pixel in Template, i.e. pixel to be ideally superposed
+;		to the presumed object's center. The default is the central pixel
+;		of the Template array
+;
+;	X_BAD, Y_BAD: x- and y- coordinates of bad pixels, i.e. unreliable data
+;		points to be excluded from the computation. Default: no bad pixels
+;
+;	TEMPLATES: stack of sub-pixel-shifted templates, used to maximize the
+;		correlation with sub-pixel accuracy positioning
+;
+;	DX, DY:	1D arrays of fractional shifts corresponding to the shifted
+;		templates in the Templates stack
+;
+; OUTPUTS:
+;	Max_correl:	maximum correlation coefficient
+;
+;	X_opt, Y_opt:	x- and y- coordinates of the object position's
+;		guess yielding the largest correlation coefficient
+;
+; RESTRICTIONS:
+;	1) The correlation between the object and the template is computed
+;	on the overlap area of the two arrays, which is found after ideally
+;	superposing their reference pixels. The template must be 'moved'
+;	within the range specified by the input parameter Search_box in order
+;	to optimize the correlation coefficient. To ensure that the area of
+;	the overlapping region be the same for all possible shifts, the Image
+;	array must be larger than the Template array, by an amount depending
+;	on the width of the search box. The CORRELATE_MAX procedure doesn't
+;	check this condition! If for some reason the overlapping region is
+;	less than 3 x 3 pixels in size, the correlation is set to 0.
+;	2) Sub-pixel positioning is performed only if all the input keywords
+;	TEMPLATES, DX and DY are defined. These parameters may be defined by
+;	means of the function SHIFT_TEMPLATES in the file 'shift_templates.pro'
+;
+; PROCEDURE:
+;	Find the intersection between Template and Image after superposing
+;	their reference pixels and compute the correlation coefficient by
+;	means of CORRELATION_COEFF. The operation is performed for all possible
+;	shifts within the range specified by the parameter Search_box; the
+;	position yielding the largest match is taken as the best estimate of
+;	the object's center.
+;	The shift + match + correlate procedure may then be repeated for sub-
+;	pixel shifts around the optimal position previously found, in order
+;	to determine a better estimate of the object's center.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+PRO correlate_max, image, template, x_i, y_i, search_box, $
+   				   XT = x_t, YT = y_t, X_BAD = xb, Y_BAD = yb, $
+   				   TEMPLATES = templates, DX = dx, DY = dy, $
+   				   max_correl, x_opt, y_opt
+
+	on_error, 2
+	; optimize correlation applying integer shifts,
+	; within the range specified by search_box
+	lo_xy = [0, 0]  &  up_xy = size52(image, /DIM) - 1  &  min_size = 3
+	h = round(search_box > 1) / 2  &  nshift = (2*h + 1)^2
+	x = lonarr(nshift)  &  y = lonarr(nshift)  &  correl = fltarr(nshift)
+	xi = round(x_i)  &  yi = round(y_i)
+	if  n_elements(x_t) eq 0 or n_elements(y_t) eq 0  then begin
+	   s = size52(template, /DIM)  &  xt = s[0]/2  &  yt = s[1]/2
+	endif else begin
+	   xt = round(x_t)  &  yt = round(y_t)
+	endelse
+	n = 0L
+	for  j = -h, +h  do  for  i = -h, +h  do begin
+	   x[n] = (xi + j) > lo_xy[0] < up_xy[0]
+	   y[n] = (yi + i) > lo_xy[1] < up_xy[1]
+	   extract_overlap, image, template, [x[n], y[n]], [xt, yt], ima, tem, $
+						lxi, uxi, lyi, uyi
+	   sx = uxi - lxi + 1  &  sy = uyi - lyi + 1
+	   if  min([sx, sy]) ge min_size  then begin
+	      if  n_elements(xb) ne 0 and n_elements(yb) ne 0  then begin
+	         wb = where(xb ge lxi and xb le uxi and yb ge lyi and yb le uyi, nb)
+	         if  nb ne 0  then $
+	            wb = coord_to_subs(xb[wb] - lxi, yb[wb] - lyi, sx)
+	      endif
+	      correl[n] = correlation_coeff(ima, tem, EXCLUDE = wb)
+	   endif
+	   n = n + 1
+	endfor
+	max_correl = max(correl, w)  &  x_opt = x[w]  &  y_opt = y[w]
+	; optimize correlation applying sub-pixel shifts
+	mag = n_elements(templates) * n_elements(dx) * n_elements(dy) ne 0
+	if  mag  then  mag = size52(templates, /N_DIM) eq 3
+	if  mag  then begin
+	nshift = (size52(templates, /DIM))[2]
+	x = x_opt + dx  &  y = y_opt + dy  &  correl = fltarr(nshift)
+	for  n = 0L, nshift - 1  do begin
+	   correlate_max, image, templates[*,*,n], x_opt, y_opt, 1, $
+	   				  XT = xt, YT = yt, X_BAD = xb, Y_BAD = yb, correl_n
+	   correl[n] = correl_n
+	endfor
+	max_correl = max(correl, w)  &  x_opt = x[w]  &  y_opt = y[w]
+	endif
+	return
+end
diff --git a/correlation_coeff.pro b/correlation_coeff.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2834cf83eb5320addc03d5feb7ff22fc2b45886b
--- /dev/null
+++ b/correlation_coeff.pro
@@ -0,0 +1,59 @@
+; $Id: correlation_coeff.pro, v 1.0 Aug 1999 e.d. $
+;+
+; NAME:
+;	CORRELATION_COEFF
+;
+; PURPOSE:
+;	Compute the correlation coefficient of a pattern with a reference template.
+;
+; CATEGORY:
+;	Image statistics.
+;
+; CALLING SEQUENCE:
+;	Results = CORRELATION_COEFF(Pattern, Template)
+;
+; INPUTS:
+;	Pattern:	Pattern to compare with the template
+
+;	Template:	Reference template
+;
+; KEYWORD PARAMETERS:
+;	EXCLUDE:	Vector of array subscripts identifying data points
+;		which must be excluded from the computation of the correlation
+;
+; OUTPUTS:
+;	Return the correlation coefficient between Pattern and Template.
+;
+; RESTRICTIONS:
+;	The input data Pattern and Template must be equally sized arrays
+;	(with any number of dimensions).
+;
+; PROCEDURE:
+;	Compute the correlation coefficient according to the formula in
+;		Gonzalez, Woods, "Digital Image Processing",
+;		Addison-Wesley (1992), p. 584'
+;	Optionally exclude 'bad pixels' from the computation
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION correlation_coeff, pattern, template, EXCLUDE = ex
+
+	on_error, 2
+	; find acceptable data points
+	n = n_elements(pattern)  &  s = lindgen(n)
+	if  n_elements(ex) ne 0  then begin
+	   w = where(ex ge min(s) and ex le max(s), n)
+	   if  n ne 0  then  e = ex[w]
+	endif
+	if  n_elements(e) ne 0  then begin
+	   s[e] = -1  &  w = where(s ge 0, n)
+	   if  n ne 0  then  s = s[w]
+	endif
+	if  n eq 0  then  return, 0.
+	; compute correlation coefficient
+	p = pattern[s]   &  p = p - mean(p)
+	t = template[s]  &  t = t - mean(t)
+	return, total(p*t) / sqrt(total(p*p) * total(t*t))
+end
diff --git a/create_element.pro b/create_element.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2e60199199fcfbee744283a59fc2404cd024d80f
--- /dev/null
+++ b/create_element.pro
@@ -0,0 +1,37 @@
+; $Id: create_element.pro, v 1.1 Mar 2012 e.d. $
+;
+;+
+; NAME:
+;	CREATE_ELEMENT
+;
+; PURPOSE:
+;	Generate new element of star list and initialize it.
+;
+; CATEGORY:
+;	STARFINDER auxiliary procedures.
+;
+; CALLING SEQUENCE:
+;	Result = CREATE_ELEMENT(X, Y, F)
+;
+; INPUTS:
+;	X, Y:	x- and y- position of object.
+;
+; OPTIONAL INPUTS:
+;	F:	object flux.
+;
+; OUTPUTS:
+;	Return initialized element, representing a (possibly)
+;	presumed star
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, June 2001.
+; 	1) Created this file (E. D., March 2012).
+;-
+
+FUNCTION create_element, x, y, f
+
+    on_error, 2
+    element = star()
+    update_list, element, x, y, f
+    return, element
+end
diff --git a/crosses.pro b/crosses.pro
new file mode 100644
index 0000000000000000000000000000000000000000..ec3b6669769a443520c2bf016d835be2566a1970
--- /dev/null
+++ b/crosses.pro
@@ -0,0 +1,82 @@
+; $Id: crosses.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	CROSSES
+;
+; PURPOSE:
+;	Mark interesting points in an image with crosses.
+;
+; CATEGORY:
+;	Data visualization.
+;
+; CALLING SEQUENCE:
+;	CROSSES, image, x, y
+;
+; INPUTS:
+;	Image:	2D data array
+;	X, Y: x- and y- coordinates of points to mark (with a '+' sign)
+;
+; KEYWORD PARAMETERS:
+;	X2, Y2:	x- and y- coordinates of another set of interesting points,
+;		to be marked with a different symbol ('x' sign)
+;
+;	EXISTING: Set this keyword when the image is already displayed on
+;		some graphic window
+;
+;	_EXTRA: Input keywords of DISPLAY_IMAGE (namely display options).
+;		Neglected if the keyword EXISTING is set.
+;
+;	DARK: Set this keyword to specify that the color of the marks must
+;		be the IDL default background color (dark marks). The default is
+;		to use the highest color number available (bright marks).
+;
+;	DEVICE:	Set this keyword to a nonzero value to specify that the input
+;		coordinates are device coordinates. The default is data coordinates.
+;
+;	SYMSIZE:	Keyword of the IDL routine PLOTS: specifies symbol size.
+;
+; OUTPUTS:
+;	Graphic output.
+;
+; SIDE EFFECTS:
+;	Open a new graphic window if the image is displayed for the first time.
+;
+; RESTRICTIONS:
+;	1) If the keyword EXISTING is set, the procedure assumes that the image
+;	is already display in the currently active window.
+;	2) If the keyword EXISTING is not set, the image is displayed on a new
+;	window, using the default display options (see the function
+;	DEFAULT_DISPLAY_OPT in the file 'default_display_opt.pro') if the input
+;	keyword OPTIONS is not used.
+;	3) The color of the marks (bright by default, dark if the keyword DARK
+;	is set) is correct assuming the IDL system variables !D and !P have not
+;	been previously modified.
+;
+; PROCEDURE:
+;	Display the image on a new window if the keyword EXISTING is not set,
+;	using the display options defined by the keyword OPTIONS or the default
+;	options if the keyword is not defined. Then put a sign on each point.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+PRO crosses, image, x, y, X2 = x2, Y2 = y2, EXISTING = existing, $
+	         _EXTRA = extra, DARK = dark, DEVICE = device, SYMSIZE = symsize
+
+	on_error, 2
+	if  not keyword_set(existing)  then $
+	   display_image, image, _EXTRA = extra
+	if  keyword_set(dark)  then $
+	   color = !P.background  else $
+	   color = !D.n_colors - 1
+	if  keyword_set(device)  then  scale = [1, 1]  else $
+	   scale = [!D.x_size, !D.y_size] / float(size52(image, /DIM) - 1)
+	plots, x * scale[0], y * scale[1], PSYM = 1, /DEVICE, $
+	       COLOR = color, SYMSIZE = symsize
+	if  n_elements(x2) * n_elements(y2) ne 0  then $
+	   plots, x2 * scale[0], y2 * scale[1], PSYM = 7, /DEVICE, $
+	          COLOR = color, SYMSIZE = symsize
+	return
+end
diff --git a/default_display_opt.pro b/default_display_opt.pro
new file mode 100644
index 0000000000000000000000000000000000000000..493ff0bede377d548873d870cc5459523b4da73c
--- /dev/null
+++ b/default_display_opt.pro
@@ -0,0 +1,41 @@
+; $Id: default_display_opt.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	DEFAULT_DISPLAY_OPT
+;
+; PURPOSE:
+;	Define default options to display a 2D image.
+;
+; CATEGORY:
+;	Data visualization
+;
+; CALLING SEQUENCE:
+;	Result = DEFAULT_DISPLAY_OPT(Image)
+;
+; INPUTS:
+;	Image: 2D image
+;
+; OUTPUTS:
+;	Return structure of default options. The structure fields are:
+;	range: 2-components vector, containing the min. and max. level to display
+;		( default = [min(image), max(image)] )
+;	chop: chopping threshold; all the gray-levels above this threshold will be
+;		replaced with the min. level. The default value is greater than the
+;		image maximum, i.e. no chopping
+;	reverse: boolean, true if the gray-levels must be reversed (default false)
+;	stretch: string, representing the stretch to be used. Possible values are
+;		'square', 'linear' (default), 'square root', 'logarithm'
+;	color_table: long integer, representing the color table number (default 0)
+;
+; MODIFICATION HISTORY:
+;	Written by: Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION default_display_opt, image
+
+	range = [min(image), max(image)]
+	chop = 1e6  &  while  chop le range[1]  do  chop = 10 * chop
+	return, { range: range, chop: chop, reverse: 0B, $
+			  stretch: 'linear', color_table: 0L }
+end
diff --git a/delete_element.pro b/delete_element.pro
new file mode 100644
index 0000000000000000000000000000000000000000..c85295c161949d5a0e446f1d8031e3d83229ef96
--- /dev/null
+++ b/delete_element.pro
@@ -0,0 +1,32 @@
+; $Id: delete_element.pro, v 1.1 Mar 2012 e.d. $
+;
+;+
+; NAME:
+;	DELETE_ELEMENT
+;
+; PURPOSE:
+;	Delete last element from list of stars.
+;
+; CATEGORY:
+;	STARFINDER auxiliary procedures.
+;
+; CALLING SEQUENCE:
+;	Result = DELETE_ELEMENT(List)
+;
+; INPUTS:
+;	List:	input list to trim.
+;
+; OUTPUTS:
+;	Return trimmed list.
+;	
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, June 2001.
+;   1) Created this file (E. D., March 2012).
+;-
+
+FUNCTION delete_element, list
+
+    on_error, 2
+    l = list  &  n = n_elements(l)
+    return, l[0:n-2]
+end
diff --git a/diag_mult.pro b/diag_mult.pro
new file mode 100644
index 0000000000000000000000000000000000000000..5f1d9d726d783fe4048c354476d36a8fc76f5cda
--- /dev/null
+++ b/diag_mult.pro
@@ -0,0 +1,41 @@
+; $Id: diag_mult.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	DIAG_MULT
+;
+; PURPOSE:
+;	Compute the array multiplication of a square array and a diagonal
+;	array, represented by a 1D vector containing its main diagonal.
+;
+; CATEGORY:
+;	Array manipulation.
+;
+; CALLING SEQUENCE:
+;	Result = DIAG_MULT(A, D)
+;
+; INPUTS:
+;	A:	Square array
+;
+;	D:	1D vector, representing main diagonal of diagonal array
+;
+; KEYWORD PARAMETERS:
+;	PREMULT:	Set this keyword to a nonzero value to pre-multiply A by D.
+;		The default is to post-multiply.
+;
+; OUTPUTS:
+;	Return product array, having the same size as A.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION diag_mult, a, d, PREMULT = premult
+
+	on_error, 2
+	size_a = (size52(a, /DIM))[0]
+	b = a  &  if  keyword_set(premult)  then  b = transpose(b)
+	for  j = 0L, size_a - 1  do  b[*,j] = b[*,j] * d
+	if  keyword_set(premult)  then  b = transpose(b)
+	return, b
+end
diff --git a/display_help.txt b/display_help.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e3f4d02e008fedb8e4a833fd0005b3342c5a991a
--- /dev/null
+++ b/display_help.txt
@@ -0,0 +1,16 @@
+  'Display' menu help page
+
+
+  The 'Display' menu contains the following sub-menus:
+
+  'Select data':
+      Select the data array to display (image, PSF, background,
+      detected stars, synthetic field, other files).
+
+  'Options':
+      Modify the display options of the currently displayed data
+      array. If the displayed array is a 'global variable' (image,
+      PSF, background, detected stars, synthetic field), the new
+      display options become the current options for the array
+      itself.
+ 
\ No newline at end of file
diff --git a/display_image.pro b/display_image.pro
new file mode 100644
index 0000000000000000000000000000000000000000..5b471349e18ee3e2fd338ca7df362088b7e5aa85
--- /dev/null
+++ b/display_image.pro
@@ -0,0 +1,98 @@
+; $Id: display_image.pro, v 1.2 Sep 2001 e.d. $
+;
+;+
+; NAME:
+;	DISPLAY_IMAGE
+;
+; PURPOSE:
+;	Display a 2D image, according to a pre-fixed or default set of options.
+;
+; CATEGORY:
+;	Data visualization.
+;
+; CALLING SEQUENCE:
+;	DISPLAY_IMAGE, Image [, wnum]
+;
+; INPUTS:
+;	Image: 2D data array
+;
+; OPTIONAL INPUT PARAMETERS:
+;	Wnum: number of existing graphic window
+;
+; KEYWORD PARAMETERS:
+;	OPTIONS: structure containing display options,
+;		as defined by the function DEFAULT_DISPLAY_OPT
+;
+;	/MODIFY_OPT: set this keyword to modify display options
+;
+; OUTPUTS:
+;	Graphic output on the window identified by the parameter wnum
+;
+; OPTIONAL OUTPUT PARAMETERS:
+;	Wnum: number of new graphic window, if undefined on input
+;
+;	OPTIONS: display options
+;
+; SIDE EFFECTS:
+;	1) Use WSET to activate the graphic window identified by the parameter wnum.
+;	2) If wnum is undefined, open a new graphic window. The size of this window
+;	is proportional to the image size and however smaller than the screen size.
+;	3) If /MODIFY_OPT is set, call XDisplayOpt to modify the display options.
+;
+; RESTRICTIONS:
+;	If the parameter Wnum is a window number < 32 but the corresponding
+;	window does not exist (or has been deleted), the new window size is set
+;	by IDL and may not fit the image x- and y size. If Wnum >=32 and the
+;	corresponding window does not exists, an error occurs.
+;
+; PROCEDURE:
+;	Activate the window identified by Wnum (or create a new one) and
+;	display the input image, using the display options passed with the
+;	keyword OPTIONS or the default ones defined by DEFAULT_DISPLAY_OPT.
+;	NOTE on intensity stretch. Possible value are:
+;	square: display  Image^2
+;	linear: display  Image
+;	square root: display  sqrt(Image > 0)
+;	logarithm: display  alog10(Image > max(Image)*1e-15)
+;
+; MODIFICATION HISTORY:
+;	Written by: Emiliano Diolaiti, August 1999.
+;	Updates:
+;	1) Replaced TVScl with scaling + TV;
+;	   Corrected stretch with reverse option.
+;     (Emiliano Diolaiti, November 1999).
+;	2) Replaced again TV with TVScl
+;     (Emiliano Diolaiti, September 2001).
+;-
+
+PRO display_image, image, wnum, OPTIONS = options, MODIFY_OPT = modify_opt
+
+	on_error, 2
+	; define graphic window if necessary
+	if  n_elements(wnum) eq 0  then begin
+	   smax = get_screen_size()  &  smax = min(smax)*2./3.
+	   s = size52(image, /DIM)  &  s = s / max(s) * smax  &  s = round(s)
+	   window, /FREE, XSIZE = s[0], YSIZE = s[1]  &  wnum = !D.window
+	endif
+	; define default display options if necessary
+	if  n_elements(options) eq 0  then $
+	   options = default_display_opt(image)
+	; process image according to display options
+	data = image
+	data = (data > options.range[0]) < options.range[1]
+	w = where(data gt options.chop, count)
+	if  count ne 0  then  data[w] = min(data)
+	case options.stretch of
+	   'square': data = data^2
+	   'linear': ; do nothing
+	   'square root': data = sqrt(data > 0)
+	   'logarithm': data = alog10(data > max(data) * 1e-15)
+	endcase
+	if  options.reverse  then  data = -data
+	; display image
+	wset, wnum  &  erase, wnum  &  loadct, options.color_table, /SILENT
+	tvscl, congrid(data, !D.x_size, !D.y_size)
+	if  keyword_set(modify_opt)  then $
+	   options = xdisplayopt(image, wnum, OPTIONS = options, /NODISPLAY)
+	return
+end
diff --git a/distance.pro b/distance.pro
new file mode 100644
index 0000000000000000000000000000000000000000..7dfd01239c29a1bbb9014ed240a41a3aba526508
--- /dev/null
+++ b/distance.pro
@@ -0,0 +1,33 @@
+; $Id: distance.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	DISTANCE
+;
+; PURPOSE:
+;	Compute the euclidean distance of a set of points on a plane from a
+;	fixed origin. Distances are computed in floating-point aritmethic.
+;
+; CATEGORY:
+;	Mathematics.
+;
+; CALLING SEQUENCE:
+;	Result = DISTANCE(X0, Y0, X, Y)
+;
+; INPUTS:
+;	X0, Y0:	Couple of scalars, representing the position of the origin
+;
+;	X, Y:	Vectors of coordinates
+;
+; OUTPUTS:
+;	Result:	Vector of euclidean distances, with the same size as X and Y
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION distance, x0, y0, x, y
+
+	on_error, 2
+	return, sqrt((x - float(x0[0]))^2 + (y - float(y0[0]))^2)
+end
diff --git a/estimate_background.pro b/estimate_background.pro
new file mode 100644
index 0000000000000000000000000000000000000000..c57251adb2ffc647eb7ac6cb9eefd2ea9d221a39
--- /dev/null
+++ b/estimate_background.pro
@@ -0,0 +1,57 @@
+; $Id: estimate_background.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	ESTIMATE_BACKGROUND
+;
+; PURPOSE:
+;	Call IMAGE_BACKGROUND to estimate intensity distribution of the
+;	background in a given image. If an error occurs, estimate the
+;	background emission by median smoothing of the input image.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = ESTIMATE_BACKGROUND(Image, Step)
+;
+; INPUTS:
+;	Image:	2D array
+;
+;	Step:	Size of sub-regions to measure local background or box size
+;		for median smoothing of the Image
+;
+; KEYWORD PARAMETERS:
+;	SKY_MEDIAN:	Set this keyword to a nonzero value to estimate the
+;		background directly by median smoothing of Image
+;
+;	_EXTRA:	All the input keywords supported by IMAGE_BACKGROUND
+;
+; OUTPUTS:
+;	Result:	2D array, having the same size as the input Image.
+;
+; RESTRICTIONS:
+;	All the restrictions described in IMAGE_BACKGROUND, if the default
+;	method is used.
+;	If median smoothing is used, it should be noticed that this technique
+;	tends to overestimate the local background level, especially in the
+;	presence of bright point sources.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION estimate_background, image, step, SKY_MEDIAN = sky_median, _EXTRA = extra
+
+	on_error, 2
+	if  keyword_set(sky_median)		   then $
+   	   b = median_filter(image, step)  else $
+   	begin
+	   b = image_background(image, step, _EXTRA = extra)
+	   if  n_elements(b) eq 1  then begin
+	      message, 'unable to estimate background; trying with median smoothing', /INFO
+	      b = median_filter(image, step)
+	   endif
+	endelse
+	return, b
+end
diff --git a/extend_array.pro b/extend_array.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f2d6c06320802b26cbbf4320296e7bebd84a4bac
--- /dev/null
+++ b/extend_array.pro
@@ -0,0 +1,82 @@
+; $Id: extend_array.pro, v 1.1 Jan 2000 e.d. $
+;
+;+
+; NAME:
+;	EXTEND_ARRAY
+;
+; PURPOSE:
+;	Pad 2D array with 0s.
+;
+; CATEGORY:
+;	Array manipulation.
+;
+; CALLING SEQUENCE:
+;	Result = EXTEND_ARRAY(Array, S0, S1)
+;
+; INPUTS:
+;	Array:	Array to be 0-padded
+;
+;	S0:	Size of extended array
+;
+; OPTIONAL INPUTS:
+;	S1:	Second (y-) size of extended array. The default is S1 = S0
+;
+; KEYWORD PARAMETERS:
+;	NO_OFF: 	Set this keyword to a nonzero value to indicate that the
+;		input array must not be centered in the final frame. In this case
+;		the element [0,0] of the output array coincides with the element
+;		[0,0] of the input
+;
+;	POW2:	Set this keyword to a nonzero value to indicate that the array
+;		size must be extended to the nearest power of 2. In this case, the
+;		input values of S0 and S1 are overriden
+;
+; OUTPUTS:
+;	Result:	0-padded array. If the keyword NO_OFF is not set, the original
+;		array is centered in the final frame.
+;		The input array is returned if the requested output size is smaller
+;		than the input size
+;
+; OPTIONAL OUTPUTS:
+;	OFFSET:	Use this output keyword to retrieve a 2-components vector with
+;		the x- and y- offsets of the [0, 0] element of the input array
+;		in the final frame
+;
+; SIDE EFFECTS:
+;	If POW2 is set, the input values of S0 and S1 are overridden. If S0 and
+;	S1 are named variables, their values are overwritten.
+;
+; RESTRICTIONS:
+;	Apply only to 2D arrays.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;	Updates:
+;	1) Fixed bug on keyword POW2 (Emiliano Diolaiti, January 2000).
+;	2) Fixed other bug on keyword POW2 (E. D., May 2014).
+;-
+
+FUNCTION extend_array, array, s0, s1, NO_OFF = no_off, POW2 = pow2, OFFSET = o
+
+	on_error, 2
+	if  size52(array, /N_DIM) ne 2  then  return, array
+	if  n_params() eq 1 and not keyword_set(pow2)  then  return, array $
+	else  if  n_params() eq 2  then  s1 = s0
+	s = size52(array, /DIM)
+	if  keyword_set(pow2)  then begin
+	   s0 = s[0]  &  s1 = s[1]
+	   l = log2(s0)  &  if  2^l ne s0  then  s0 = 2^(l + 1)
+	   l = log2(s1)  &  if  2^l ne s1  then  s1 = 2^(l + 1)
+	endif
+	if  s0 eq s[0] and s1 eq s[1] or s0 lt s[0] or s1 lt s[1]  then begin
+	   array1 = array  &  o = [0, 0]
+	endif else begin
+	   if  keyword_set(no_off)  then  o = [0, 0] $
+	   else begin
+	      o = [s0, s1] - s  &  o = (o + o mod 2) / 2
+	   endelse
+	   array1 = make_array(s0, s1, TYPE = size52(array, /TYPE))
+	   array1[o[0],o[1]] = array
+	endelse
+	return, array1
+end
diff --git a/extend_shift.pro b/extend_shift.pro
new file mode 100644
index 0000000000000000000000000000000000000000..c5a588607328a4f88bbc7794b4f44cde2d64056e
--- /dev/null
+++ b/extend_shift.pro
@@ -0,0 +1,43 @@
+; $Id: extend_shift.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	EXTEND_SHIFT
+;
+; PURPOSE:
+;	Shift a 2D array without edge effects.
+;
+; CATEGORY:
+;	Array manipulation.
+;
+; CALLING SEQUENCE:
+;	Result = EXTEND_SHIFT(Array, Xshift, Yshift)
+;
+; INPUTS:
+;	Array:	2D array
+;
+;	Xshift, Yshift:	X- and Y- integer shifts
+;
+; OUTPUTS:
+;	Result:	Shifted array
+;
+; RESTRICTIONS:
+;	Apply only to 2D arrays.
+;
+; PROCEDURE:
+;	Pad the array with 0s, perform the shift and restore
+;	the original size.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION extend_shift, array, xshift, yshift
+
+	on_error, 2
+	if  xshift eq 0 and yshift eq 0  then  return, array
+	s = size52(array, /DIM)  &  xs = round(xshift)  &  ys = round(yshift)
+	a = extend_array(array, s[0] + abs(xs), s[1] + abs(ys), /NO_OFF)
+	a = (shift(a, xs, ys))[0:s[0]-1,0:s[1]-1]
+	return, a
+end
diff --git a/extract_overlap.pro b/extract_overlap.pro
new file mode 100644
index 0000000000000000000000000000000000000000..44e4b47a22f45ffbd689bb0f61fbc8a3e133a8bb
--- /dev/null
+++ b/extract_overlap.pro
@@ -0,0 +1,46 @@
+; $Id: extract_overlap.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	EXTRACT_OVERLAP
+;
+; PURPOSE:
+;	Extract the overlap region of two 2D arrays, after ideally superposing
+;	the positions of a reference point.
+;
+; CATEGORY:
+;	Array manipulation.
+;
+; CALLING SEQUENCE:
+;	EXTRACT_OVERLAP, Array1, Array2, R1, R2, Over1, Over2, $
+;					 Lx1, Ux1, Ly1, Uy1, Lx2, Ux2, Ly2, Uy2
+;
+; INPUTS:
+;	Array1, Array2:	2D input arrays
+;
+;	R1:	2-components vector, coordinates of reference point in array 1
+;
+;	R2:	2-components vector, coordinates of reference point in array 1
+;
+; OUTPUTS:
+;	Over1, Over2:	Regions of overlap
+;
+; OPTIONAL OUTPUTS:
+;	Lx1, Ux1, Ly1, Uy1:	Lower and Upper, X- and Y- bounds of overlap region
+;		in Array1
+;	Lx2, Ux2, Ly2, Uy2:	Lower and Upper, X- and Y- bounds of overlap region
+;		in Array2
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+PRO extract_overlap, array1, array2, r1, r2, over1, over2, $
+					 lx1, ux1, ly1, uy1, lx2, ux2, ly2, uy2
+
+	on_error, 2
+	array_overlap, size52(array1, /DIM), size52(array2, /DIM), $
+				   r1, r2, lx1, ux1, ly1, uy1, lx2, ux2, ly2, uy2
+	over1 = array1[lx1:ux1,ly1:uy1]  &  over2 = array2[lx2:ux2,ly2:uy2]
+	return
+end
diff --git a/extract_stars.pro b/extract_stars.pro
new file mode 100644
index 0000000000000000000000000000000000000000..ff0e6a88ac60828c31f90b5d670837a548505a6e
--- /dev/null
+++ b/extract_stars.pro
@@ -0,0 +1,36 @@
+; $Id: extract_stars.pro, v 1.1 Mar 2012 e.d. $
+;
+;+
+; NAME:
+;	EXTRACT_STARS
+;
+; PURPOSE:
+;	Return sub-list of stars, extracted from a list which might include
+;	presumed stars.
+;
+; CATEGORY:
+;	STARFINDER auxiliary procedures.
+;
+; CALLING SEQUENCE:
+;	Result = EXTRACT_STARS(List, N)
+;
+; INPUTS:
+;	List:	star list
+;
+; OUTPUTS:
+;	Return sublist of true stars
+;
+; OPTIONAL OUTPUTS:
+;	N:	number of extracted stars
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, June 2001.
+;   1) Created this file (E. D., March 2012).
+;-
+
+FUNCTION extract_stars, list, n
+
+    on_error, 2
+    s = where_stars(list, n)
+    if  n ne 0  then  return, list[s]  else  return, -1
+end
diff --git a/file_name.pro b/file_name.pro
new file mode 100644
index 0000000000000000000000000000000000000000..a0f6fe2f7220113d03ea35e7764fc28456cef4b3
--- /dev/null
+++ b/file_name.pro
@@ -0,0 +1,77 @@
+; $Id: file_name.pro, v 1.2 Jun 2000 e.d. $
+;
+;+
+; NAME:
+;	FILE_NAME
+;
+; PURPOSE:
+;	Given the name of a file contained in a directory included
+;	in the IDL !Path system variable, return the fully specified
+;	name of the file. Operating system dependencies are taken
+;	into account.
+;
+; CATEGORY:
+;	Input/Output.
+;
+; CALLING SEQUENCE:
+;	Result = FILE_NAME(Dir, File)
+;
+; INPUTS:
+;	Dir:	Scalar string, name of parent directory.
+;		It must be a directory included in the !Path variable.
+;
+;	File:	Scalar string, containing the name of the file with no
+;		path divider.
+;
+; OUTPUTS:
+;	Result:	Scalar string with the complete name of the file.
+;
+; RESTRICTIONS:
+;	Apply only to files in directories included in the !Path system
+;	variable.
+;
+; PROCEDURE:
+;	Search the substring specified by the input variable Dir into the
+;	!Path system variable. Append a path divider and the name of the
+;	file specified by the input variable File.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, November 1999.
+;	Updates:
+;	1) Fixed bug related to sub-directories
+;	   (Emiliano Diolaiti, May 2000).
+;	2) Case-insensitive (Emiliano Diolaiti, June 2000).
+;-
+
+FUNCTION file_name, dir, file
+
+	on_error, 2
+	; Define path of directory
+	case  !Version.OS  of
+           'vms': begin
+              pdiv = ','  &  ddiv = '.'
+              end
+           'Win32': begin
+              pdiv = ';'  &  ddiv = '\'
+              end
+           'MacOS' : begin
+              pdiv = ','  &  ddiv = ':'
+              end
+           else: begin
+              pdiv = ':'  &  ddiv = '/'
+              end
+	endcase
+	lowpath = strlowcase(!Path)  &  lowdir = strlowcase(dir)
+	first = strpos(lowpath, lowdir)
+	while  first gt 0 and strmid(lowpath, first, 1) ne pdiv  do $
+	   first = first - 1
+	if  strmid(lowpath, first, 1) eq pdiv  then  first = first + 1
+	last = strpos(lowpath, lowdir)  &  length = strlen(lowpath)
+	while  last lt length - 1 and strmid(lowpath, last, 1) ne pdiv and $
+	       strmid(lowpath, last, 1) ne ddiv  do $
+	   last = last + 1
+	if  strmid(lowpath, last, 1) eq ddiv or $
+	    strmid(lowpath, last, 1) eq pdiv  then  last = last - 1
+	path = strmid(!Path, first, last - first + 1)
+	return, path + ddiv + file
+end
diff --git a/find_rot_trans.pro b/find_rot_trans.pro
new file mode 100644
index 0000000000000000000000000000000000000000..62bba021e1f832926c53c58da30fa9a42c7a6222
--- /dev/null
+++ b/find_rot_trans.pro
@@ -0,0 +1,142 @@
+; $Id: find_rot_trans.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	FIND_ROT_TRANS
+;
+; PURPOSE:
+;	Given two sets of coordinates representing the same points in different
+;	reference frames, supposed to be reciprocally translated and rotated,
+;	estimate the reciprocal translation and rotation by means of the
+;	Newton-Gauss iterative method.
+;
+; CATEGORY:
+;	Mathematics. Spatial transformations.
+;
+; CALLING SEQUENCE:
+;	FIND_ROT_TRANS, X1, Y1, X2, Y2, Origin_0, Angle_0, Origin, Angle, Found
+;
+; INPUTS:
+;	X1, Y1:	Vectors of x- and y- coordinates of points in
+;		reference frame no. 1
+;
+;	X2, Y2:	Vectors of x- and y- coordinates of points in
+;		reference frame no. 2
+;
+;	Origin_0:	2-components vector representing an initial guess of the
+;		coordinates of the origin of reference frame 2 with respect to
+;		reference frame 1
+;
+;	Angle_0:	Scalar value representing an initial guess of the rotation
+;		angle (in radians) of the x- axis of ref. frame 2 with respect to
+;		the x- axis of ref. frame 1
+;
+; KEYWORD PARAMETERS:
+;	ORIGIN_TOL:	Absolute tolerance (presumably in pixel units) to check the
+;		convergence condition of the origin in the iterative estimation.
+;		The default is 0.1
+;
+;	ANGLE_TOL:	Relative tolerance to check the convergence of the angle.
+;		The default is 0.01 (i.e. 1%)
+;
+;	_EXTRA:	Optional keywords for NEWTON_GAUSS (see the NEWTON_GAUSS procedure
+;		in the file 'newton_gauss.pro')
+;
+; OUTPUTS:
+;	Origin:	2-components vector, representing the x- and y- coordinates of
+;		the origin of reference frame 2 in reference frame 1
+;
+;	Angle:	Scalar, angle (in radians) between the x- axis of reference
+;		frame 2 and the x- axis of reference frame 1
+;
+;	Found:	Logical value, true if the Newton-Gauss optimization has converged
+;
+; RESTRICTIONS:
+;	If the reciprocal translation and/or rotation between the two reference
+;	frames are large, it is better to provide initial guesses of the
+;	corresponding parameters, to ensure the convergence of the Newton-Gauss
+;	algorithm.
+;
+; PROCEDURE:
+;	Assume the following relationship between coordinates in ref. frame 2
+;	and coordinates in ref. frame 1:
+;	X2 = - Origin[0] + X1 * COS(Angle) + Y1 * SIN(Angle)
+;	Y2 = - Origin[1] - X2 * SIN(Angle) + Y2 * COS(Angle)
+;	and estimate Origin and Angle by means of the iterative Newton-Gauss
+;	algorithm.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+
+
+;;; Auxiliary procedures/functions.
+
+FUNCTION frt_parametrize, origin, angle
+	return, [origin[0], origin[1], angle]
+end
+
+PRO frt_deparametrize, p, origin, angle
+	origin = p[0:1]  &  angle = p[2]
+	return
+end
+
+FUNCTION frt_stack, x, y
+
+	on_error, 2
+	n = n_elements(x)  &  z = fltarr(2*n)
+	sx = 2 * lindgen(n)  &  sy = sx + 1
+	z[sx] = x  &  z[sy] = y
+	return, z
+end
+
+FUNCTION frt_model, p, DATA = data
+
+	on_error, 2
+	frt_deparametrize, p, origin, angle
+	rot_trans, data.x, data.y, origin, angle, rtx, rty
+	return, frt_stack(rtx, rty)
+end
+
+FUNCTION frt_iacobi, p, DATA = data
+
+	on_error, 2
+	n = n_elements(data.x)  &  iacobi = fltarr(2*n, 3)
+	one = make_array(n, /FLOAT, VALUE = 1.)  &  zero = fltarr(n)
+	iacobi[*,0] = frt_stack(-one, zero)
+	iacobi[*,1] = frt_stack(zero, -one)
+	frt_deparametrize, p, origin, angle  &  origin = [0, 0]
+	rot_trans, data.x, data.y, origin, angle, rtx, rty
+	iacobi[*,2] = frt_stack(rty, -rtx)
+	return, transpose(iacobi)
+end
+
+FUNCTION frt_converg, p0, p1, DATA = data
+
+	on_error, 2
+	frt_deparametrize, p0, o0, a0
+	frt_deparametrize, p1, o1, a1
+	return, convergence(o0, o1, data.o_tol, /ABSOLUTE) and $
+			convergence(a0, a1, data.a_tol)
+end
+
+;;; The main routine.
+
+PRO find_rot_trans, x1, y1, x2, y2, origin_0, angle_0, origin, angle, found, $
+					ORIGIN_TOL = o_tol, ANGLE_TOL = a_tol, _EXTRA = extra
+
+	on_error, 2
+	if  n_elements(x1) lt 2  then $
+	   message, 'at least 2 points are required'
+	if  n_elements(o_tol) eq 0  then  o_tol = 0.1
+	if  n_elements(a_tol) eq 0  then  a_tol = 0.01
+	; define "global" data structure.
+	data = {x: x1, y: y1, o_tol: o_tol, a_tol: a_tol}
+	; parameters estimation
+	newton_gauss, "frt_model", "frt_iacobi", "frt_converg", $
+				  frt_parametrize(origin_0, angle_0), frt_stack(x2, y2), $
+				  DATA = data, _EXTRA = extra, found, p
+	if  found  then  frt_deparametrize, p, origin, angle
+	return
+end
diff --git a/fitstars.pro b/fitstars.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0748524047c7d8de2c8cea4d06d799ce44b4f2ab
--- /dev/null
+++ b/fitstars.pro
@@ -0,0 +1,439 @@
+; $Id: fitstars.pro, v 1.5 Oct 2013 e.d. $
+;
+;+
+; NAME:
+;   FITSTARS
+;
+; PURPOSE:
+;   Fit a multiple-component stellar image with a model given by a sum
+;   of shifted scaled replicas of a reference image (one for each star),
+;   superposed on a background represented by a slanting plane plus a
+;   fixed additive contribution.
+;   The parameters to be optimized are the stellar fluxes and sub-pixel
+;   positions along with the coefficients of the slanting plane.
+;   The optimization is performed by means of the Newton-Gauss iterative
+;   method.
+;   The reference image to be replicated (PSF) may either be a fixed
+;   template ("input PSF" option) or a model computed by an auxiliary
+;   procedure ("PSF model" option).
+;
+; CATEGORY:
+;   Stellar astrometry and photometry.
+;
+; CALLING SEQUENCE:
+;   FITSTARS, Image, Psf, X0, Y0, X, Y, F, B, Fit_error, $
+;        Sigma_x, Sigma_y, Sigma_f, Sigma_b
+;
+; INPUTS:
+;   Image:    Stellar image
+;
+;   Psf:  When the "input PSF" option is used, this parameter must
+;     contain a 2D image of the PSF.
+;     When the "space-variant PSF" option is used, Psf must be a 3D stack
+;     of PSF images. In this case it is necessary to supply the bounds of
+;     image domain partition (see KEYWORDS LX, UX, LY, UY).
+;     When the "PSF model" option is used, it must contain the string
+;     which identifies the type of PSF model to apply, as defined in the
+;     function IMAGE_MODEL (see the file 'image_model.pro').
+;     Notice that when the first option is applied, the input template
+;     is shifted by interpolation to match the stars in the Image to fit.
+;     In this case it is possible to select an interpolation technique
+;     with the keyword INTERP_TYPE (see below). For details on the
+;     supported interpolation techniques see the functions IMAGE_SHIFT
+;     or IMAGE_MODEL. When the second option is applied instead, the
+;     procedure which computes the PSF model probably requires additional
+;     information, which should be passed through with the keyword
+;     PSF_DATA (see below).
+;
+;   X0, Y0:   Vectors of approximate positions of point sources
+;
+; KEYWORD PARAMETERS:
+;   FIXED:    Fixed additive contribution, not optimized in the fitting
+;     process. It must have the same size has the Image.
+;     It may represent the contribution of point sources whose centers
+;     lie outside the Image support
+;
+;   LX, UX, LY, UY:   Vectors specifying the bounds of the image domain
+;     partition when the "space-variant PSF" option is used. In this case
+;     the sub-domain  [LX[j]: Ux[j], LY[i]: UY[i]]  must correspond to the
+;     (i * X_size + j)-th  PSF in the input stack.
+;
+;   PSF_DATA: Use this keyword to pass a pointer to the auxiliary data
+;     required either to shift the input PSF ("input PSF" option) or
+;     to compute the PSF model ("PSF model" option).
+;     Notice that when the "input PSF" option is applied, this keyword
+;     may be undefined on input and may be used to retrieve on output
+;     the auxiliary data which can be recycled in further calls. When
+;     the "PSF model" option is applied instead, the keyword PSF_DATA
+;     must generally be defined also on input (unless the user defines
+;     a procedure for the PSF model based on COMMON blocks).
+;
+;   F0:   Initial guesses of scaling factors (i.e. fluxes) for each point
+;     source. Fluxes must be referred to the normalization of the Psf.
+;
+;   BACKGROUND:   The image background is fitted with a slanting plane.
+;     To obtain an initial guess of the stellar fluxes (if F0 is not
+;     defined), it is better to have an approximate knowledge of the
+;     image background. If no approximate background is provided and
+;     F0 is not defined, the initial guesses of the stellar fluxes are
+;     computed under the hypothesis of no background in the image.
+;
+;   NO_SLANT: Set this keyword to a nonzero value to fit the stellar
+;     image with a model made of a sum of stars (plus FIXED contribution)
+;     but without slanting plane
+;
+;   NOISE_STD:    Noise standard deviation. It may be a scalar
+;     ('white noise' case) or an array, having the same size as Image
+;
+;   BAD_DATA: 1D vector of Image subscripts representing bad pixels in the
+;     Image to be masked, i.e. excluded from the fitting process
+;
+;   POS_TOL:  Absolute tolerance on stars positions, used by the fitting
+;     procedure for a convergence check. The default is 0.01 pixels
+;
+;   PHOT_TOL: Relative tolerance on stars fluxes, used for the convergence
+;     check. The default is 0.01, i.e. 1%
+;
+;   VERBOSE:  Set this keyword to a nonzero value to have some output at
+;     the end of the fit
+;
+;   INTERP_TYPE:  String constant, indicating the interpolating technique
+;     used by IMAGE_SHIFT to interpolate the input Psf in order to match
+;     it to an observed star, which is generally off-centered.
+;     For more details, see the function IMAGE_SHIFT in the file
+;     'image_shift.pro'
+;     
+;   FLUXOPT: Set this binary keyword to keep the positions of the sources 
+;     fixed in the optimization process. The input values set by parameters 
+;     X0 and Y0 are retained. Only fluxes (and background parameters unless 
+;     keyword NO_SLANT is set) are estimated.
+;
+;   _EXTRA:   Optional input keyword of NEWTON_GAUSS (e.g. MAXIT, MASK, 
+;     SVDINV, etc.), For more details, see the procedure NEWTON_GAUSS 
+;     in the file 'newton_gauss.pro'
+;
+; OUTPUTS:
+;   X, Y: Vector of stars positions, estimated with sub-pixel accuracy
+;
+;   F:    Vector of stellar fluxes, referred to the normalization of the Psf
+;
+;   B:    3-components vector of [B0, B1, B2] background coefficients.
+;     The background is defined as follows
+;     B(x,y) = B0 + B1 * x + B2 * y
+;
+;   Fit_error:    Least squares fitting error between the best fit model and
+;     the input Image. A negative value indicates that the fitting procedure
+;     has not converged: the output results are not reliable.
+;
+;   Sigma_x, Sigma_y, Sigma_f, Sigma_b:   Vectors containing the formal errors
+;     (standard deviation) on the estimated parameters (X, Y, F, B).
+;     Available only if some information on the noise is given on input,
+;     by means of the keywords GAUSSIAN_NOISE and/or PHOTON_COUNTS.
+;     If the keyword FIXEDPOS is set, the output values of Sigma_x and Sigma_y 
+;     are 0 by definition.
+;
+; OPTIONAL OUTPUTS:
+;   PSF_DATA: This input keyword may also be used as output keyword to
+;     retrieve the additional data required for the PSF shift or the PSF
+;     model computation, in case these data are undefined on input or have
+;     been modified by IMAGE_MODEL, the function which actually shift the
+;     PSF or compute the PSF model. For more details, see the section about
+;     KEYWORD PARAMETERS above.
+;
+;   MODEL:    Best fit image model
+;
+;   IT:   Actual number of iterations performed by NEWTON_GAUSS
+;
+;   W_BAD:    Array of Image subscripts representing bad pixels which have
+;     been masked. It coincides with the value of the input keyword
+;     BAD_DATA, unless additional bad data masking has been performed
+;     by NEWTON_GAUSS. For more details on data masking, see the procedure
+;     NEWTON_GAUSS in the file 'newton_gauss.pro'
+;
+; RESTRICTIONS:
+;   The main restriction concerns Psf interpolation, a necessary step to
+;   match an observed off-centered star with a reference template if the
+;   "input PSF" of "space-variant PSF" option is applied. Common interpolation
+;   techniques (Fourier transform shift, spline interpolation) cannot be
+;   applied to undersampled data. In this case suitable techiques should be
+;   used instead, exploiting the "PSF model" option. For details on supported
+;   PSF models, see the function IMAGE_MODEL in the file 'image_model.pro'.
+;
+; MODIFICATION HISTORY:
+;   Written by:  Emiliano Diolaiti, August 1999.
+;   Updates:
+;   1) Fixed bug on output PSF_DATA (Emiliano Diolaiti, February 2000).
+;   2) Added initial estimate on background (Emiliano Diolaiti, April 2000).
+;   3) PSF_DATA again (Emiliano Diolaiti, June 2000).
+;   4) Added space-variant PSF stack option (E.D., December 2004).
+;   5) Added check on PSF_DATA to avoid confusion with other keywords
+;      (E.D., February 2006).
+;   6) Added keyword FLUXOPT (E.D., April 2012).
+;   7) Modified initial flux estimate at lines 378-ecc (L.S, E.D, October 2013)
+;-
+
+
+
+;;; Auxiliary procedures/functions.
+
+; FS_MODEL: compute the image model for the current set of parameters.
+
+FUNCTION fs_model, parameters, DATA = data, PSF_DATA = psf_data
+
+    if n_tags((*data).extra) ne 0 then extra = (*data).extra
+    sx = (*data).sx  &  sy = (*data).sy
+    nstar = (*data).nstar  &  b_nterms = (*data).b_nterms
+    fs_deparam, parameters, x, y, f, b, nstar, b_nterms
+    unit_flux = 1  &  model = fltarr(sx, sy)
+    for  n = 0L, nstar - 1  do begin
+       (*data).psf_stack[*,*,n] = $
+          image_model(x[n], y[n], unit_flux, sx, sy, (*data).psf, $
+                    psf_data, INTERP_TYPE = (*data).interp_type, _EXTRA = extra)
+       model = model + f[n] * (*data).psf_stack[*,*,n]
+    endfor
+    bplane = 0
+    if  b_nterms ne 0  then  bplane = plane(b[0], b[1], b[2], sx, sy)
+    model = model + (*data).fixed_image + bplane
+    return, model
+end
+
+; FS_PARAM: store the model parameters (i.e. user parameters x, y, etc.)
+;   into a single vector (program parameters).
+
+FUNCTION fs_param, x, y, f, b, nstar, b_nterms
+
+    parameters = fltarr(3*nstar + b_nterms)
+    parameters[0] = f
+    subs = nstar + 2*lindgen(nstar)
+    parameters[subs] = x  &  parameters[subs+1] = y
+    if  b_nterms ne 0  then  parameters[3*nstar] = b
+    return, parameters
+end
+
+; FS_DEPARAM: convert program parameters vector to user parameters.
+
+PRO fs_deparam, parameters, x, y, f, b, nstar, b_nterms
+
+    f = parameters[0:nstar-1]
+    subs = nstar + 2*lindgen(nstar)
+    x = parameters[subs]  &  y = parameters[subs+1]
+    if  b_nterms ne 0  then  b = parameters[3*nstar:3*nstar+b_nterms-1]
+    return
+end
+
+; FS_CENTER_DERIVATIVE: compute the partial derivative of an image
+; with respect to the x- or y- coordinate of its center (maximum).
+
+FUNCTION fs_center_derivative, image, f, siz
+
+    deriv = 2*!pi/siz * fft(image) * f
+    deriv = complex(imaginary(deriv), -float(deriv))
+    deriv = float(fft(deriv, /INVERSE))
+    return, deriv
+end
+
+; FS_IACOBI: compute the Iacobi matrix of the parametric model.
+
+FUNCTION fs_iacobi, parameters, DATA = data, PVAR = pvar
+
+    sx = (*data).sx  &  sy = (*data).sy
+    nstar = (*data).nstar  &  b_nterms = (*data).b_nterms
+    varpos = n_elements(pvar) eq 0
+    if varpos then $
+       npar = 3*nstar + b_nterms else $
+       npar = nstar + b_nterms
+    n_pix = sx * sy
+    iacobi = fltarr(n_pix, npar)
+    for  n = 0L, nstar - 1  do begin
+       iacobi[*,n] = reform((*data).psf_stack[*,*,n], n_pix)
+       if varpos then begin
+       deriv = fs_center_derivative((*data).psf_stack[*,*,n], (*data).x_frequency, sx)
+       iacobi[*,nstar+2*n] = reform(parameters[n] * deriv, n_pix)
+       deriv = fs_center_derivative((*data).psf_stack[*,*,n], (*data).y_frequency, sy)
+       iacobi[*,nstar+2*n+1] = reform(parameters[n] * deriv, n_pix)
+       endif
+    endfor
+    if varpos then k = 3*nstar else k = nstar
+    if  b_nterms ne 0  then  iacobi[*,k] = 1
+    if  b_nterms eq 3  then begin
+       iacobi[*,k+1] = reform(plane(0, 1, 0, sx, sy), n_pix)
+       iacobi[*,k+2] = reform(plane(0, 0, 1, sx, sy), n_pix)
+    endif
+    return, transpose(iacobi)
+end
+
+; FS_CONVERGENCE: check the convergence condition for the iterative estimation.
+
+FUNCTION fs_convergence, p0, p, DATA = data
+
+    fs_deparam, p0, x0, y0, f0, b0, (*data).nstar, (*data).b_nterms
+    fs_deparam, p,  x,  y,  f,  b, (*data).nstar, (*data).b_nterms
+    check = convergence(x0, x, (*data).pos_tol, /ABSOLUTE) and $
+         convergence(y0, y, (*data).pos_tol, /ABSOLUTE) and $
+         convergence(f0, f, (*data).phot_tol)
+;   if  (*data).b_nterms ne 0  then $
+;      check = check and convergence(b0, b, (*data).phot_tol)
+    return, check
+end
+
+; FS_WEIGHTS: compute inverse variances for weighted least squares fit.
+
+ FUNCTION fs_weights, var
+
+    min_var = min(var)
+    if  min_var le 0.  then  min_var = max(var) * 1e-15
+    return, 1 / (var > min_var)
+end
+
+; FS_ERROR: compute the least squares error between the model and the image.
+
+FUNCTION fs_error, model, data, WEIGHTS = weights, W_BAD = w_bad
+
+    if  n_elements(weights) ne 0  then  w = weights  else  w = 1
+    d = w * (model - data)^2
+    if  n_elements(w_bad) ne 0  then $
+       if  min(w_bad) ge 0  then  d[w_bad] = 0
+    return, total(d)
+end
+
+; FS_OUT: print iteration no., fitting error, parameters.
+
+PRO fs_out, it, fit_error, parameters, sigma_p, nstar, b_nterms
+
+    print, ''
+    print, 'no. of iterations ', it
+    print, 'fitting error ', fit_error
+    print, 'parameters: '
+    fs_deparam, parameters, x, y, f, b, nstar, b_nterms
+    if  n_elements(sigma_p) ne 0  then $
+       fs_deparam, sigma_p, sigma_x, sigma_y, sigma_f, sigma_b, nstar, b_nterms
+    print, 'x coordinates:             ', x
+    if  n_elements(sigma_x) ne 0  then $
+           print, 'st. dev. on x coordinates: ', sigma_x
+    print, 'y coordinates: ', y
+    if  n_elements(sigma_y) ne 0  then $
+           print, 'st. dev. on y coordinates: ', sigma_y
+    print, 'fluxes      : ', f ;* scale
+    if  n_elements(sigma_f) ne 0  then $
+           print, 'st. dev. on fluxes       : ', sigma_f
+    if  b_nterms ne 0  then  print, 'background   : ', b
+    if  n_elements(sigma_b) ne 0  then $
+           print, 'st. dev. on background   : ', sigma_b
+    return
+end
+
+;;; The main routine.
+
+PRO fitstars, $
+    image, FIXED = fixed_image, psf, PSF_DATA = psf_data, $
+    x0, y0, F0 = f0, BACKGROUND = background, NO_SLANT = no_slant, $
+    POS_TOL = pos_tol, PHOT_TOL = phot_tol, VERBOSE = verbose, $
+    _EXTRA = extra, INTERP_TYPE = interp_type, NOISE_STD = noise_std, $
+    x, y, f, b, fit_error, sigma_x, sigma_y, sigma_f, sigma_b, $
+    MODEL = model, IT = it, BAD_DATA = bad_data, W_BAD = w_bad, $
+    FLUXOPT = fluxopt
+
+    catch, error
+    if  error ne 0  then begin
+       if  ptr_valid(data)  then  ptr_free, data
+       if  ptr_valid(pdata)  then  ptr_free, pdata
+       fit_error = -1
+       return
+    endif
+    ; Define pointers to 'global' variables
+    s = size52(image, /DIM)  &  sx = s[0]  &  sy = s[1]
+    if  n_elements(fixed_image) eq 0  then  fixed_image = 0
+    if  n_elements(background) eq 0  then $
+       if  n_elements(f0) eq 0  then  background = 0
+    if  not keyword_set(no_slant)  then begin
+       b_nterms = 3  &  b = fltarr(b_nterms)
+       if  n_elements(background) ne 0  then $
+          b[0] = total(background) / n_elements(background)
+    endif else begin
+       b_nterms = 0  &  b = 0
+    endelse
+    if  n_elements(interp_type) eq 0  then  interp_type = ''
+    nstar = n_elements(x0)
+    psf_stack = fltarr(sx, sy, nstar)
+    if n_elements(extra) ne 0 then extra_data = extra else extra_data = 0
+    if n_elements(pos_tol)  eq 0  then  pos_tol = 0.01
+    if n_elements(phot_tol) eq 0  then  phot_tol = 0.01
+    x_frequency = frequency(sx) # (fltarr(sy) + 1)
+    y_frequency = (fltarr(sx) + 1) # frequency(sy)
+    data = {image: image, fixed_image: fixed_image, psf: psf, $
+         psf_stack: psf_stack, x_frequency: x_frequency,    $
+         y_frequency: y_frequency, sx: sx, sy: sy, nstar: nstar,   $
+         b_nterms: b_nterms, pos_tol: pos_tol, phot_tol: phot_tol, $
+         interp_type: interp_type, extra: extra_data}
+    data = ptr_new(data, /NO_COPY) ; pointer to data structure
+    pdata = ptr_new(/ALLOCATE)     ; pointer to PSF auxiliary data
+    if  (ptr_valid(psf_data))[0]  then $
+       if  n_elements(*psf_data) ne 0  then  *pdata = *psf_data
+
+    ; Initial estimates of parameter
+    ndim_psf = size52(psf, /N_DIM)
+    if ndim_psf lt 2 then begin
+       avg_psf = image_model(sx/2, sy/2, 1, sx, sy, psf, pdata)
+       tot_psf = total(avg_psf)
+       max_psf = max(avg_psf)
+    endif else $
+    if ndim_psf eq 2 then begin
+       tot_psf = total(sub_array(psf, sx, sy))
+       max_psf = max(sub_array(psf, sx, sy))
+    endif else $
+    begin
+       npsf = (size52(psf, /DIM))[2]
+       avg_psf = total(psf, 3) / npsf
+       tot_psf = total(sub_array(avg_psf, sx, sy))
+       max_psf = max(sub_array(avg_psf, sx, sy))
+    endelse
+    x = x0  &  y = y0
+    if  n_elements(f0) eq 0  then begin
+       sub = image - fixed_image - background
+       f = sub[round(x)>0<(sx - 1), round(y)>0<(sy - 1)]   ; intensities
+      ; f = f / total(f) * total(sub) / tot_psf     ; fluxes
+      f = f / max_psf
+    endif else  f = f0
+    p0 = fs_param(x, y, f, b, nstar, b_nterms)
+    if keyword_set(fluxopt) then begin
+       pvar = make_array(n_elements(p0), VALUE = 1)
+       k = nstar + 2*lindgen(nstar)
+       pvar[k] = 0
+       pvar[k + 1] = 0
+    endif
+
+    ; Define noise weights
+    if  n_elements(noise_std) ne 0  then  weights = fs_weights(noise_std^2)
+
+    ; Iterative estimation of parameters
+    newton_gauss, 'fs_model', 'fs_iacobi', 'fs_convergence', p0, image, $
+                  _EXTRA = extra, NOISE_STD = noise_std, INVERSE_DATA_VAR = $
+                  weights, converged, p, sigma_p, model, IT = it, $
+                  BAD_DATA = bad_data, W_BAD = w_bad, DATA = data, $
+                  PSF_DATA = pdata, PVAR = pvar
+    if  converged  then begin
+       fit_error = fs_error(model, image, WEIGHTS = weights, W_BAD = w_bad)
+       fs_deparam, p, x, y, f, b, nstar, b_nterms
+       if  n_elements(sigma_p) ne 0  then $
+       fs_deparam, sigma_p, sigma_x, sigma_y, sigma_f, sigma_b, nstar, b_nterms
+       if keyword_set(fluxopt) then begin
+          sigma_x = fltarr(nstar)
+          sigma_y = fltarr(nstar)
+       endif
+       if  (size52(x0))[0] eq 0  then begin
+          x = x[0]  &  y = y[0]  &  f = f[0]
+       endif
+       if  keyword_set(verbose)  then begin
+          print, 'FITSTARS: converged'
+          fs_out, it, fit_error, p, sigma_p, nstar, b_nterms
+       endif
+    endif else begin
+       fit_error = -1
+       if  keyword_set(verbose)  then  print, 'FITSTARS: not converged'
+    endelse
+    ptr_free, data
+    if  (ptr_valid(psf_data))[0]  then $
+       if  n_elements(*pdata) ne 0  then  *psf_data = *pdata
+    if  ptr_valid(pdata)  then  ptr_free, pdata
+    return
+end
diff --git a/fitting_errors.pro b/fitting_errors.pro
new file mode 100644
index 0000000000000000000000000000000000000000..ccd1041ad03d2c4ea2585b3394a382ccf64fe80a
--- /dev/null
+++ b/fitting_errors.pro
@@ -0,0 +1,53 @@
+; $Id: fitting_errors.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	FITTING_ERRORS
+;
+; PURPOSE:
+;	Estimate formal errors (standard deviations) on the solution
+;	of an algebraic system of linear equations, given the inverse
+;	of the system matrix.
+;
+; CATEGORY:
+;	Mathematics. Linear systems.
+;
+; CALLING SEQUENCE:
+;	Result = FITTING_ERRORS(Inverse)
+;
+; INPUTS:
+;	Inverse:	Inverse matrix of the linear system
+;
+; KEYWORD PARAMETERS:
+;	SCALING:	Set this keyword to the vector of scaling factors
+;		used to scale the linear system before inversion
+;
+; OUTPUTS:
+;	Return a vector of formal errors on the components of the solution
+;	of the linear system.
+;
+; RESTRICTIONS:
+;	The input array must be square, as always happens when it is the
+;	inverse matrix of a linear system of "normal equations".
+;	The system of normal equations should represent the mathematical
+;	formulation of a weighted least squares fitting problem. It is
+;	essential that the least squares error is weighted (by the inverse
+;	variances on the data), otherwise the formal errors on the solution
+;	have no meaning.
+;
+; PROCEDURE:
+;	Estimate the errors as the square roots of the diagonal elements
+;	of the inverse array.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION fitting_errors, inverse, SCALING = scaling
+
+	on_error, 2
+	n = (size52(inverse, /DIM))[0]  &  d = lindgen(n)
+	e = sqrt(inverse[d,d] > 0)
+	if  n_elements(scaling) eq n  then  e = e * scaling
+	return, e
+end
\ No newline at end of file
diff --git a/frequency.pro b/frequency.pro
new file mode 100644
index 0000000000000000000000000000000000000000..ec2d28bfb1799fa74477b8a91b9ff637e7ee2744
--- /dev/null
+++ b/frequency.pro
@@ -0,0 +1,36 @@
+; $Id: frequency.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	FREQUENCY
+;
+; PURPOSE:
+;	Return a 1D vector of Fourier frequencies, according to how IDL
+;	orders the components of the Fourier Transform of an array.
+;
+; CATEGORY:
+;	Mathematics. Transforms.
+;
+; CALLING SEQUENCE:
+;	Result = FREQUENCY(N)
+;
+; INPUTS:
+;	N:	number of frequencies to compute
+;
+; OUTPUTS:
+;	Return a n-elements vector of floating-point frequencies.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION frequency, n
+
+	f = fltarr(n)  &  nv2 = n/2
+	f[0:nv2] = findgen(nv2 + 1)
+	if  n gt 2  then $
+	if  n mod 2 eq 0  then $
+	   f[nv2+1:n-1] = -reverse(findgen(nv2-1)) - 1  else $
+	   f[nv2+1:n-1] = -reverse(findgen(nv2)) - 1
+  	return, f
+end
diff --git a/fwhm.pro b/fwhm.pro
new file mode 100644
index 0000000000000000000000000000000000000000..bdd8087d3103f78c9348225cb109c383cb7b2578
--- /dev/null
+++ b/fwhm.pro
@@ -0,0 +1,78 @@
+; $Id: fwhm.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	FWHM
+;
+; PURPOSE:
+;	Compute the FWHM (Full Width at Half Maximum) of a peak in an image.
+;	The FWHM is estimated as the diameter of a circle having the same area
+;	as the peak.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = FWHM(Array)
+;
+; INPUTS:
+;	Array:	Image containing the peak to be measured
+;
+; KEYWORD PARAMETERS:
+;	X, Y:	Coordinates of the peak.
+;		The default is the Image absolute maximum
+;
+;	MAG:	Integer magnification factor for array magnification. It may be
+;		useful to improve the accuracy of the initial measurement, based on
+;		the area of the peak.
+;		The default is MAG = 1, i.e. no magnification.
+;
+;	CUBIC:	Set this keyword to a nonzero value to magnify the image with
+;		the cubic convolution interpolation implemented in the library
+;		routine CONGRID. This keyword has effect only if MAG is defined.
+;		If CUBIC is not set, the array magnification, when required, is
+;		performed with REBIN (bilinear interpolation).
+;
+; OUTPUTS:
+;	Result:	FWHM of the peak.
+;
+; RESTRICTIONS:
+;	1) The input Array is supposed to have been background-subtracted and
+;	centered with sub-pixel accuracy, especially if the FWHM is a few
+;	pixels.
+;	2) The results with the default settings are not much accurate in general.
+;	The following calling sequence is recommended:
+;	Result = FWHM(Array, MAG = 3, /CUBIC).
+;	3) To compute the FWHM of a peak in a large array, use PEAK_FWHM.
+;	For more details see the routine PEAK_FWHM in the file 'peak_fwhm.pro'.
+;
+; PROCEDURE:
+;	Call PEAK_WIDTH to obtain an initial guess of the FWHM, based on
+;	the area of the peak thresholded at half maximum.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION fwhm, array, X = x0, Y = y0, MAG = mag_fac, CUBIC = cubic
+
+	on_error, 2
+	; magnify array
+	if  n_elements(mag_fac) eq 0  then  mag_fac = 1
+	mag = round(mag_fac) > 1
+	a = array  &  siz = size52(a, /DIM) * mag
+	if  mag gt 1  then $
+	   if  keyword_set(cubic)  then $
+	      a = congrid(a, siz[0], siz[1], CUBIC = -0.5)  else $
+	      a = rebin(a, siz[0], siz[1])
+	; define peak position
+	if  n_elements(x0) * n_elements(y0) eq 0  then begin
+	   m = get_max(a)  &  x = m[0]  &  y = m[1]
+	endif else begin
+	   x = round(x0) * mag  &  y = round(y0) * mag
+	endelse
+	; estimate FWHM
+	fw = peak_width(a, X = x, Y = y)
+	if  mag gt 1  then  fw = float(fw) / mag
+	return, fw
+end
diff --git a/gauss_noise_std.pro b/gauss_noise_std.pro
new file mode 100644
index 0000000000000000000000000000000000000000..4975bab1473d992aab5df43a403543f235f28c76
--- /dev/null
+++ b/gauss_noise_std.pro
@@ -0,0 +1,248 @@
+; $Id: gaussian_noise_std.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	GAUSSIAN_NOISE_STD
+;
+; PURPOSE:
+;	Given a 2D image, compute standard deviation of normally distributed
+;	noise by histogram fitting.
+;
+; CATEGORY:
+;	Statistics.
+;
+; CALLING SEQUENCE:
+;	GAUSSIAN_NOISE_STD, Data, Mode, Std, H, V, Vmean, Hfit
+;
+; INPUTS:
+;	Data: 2D data array
+;
+; KEYWORD PARAMETERS:
+;	PATCH: 	Box size for median smoothing of the data. The median smoothed
+;		image is subtracted from the input data, to remove all the features
+;		which would cause an anomalous spread of the histogram
+;
+;	POINT_FRAC:	The histogram is computed on a subset of the input data.
+;		The number of points in the sample is given by the number of
+;		elements in the image / the value set by this keyword. The default
+;		is 1, i.e. all the input data are used.
+;
+;	NOSUB:	Set this keyword to a nonzero value to skip median subtraction
+;
+;	N_STD:	After extracting a sample from the original image, a further
+;		restriction is applied to exclude the so-called "outliers", i.e.
+;		pixels whose value is too distant from the sample median.
+;		The keyword N_STD fixes a tolerance for outliers identification.
+;		The rejection condition for a given element called "value" is
+;		abs("value" - "sample median") >
+;				N_STD * "standard deviation of (sample - sample median)"
+;		The default is 3
+;
+;	HIST_MINSIZE:	The data histogram is optimized in order to have at
+;		least a minimum number of bins in the histogram's Half Width at
+;		Half Maximum (HWHM). The minimum number of bins in one histogram's
+;		HWHM is fixed by this keyword. The default is 5.
+;		Notice this keyword is just a hint and may be overridden.
+;
+;	HIST_MAXSIZE:	The data histogram is fitted with a gaussian curve, to
+;		estimate the noise standard deviation. In practice only the central
+;		part of the histogram is considered, around the mode. The size of
+;		the useful section of the histogram may be defined in units of the
+;		approximate histogram's FWHM by means of this keyword.
+;		The default is 5.
+;		Notice this keyword is just a hint and may be overridden.
+;
+;	MAXIT:	The gaussian fit to the histogram is performed in the range
+;		[MIN(V), Mode + Std], because the right tail of the histogram may
+;		be contaminated by the photon noise due to spatially non-uniform
+;		sources. The first fit is performed starting from an initial guess
+;		of the quantities Mode and Std and is then repeated iteratively,
+;		until the estimated Std converges to a stable value or a maximum
+;		number of iterations reached. Use the keyword MAXIT to fix the
+;		maximum number of iterations. The default is 10, even though 2-3
+;		are generally sufficient
+;
+;	TOL:	Tolerance for the convergence of Std in the iteration of the
+;		gaussian fit. The default is 0.01
+;
+;	NTERMS_FIT:	Same as the input keyword NTERMS of the library routine
+;		GAUSSFIT. The default is 3, i.e. the histogram is fitted with a
+;		pure gaussian curve (having 3 parameters: a normalization constant,
+;		the center and the standard deviation). Set NTERMS = 4 to add a
+;		constant terms to the fitting curve, NTERMS = 5 to add a linear
+;		background and NTERMS = 6 to add a quadratic background.
+;
+; OUTPUTS:
+;	Mode:	Histogram mode, determined as the center of the best fit
+;		gaussian. If median subtraction is performed, Mode should be near 0.
+;		When median subtraction is skipped, Mode represents the mean level
+;		of the image gaussian noise
+;
+;	Std:	Standard deviation of gaussian noise, estimated as the "sigma"
+;		of the best fit gaussian. A negative value indicates an error
+;
+;	H:	Histogram (1D array)
+;
+;	V:	1D array of data values, corresponding to the center of each
+;		histogram bin
+;
+;	Vmean: 1D array of data values, corresponding to the mean of the
+;		pixels entering each histogram bin
+;
+;	Hfit:	Best fit gaussian. The right tail of the gaussian is truncated
+;		at 1 Std from the histogram mode
+;
+; OPTIONAL OUTPUTS:
+;	COEFF:	Vector of best fit model coefficients, returned by GAUSSFIT.
+;
+; RESTRICTIONS:
+;	1) This procedure assumes the image noise is normally distributed.
+;	Normally distributed noise includes for instance read-out-noise, but
+;	also the photon (Poisson) noise associated to nearly spatially uniform
+;	signals contributing to the image (e.g. dark current, smooth nebulosities
+;	in the sky, etc.). A Poisson-distributed 2-D signal may be considered as
+;	distributed according to a unique gaussian probability law if:
+;	a) the signal is not too faint
+;	b) the signal is approximately spatially uniform
+;	If the image contains both gaussian and photon noise due to non-smooth
+;	sources (e.g. stars), the noise standard deviation will be of course
+;	over-estimated.
+;
+;	2) A maximum number of bins is fixed when computing the histogram.
+;	This threshold is equal to number of elements in the data sub-sample,
+;	which corresponds to having (in the mean) one value per histogram bin!
+;	In practice the computation of the histogram starts with a minimum
+;	number of bins. The bin number is then iteratively increased (by a
+;	factor of 2 at every iteration) until there is a minimum number of bins
+;	(fixed by the keyword HIST_MINSIZE) in one histogram's HWHM or the
+;	maximum number of bins is reached. In the latter case the former
+;	condition may not be fulfilled.
+;
+; PROCEDURE:
+;	Extract a sample of spatially uniformly distributed image pixels,
+;	remove outliers and compute the sample histogram. When median removal
+;	is performed, the histogram bin corresponding to the data values around
+;	0 may be strongly over-populated, due to the large number of small
+;	positive values produced by median subtraction. This bin is thus
+;	replaced with the mean of the two adjacent ones. The data histogram is
+;	then fit with a gaussian curve, whose sigma represents the standard
+;	deviation of the image gaussian noise. The fit is performed by means of
+;	the library routine GAUSSFIT.
+;
+; EXAMPLE:
+;	Compute the mean and standard deviation of an array of normally
+;	distributed pesudo random numbers.
+;		Noise = RANDOMN(Seed, 512, 512)
+;		GAUSSIAN_NOISE_STD, Noise, Mode, Std, H, V, Vmean, Hfit
+;		PRINT, Mode, Std
+;		PLOT, PSYM = 10, V, H  &  OPLOT, LINESTYLE = 1, V, Hfit
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+
+
+
+
+;;; Auxiliary procedures / functions.
+
+; OPT_HISTO: auxiliary procedure. Compute the optimal histogram
+; by adjusting iteratively the bin size so that the histogram FWHM
+; contains at least a minimum number of bins.
+
+; INPUT
+;	data: data to compute histogram
+;	[HIST_MINSIZE = ]: min. no. of bins in histogram HWHM (default = 5)
+;	[HIST_MAXSIZE = ]: size of output histogram in FWHM units (default = 5)
+;	[/REPLACE_MAX]: replace most populated histogram bin, which may be
+;		an artifact (e.g. if the original data are median-subtracted)
+; OUTPUT
+;	h: histogram
+;	x: center of each bin
+;	xmean: vector containing mean data value for each histogram bin
+
+; REMOVE_SPIKE: remove spike (corresponding to 0-bin).
+
+FUNCTION remove_spike, h
+
+	on_error, 2
+	m = max(h, w)
+	if  w gt 0 and w lt n_elements(h)-1  then $
+	   h[w] = round(( h[w-1]+h[w+1] ) / 2.)
+	return, h
+end
+
+PRO opt_histo, data, HIST_MINSIZE = min_size, HIST_MAXSIZE = max_size, $
+   			   REPLACE_MAX = replace, h, v, vmean
+
+	on_error, 2
+	if  n_elements(min_size) eq 0  then  min_size = 5	; bin units
+	if  n_elements(max_size) eq 0  then  max_size = 5	; FWHM units
+	max_nbin = n_elements(data)	; max total no. of histogram bins
+	range = float(max([ abs(min(data)), abs(max(data)) ]))
+	dmin = -range  &  dmax = +range  &  range = 2*range  &  nbin = 1L
+	; compute the histogram, adjusting iteratively the bin size
+	repeat begin
+	   nbin = nbin * 2  &  bin = range / nbin
+	   histo, data, dmin, dmax, bin, h, v, vmean
+	   if  keyword_set(replace)  then  h = remove_spike(h)
+	   l = histo_hwhm(h, -1, mode_sub)
+	   r = histo_hwhm(h, +1, mode_sub)
+	endrep until min([l, r]) ge min_size or 2*nbin ge max_nbin
+	; reduce histogram size
+	l = (mode_sub - max_size * l) > 0
+	r = (mode_sub + max_size * r) < (n_elements(h) - 1)
+	h = h[l:r]  &  v = v[l:r]  &  vmean = vmean[l:r]
+	return
+end
+
+;;; The main routine.
+
+PRO gauss_noise_std, data, PATCH = patch_, POINT_FRAC = point_frac, $
+					 NOSUB = nosub, N_STD = n_std, _EXTRA = extra,  $
+					 MAXIT = maxit, TOL = tol, NTERMS_FIT = nterms, $
+					 mode, std, h, v, vmean, hfit, COEFF = c
+
+	on_error, 2
+	; remove median
+	if  n_elements(patch_) eq 0  then  patch = 3  else  patch = patch_ > 3
+	d = data
+	if  not keyword_set(nosub)  then  d = d - median_filter(d, patch)
+	; extract a sample of uniformly distributed points
+	if  n_elements(point_frac) eq 0  then  point_frac = 1
+	if  point_frac ne 1  then begin
+	   npoints = round(n_elements(d) / float(point_frac))
+	   s = float(size52(d, /DIM))
+	   nx = round(sqrt( s[0]/s[1] * npoints ))
+	   ny = round(sqrt( s[1]/s[0] * npoints ))
+	   x = round(sampling_grid(nx, s[0] / nx))
+	   y = round(sampling_grid(ny, s[1] / ny))
+	   x = x # (lonarr(ny) + 1)  &  y = (lonarr(nx) + 1) #  y
+	   d = d[x, y]
+	endif
+	; extract data within suitable intensity range
+	if  n_elements(n_std) eq 0  then  n_std = 3
+	d_med = median(d)  &  m = moment(d - d_med, SDEV = std)
+	w = where(abs(d - d_med) lt n_std*std)  &  d = d[w]
+	; compute histogram with suitable bin size
+	opt_histo, d, h, v, vmean, _EXTRA = extra, $
+			   REPLACE_MAX = not keyword_set(no_sub) and 1B
+	; iterative gaussian fit
+	if  n_elements(maxit) eq 0  then  maxit = 10
+	if  n_elements(tol) eq 0  then  tol = 1e-2
+	if  n_elements(nterms) eq 0  then  nterms = 3
+	it = 0  &  converging = 0B
+	m = max(h, mode)  &  mode = v[mode]
+	std = max([ mode-min(v), max(v)-mode ])
+	while  not converging and it lt maxit  do begin
+;	   w = where(v le mode + std)	; this line to fit left-tail
+	   w = lindgen(n_elements(h))	; this line to fit all histogram
+	   hfit = gaussfit(vmean[w], h[w], NTERMS = nterms, c)
+	   std0 = std  &  mode = c[1]  &  std = abs(c[2])
+	   converging = abs((std - std0) / std0) lt tol
+	   it = it + 1
+	endwhile
+	if  not converging  then  std = -1
+	return
+end
diff --git a/gaussian2d.pro b/gaussian2d.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1a341b8db9bd3baa74c8d07fe86ed37a3ab6ad3c
--- /dev/null
+++ b/gaussian2d.pro
@@ -0,0 +1,67 @@
+; $Id: gaussian2d.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	GAUSSIAN2D
+;
+; PURPOSE:
+;	Compute bivariate gaussian function, normalized to unit maximum.
+;
+; CATEGORY:
+;	Models.
+;
+; CALLING SEQUENCE:
+;	Result = GAUSSIAN2D(X_size, Y_size, X_center, Y_center, $
+;						Sigma_x, Sigma_y, Angle)
+;
+; INPUTS:
+;	X_size, Y_size:	First and second size of output array
+;
+;	X_center, Y_center:	Coordinates of center, not necessarily integer
+;
+;	Sigma_x, Sigma_y:	Standard deviations of gaussian along principal axes
+;
+; OPTIONAL INPUTS:
+;	Angle:	Position angle (radians) of the x- principal axis with respect
+;		to the horizontal axis of the array reference frame.
+;		The default is Angle = 0., i.e. the gaussian's principal axes are
+;		parallel to the array edges
+;
+; OUTPUTS:
+;	Result:	2D floating-point array
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION gaussian2d, x_size, y_size, x_center, y_center, sigma_x, sigma_y, angle
+
+	on_error, 2
+	; check inputs
+	s = round([x_size, y_size])
+	c = [x_center, y_center]
+	sigma = [sigma_x, sigma_y]
+	if  n_elements(angle) eq 0  then  a = 0.  else  a = angle
+	; check sigma's
+	min_sigma = 1e-2
+	if  min(sigma) lt min_sigma  then begin
+	   gaussian = fltarr(s[0], s[1])
+	   gaussian[round(c[0]), round(c[1])] = 1
+	   return, gaussian
+	endif
+	w = sqrt(2)*sigma
+	if  w[0] eq w[1]  then  a = 0.	; a circular gaussian has no position angle
+	; define arrays of x- and y- centered coordinates
+	x = findgen(s[0]) - c[0]  &  y = findgen(s[1]) - c[1]
+	x = temporary(x) # make_array(s[1], VALUE = 1)
+	y = make_array(s[0], VALUE = 1) # temporary(y)
+	; compute x- gaussian
+	if  a ne 0  then $
+	   z = x * cos(a) + y * sin(a)  else  z = x
+	gaussian = exp(-(z/w[0])^2)
+	; multiply by y- gaussian
+	if  a ne 0  then $
+	   z = -x * sin(a) + y * cos(a)  else  z = y
+	gaussian = temporary(gaussian) * exp(-(z/w[1])^2)
+	return, gaussian
+end
diff --git a/get_max.pro b/get_max.pro
new file mode 100644
index 0000000000000000000000000000000000000000..afdefaac140ca4126cd3b5872bf8cd25eb41d037
--- /dev/null
+++ b/get_max.pro
@@ -0,0 +1,49 @@
+; $Id: get_max.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	GET_MAX
+;
+; PURPOSE:
+;	Find coordinates of maximum intensity pixel(s) in a 2D array.
+;
+; CATEGORY:
+;	Array manipulation.
+;
+; CALLING SEQUENCE:
+;	Result = GET_MAX(Array)
+;
+; INPUTS:
+;	Array:	2D array
+;
+; KEYWORD PARAMETERS:
+;	ALL:	If this keyword is set, all the pixels with maximum intensity
+;		are returned. Otherwise only the first pixel (according to how IDL
+;		access arrays in memory address order) is returned.
+;
+; OUTPUTS:
+;	Result:	If ALL is not set, Result is a 2-components long integer vector,
+;		with the column and row coordinates of the maximum intensity pixel.
+;		If ALL is set, Result is a N*2 long integer array, where N (number of
+;		columns) is the number of maximum intensity pixels: the first row of
+;		Result will contain the x- coordinates of the pixels, the second row
+;		of Result will contain the y- coordinates. It N = 1 and ALL is set,
+;		Result is however a 2-components vector.
+;		A negative scalar is always returned if Array has not 2 dimensions.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION get_max, array, ALL = all
+
+	on_error, 2
+	s = size52(array)
+	if  s[0] ne 2  then  return, -1
+	if  keyword_set(all)  then $
+	   index = where(array ge max(array))  else  m = max(array, index)
+	subs_to_coord, index, s[1], x, y
+	if  n_elements(x) eq 1  then $
+	   p = [x[0], y[0]]  else  p = transpose([transpose(x), transpose(y)])
+	return, p
+end
diff --git a/ginv.pro b/ginv.pro
new file mode 100644
index 0000000000000000000000000000000000000000..7e9b6a3a2b2844e672bee6d6e5736ead2732867f
--- /dev/null
+++ b/ginv.pro
@@ -0,0 +1,115 @@
+; $Id: ginv.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	GINV
+;
+; PURPOSE:
+;	Compute the Moore-Penrose generalized inverse of a rectangular matrix
+;	by applying the Gram-Schmidt orthogonalization procedure to the columns
+;	of the input array.
+;
+; CATEGORY:
+;	Mathematics. Matrix inversion.
+;
+; CALLING SEQUENCE:
+;	Results = GINV(A)
+;
+; INPUTS:
+;	A:	2D array to be inverted (not necessarily square)
+;
+; OUTPUTS:
+;	Return generalized inverse of input array A. If A has size m*n, its
+;	generalized inverse will have size n*m.
+;	If A is a double precision floating-point array, the output is in
+;	double precision, otherwise it is in single precision
+;
+; OPTIONAL OUTPUTS:
+;	Rank:	Rank of A, i.e. number of linearly indepent columns
+;
+; PROCEDURE:
+;	Apply the recursive Gram-Schmidt orthogonalization procedure to the
+;	columns of the input matrix A to compute the generalized inverse A'.
+;	We briefly recall the properties of the Moore-Penrose generalized
+;	inverse:
+;	TRANPOSE(A'A) = A'A
+;	TRANPOSE(AA') = AA'
+;	AA'A = A
+;	A'AA' = A'
+;	The generalized inverse conicides with the ordinary inverse in the
+;	case of a non-singular square matrix.
+;	When used to solved a linear system of "normal equations", the
+;	generalized inverse produces the so-called "minimum norm solution",
+;	which is particularly meaningful in the case of singular of nearly
+;	singular linear systems. For more details, see
+;	B.W.Rust, W.R.Burrus, "Mathematical programming and the numerical
+;		solution of linear equations",
+;		American Elsevier Publishing Company, 1972
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;	Originally written in FORTRAN by S.Lorenzutta
+;-
+
+
+
+
+; GS_ORTH: recursive Gram-Schmidt orthogonalization of a set of n
+; m-components vectors. The vectors are stored as a (m*n) array,
+; to speed up the computation if virtual memory should be used.
+
+PRO gs_orth, v, u, lin_indep, n, m, tol
+
+	on_error, 2
+	this = n - 1
+	if  this gt 0  then begin
+	   ; Induction case: apply the G-S orthogonalization to this vector.
+	   ; Orthogonalize the first (n - 1) vectors before
+	   gs_orth, v, u, lin_indep, n - 1, m, tol
+	   norm = total(v[*,this] * v[*,this])
+	   prod = (v[*,this] # v )[0:this-1]
+	   v[*,this] = v[*,this] - (prod * lin_indep[0:this-1]) # $
+	   						   transpose(v[*,0:this-1])
+	   u[*,this] = u[*,this] - prod # transpose(u[*,0:this-1])
+	   new_norm = total(v[*,this] * v[*,this])
+	   is_lin_indep = norm ne 0
+	   if  is_lin_indep  then  is_lin_indep = new_norm / norm gt tol
+	   if  is_lin_indep  then begin
+	      ; this vector is linearly independent
+	      lin_indep[this] = 1  &  norm = 1 / sqrt(new_norm)
+	   endif else begin
+		  ; this vector is linearly dependent
+	      prod = u[*,this] # u[*,0:this-1]
+		  v[*,this] = - (prod * lin_indep[0:this-1]) # $
+		  				transpose(v[*,0:this-1])
+	      lin_indep[this] = 0
+	      norm = 1 / sqrt(total(u[*,this] * u[*,this]))
+	   endelse
+	endif else begin
+	   ; Base case: one vector to normalize
+	   norm = sqrt(total(v[*,this] * v[*,this]))
+	   if  norm ne 0  then begin
+	      norm = 1 / norm  &  lin_indep[this] = 1
+	   endif else  lin_indep[this] = 0
+	endelse
+	v[*,this] = v[*,this] * norm  &  u[*,this] = u[*,this] * norm
+	return
+end
+
+
+FUNCTION ginv, a, rank
+
+	on_error, 2
+	s = size52(a, /DIM)  &  n = s[0]  &  m = s[1]
+	type_a = size52(a, /TYPE)
+	a_inv = transpose(double(a))	; transpose the set of column
+						; vectors to speed up the computation if virtual
+						; memory should be used
+	u = dblarr(n, n)  &  diag = lindgen(n)  &  u[diag,diag] = 1
+	lin_indep = lonarr(n)  &  tol = 2 * (machar(/DOUBLE)).eps
+	gs_orth, a_inv, u, lin_indep, n, m, tol
+	a_inv = temporary(a_inv) # transpose(u)
+	if  type_a lt 5  then  a_inv = float(a_inv)
+	rank = total(lin_indep)
+	return, a_inv
+end
diff --git a/halo_smooth.pro b/halo_smooth.pro
new file mode 100644
index 0000000000000000000000000000000000000000..88503f30c7bbeed9ef08f8c2cfc9072290098a12
--- /dev/null
+++ b/halo_smooth.pro
@@ -0,0 +1,141 @@
+; $Id: halo_smooth.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	HALO_SMOOTH
+;
+; PURPOSE:
+;	Smooth the halo of a stellar image by means of a variable box size
+;	median filtering technique. The width of the smoothing box for a
+;	given pixel increases with the radial distance of the pixel itself
+;	from the center of the image.
+;	This routine may be used to smooth the halo of a PSF image,
+;	exctracted from a stellar field.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = HALO_SMOOTH(Image, R0)
+;
+; INPUTS:
+;	Image:	2D image to smooth
+;
+;	R0:	Scalar, indicates the radius of the region around the Image
+;		maximum which is not processed by median filtering.
+;		In practice the halo smoothing starts from this distance.
+;
+; KEYWORD PARAMETERS:
+;	R_WIDTH:	Use this keyword to specify the radial width of the
+;		smoothing box at a distance of 2*R0 from the Image maximum.
+;		The default is  R_WIDTH = FLOAT(R0)/2 pixels.
+;
+;	A_WIDTH:	Use this keyword to specify the azimuthal width of the
+;		smoothing box at a distance of 2*R0 from the Image maximum.
+;		The default is  A_WIDTH = !pi/8 rad
+;
+;	R_EXP, A_EXP:	The radial and azimuthal widths of the smoothing box
+;		increase as power-law functions of the radial distance from the
+;		Image maximum. The keywords R_EXP and A_EXP allow the user to
+;		specify the power degree.
+;		The default values are  R_EXP = 2, A_EXP = 3.
+;
+;	PAD_0:	Set this keyword to a nonzero value to have the Image padded
+;		with a frame of 0s before smoothing. The use of this strategy may
+;		prevent the onset of undesired edge effects and force the smoothed
+;		image to approach 0 at the edge. The default is no padding.
+;
+;	SHOW:	Set this keyword to a nonzero value to show the shape and
+;		area of the smoothing box for each radial distance from the Image
+;		maximum, along the main diagonal of the input array.
+;		In practice a binary image is displayed, equal to 1 on the support
+;		of the smoothing box. The image is displayed on the currently
+;		active graphic window.
+;
+; OUTPUTS:
+;	Result:	Halo-smoothed image, with the same size as the input array
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+
+
+;;; Auxiliary functions.
+
+;RAD_WIDTH:	compute radial width of smoothing neighborhood for a given pixel.
+
+FUNCTION rad_width, r, r0, rad_coeff, rad_exp
+
+	return, rad_coeff * (r / (2.* r0)) ^rad_exp
+end
+
+;AZI_WIDTH:	compute azimuthal width of smoothing neighborhood for a given pixel.
+
+FUNCTION azi_width, r, r0, azi_coeff, azi_exp
+
+	return, azi_coeff * (r / (2.* r0)) ^azi_exp
+end
+
+
+;;; The main routine.
+
+FUNCTION halo_smooth, image, r0, PAD_0 = pad_0, SHOW = show, $
+					  R_WIDTH = rw, A_WIDTH = aw, R_EXP = re, A_EXP = ae
+
+	on_error, 2
+	if  size52(image, /N_DIM) ne 2  then  return, image
+	siz = size52(image, /DIM)  &  sx = siz[0]  &  sy = siz[1]
+	smooth_image = image
+	; Pad with 0s?
+	if  keyword_set(pad_0)  then begin
+	   siz = 2 * siz  &  sx = siz[0]  &  sy = siz[1]
+	   smooth_image = extend_array(smooth_image, sx, sy)
+	endif
+	saved_image = smooth_image
+	; Define default width of filtering box at 2*r0 from the center
+	if  n_elements(rw) eq 0  then  rw = r0 / 2.
+	if  n_elements(aw) eq 0  then  aw = !pi / 8
+	if  n_elements(re) eq 0  then  re = 2
+	if  n_elements(ae) eq 0  then  ae = 3
+	rad_coeff = rw  &  azi_coeff = 2 * r0 * aw
+	; For each pixel, compute distance from the center and azimuthal angle
+	m = get_max(smooth_image)  &  x0 = m[0]  &  y0 = m[1]
+	x = findgen(sx) # make_array(sy, VALUE = 1)
+	y = make_array(sx, VALUE = 1) # findgen(sy)
+	r_distance = round(distance(x0, y0, x, y))
+	azi = angle(x0, y0, x, y)
+	outer_rad = max(r_distance)
+	; Define parameters for display
+	if  keyword_set(show)  then begin
+	   dsiz = min([!D.x_vsize, !D.y_vsize]) * siz/max(siz)
+	   dxy = m[1] - m[0]
+	endif
+	; Iterate on annular regions of increasing radius, from inner to outer
+	for  r = r0, outer_rad  do begin
+	   ; Identify pixels at this distance from the center
+	   wr = where(r_distance eq r, nr)
+	   if  nr ne 0  then begin
+	      ; Compute radial and azimuthal width of smoothing box
+		  w = rad_width(r, r0, rad_coeff, re)
+		  l = azi_width(r, r0, azi_coeff, ae) / r
+		  rad_range = abs(r_distance - r) le w/2
+		  for  n = 0, nr - 1  do begin
+		  	 ; Define the smoothing 'box' of each pixel
+			 delta_azi = abs(azi - azi[wr[n]])
+			 azi_range = delta_azi le l/2  or  2*!pi - delta_azi le l/2
+		     neigh = where((rad_range and azi_range) and 1B)
+		     if  keyword_set(show)  then $
+		     if  y[wr[n]] eq (x[wr[n]] + dxy) and x[wr[n]] gt x0  then begin
+			    b = bytarr(sx, sy)  &  b[neigh] = 1
+			    tvscl, congrid(b, dsiz[0], dsiz[1])
+		     endif
+			 ; Compute median of box
+			 smooth_image[x[wr[n]], y[wr[n]]] = median(saved_image[neigh], /EVEN)
+		  endfor
+	   endif
+	endfor
+	if  keyword_set(pad_0)  then $
+	   smooth_image = sub_array(smooth_image, sx/2, sy/2)
+	return, smooth_image
+end
\ No newline at end of file
diff --git a/histo.pro b/histo.pro
new file mode 100644
index 0000000000000000000000000000000000000000..b38ba3f43036af2a1a4c81cc7d7a5fa147233d7d
--- /dev/null
+++ b/histo.pro
@@ -0,0 +1,62 @@
+; $Id: histo.pro, v 1.1 Jan 2000 e.d. $
+;
+;+
+; NAME:
+;	HISTO
+;
+; PURPOSE:
+;	Compute histogram of input data and array of data values
+;	corresponding to histogram bins.
+;
+; CATEGORY:
+;	Mathematics. Statistics.
+;
+; CALLING SEQUENCE:
+;	HISTO, Data, Dmin, Dmax, Bin, H, X, Xmean
+;
+; INPUTS:
+;	Data: Data to compute histogram (any number of IDL dimensions)
+;
+;	Dmin, Dmax:	Min. and max. data value to be considered in the histogram
+;
+;	Bin:	Size of histogram bin
+;
+; OUTPUTS:
+;	H: Histogram
+;
+;	X: 1D array of data values corresponding to the center of each bin
+;
+;	Xmean: 1D array corresponding to the mean of the data values entering
+;		each histogram bin
+;
+; PROCEDURE:
+;	Compute the histogram with the IDL intrinsic function HISTOGRAM, using
+;	the input options specified by the parameters Dmin, Dmax, Bin. All
+;	the computations are performed in floating-point arithmetics.
+;	Then compute arrays of values corresponding to each histogram bin,
+;	useful for plots, fitting, etc.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;	Updates:
+;	1) long integer loop variable (Emiliano Diolaiti, January 2000).
+;-
+
+PRO histo, data, dmin, dmax, bin, h, x, xmean
+
+	on_error, 2
+	; compute histogram
+	h = histogram(float(data), BINSIZE = float(bin), MIN = float(dmin), $
+				  MAX = float(dmax), REVERSE_INDICES = r)
+	; compute center of each bin
+	range = float(dmax - dmin)  &  nbin = long(range/bin) + 1
+	x = findgen(nbin) * bin + dmin + bin/2.
+	; compute mean data value for each bin
+	n_el = n_elements(h)  &  xmean = fltarr(n_el)
+	for  n = 0L, n_el - 1  do begin
+	   lo = r[n]  &  up = r[n+1] - 1
+	   if  lo lt up  then $
+	      xmean[n] = mean(data[r[lo:up]])  else  xmean[n] = x[n]
+	endfor
+   return
+end
diff --git a/histo_hwhm.pro b/histo_hwhm.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0ab27b8dae2402cefdcd2699e5edcc92f9c7988b
--- /dev/null
+++ b/histo_hwhm.pro
@@ -0,0 +1,54 @@
+; $Id: histo_hwhm.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	HISTO_HWHM
+;
+; PURPOSE:
+;	Compute the Half Width at Half Maximum (HWHM) of an histogram.
+;
+; CATEGORY:
+;	Mathematics. Statistics.
+;
+; CALLING SEQUENCE:
+;	Result = HISTO_HWHM(H, Increment, Mode)
+;
+; INPUTS:
+;	H:	Histogram
+;
+;	Increment:	+1 to compute the right tail HWHM, -1 to compute the left
+;		tail HWHM. If Increment is different from +/-1, the value -1 is
+;		used by default
+;
+; OUTPUTS:
+;	Return the (left- or right- tail) HWHM of the histogram, expressed
+;	in bin units.
+;
+; OPTIONAL OUTPUTS:
+;	Mode:	subscript of the most populated bin in the input histogram.
+;
+; RESTRICTIONS:
+;	The algorithm assumes there are no secondary maxima in the histogram
+;	within a distance comparable to the HWHM from the most populated bin.
+;	Otherwise the estimated HWHM may be overestimated.
+;
+; PROCEDURE:
+;	Starting from the most populated bin, move leftwards (rightwards)
+;	until a bin with intensity equal or smaller than half the intensity
+;	of the initial bin is found. The distance (in bin units) between this
+;	bin and the initial one is an estimate of the histogram HWHM.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION histo_hwhm, h, increment, mode
+
+	on_error, 2
+	if  abs(increment) ne 1  then  incr = -1  else  incr = increment
+	s = reverse(sort(h))  &  mode = s[0]  &  threshold = 0.5 * h[mode]
+	l = mode  &  l_min = 0  &  l_max = n_elements(h) - 1
+	while  h[l] gt threshold and l gt l_min and l lt l_max  do  l = l + incr
+	l = (l - incr) > l_min < l_max
+	return, abs(mode - l)
+end
diff --git a/image_background.pro b/image_background.pro
new file mode 100644
index 0000000000000000000000000000000000000000..ec6f4af0e263e7f9378337eff23dc85853a9d021
--- /dev/null
+++ b/image_background.pro
@@ -0,0 +1,113 @@
+; $Id: image_background.pro, v 1.1 Apr 2000 e.d. $
+;
+;+
+; NAME:
+;	IMAGE_BACKGROUND
+;
+; PURPOSE:
+;	Compute the intensity distribution of the background in a given image.
+;	Local measurements of the background are obtained after partitioning the
+;	input array; the sampled distribution is then magnified onto the same
+;	grid of the original image by interpolation.
+;	This method is especially useful when the image background is not
+;	spatially uniform.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = IMAGE_BACKGROUND(Image, Step)
+;
+; INPUTS:
+;	Image:	2D array
+;
+;	Step:	Size of sub-regions to measure local background
+;
+; KEYWORD PARAMETERS:
+;	SKY_MEDBOX:	The array of local measurements is smoothed by median
+;		filtering. Use the keyword SKY_MEDBOX to fix a box size for median
+;		smoothing. In general, the larger the Step size the smaller should
+;		be the box for median filtering. The default is SKY_MEDBOX = 3,
+;		which represents also the minimum box size.
+;
+;	CUBIC:	Set this keyword to magnify the sampled background with the
+;		cubic convolution interpolation method implemented in the library
+;		routine CONGRID. The default is to use bilinear interpolation as;
+;		implemented in the IDL intrinsic function REBIN.
+;
+; OUTPUTS:
+;	Result:	2D array, having the same size as the input Image.
+;
+; RESTRICTIONS:
+;	1) Bad pixels are assumed to have been corrected.
+;	2) The background may be over-estimated in the presence of strong
+;	sources, even though the present method seems to be less biased
+;	than median smoothing.
+;
+; PROCEDURE:
+;	The input Image is partitioned into sub-frames defined by a rectangular
+;	grid. The mesh points coincide with the centers of the corresponding
+;	regions. For each sub-image a local background estimate is obtained by
+;	means of the IDL library routine SKY, written by W.Landsman and adapted
+;	from the DAOPHOT routine of the same name. If SKY doesn't converge, the
+;	local background is estimated as the median value of the sub-image.
+;	Each local background estimate is associated to the mesh point
+;	corresponding to the sub-image under examination. The sampled version of
+;	the background is smoothed by median filtering and magnified onto the
+;	same grid of the input Image by means of interpolation.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;	Updates:
+;	1) Corrected edge effect due to 0-padding
+;	   (Emiliano Diolaiti, October 1999).
+;	2) Fixed bug on small arrays (Emiliano Diolaiti, April 2000).
+;	3) Introduced error handler to handle run-time error generated by call
+;	   to SKY (Emiliano Diolaiti, April 2000).
+;   4) Local background estimate by median (E. D., August 2004)
+;-
+
+FUNCTION image_background, image, sampling_step, $
+						   SKY_MEDBOX = med_box, CUBIC = cubic
+
+	on_error, 2
+	siz = size52(image, /DIM)  &  sx = siz[0]  &  sy = siz[1]
+	step = round(sampling_step)
+	if  n_elements(med_box) ne 0  then  box = med_box  else  box = 3
+	box = box > 3
+	; Pad the image with 0s
+	sx = (sx / step + 1) * step  &  sy = (sy / step + 1) * step
+	ima = extend_array(image, sx, sy, OFFSET = off)
+	lo = off  &  up = lo + siz - 1
+	; Define the sampling grid
+	nx = sx / step  &  ny = sy / step
+	x = sampling_grid(nx, step, lx0, ux0)  &  ux0 = ux0 < sx
+	y = sampling_grid(ny, step, ly0, uy0)  &  uy0 = uy0 < sy
+	lx = round(x - step / 2.) > lo[0]  &  ux = round(x + step / 2.) < up[0]
+	ly = round(y - step / 2.) > lo[1]  &  uy = round(y + step / 2.) < up[1]
+	; Background sampling
+	b = fltarr(nx, ny)
+	for  i = 0L, ny - 1  do  for  j = 0L, nx - 1  do begin
+	   catch, error
+	   if  error ne 0  then begin
+	      local_back = median(ima[lx[j]:ux[j],ly[i]:uy[i]], /EVEN)
+	      catch, /CANCEL
+	   endif else begin
+;	      sky, /SILENT, ima[lx[j]:ux[j],ly[i]:uy[i]], local_back, stdev
+;	      if  stdev lt 0  then $
+	         local_back = median(ima[lx[j]:ux[j],ly[i]:uy[i]], /EVEN)
+	   endelse
+	   b[j,i] = local_back
+	endfor
+	; Sampled background smoothing
+	b = median_filter(b, box)
+	; Background interpolation
+	siz = size52(b, /DIM) * step
+	if  n_elements(b) gt 1  then begin
+	   if  keyword_set(cubic)  then $
+	      b = congrid(b, siz[0], siz[1], CUBIC = -0.5)  else $
+	      b = rebin(b, siz[0], siz[1])
+	endif else  b = make_array(siz, siz, VALUE = b)
+	b = b[lo[0]:up[0],lo[1]:up[1]]
+	return, b
+end
diff --git a/image_core.pro b/image_core.pro
new file mode 100644
index 0000000000000000000000000000000000000000..be532967577eb75c028dce5b5a65fce3b6164525
--- /dev/null
+++ b/image_core.pro
@@ -0,0 +1,62 @@
+; $Id: image_core.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	IMAGE_CORE
+;
+; PURPOSE:
+;	Given an image, identify the component connected to a specified
+;	starting position and above a pre-fixed threshold.
+;
+; CATEGORY:
+;	Data subsetting.
+;
+; CALLING SEQUENCE:
+;	Result = IMAGE_CORE(Image, Threshold, Flag)
+;
+; INPUTS:
+;	Image:	2D array to be searched
+;
+;	Threshold:	Lower threshold for connected component identification
+;
+; KEYWORD PARAMETERS:
+;	X, Y:	Use this keywords to specify the starting position.
+;		The default starting point is the maximum intensity pixel
+;
+;	SUBTRACT:	Set this keyword to a nonzero value to subtract the
+;		value set by Threshold after extraction of the connected component
+;
+; OUTPUTS:
+;	Result:	2D array, with the same size as the input Image, containing
+;		the extracted connected component. Return the input Image if an
+;		error occurs in SEARCH2D.
+;
+; OPTIONAL OUTPUTS:
+;	Flag:	Logical value. It is set to true if the input Threshold is
+;		greater than the intensity of the starting pixel specified by
+;		the keywords X and Y.
+;
+; PROCEDURE:
+;	Use the library routine SEARCH2D to identify the component connected
+;	to the starting position and above the fixed Threshold.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION image_core, image, threshold, X = x, Y = y, SUBTRACT = subtract, flag
+
+	on_error, 2
+	flag = 0B
+	if  n_elements(x) eq 0 or n_elements(y) eq 0  then begin
+	   m = get_max(image)  &  x = m[0]  &  y = m[1]
+	endif
+	s = size52(image, /DIM)
+	ccc = make_array(s[0], s[1], TYPE = size52(image, /TYPE))
+	flag = threshold gt image[x,y]
+	if  flag  then  return, image
+	w = search2d(image, x, y, threshold, max(image))
+	ccc[w] = image[w]
+	if  keyword_set(subtract)  then  ccc[w] = ccc[w] - threshold
+	return, ccc
+end
diff --git a/image_help.txt b/image_help.txt
new file mode 100644
index 0000000000000000000000000000000000000000..be5d73ba7995c6da45d7547891e78c53002570a4
--- /dev/null
+++ b/image_help.txt
@@ -0,0 +1,36 @@
+  'Image' menu help page
+
+
+  The 'Image' menu contains the following sub-menus:
+
+  'Load':
+      Load an image and/or the background emission from a FITS file.
+
+  'Noise':
+      Estimate the standard deviation of the noise in each pixel of
+      the image. The noise array can also be load from a FITS file.
+
+  'Bad Pixels':
+      Load a bad pixels mask from a FITS file and replace bad pixels
+      in the image. This task might be used to just read bad data
+      points without replacing them.
+
+  'Reference sources':
+      Select reference stars in the currently displayed image by
+      mouse click. The selected sources can be saved to a file and
+      used for instance to compare different lists of stars (see the
+      'Compare Lists' button).
+
+  'Save':
+      Save to a FITS file the following items:
+      - processed image (e.g. after bad pixels repair)
+      - background array (after PSF extraction or stars detection)
+      - detected stars and synthetic stellar field
+        (after stars detection)
+      Save to an ASCII file the following item:
+      - list of detected stars, with position, flux, formal errors
+        and correlation coefficient. This operation may be done
+        also before quitting the stars detection widget application
+        (see 'Astrometry and Photometry' button in the main widget
+        on-line help).
+ 
diff --git a/image_model.pro b/image_model.pro
new file mode 100644
index 0000000000000000000000000000000000000000..11c84b70747da180f4d18ac2aa18c4878a24c3e5
--- /dev/null
+++ b/image_model.pro
@@ -0,0 +1,437 @@
+; $Id: image_model.pro, v 2.4 May 2014 e.d. $
+;
+;+
+; NAME:
+;   IMAGE_MODEL
+;
+; PURPOSE:
+;   Create a synthetic image given by a sum of shifted scaled replicas
+;   of a PSF. The PSF may either be a replica of the input template
+;   ("fixed PSF" option) or may be extracted from a set of local PSFs
+;   ("space-variant PSF" option) or computed for each location, according
+;   to some user-defined model ("PSF model" option).
+;
+; CATEGORY:
+;   Models.
+;
+; CALLING SEQUENCE:
+;   Result = IMAGE_MODEL(X, Y, F, X_size, Y_size, Psf, Data)
+;
+; INPUTS:
+;   X, Y: Vectors of stars positions
+;
+;   F:    Vector of stellar fluxes
+;
+;   X_size, Y_size:   First and second size of the output array
+;
+;   Psf:  When the "fixed PSF" option is used, Psf must be a 2D array
+;     containing the image of the PSF to be replicated in the output image
+;     model.
+;     When the "space-variant PSF" option is used, Psf must be a 3D stack
+;     of PSF images. In this case it is necessary to supply the bounds of
+;     image domain partition (see KEYWORDS LX, UX, LY, UY).
+;     When the "PSF model" option is used, Psf must be a string parameter 
+;     with the name of the function used to computer the desired PSF model. 
+;     The following PSF models are available:
+;     - Sum of Moffat functions elongated to a common point; the width in the 
+;       elongated axis is described by a polynomial function.
+;       Set Psf = "mm_psf"
+;     - Airy diffraction pattern. Set Psf = "airy"
+;     - Resampled version of an input numerical PSF. Set Psf = "resampled". This 
+;       model may be useful if a PSF is known on a fine pixel grid and it has to 
+;       be resampled on a coarser grid.
+;     If the "PSF model" option is applied, the user may have to supply
+;     additional information with the parameter Data (see OPTIONAL INPUTS),
+;     depending on how the procedure which actually computes the PSF model
+;     is defined.
+;
+; OPTIONAL INPUTS:
+;   Data: Use this variable to provide a pointer to the additional information
+;     required by the "model" option.
+;     In general the heap variable pointed by Data is a structure, containing
+;     miscellaneous information.
+;     For the supported model types, the structure pointed by Data must be
+;     defined as follows:
+;     1) Psf type = 'mm_psf'
+;      *Data = {Xref: xref, Yref: yref, Xori: xori, Yori: yori, $
+;               C: c, Pow: k, Ncomp: ncomp, Nparcomp: nparcomp, $
+;               X_size: x_size, Y_size: y_size}
+;      where
+;      Xref, Yref: (float) coordinates of reference position in the image
+;      Xori, Yori: (float) coordinates of pixel [0,0] of PSF model array with respect to 
+;         image array
+;      C: (float) array of coefficients defining the multi-Moffat PSF model and its variation 
+;         across the image. For more details, see 'mm_psf_setup.pro'
+;      Pow: vector with power law of Moffat functions
+;      Ncomp: number of Moffat components in the model
+;      Nparcomp: number of parameters per component (3)
+;      X_size, Y_size: size of the PSF model array
+;     2) Psf type = 'airy'
+;      *Data = {X_size: x_size, Y_size: y_size, Sampling_factor: sampling_factor},
+;      where
+;      X_size, Y_size: size of the PSF model array
+;      Sampling_factor: ratio of the actual sampling step to the critical step size
+;     3) Psf type = 'resampled_psf'
+;      *Data = {X_size0: x_size0, Y_size0: y_size0, X_size: x_size, Y_size: y_size, $
+;               Psf: psf, Xpsf: xpsf, Ypsf: ypsf}
+;      where
+;      X_size0, Y_size0: integer scalars, X and Y size of given PSF
+;      X_size, Y_size: integer scalars, X and Y size of resampled PSF
+;      Psf: 2D or 3D cube of PSFs; size x_size0*y_size0*npsf, where npsf is the number 
+;         of input PSFs
+;      Xpsf, Ypsf: vectors of npsf elements representing the X and Y positions of the 
+;         PSFs in the psf cube.
+;         
+;     When the "fixed PSF" options is chosen, the variable Data may also be
+;     used to provide additional information for the Psf shift, which has
+;     been released on output in a previous call to IMAGE_MODEL (see OPTIONAL
+;     OUTPUTS below).
+;     The parameter Data must NOT be supplied when a stack of space-variant
+;     PSFs is supplied.
+;
+; KEYWORD PARAMETERS:
+;   XPSF, YPSF:   Vectors specifying the positions of the local PSFs in 
+;     the image when the "space-variant PSF" option is used.
+;
+;   LX, UX, LY, UY:   Vectors specifying the bounds of the image domain
+;     partition when the "space-variant PSF" option is used. In this case
+;     the sub-domain  [LX[j]: Ux[j], LY[i]: UY[i]]  must correspond to the
+;     (i * X_size + j)-th  PSF in the input stack.
+;
+;   INTERP_TYPE:  Set this keyword to a string identifying one of the
+;     interpolation techniques supported by the function IMAGE_SHIFT
+;     (for more details see the file 'image_shift.pro'). This keyword
+;     is neglected if the "PSF model" option is used.
+;
+;   REFERENCE_PIX:    Set this keyword to a two-elements integer vector with
+;     the coordinates of the reference pixel in the Psf array which must
+;     be placed at the positions (X, Y) in the output array.
+;     The default is the Psf maximum.
+;
+; OUTPUTS:
+;   Result:   2D array containing the synthetic model
+;
+; OPTIONAL OUTPUTS:
+;   Data: The heap variable pointed by Data may be modified by the
+;     procedures called by IMAGE_MODEL to shift the input Psf ("input PSF"
+;     option) or to compute a PSF model ("PSF model" option).
+;     This pointer can be used as a useful input/output variable to
+;     provide or retrieve information for subsequent calls to IMAGE_MODEL.
+;     Let us consider the following example: suppose IMAGE_MODEL is
+;     called the first time with the heap variable (*Data) undefined and
+;     using the "input PSF" option. The pointer variable Data released on
+;     output will reference an anonymous structure (created by IMAGE_SHIFT)
+;     with useful information which can be recycled in a further call to
+;     IMAGE_MODEL (provided all the options are the same).
+;
+; RESTRICTIONS:
+;   The "fixed" and "space-variant" PSF options are suited to a well sampled
+;   PSF: in this case it is possible to interpolate the template when a
+;   fractional shift is required for sub-pixel positioning. When the data are
+;   sub-sampled, interpolation errors may occur. In this case a PSF model should 
+;   be used instead, if available (with the "PSF model" option).
+;
+; PROCEDURE:
+;   For each input position and stellar flux, put one PSF in the output image.
+;   The PSF may be simply a replica of the input template or may be extracted
+;   from an stack of local PSFs or even computed for each location according to 
+;   a given model. In the first two cases, sub-pixel positioning is performed 
+;   by interpolating the input PSF (see the function IMAGE_SHIFT in the file 
+;   'image_shift.pro' for more details).
+;   If the user wishes to define new model options, he/she must write a new
+;   procedure according to the following template:
+;
+;   PRO model_psf, X, Y, Aux, Psf, Reference_pixel
+;     dx = X - round(X)  &  dy = Y - round(Y)
+;     "function call" to define the PSF model,
+;      having its maximum at (x_size/2,y_size/2)
+;     Psf = Psf / total(Psf)
+;     Reference_pixel = [Aux.x_size, Aux.y_size] / 2
+;     return
+;   end
+;
+;   where X and Y represent the location of a star in the image, Aux is a
+;   structure passed to IMAGE_MODEL through the pointer Data (see OPTIONAL
+;   INPUTS above), Psf is the output PSF model and Reference_pixel will be
+;   used by IMAGE_MODEL to position the computed PSF in the output array.
+;   The line "function call" in the above template is a call to some
+;   procedure/function which actually computes the PSF model. The maximum
+;   intensity pixel should lie at (x_size/2,y_size/2). For more details,
+;   see the procedures 'gaussian_psf' and 'airy_psf' in this file.
+;
+;
+; MODIFICATION HISTORY:
+;   Written by:  Emiliano Diolaiti, August 1999.
+;   Updates:
+;   1) Added REFERENCE_PIX keyword (Emiliano Diolaiti, December 1999)
+;   2) Space-Variant PSF option (Emiliano Diolaiti, January 2000)
+;   3) Added MODEL keyword (Emiliano Diolaiti, December 2000)
+;   4) Space-Variant PSF option: fixed error in call to PICK_REGION
+;      and adjusted call to IMAGE_SHIFT (Emiliano Diolaiti, December 2004)
+;   5) Added "multigaussian_psf" and "powergau_psf" options
+;      (E. D., January 2005)
+;   6) Added keywords XPSF, YPSF for space-variant option
+;      (E. D., May 2008)
+;   7) Added MOFFAT_PSF (E. D., June 2008)
+;   8) Added RESAMPLED_PSF (E. D., May 2009)
+;   9) Removed "CASE" instruction in main routine. Now the value of the input
+;      Psf in the "PSF model" option must be equal to the name of the function 
+;      used to compute the PSF model (E. D., January 2012).
+;   10) Updated multi-Moffat PSF function, now called MMR_PSF (E. D., January 2012).
+;   11) Updated multi-Moffat PSF function, now called MM_PSF and temporarly removed 
+;       other PSF models that need verification and documentation (moved to block 
+;       comment at the end of the file) (E. D., March 2012).
+;   12) Updated documentation (E. D., May 2014).
+;-
+
+
+;;; Auxiliary procedures to compute PSF model.
+
+
+; MM_PSF: Sum of N Moffat functions elongated to a common point.
+; All Moffat functions have same center and position angle.
+
+PRO mm_psf, x, y, data, psf, ref_pix
+
+    on_error, 2
+    xglo = x + data.xori
+    yglo = y + data.yori
+    dx = x - round(x)  &  dy = y - round(y)
+    ref_pix = [data.x_size/2, data.y_size/2]
+    psf = fltarr(data.x_size, data.y_size)
+    r = distance(data.xref, data.yref, xglo, yglo)
+    if xglo ne data.xref then $
+       tilt = atan(float(yglo - data.yref) / float(xglo - data.xref)) else tilt = !pi/2
+    par = fltarr(data.nparcomp, data.ncomp)
+    for k = 0, data.ncomp-1 do $
+       for j = 0, data.nparcomp-1 do $
+          for d = 1, round(data.c[0,j,k])+1 do par[j,k] = par[j,k] + data.c[d,j,k] * r^(d-1)
+    for k = 0, data.ncomp-1 do $
+       psf = temporary(psf) + par[0,k] * $
+       moffat2d(data.x_size, data.y_size, ref_pix[0] + dx, ref_pix[1] + dy, $
+                par[1,k], par[2,k], tilt, POWER = data.pow[k], /NORMAL)
+
+    return
+end
+
+; AIRY_PSF: Airy diffraction pattern.
+
+PRO airy_psf, x, y, data, psf, ref_pix
+
+    on_error, 2
+    dx = x - round(x)  &  dy = y - round(y)
+    psf = airy_pattern(data.x_size, data.y_size, $
+                 data.x_size/2+dx, data.y_size/2+dy, data.sampling_factor)
+    psf = psf / total(psf)
+    ref_pix = [data.x_size, data.y_size] / 2
+    return
+end
+
+; RESAMPLED_PSF: resample given PSF to desired size.
+
+PRO resampled_psf, x, y, data, psf, ref_pix
+
+    on_error, 2
+    dx = x - round(x)  &  dy = y - round(y)
+    dx = dx * float(data.x_size0) / float(data.x_size)
+    dy = dy * float(data.y_size0) / float(data.y_size)
+    m = min(distance(x, y, data.xpsf, data.ypsf), w)
+    psf = image_shift(data.psf[*,*,w], dx, dy)
+    norm = (float(data.x_size0) / data.x_size) * (float(data.y_size0) / data.y_size)
+    psf = norm * congrid(psf, data.x_size, data.y_size, CUBIC = -0.5)
+    ref_pix = [data.x_size, data.y_size] / 2
+    return
+end
+
+; TEMPLATE_PSF: template procedure for user-written PSF model procedures.
+
+PRO template_psf, x, y, data, psf, ref_pix
+
+    on_error, 2
+    dx = x - round(x)  &  dy = y - round(y)
+;   psf = "function call"
+    psf = psf / total(psf)
+    ref_pix = [data.x_size, data.y_size] / 2
+    return
+end
+
+
+
+;;; The main routine.
+
+FUNCTION image_model, x, y, f, x_size, y_size, psf, data, $
+                      REFERENCE_PIX = psf_ref_pix, _EXTRA = extra, $
+                      LX = lx, UX = ux, LY = ly, UY = uy, $
+                      XPSF = xpsf, YPSF = ypsf, MODEL = image
+
+   on_error, 2
+    ; Define output image model
+    if  n_elements(image) eq 0  then  image = fltarr(x_size, y_size)
+    nstar = n_elements(f)
+    ; Define PSF option ("fixed" or "space variant" or "model")
+    fixed_psf = size52(psf, /N_DIM) eq 2
+    space_var = not fixed_psf
+    if  not fixed_psf  then begin
+       space_var = size52(psf, /N_DIM) eq 3
+       if space_var then $
+          space_var = (n_elements(lx) ne 0 and n_elements(ux) ne 0 and $
+                       n_elements(ly) ne 0 and n_elements(uy) ne 0) or $
+                      (n_elements(xpsf) ne 0 and n_elements(ypsf) ne 0)
+    endif
+    if  fixed_psf or space_var  then begin
+       psf_size = (size52(psf, /DIM))[0:1]
+       if  n_elements(psf_ref_pix) eq 0  then $
+          psf_ref_pix = get_max(psf[*, *, 0])
+    endif else $
+       psf_pro = strlowcase(psf)
+    ; If there are some additional data defined, de-reference them
+    if  ptr_valid(data)  then $
+       if  n_elements(*data) ne 0  then  aux = *data
+    ; Compute image model
+    for  n = 0L, nstar - 1  do begin
+       ix = round(x[n])  &  iy = round(y[n])
+       if  fixed_psf  then $
+          psf_xy = image_shift(psf, x[n] - ix, y[n] - iy, _EXTRA = extra, aux) $
+       else  if  space_var  then $
+          psf_xy = image_shift(psf[*,*,pick_region(lx, ux, ly, uy, x[n], y[n])], $
+                               x[n] - ix, y[n] - iy, _EXTRA = extra) $
+       else $
+          call_procedure, psf_pro, x[n], y[n], aux, psf_xy, psf_ref_pix
+       add_overlap, image, f[n] * psf_xy, [ix, iy], psf_ref_pix
+    endfor
+    ; Update additional data if necessary
+    if  ptr_valid(data)  then $
+       if  n_elements(aux) ne 0  then  *data = aux
+    return, image
+end
+
+
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; MGR_PSF: Sum of N Gaussian functions elongated to a common point.
+; All Gaussian functions have same center and position angle.
+
+;PRO mgr_psf, x, y, data, psf, ref_pix
+;
+;    on_error, 2
+;;    data.xglo = x + data.xori
+;;    data.yglo = y + data.yori
+;    xglo = x + data.xori
+;    yglo = y + data.yori
+;    dx = x - round(x)  &  dy = y - round(y)
+;    ref_pix = [data.dim/2, data.dim/2]
+;    psf = fltarr(data.dim, data.dim)
+;    r = distance(data.xref, data.yref, xglo, yglo)
+;    if x ne data.xref then $
+;       tilt = atan(float(yglo - data.yref) / float(xglo - data.xref)) else tilt = !pi/2
+;    npc = 3
+;    par = fltarr(npc * data.ncomp)
+;    for k = 0, data.ncomp-1 do begin
+;       j = npc * k
+;       for d = 1, round(data.m[0, k]) + 1  do par[j] = par[j] + data.m[d, k] * r^(d-1)
+;       for d = 1, round(data.rx[0, k]) + 1 do par[j+1] = par[j+1] + data.rx[d, k] * r^(d-1)
+;       for d = 1, round(data.ry[0, k]) + 1 do par[j+2] = par[j+2] + data.ry[d, k] * r^(d-1)
+;    endfor
+;    k = lindgen(data.ncomp) * npc
+;    par[k] = par[k] / total(2 * !pi * par[k] * par[k+1] * par[k+2])
+;    for k = 0, data.ncomp-1 do begin
+;       j = npc * k
+;       psf = temporary(psf) + par[j] * $
+;       gaussian2d(data.dim, data.dim, ref_pix[0] + dx, ref_pix[1] + dy, $
+;                  par[j + 1], par[j + 2], tilt)
+;    endfor
+;
+;    return
+;end
+
+
+;;;;; GAUSSIAN_PSF: 2D (elliptical) gaussian PSF.
+;;;;
+;;;;PRO gaussian_psf, x, y, data, psf, ref_pix
+;;;;
+;;;;    on_error, 2
+;;;;    dx = x - round(x)  &  dy = y - round(y)
+;;;;    psf = gaussian2d(data.x_size, data.y_size, $
+;;;;               data.x_size/2+dx, data.y_size/2+dy, $
+;;;;               data.sigma_x, data.sigma_y, data.angle)
+;;;;    psf = psf / total(psf)
+;;;;    ref_pix = [data.x_size, data.y_size] / 2
+;;;;    return
+;;;;end
+
+;;;;;; MULTIGAUSSIAN_PSF: Sum of 2D gaussians.
+;;;;;; All gaussians have same center and position angle.
+;;;;;
+;;;;;PRO multigaussian_psf, x, y, data, psf, ref_pix
+;;;;;
+;;;;;    on_error, 2
+;;;;;    dx = x - round(x)  &  dy = y - round(y)
+;;;;;    ref_pix = [data.x_size/2, data.y_size/2]
+;;;;;    npar = data.ngau * data.npar_gau + 1
+;;;;;    psf = fltarr(data.x_size, data.y_size)
+;;;;;    for g = 0, data.ngau-1 do begin
+;;;;;       k = g * data.npar_gau
+;;;;;       psf = temporary(psf) + data.p[k] * $
+;;;;;       gaussian2d(data.x_size, data.y_size, ref_pix[0] + dx, ref_pix[1] + dy, $
+;;;;;                  data.p[k + 1], data.p[k + 2], data.p[npar - 1])
+;;;;;    endfor
+;;;;;    return
+;;;;;end
+;;;;;
+;;;;;; MULTIGAUSSIAN_PSF: Sum of 2D gaussians.
+;;;;;; Each gaussian may have different center and position angle.
+;;;;;
+;;;;;PRO multigaussian_psf_, x, y, data, psf, ref_pix
+;;;;;
+;;;;;    on_error, 2
+;;;;;    psf = fltarr(data.x_size, data.y_size)
+;;;;;    dx = x - round(x)  &  dy = y - round(y)
+;;;;;    for g = 0, data.ngau-1 do begin
+;;;;;       k = g * data.npar_gau
+;;;;;       psf = temporary(psf) + data.p[k] * $
+;;;;;       gaussian2d(data.x_size, data.y_size, $
+;;;;;       data.x_size/2 + data.p[k + 3] + dx, data.y_size/2 + data.p[k + 4] + dy, $
+;;;;;       data.p[k + 1], data.p[k + 2], data.p[k + 5])
+;;;;;    endfor
+;;;;;    ref_pix = [data.x_size/2, data.y_size/2]
+;;;;;    return
+;;;;;end
+;;;;;
+;;;;;; POWERGAU_PSF: Gaussian with power profile.
+;;;;;
+;;;;;PRO powergau_psf, x, y, data, psf, ref_pix
+;;;;;
+;;;;;    on_error, 2
+;;;;;    psf = fltarr(data.x_size, data.y_size)
+;;;;;    dx = x - round(x)  &  dy = y - round(y)
+;;;;;    psf = powergau(data.x_size, data.y_size, data.x_size/2 + dx, data.y_size/2 + dy, $
+;;;;;                   data.p[0], data.p[1], data.p[2], data.p[3])
+;;;;;    psf = psf / total(psf)
+;;;;;    ref_pix = [data.x_size/2, data.y_size/2]
+;;;;;    return
+;;;;;end
+;;;;;
+;;;;;; MULTIPOWERGAU_PSF: Sum of 2D gaussians with power profile.
+;;;;;; All gaussians have same center and position angle.
+;;;;;
+;;;;;PRO multipowergau_psf, x, y, data, psf, ref_pix
+;;;;;
+;;;;;    on_error, 2
+;;;;;    dx = x - round(x)  &  dy = y - round(y)
+;;;;;    ref_pix = [data.x_size/2, data.y_size/2]
+;;;;;    npar = data.ngau * data.npar_gau + 2
+;;;;;    phi = data.p[npar - 2]
+;;;;;    pow = data.p[npar - 1]
+;;;;;    psf = fltarr(data.x_size, data.y_size)
+;;;;;    for g = 0, data.ngau-1 do begin
+;;;;;       k = g * data.npar_gau
+;;;;;       psf = temporary(psf) + data.p[k] * $
+;;;;;             powergau(data.x_size, data.y_size, ref_pix[0] + dx, ref_pix[1] + dy, $
+;;;;;                      data.p[k + 1], data.p[k + 2], phi, pow)
+;;;;;    endfor
+;;;;;    psf = psf / total(psf)
+;;;;;    return
+;;;;;end
diff --git a/image_shift.pro b/image_shift.pro
new file mode 100644
index 0000000000000000000000000000000000000000..b6a491dde675eb658cc73dba0ae356819f5e4a08
--- /dev/null
+++ b/image_shift.pro
@@ -0,0 +1,121 @@
+; $Id: image_shift.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	IMAGE_SHIFT
+;
+; PURPOSE:
+;	Interpolate a 2D image in order to perform a fractional
+;	shift of the origin.
+;
+; CATEGORY:
+;	Mathematics. Interpolation.
+;
+; CALLING SEQUENCE:
+;	Result = IMAGE_SHIFT(Image, X_shift, Y_shift, Data)
+;
+; INPUTS:
+;	Image:	2D array to be shifted
+;
+;	X_shift, Y_shift:	Components of the fractional shift
+;
+; OPTIONAL INPUTS:
+;	Data:	See OPTIONAL OUTPUTS
+;
+; KEYWORD PARAMETERS:
+;	INTERP_TYPE:	Use this keyword to choose an interpolation technique.
+;		The supported options are
+;		'F': interpolation by Fourier transform shift
+;		'S': interpolation by spline functions
+;		'I': interpolation by the IDL function INTERPOLATE with keyword_set CUBIC = -0.5 (default)
+;   'B': interpolation by the IDL function INTERPOLATE 
+;
+; OPTIONAL OUTPUTS:
+;	Data:	Structure containing useful information to be used on input
+;		if another shift of the same Image array must be performed.
+;		This allows the user to save some computation time
+;
+; RESTRICTIONS:
+;	1) Interpolation is suited to well-sampled data. For undersampled images,
+;	other techiques should be used. For this purpose, see the function
+;	STARS in the file 'stars.pro'.
+;	2) This routine may perform a fractional shift, i.e. abs(X_shift) <= 0.5,
+;	abs(Y_shift) <= 0.5. When the fractional shift exceeds 0.5 pixels, strong
+;	edge effects might occur.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION image_shift, image, x_shift, y_shift, INTERP_TYPE = interp_type, data
+
+;	on_error, 2
+	if  x_shift eq 0 and y_shift eq 0  then  return, image
+	; is the variable data defined?
+	no_data = n_tags(data) eq 0
+	; some operations if the auxiliary data are undefined
+	if  no_data  then begin
+	   ; define interpolation type to use
+	   if  n_elements(interp_type) eq 0  then  interp_type = 'I'
+	   interp = strupcase(strmid(interp_type, 0, 1))
+	   if  interp ne 'F' and interp ne 'S' and interp ne 'I' and interp ne 'B' then  interp = 'I'
+	   if  interp eq 'S' and strlen(interp_type) eq 7  then $
+	      degree = fix(strmid(interp_type, 6, 1))  else  degree = 3
+	   ; extend image to prevent edge effects
+	   siz = size52(image, /DIM)  &  extsiz = siz + 2
+	   imag = extend_array(image, extsiz[0], extsiz[1], OFFSET = offset)
+	   if  interp eq 'F'  then begin
+	      imag = extend_array(imag, sx, sy, /POW2, OFFSET = add_off)
+	      extsiz = [sx, sy]  &  offset = offset + add_off
+	   endif
+	   lo = offset  &  up = lo + siz - 1
+	endif else  interp = data.interp_type
+
+	; interpolate
+	case  interp  of
+
+	   'S': begin			; SPLINE
+	   		if  no_data  then begin
+	   		   spline_coeff, imag, DEGREE = degree, $
+	   			    		 coefficients, x_knots, y_knots, x, y
+	   		   data = {coefficients: coefficients, $
+	   		           x_knots: x_knots, y_knots: y_knots, $
+	   		           x: x, y: y, degree: degree, lo: lo, up: up, $
+	   		           interp_type: interp}
+	   		endif
+	   		imag = spline_interp(data.coefficients, data.x_knots, $
+	   						     data.y_knots, DEGREE = data.degree, $
+	   						     data.x - x_shift, data.y - y_shift)
+	   		end
+
+	   'F':	begin			; Fourier Transform
+	   		if  no_data  then $
+	   		   data = {image_ft: fft(imag), extsiz: extsiz, $
+	   		   		   lo: lo, up: up, interp_type: interp}
+	   		phi = phase2d(x_shift, y_shift, data.extsiz[0], data.extsiz[1])
+	   		imag = float(fft(data.image_ft * phi, /INVERSE))
+	   		end
+
+	   'I': begin			; IDL INTERPOLATE
+	   		if  no_data  then $
+	   		   data = {image: imag, $
+	   		   		   x: findgen(extsiz[0]), y: findgen(extsiz[1]), $
+	   		   		   lo: lo, up: up, interp_type: interp}
+	   		imag = interpolate(data.image, data.x - x_shift, data.y - y_shift, $
+	   						   /GRID , CUBIC = -0.5, MISSING = 0.)
+	   		end
+
+	   	'B': begin     ; IDL INTERPOLATE
+	   		  if  no_data  then $
+	   		    data = {image: imag, $
+	   		    x: findgen(extsiz[0]), y: findgen(extsiz[1]), $
+	   		    lo: lo, up: up, interp_type: interp}
+	   		  imag = interpolate(data.image, data.x - x_shift, data.y - y_shift, $
+	   		    /GRID , MISSING = 0.)
+	   		end
+
+
+	endcase
+
+	return, imag[data.lo[0]:data.up[0],data.lo[1]:data.up[1]]
+end
diff --git a/instr_noise.pro b/instr_noise.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1c1b6d6f31defd943360a47deab2802b9e210838
--- /dev/null
+++ b/instr_noise.pro
@@ -0,0 +1,52 @@
+; $Id: instr_noise, v 1.0 May 2000 e.d. $
+;
+;+
+; NAME:
+;	INSTR_NOISE
+;
+; PURPOSE:
+;	Evaluate the overall standard deviation of the normally-distributed noise
+;	in an image, given by the sum or the mean of many exposures.
+;	Normally-distributed noise sources are read-out, dark current, thermal
+;	background and sky background.
+;	Most of these sources are instrumental.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = INSTR_NOISE(Ron, Dark, Therm, Sky, El_per_adu, Nexp)
+;
+; INPUTS:
+;	Ron:	Read-out-noise standard deviation in electron (el.) units
+;
+;	Dark:	Dark current level in el.
+;
+;	Therm:	Thermal background in el.
+;
+;	Sky:	Sky background in el.
+;
+;	El_per_adu:	Conversion constant from el. to ADU
+;		(No. of ADU = No. of el. / El_per_adu)
+;
+;	Nexp:	Number of exposures (with the same exposure time)
+;
+; KEYWORD PARAMETERS:
+;	AVG:	Set this keyword to specify that the image is the average of
+;		Nexp exposures. If AVG is not set, the routine assumes the image
+;		is the sum of Nexp exposures.
+;
+; OUTPUTS:
+;	Result:	Scalar, representing the noise standard deviation in ADU
+;
+; MODIFICATION HISTORY:
+;	Written by: Emiliano Diolaiti, May 2000.
+;-
+
+
+FUNCTION instr_noise, ron, dark, therm, sky, el_per_adu, nexp, AVG = avg
+
+	on_error, 2
+	norm = 1.  &  if  keyword_set(avg)  then  norm = 1. / nexp
+	return, norm / el_per_adu * sqrt(nexp * (float(ron)^2 + dark + therm + sky))
+end
diff --git a/list_of_modules.txt b/list_of_modules.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4ec80cd2b24a55f5b1a34df82e14344b76676e8f
--- /dev/null
+++ b/list_of_modules.txt
@@ -0,0 +1,389 @@
+StarFinder v 1.8.2a: list of modules
+
+
+ADD_OVERLAP
+Find and add the overlap region of two 2D arrays.
+
+ADD_SUBSCRIPT
+STARFINDER auxiliary routine to handle internal data structure.
+
+AIRY_PATTERN
+Compute an Airy pattern.
+
+ALL_MAX
+Find relative maxima in a 2D array.
+
+ANGLE
+Compute the position angles of a set of points on a plane.
+
+ARRAY_OVERLAP
+Find bounds of overlap region of two 2D arrays.
+
+ARRAY_PARTITION
+Define bounds to partition an array into a pre-fixed
+number of parts along one dimension.
+
+B_SPLINES
+Compute the 1-D observation matrix to determine the
+coefficients of an interpolating spline in the B-splines
+representation.
+
+BINARY_ARRAY
+Transform a 2D array to binary by thresholding.
+
+CENTER_ARRAY
+Shift a 2D array in order to put its maximum at a given
+specified position.
+
+CENTROID
+Compute the centroid of a 2D array.
+
+CENTROIDER
+Sub-pixel centering of an image by iterative fractional
+shift.
+
+CHECK_BORDER
+Check overlapping region of two 2D arrays.
+
+CIRC_MASK
+Apply a circular mask to a 2D array.
+
+CLICK_ON_MAX
+Select local maxima in an image by mouse click.
+
+COMPARE_LISTS
+Find coincidences between two sets of points on a plane.
+
+CONVERGENCE
+Check convergence condition between two variables.
+
+COORD_TO_SUBS
+Convert pixel coordinates in a 2D array to subscripts.
+
+CORRELATION_COEFF
+Compute the correlation coefficient of two 2D patterns.
+
+CORRELATE_MAX
+Estimate the position of a feature in an image by
+maximizing its correlation with a reference template.
+
+CREATE_ELEMENT
+STARFINDER auxiliary routine to handle internal data structure.
+
+CROSSES
+Mark interesting points in an image with crosses.
+
+DEFAULT_DISPLAY_OPT
+Define default options to display a 2D image.
+
+DELETE_ELEMENT
+STARFINDER auxiliary routine to handle internal data structure.
+
+DIAG_MULT
+Multiply a square array by a diagonal matrix.
+
+DISPLAY_IMAGE
+Display a 2D image according to a set of options.
+
+DISTANCE
+Compute the euclidean distance of a set of points on a
+plane from an origin.
+
+ESTIMATE_BACKGROUND
+Estimate the background emission in an image by means
+of IMAGE_BACKGROUND or MEDIAN_FILTER.
+
+EXTEND_ARRAY
+Pad 2D array with 0s.
+
+EXTEND_SHIFT
+Shift a 2D array without edge effects.
+
+EXTRACT_OVERLAP
+Extract the overlap region of two 2D arrays.
+
+EXTRACT_STARS
+STARFINDER auxiliary routine to handle internal data structure.
+
+FILE_NAME
+Return the complete name of a file in a directory
+whose path is among the IDL search paths.
+Operating system dependencies are taken into account.
+
+FIND_ROT_TRANS
+Find translation and rotation angle between two reference
+frames, given the coordinates of a set of points in the
+two reference frames.
+
+FITSTARS
+Multi-component PSF-fitting of one or more stellar images.
+
+FITTING_ERRORS
+Estimate formal errors on the solution of a linear
+algebraic system.
+
+FREQUENCY
+Compute a 1D vector of Fourier frequencies.
+
+FWHM
+Compute the FWHM of a peak in an image.
+
+GAUSS_NOISE_STD
+Compute standard deviation of normally distributed
+noise in an image.
+
+GAUSSIAN2D
+Compute bivariate gaussian function.
+
+GET_MAX
+Find coordinates of maximum intensity pixel in a
+2D array.
+
+GINV
+Compute the Moore-Penrose generalized inverse of a
+rectangular matrix.
+
+HALO_SMOOTH
+Smooth the halo of a stellar image by means of a
+variable box size median filtering technique.
+
+HISTO
+Compute histogram.
+
+HISTO_HWHM
+Compute the Half Width at Half Maximum of an histogram.
+
+IMAGE_BACKGROUND
+Compute the background emission in a given image.
+
+IMAGE_CORE
+Identify the component connected to a specified
+starting position and above a pre-fixed threshold
+in a 2D array.
+
+IMAGE_MODEL
+Create a synthetic image given by a sum of shifted
+scaled replicas of a given template.
+
+IMAGE_SHIFT
+Apply a fractional shift to an image by interpolation.
+
+INSTR_NOISE
+Evaluate overall standard deviation due to normally
+distributed noise sources in an image.
+
+LOG2
+Compute the base 2 logarithm of an integer number.
+
+LS_SYS
+Put a linear algebraic system into normal form.
+
+MATCH_COORD
+Given two sets of coordinates on a plane, representing
+the same points in reciprocally translated and rotated
+reference frames, map one of them onto the other.
+
+MAX_SEARCH
+Identify relative maxima in a 2D array, according to a
+specified set of options.
+
+MEDIAN_FILTER
+Extension of the IDL function MEDIAN: apply median
+smoothing to a 2D array, using a reduced box size at the
+array edge.
+
+MERGE_LIST
+STARFINDER auxiliary routine to handle internal data structure.
+
+MIN_NORM_INVERSION
+Compute the minimum norm solution of an algebraic system
+of linear equations.
+
+MM_PSF_SETUP
+Define auxiliary data of multi-Moffat parametric PSF model 
+used by "starfinder.pro".
+
+MMFIT
+Fit 2D data array with parametric model made of a sum of 
+Moffat functions.
+
+MOFFAT2D
+Define a 2-dim Moffat function.
+
+NEWTON_GAUSS
+Fit a set of data with a parametric model.
+
+PEAK_AREA
+Estimate the area of a peak in an image.
+
+PEAK_FWHM
+Compute the FWHM of a peak in an image.
+
+PEAK_WIDTH
+Estimate the width of a peak in an image.
+
+PHASE2D
+Compute the phase array for a 2D delta-function.
+
+PHOTON_NOISE
+Evaluate photon noise standard deviation in an image.
+
+PICK_REGION
+Given a partition of a planar domain, find the
+sub-region containing an assigned point.
+
+PLANE
+Compute a plane surface.
+
+PSF_EXTRACT
+Estimate the PSF in a stellar field image by combination
+of a stack of stars.
+
+RADIAL_DIST
+Compute a 2D array of radial distances from an origin.
+
+READ_FLOAT_DATA
+Read a Free Format file containing floating-point
+numbers, ordered by columns.
+
+RECIPROCAL_DISTANCE
+Compute the euclidean distance for each couple of
+points in a set of given points on a plane.
+
+RELATIVE_ERROR
+Compute the relative error between two variables.
+
+REMOVE_COINCIDENT
+Remove multiple occurences from a set of points on
+a plane.
+
+REPAIR_SATURATED
+Repair saturated stars in an stellar field image.
+
+REPLACE_PIX
+Replace known bad pixels in a 2D array by local median.
+
+RESAMPLE
+Resample a bivariate function defined on a rectangular
+domain by integrating it over square regions.
+
+REVERSE_CLASS
+STARFINDER auxiliary routine to handle internal data structure.
+
+ROT_TRANS
+Rotate and translate a set of points on a plane.
+
+SAMPLING_GRID
+Define a set of equally-spaced points along an axis.
+
+SCALE_LS_SYS
+Scale a linear system of normal equations to improve
+the eigenvalue ratio.
+
+SEARCH_OBJECTS
+Search meaningful maxima in a given image.
+
+SHIFTED_TEMPLATES
+Shift a template image by an integer multiple of a
+pre-fixed sub-pixel shift.
+
+SIMPSON_PIX_INTEGRAL
+Resample a bivariate function defined on a rectangular
+domain by integration over square regions with the
+Simpson rule.
+
+SIZE52
+Alias of IDL 5.2 intrinsic SIZE function for previous
+versions.
+
+SORT_LIST
+STARFINDER auxiliary routine to handle internal data structure.
+
+SPLINE_COEFF
+Compute the coefficients of the interpolating spline
+to a set of observations on a rectangular grid.
+
+SPLINE_INTERP
+Evaluate a spline function on a rectangular grid.
+
+STACK_COMBINE
+Combine frames in a 3D stack.
+
+STAR
+STARFINDER auxiliary routine to handle internal data structure.
+
+STAR_PARAM
+STARFINDER auxiliary routine to handle internal data structure.
+
+STARFINDER
+Stars detection, astrometry and photometry in a stellar field.
+
+STARLIST
+STARFINDER auxiliary routine to handle internal data structure.
+
+SUB_ARRAY
+Extract sub-array from a 2D array.
+
+SUB_ARRAYS
+Given a 2D array, extract a stack of sub-arrays
+centered at specified positions.
+
+SUBS_TO_COORD
+Convert vector of array subscripts to pixel coordinates.
+
+SUPERPOSE_STARS
+Compute stack median of a set of stars in an image.
+
+SVD_INV_MATRIX
+Compute the inverse of a rectangular matrix by Singular Value 
+Decomposition.
+
+SVPSF_EXTRACT
+Partition an image into a grid of sub-regions and extract 
+a local PSF estimate for each region.
+
+UPDATE_LIST
+STARFINDER auxiliary routine to handle internal data structure.
+
+WHERE_STARS
+STARFINDER auxiliary routine to handle internal data structure.
+
+XCOMPARE_LISTS
+Compare two lists of objects. Widget interface.
+
+XDISPFILE
+Read an ASCII file and display its content on a text widget.
+
+XDISPLAYOPT
+Modify the display options of an image. Widget interface.
+
+XIMAGE_SUPPORT
+Modify the support of an image. Widget interface.
+
+XMATCH_COORD
+Widget interface for the MATCH_COORD procedure.
+
+XNOISE
+Widget application to compute the noise standard
+deviation for each pixel in a given image.
+
+XNOISE_STDEV
+Widget interface for the GAUSS_NOISE_STD procedure.
+
+XPLOT
+Execute simple plots. Widget interface.
+
+XPSF_EXTRACT
+Widget interface for the PSF_EXTRACT procedure.
+
+XPSF_SMOOTH
+Widget interface for the HALO_SMOOTH function.
+
+XREPLACE_PIX
+Widget interface for the REPLACE_PIX function.
+
+XSTARFINDER
+Package for stellar fields analysis. Widget interface.
+
+XSTARFINDER_RUN
+Widget interface for the STARFINDER procedure.
diff --git a/log2.pro b/log2.pro
new file mode 100644
index 0000000000000000000000000000000000000000..a19af0e586a261adc647adbae7da5fba65c32f5b
--- /dev/null
+++ b/log2.pro
@@ -0,0 +1,33 @@
+; $Id: log2.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	LOG2
+;
+; PURPOSE:
+;	Compute the base 2 logarithm of an integer number.
+;
+; CATEGORY:
+;	Mathematics.
+;
+; CALLING SEQUENCE:
+;	Result = LOG2(N)
+;
+; INPUTS:
+;	N:	Integer number
+;
+; OUTPUTS:
+;	Result:	Base 2 logarithm of N
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION log2, n
+
+	on_error, 2
+	if  n/2 le 1  then  l = 1  else  l = 1 + log2(n/2)
+	return, l
+end
+
+
diff --git a/ls_sys.pro b/ls_sys.pro
new file mode 100644
index 0000000000000000000000000000000000000000..df6e5aa82798d0783a65a994dd935d5c704a94da
--- /dev/null
+++ b/ls_sys.pro
@@ -0,0 +1,65 @@
+; $Id: ls_sys.pro, v 1.1 Jan 2000 e.d. $
+;
+;+
+; NAME:
+;	LS_SYS
+;
+; PURPOSE:
+;	Put the algebraic system of linear equations
+;	Ax = b
+;	in the least squares form
+;	(A'A)x = A'b,
+;	where A' is the transpose of A.
+;
+; CATEGORY:
+;	Mathematics. Linear systems.
+;
+; CALLING SEQUENCE:
+;	LS_SYS, A, B, A_ls, B_ls
+;
+; INPUTS:
+;	A:	2D array of size n*m (i.e. n  columns and m rows), representing
+;		the linear system matrix
+;
+;	B:	1D array of size m, representing a set of measurements
+;
+; KEYWORD PARAMETERS:
+;	WEIGHTS:	1D array of size m, representing squared weights to be
+;		applied to the measurements vector B. In this case the least
+;		squares form of the input system is
+;		(A'WA)x = A'Wb,
+;		where W is the vector of squared weights
+;
+;	MASK:	1D array of valid subscripts, indicating the components of the
+;		mesurements array B which must be masked, i.e. excluded
+;
+; OUTPUTS:
+;	A_ls:	Same as  A'A  in PURPOSE above
+;
+;	B_ls:	Same as  A'b  in PURPOSE above
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;	Updates:
+;	1) Fixed bug on transposition of b, when it is a scalar
+;	   (Emiliano Diolaiti, January 2000)
+;-
+
+PRO ls_sys, a, b, WEIGHTS = w, MASK = pix, a_ls, b_ls
+
+	on_error, 2
+	s = size52(a, /DIM)  &  n_col = s[0]  &  n_rows = s[1]
+	a_ls = a
+	if  n_elements(w) eq n_rows  then $
+	   a_ls = diag_mult(a_ls, w, /PRE)
+	if  n_elements(pix) ne 0  then $
+	if  min(pix) ge 0 and max(pix) lt n_rows  then begin
+	   m = make_array(n_rows, VALUE = 1.)  &  m[pix] = 0
+	   a_ls = diag_mult(a_ls, m, /PRE)
+	endif
+	a_ls = transpose(a_ls)
+	if  n_col gt 1  then  b_ls = b # a_ls  else  b_ls = total(b * a_ls)
+	a_ls = a # a_ls  &  if  n_col gt 1  then  b_ls = transpose(b_ls)
+;	a_ls = a # a_ls  &  b_ls = transpose(b_ls)
+	return
+end
diff --git a/match_coord.pro b/match_coord.pro
new file mode 100644
index 0000000000000000000000000000000000000000..c621f8c16ff63db5a5fc82e504402ee4a5e5ed3c
--- /dev/null
+++ b/match_coord.pro
@@ -0,0 +1,115 @@
+; $Id: match_coord.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	MATCH_COORD
+;
+; PURPOSE:
+;	Given two sets of coordinates on a plane, representing the same points
+;	in two different reference frames supposed to be reciprocally translated
+;	and rotated, find the optimal transformation between the two sets and
+;	map one of them onto the other.
+;	The transformation between the two reference frames is defined by the
+;	position of the origin of frame 2 in frame 1 and the angle between the
+;	x- axes of frames 1 and 2, measured counter-clockwise from 1 to 2.
+;
+; CATEGORY:
+;	Mathematics. Spatial transformations.
+;
+; CALLING SEQUENCE:
+;	MATCH_COORD, X1, Y1, X2, Y2, X_ref, Y_ref, X2rt, Y2rt, Origin, Angle
+;
+; INPUTS:
+;	X1, Y1:	Coordinates of points in reference frame no. 1
+;
+;	X2, Y2:	Coordinates of points in reference frame no. 2
+;
+;	X_ref, Y_ref:	Coordinates of reference points, used to find the
+;		optimal transformation. X_ref, Y_ref may be a subset of X1, Y1
+;
+; KEYWORD PARAMETERS:
+;	ORIGIN_0:	2-components vector, representing a guess of the position
+;		of the origin of reference frame 2 in reference frame 1. The
+;		default is  ORIGIN_0 = [0., 0.]
+;
+;	ANGLE_0:	Scalar, guess of the angle (in radians) between the x- axis
+;		of reference frame 1 and the x- axis of reference frame 2, measured
+;		counter-clockwise from 1 to 2. The default is  ANGLE_0 = 0. rad
+;
+;	_EXTRA:	Optional input keywords of FIND_ROT_TRANS (see the file
+;		'find_rot_trans.pro')
+;
+; OUTPUTS:
+;	X2rt, Y2rt:	Coordinates (X2, Y2) mapped onto reference frame 1.
+;		These coordinates may be directly compared to (X1, Y1).
+;		A negative scalar value indicates an error condition
+;
+; OPTIONAL OUTPUTS:
+;	Origin:	2-components vector, representing the estimated position of
+;		the origin of reference frame 2 in reference frame 1
+;
+;	Angle:	Scalar, estimated angle (in radians) between the x- axis of
+;		reference frame 1 and the x- axis of reference frame 2, measured
+;		counter-clockwise from 1 to 2
+;
+; RESTRICTIONS:
+;	1) The procedure assumes the two reference frames are reciprocally rotated
+;	and translated. Other kinds of spatial transformation, e.g. those due to
+;	geometric distorsions, are not considered and should be negligible.
+;	2) The set (X_ref, Y_ref) of reference positions may be a subset of
+;	(X1, Y1), even though this is not necessary. What's essential is that,
+;	after applying an approximate inverse transformation to (X2, Y2) using
+;	the initial guesses ORIGIN_0 and ANGLE_0, it is possible to match each
+;	point in the reference set (X_ref, Y_ref) with one and only one point in
+;	both the sets (X1, Y1) and (X2, Y2). This occurs if
+;		a) the initial guesses ORIGIN_0 and ANGLE_0 are accurate enough
+;		b) the reference points are sufficiently isolated
+;
+; PROCEDURE:
+;	Apply an inverse transformation to (X2, Y2) using the initial guesses.
+;	Then match the reference points (X_ref, Y_ref) with their counterparts
+;	in the sets (X1, Y1) and (X2, Y2) by a minimum distance criterion.
+;	Use these subsets of (X1, Y1) and (X2, Y2) to find the transformation
+;	between the reference frames 1 and 2 and then apply it to (X2, Y2), in
+;	order to map this set of coordinates onto the reference frame of (X1, Y1).
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+PRO match_coord, x1, y1, x2, y2, x_ref, y_ref, x2rt, y2rt, origin, angle, $
+				 ORIGIN_0 = origin_0, ANGLE_0 = angle_0, _EXTRA = extra
+
+	on_error, 2
+	; default values of reciprocal shift and rotation
+	if  n_elements(origin_0) eq 0  then  origin_0 = [0., 0.]
+	if  n_elements(angle_0) eq 0  then  angle_0 = 0.
+	; approximate inverse transformation of (x2,y2) using origin_0 and angle_0
+	rot_trans, x2 + origin_0[0], y2 + origin_0[1], [0., 0.], -angle_0, $
+			   x2_temp, y2_temp
+	; match reference positions with both the sets of coordinates
+	n_ref = n_elements(x_ref)
+	x1_ref = fltarr(n_ref)  &  y1_ref = x1_ref
+	x2_ref = fltarr(n_ref)  &  y2_ref = x2_ref
+	for  n = 0L, n_ref - 1  do begin
+	   m = min(distance(x_ref[n], y_ref[n], x1, y1), w)
+	   x1_ref[n] = x1[w]  &  y1_ref[n] = y1[w]
+	   m = min(distance(x_ref[n], y_ref[n], x2_temp, y2_temp), w)
+	   x2_ref[n] = x2_temp[w]  &  y2_ref[n] = y2_temp[w]
+	endfor
+	; check if the couples of reference coordinates are all distinct
+	x2rt = -1  &  y2rt = -1	; set error condition
+	remove_coincident, x1_ref, y1_ref, x1_ref, y1_ref
+	remove_coincident, x2_ref, y2_ref, x2_ref, y2_ref
+	if  n_elements(x1_ref) eq n_ref and n_elements(x2_ref) eq n_ref  then begin
+	   ; direct transformation of (x2_ref, y2_ref) with origin_0 and angle_0
+	   rot_trans, x2_ref, y2_ref, origin_0, angle_0, x2_temp, y2_temp
+	   ; estimate optimal translation and rotation
+	   find_rot_trans, x1_ref, y1_ref, x2_temp, y2_temp, origin_0, angle_0, $
+					   origin, angle, found, _EXTRA = extra
+	   ; apply optimal inverse transformation to original set (x2, y2)
+	   if  found  then $
+	      rot_trans, x2 + origin[0], y2 + origin[1], [0, 0], -angle, x2rt, y2rt
+	endif
+	return
+end
diff --git a/max_search.pro b/max_search.pro
new file mode 100644
index 0000000000000000000000000000000000000000..181dc1d5d2b5e7bb9fdae19d19a6e9e5e02caf1f
--- /dev/null
+++ b/max_search.pro
@@ -0,0 +1,120 @@
+; $Id: max_search.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	MAX_SEARCH
+;
+; PURPOSE:
+;	Given a 2D array, search for relative maxima above a fixed threshold
+;	and fulfilling a set of optional conditions.
+;	A given pixel is considered a relative maximum if it is brighter
+;	than its 8-neighbors or 4-neighbors.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	MAX_SEARCH, Array, Threshold, N, X, Y, I
+;
+; INPUTS:
+;	Array:	2D array to be searched
+;
+;	Threshold:	lower detection threshold; it may be either a scalar or
+;		a 2D array, with the same size as Array
+;
+; KEYWORD PARAMETERS:
+;	X0, Y0:	Coordinates of reference pixel, representing an origin to
+;		compute distances of detected maxima.
+;
+;	CHECK_DIST:	Set this keyword to a scalar value representing the maximum
+;		allowed distance of an acceptable local max. from the reference
+;		pixel defined by X0 and Y0. This keyword has no effect if X0 and Y0
+;		are undefined.
+;
+;	NEAREST:	Set this keyword to select the maximum lying next to the
+;		reference position defined by X0 and Y0. If there are more than
+;		one maximum at the same distance, return all. This keyword has no
+;		effect if X0 and Y0 are undefined.
+;
+;	MAXIMUM:	Set this keyword to select the brightest maximum
+;		in the input array. If there are more than one maximum with the
+;		same value, return all.
+;
+;	FOUR:	Set this keyword to identify relative maxima as pixels
+;		brighter than their 4-neighbors. The default is to use
+;		8-neighbors.
+;
+;	SORTED:	Set this keyword to have the output maxima sorted by
+;		decreasing intensity
+;
+; OUTPUTS:
+;	N:	Number of detected maxima
+;
+;	X, Y:	Long integer coordinates of detected maxima. If no maximum is
+;		found, X and Y are set to negative scalars
+;
+;	I:	Intensities of detected maxima. The type of I is the same as that of
+;		Array. If no maximum is found, I is set to a negative scalar
+;
+; RESTRICTIONS:
+;	The optional conditions specified by the keywords CHECK_DIST, NEAREST,
+;	MAXIMUM are checked in the same order they have been presented.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+PRO max_search, array, threshold, X0 = x0, Y0 = y0, CHECK_DIST = max_dist, $
+   				NEAREST = nearest, MAXIMUM = maximum, _EXTRA = extra, $
+   				SORTED = sorted, n, x, y, i
+
+	on_error, 2
+	; define search options
+	check_dist = n_elements(max_dist) ne 0 and $
+				 n_elements(x0) ne 0 and n_elements(y0) ne 0
+	select_nearest = keyword_set(nearest) and $
+					 n_elements(x0) ne 0 and n_elements(y0) ne 0
+	select_maximum = keyword_set(maximum)
+	; find local maxima
+	all_max, array, x, y, n, _EXTRA = extra
+	found = n ne 0
+	if  found  then  i = array[x,y]
+	; select detected maxima according to options
+	if  found  then begin
+	   if  check_dist or select_nearest then begin
+	      d = distance(x0, y0, x, y)
+	      if  check_dist  then begin
+	         w = where(d le max_dist, n)  &  found = n ne 0
+	         if  found  then begin
+	            d = d[w]  &  x = x[w]  &  y = y[w]  &  i = i[w]
+	         endif
+	      endif
+	      if  found and select_nearest  then begin
+	         w = where(d le min(d), n)  &  found = n ne 0
+	         if  found  then begin
+	            d = d[w]  &  x = x[w]  &  y = y[w]  &  i = i[w]
+	         endif
+	      endif
+	   endif
+	   if  found and select_maximum  then begin
+	      w = where(i ge max(i))
+	      x = x[w]  &  y = y[w]  &  i = i[w]
+	   endif
+	endif
+	if  found  then begin
+	   n = n_elements(i)
+	   if  size52(threshold, /N_DIM) eq 2  then $
+	      w = where(i gt threshold[x,y], n)  else $
+	      w = where(i gt threshold[0], n)
+	   if  n ne 0  then begin
+	      x = x[w]  &  y = y[w]  &  i = i[w]
+	   endif
+	endif
+	if  n eq 0  then begin
+	   x = -1  &  y = -1  &  i = -1
+	endif else $
+	   if  keyword_set(sorted)  then begin
+	      s = reverse(sort(i))  &  x = x[s]  &  y = y[s]  &  i = i[s]
+	   endif
+	return
+end
diff --git a/median_filter.pro b/median_filter.pro
new file mode 100644
index 0000000000000000000000000000000000000000..634c8cf684302f00368d47db88a50866ff02f89b
--- /dev/null
+++ b/median_filter.pro
@@ -0,0 +1,63 @@
+; $Id: median_filter.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	MEDIAN_FILTER
+;
+; PURPOSE:
+;	Apply median smoothing to a 2D array, using the intrinsic function
+;	MEDIAN. In the inner portion of the array, the result is the same as
+;	that of MEDIAN. At the array edge, perform a median smoothing with
+;	reduced box size.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = MEDIAN_FILTER(Array, Box)
+;
+; INPUTS:
+;	Array:	2D array to smooth
+;
+;	Box:	Box size for smoothing
+;
+; KEYWORD PARAMETERS:
+;	EVEN:	If the EVEN keyword is set when Array contains an even number
+;		of points (i.e. there is no middle number), MEDIAN returns the
+;		average of the two middle numbers.
+;
+; OUTPUTS:
+;	Result:	2D median smoothed array.
+;		Return the input array if an error occurs.
+;
+; RESTRICTIONS:
+;	Apply only to 2D arrays.
+;
+; PROCEDURE:
+;	Apply MEDIAN on the inner part of the array. At the edge perform
+;	smoothing on an asymmetric box of reduced size.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION median_filter, array, box, _EXTRA = extra
+
+	catch, error
+	if  error ne 0  then  return, array
+	s = size52(array, /DIM)  &  sx = s[0]  &  sy = s[1]
+	b = round(box) > 1
+	j = lindgen(sx)  &  i = lindgen(sy)  &  w = b / 2
+	lo_j = (j - w) > 0  &  up_j = (j + w) < (sx - 1)
+	lo_i = (i - w) > 0  &  up_i = (i + w) < (sy - 1)
+	filtered = median(array, 2*w + 1, _EXTRA = extra)
+	for  i = 0, w - 1  do  for  j = 0, sx - 1  do $
+	   filtered[j,i] = median(array[ lo_j[j]:up_j[j],lo_i[i]:up_i[i] ], _EXTRA = extra)
+	for  i = sy - w, sy - 1  do  for  j = 0, sx - 1  do $
+	   filtered[j,i] = median(array[ lo_j[j]:up_j[j],lo_i[i]:up_i[i] ], _EXTRA = extra)
+	for  i = w, sy - w - 1  do  for  j = 0, w - 1  do $
+	   filtered[j,i] = median(array[ lo_j[j]:up_j[j],lo_i[i]:up_i[i] ], _EXTRA = extra)
+	for  i = w, sy - w - 1  do  for  j = sx - w, sx - 1  do $
+	   filtered[j,i] = median(array[ lo_j[j]:up_j[j],lo_i[i]:up_i[i] ], _EXTRA = extra)
+	return, filtered
+end
diff --git a/merge_list.pro b/merge_list.pro
new file mode 100644
index 0000000000000000000000000000000000000000..313806387cfedd0f65f30144e7010b9db0df7633
--- /dev/null
+++ b/merge_list.pro
@@ -0,0 +1,43 @@
+; $Id: merge_list.pro, v 1.1 Mar 2001 e.d. $
+;
+;+
+; NAME:
+;	MERGE_LIST
+;
+; PURPOSE:
+;	Merge two lists of stars.
+;
+; CATEGORY:
+;	STARFINDER auxiliary procedures.
+;
+; CALLING SEQUENCE:
+;	Result = MERGE_LIST(L1, L2)
+;
+; INPUTS:
+;	L1, L2:	lists to merge. If L1 is empty, return L2.
+;
+; OUTPUTS:
+;	Return merged list
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, June 2001.
+; 	1) Created this file (E. D., March 2012).
+; 	2) Fixed bug when input list L1 is empty (E. D., April 2012).
+;-
+
+FUNCTION merge_list, l1, l2
+
+    on_error, 2
+    if n_tags(l1) eq 0 then $
+       l = l2 else $
+    begin
+       n1 = n_elements(l1)
+;       if  n1 eq 0  then  l = l2  else $
+;       begin
+       n2 = n_elements(l2)
+       l = starlist(n1 + n2)
+       l[0] = l1  &  l[n1] = l2
+;       endelse
+    endelse
+    return, l
+end
diff --git a/min_norm_inversion.pro b/min_norm_inversion.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1f00d0c6ba788f1677f1981b29f509ca289fbf16
--- /dev/null
+++ b/min_norm_inversion.pro
@@ -0,0 +1,69 @@
+; $Id: min_norm_inversion.pro, v 1.2 Mar 2012 e.d. $
+;
+;+
+; NAME:
+;	MIN_NORM_INVERSION
+;
+; PURPOSE:
+;	Compute the minimum norm solution of an algebraic system
+;	of linear equations
+;
+; CATEGORY:
+;	Mathematics. Linear systems.
+;
+; CALLING SEQUENCE:
+;	Result = MIN_NORM_INVERSION(A, B)
+;
+; INPUTS:
+;	A:	matrix of linear system (n columns, m rows)
+;
+;	B:	vector of measurements (m rows)
+;
+; KEYWORD PARAMETERS:
+;	SCALING:	If the linear system has been previously scaled (see the
+;		routine SCALE_LS_SYS in the file 'scale_ls_sys.pro'), the solution
+;		must be multiplied by the scaling factors. Set the keyword SCALING
+;		to the vector of scaling factors to do this
+;		
+; SVDINV:   Set this keyword parameter to invert the matrix A by 
+;   singular value decomposition.
+;
+; OUTPUTS:
+;	Return n-components vector, representing the minimum norm solution
+;	of the linear system, defined as A'b, where A' is the generalized
+;	inverse of A computed by GINV (see the file 'ginv.pro') or by SVD 
+;	(see the file 'svd_inv_matrix.pro').
+;	If the first input A has just one element (i.e. A represents a scalar),
+;	just divide B by A.
+;
+; OPTIONAL OUTPUTS:
+;	INVERSE:	Use this output keyword to retrieve the generalized inverse
+;		of the input matrix A
+;
+; RESTRICTIONS:
+;	If an error occur (A is a scalar equal to 0 or the size of the input
+;	arrays are not correct), return to caller
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;	Updates:
+;	1) Fixed bug on output keyword INVERSE when A is a scalar
+;	   (Emiliano Diolaiti, August 2000).
+;	2) Added SVD inversion option (E. D., March 2012).
+;-
+
+FUNCTION min_norm_inversion, a, b, SCALING = scaling, $
+                             SVDINV = svdinv, INVERSE = inv_a
+
+	on_error, 2
+	if  n_elements(a) eq 1  then begin
+	   inv_a = 1. / a   &  x = b * inv_a
+	endif else begin
+	   if keyword_set(svdinv) then $
+	      inv_a = svd_inv_matrix(a) else $
+	      inv_a = ginv(a)
+	   x = b # inv_a
+	endelse
+	if  n_elements(scaling) eq n_elements(x)  then  x = x * scaling
+	return, x
+end
diff --git a/mm_psf_setup.pro b/mm_psf_setup.pro
new file mode 100644
index 0000000000000000000000000000000000000000..4abc0f82dab51b7a5daa9a11324af31791ea9ad6
--- /dev/null
+++ b/mm_psf_setup.pro
@@ -0,0 +1,155 @@
+; $Id: mm_psf_setup.pro, v 1.0 March 2012 e.d. $
+;
+;+
+; NAME:
+; MM_PSF_SETUP
+;
+; PURPOSE:
+; Define auxiliary PSF data to be used by main routine of "starfinder.pro" 
+; when a parametric space-variant PSF model called is adopted.
+; The PSF model defined here is based on a sum of Moffat functions. 
+; The relative weight, width and position angle of the Moffat components are 
+; assumed to change across the image which the PSF model refers to. 
+; The variation model makes the following assumptions:
+; - all elongated Moffat components point to the same reference position 
+;   in the image
+; - relative weight and width of Moffat components change across the image 
+;   according to a polynomial law depending on the distance of the considered 
+;   location in the image from the reference position.
+; 
+; CATEGORY:
+; Stellar fields astrometry and photometry.
+;
+; CALLING SEQUENCE:
+; MM_PSF_SETUP, C, Pow, Xref, Yref, Xsize_ima, Ysize_ima, Nx, Ny, $
+;               Xsize_psf, Ysize_psf, Xsize_svpsf, Ysize_svpsf, $
+;               Psf_data, Psf, Sv_par
+;               
+; INPUTS:
+; C: 2-dim or 3-dim floating-point array of coefficients defining the multi-Moffat PSF 
+;    model and its variation across the image. The variation of each parameter is 
+;    assumed to be described by a polynomial function of the distance of the PSF 
+;    location in the image from the reference position.
+;    The array C is defined as follows:
+;    C[i,j,k], 0 <= i <= maxdeg+2, 0 <= j <= Nparcomp-1, 0 <= k <= Ncomp-1, where
+;    - Ncomp: number of Moffat functions in the PSF model
+;    - Nparcomp: number of parameters per Moffat component (3)
+;    - maxdeg: maximum degree among polynomials defining parameters variations across the image
+;    It is assumed that each Moffat function is defined by 3 parameters:
+;    - relative weight (scale factor)
+;    - half-light radius along elongated axis
+;    - half-light radius along axis perpendicular to elongation
+;    The elongation axis is defined as the line connecting the PSF position in the image
+;    and the reference position.
+;    The element C[0,j,k] is the degree of the polynomial associated to parameter j 
+;    of Moffat function k.
+;    The elements C[i,j,k] with 1 <= i <= C[0,j,k]+1 are the coefficients of the 
+;    polynomial associated to parameter j of Moffat function k.
+; 
+; Pow: scalar or floating-point array with power law of Moffat functions. If scalar, 
+;    the same power law is assumed for all components. If array, the number of elements 
+;    must be the same as the number of components.
+;
+; Xref, Yref: pixel coordinates of reference position in the image.
+; 
+; Xsize_ima, Ysize_ima: integers, number of columns and rows of image array.
+; 
+; Nx, Ny: number of regions along X and Y axes of image to determine cube of
+;   piecewise constant PSFs.
+; 
+; Xsize_psf, Ysize_psf: integers, number of columns and rows of PSF array to be 
+;   computed at any desired location in the image according to the continuous 
+;   variation model.
+; 
+; Xsize_svpsf, Ysize_svpsf: integers, number of columns and rows of PSF arrays 
+;   in the cube of piecewise constant PSFs (see Nx, Ny above).
+; 
+; OUTPUTS:
+; Psf_data: pointer to structure of PSF model parameters used to compute the PSF 
+;    at any position in the image.
+; 
+; Psf: floating-point array of piece-wise constant PSFs; cube of size 
+;    Xsize_svpsf * Ysize_svpsf * (Nx*Ny).
+; 
+; Sv_par: structure defining the boundaries of the Nx*Ny sub-regions into which the 
+;    image is virtually partitioned and over which the piece-wise constant PSFs are 
+;    defined.
+;
+; EXAMPLE:
+; 1) Define PSF model based on 2 Moffat components with following parameters:
+; 
+; 
+; IDL> c=[[[0,0.5,0,0],[2,1.0,1e-3,1e-4],[1,1.0,1e-3,0.0]],$
+;         [[0,0.5,0,0],[0,4.0,0,0],[0,4.0,0,0]]]
+; IDL> help,c
+; C               FLOAT     = Array[4, 3, 2]
+; IDL> pow=[1.5,2.0]
+; IDL> xref=128.0 & yref=128.0
+; IDL> xsize_ima=256
+; IDL> ysize_ima=256
+; IDL> nx=4
+; IDL> ny=4
+; IDL> xsize_psf=64
+; IDL> ysize_psf=64
+; IDL> xsize_svpsf=32
+; IDL> ysize_svpsf=32
+; IDL> mm_psf_setup, c, pow, xref, yref, xsize_ima, ysize_ima, nx, ny, $
+;                    xsize_psf, ysize_psf, xsize_svpsf, ysize_svpsf, psf_data, psf, sv_par 
+; IDL> help,*psf_data,/STRUCTURE
+; ** Structure <1374398>, 10 tags, length=132, data length=130, refs=1:
+;    XREF            FLOAT           128.000
+;    YREF            FLOAT           128.000
+;    XORI            FLOAT          0.000000
+;    YORI            FLOAT          0.000000
+;    C               FLOAT     Array[4, 3, 2]
+;    POW             FLOAT     Array[2]
+;    NCOMP           LONG                 2
+;    NPARCOMP        INT              3
+;    X_SIZE          INT             64
+;    Y_SIZE          INT             64
+; IDL> help,psf
+; PSF             FLOAT     = Array[32, 32, 16];
+; IDL> help,sv_par,/STRUCTURE
+; ** Structure <181f8a0>, 4 tags, length=64, data length=64, refs=1:
+;    LX              LONG      Array[4]
+;    UX              LONG      Array[4]
+;    LY              LONG      Array[4]
+;    UY              LONG      Array[4]
+;
+; MODIFICATION HISTORY:
+;   Written by: Emiliano Diolaiti, March 2012.
+;-
+
+PRO mm_psf_setup, c, pow, xref, yref, xsize_ima, ysize_ima, nx, ny, $
+                  xsize_psf, ysize_psf, xsize_svpsf, ysize_svpsf, $
+                  psf_data, psf, sv_par
+
+catch, error
+if error ne 0 then begin
+   if  ptr_valid(psf_data) then ptr_free, psf_data
+   return
+endif
+
+if size(c, /N_DIM) gt 2 then ncomp = (size(c, /DIM))[2] else ncomp = 1
+if n_elements(pow) eq ncomp then k = pow else k = replicate(pow[0], ncomp)
+nparcomp = 3 ; number of parameters per component
+psf_data = {xref: float(xref), yref: float(yref), xori: 0.0, yori: 0.0, $
+            c: c, pow: k, ncomp: ncomp, nparcomp: nparcomp, $
+            x_size: xsize_psf, y_size: ysize_psf}
+psf_data = ptr_new(psf_data)
+
+array_partition, xsize_ima, nx, lx, ux, /OVERLAP
+array_partition, ysize_ima, ny, ly, uy, /OVERLAP
+sv_par = {lx: lx, ux: ux, ly: ly, uy: uy}
+psf = fltarr(xsize_svpsf, ysize_svpsf, nx*ny)
+for j = 0L, nx-1 do for i = 0L, ny-1 do begin
+   (*psf_data).xori = (lx[j] + ux[j]) / 2 - xsize_svpsf/2
+   (*psf_data).yori = (ly[i] + uy[i]) / 2 - ysize_svpsf/2
+   psf[*,*,i*nx+j] = $
+   image_model(xsize_svpsf/2, ysize_svpsf/2, 1.0, xsize_svpsf, ysize_svpsf, "mm_psf", psf_data)
+endfor
+(*psf_data).xori = 0.0
+(*psf_data).yori = 0.0
+
+return
+end
diff --git a/mmfit.pro b/mmfit.pro
new file mode 100644
index 0000000000000000000000000000000000000000..6246445043fd4f94f4fa055d9c79057feb8cceaf
--- /dev/null
+++ b/mmfit.pro
@@ -0,0 +1,328 @@
+; $Id: mmfit.pro, v 1.0 March 2012 e.d. $
+;
+;+
+; NAME:
+;   MMFIT
+;
+; PURPOSE:
+;   Fit a 2D data array defined over a regular (X,Y) grid with a parametric 
+;   model given by the sum of 2D Moffat functions. The Moffat functions have 
+;   all the same position angle with respect to the X axis and have all the 
+;   same center. One of the Moffat functions (typically the wider one) may 
+;   have round simmetry. The fit is carried out by the iterative 
+;   Newton-Gauss method.
+;   
+; CATEGORY:
+;   Fitting.
+;   
+; CALLING SEQUENCE:
+;   MMFIT, Image, Ncomp, P, Sigma_p, Model, Converged
+;
+; INPUTS:
+;   Image:  2D floating-point array with data to be fitted (e.g. Point 
+;     Spread Function of an optical system).
+;   
+;   Ncomp:  Integer, number of Moffat components.
+;
+; KEYWORD PARAMETERS:
+;   NOISE:  Scalar or 2D array with the same size as Image with an estimate 
+;     of the 1-sigma uncertainties on the data. This keyword parameter is 
+;     used to perform a weighted least-squares fit to the data. If missing, 
+;     the fit is unweighted.
+;   
+;   P0: Floating point vector of optional initial values of model parameters. 
+;     For Ncomp components the vector has the following structure:
+;     P0 = [f_1, r_1_1, r_1_2, ...., f_Ncomp, r_1_Ncomp, r_2_Ncomp, $
+;           x0, y0, phi, b, bx, by]
+;     where
+;     f_n: scale factor of the n-th component (n = 1, ..., Ncomp)
+;     r_1_n, r_2_n: radius along major and minor axes of n-th component
+;     x0, y0: coordinates in pixel units of the center of the model
+;     phi: angle of major axis of Moffat components with respect to X axis; 
+;       it is measured counter-clockwise in radians
+;     b, bx, by: background terms (constant, X-gradient, Y-gradient).
+;   
+;   PVAR: Integer vector with the same length as P0 defined as follows:
+;     PVAR[n] = 1, if n-th parameter has to be optimized
+;     PVAR[n] = 0, if n-th parameter has to be kept fixed to its initial value
+;     By default, all parameters are optimized with the following exceptions:
+;     * background parameters (see b, bx, by under P0 above)
+;     * position angle phi (see P0 above) when only one component is used 
+;       and it is round
+;   
+;   POWER:  Vector of Ncomp elements describing the power law of each 
+;     Moffat component (see procedure 'moffat2d.pro' for details). 
+;     If undefined, it is assumed that all components follow the same 
+;     power 1.5.
+;   
+;   LMROUND:  Set this binary keyword to consider the last component in 
+;     the model round. By default all Moffat functions are elongated.
+;     
+;   MAXIT:  Maximum number of iterations allowed. The default is 30.
+;   
+;   TOL:  Floating-point tolerance used as convergence criterion in 
+;     iterative fitting process. The tolerance is absolute for all the 
+;     parameters, with the exception of the scaling factors of the Moffat 
+;     components (see parameters f_n under P0 above) for which it is 
+;     relative. Default TOL = 1e-2. 
+;   
+; OUTPUTS:
+;   P: Floating-point vector of best fit model parameters. Same length and 
+;     structure as P0. If fit does not converge, the output value of P is 
+;     set to the initial estimates P0.
+;   
+;   Sigma_p:  Vector with estimates of errors on model parameters P. 
+;     Available only if keyword NOISE is set.
+;      
+;   Model: 2D array with the best fit model. Same size as input Image.
+;     The model is a sum of scaled Moffat functions, as defined by the procedure 
+;     'moffat2d.pro' (NOTE: without /NORMAL keyword).
+;   
+;   Converged:  Byte. True if the fit has converged.
+;
+; RESTRICTIONS:
+;
+; PROCEDURE:
+;   Find initial estimate of model parameters (if not given on input) and 
+;   refine this estimate by the iterative Newton-Gauss method (see 
+;   'newton_gauss.pro').
+;   
+; MODIFICATION HISTORY:
+;   Written by:  Emiliano Diolaiti, March 2012.
+;-
+
+
+
+;;; Auxiliary procedures/functions.
+
+FUNCTION mmfit_model, p, DATA = data
+
+    on_error, 2
+    if (*data).lmround then begin
+       k = ((*data).ncomp - 1) * (*data).npc
+       p[k + 2] = p[k + 1]
+    endif
+    npar = n_elements(p)
+    k = (*data).ncomp * (*data).npc
+    x0 = p[k]
+    y0 = p[k + 1]
+    phi = p[k + 2]
+    (*data).model = fltarr((*data).siz[0], (*data).siz[1])
+    for  n = 0, (*data).ncomp - 1  do begin
+       k = (*data).npc * n
+       (*data).mof[*,*,n] = moffat2d((*data).siz[0], (*data).siz[1], x0, y0, $
+                            p[k + 1], p[k + 2], phi, POWER = (*data).pow[n])
+       (*data).model = (*data).model + p[k] * (*data).mof[*,*,n]
+    endfor
+    k = (*data).ncomp * (*data).npc + 3
+    (*data).model = (*data).model + p[k] + $
+                    plane(0.0, p[k + 1], p[k + 2], (*data).siz[0], (*data).siz[1])
+    return, (*data).model
+end
+
+FUNCTION mmfit_iacobi, p, PVAR = pvar, DATA = data
+
+    on_error, 2
+    if (*data).lmround then begin
+       k = ((*data).ncomp - 1) * (*data).npc
+       p[k + 2] = p[k + 1]
+    endif
+    npix = (*data).siz[0] * (*data).siz[1]
+    npar = total(pvar)
+    k = (*data).ncomp * (*data).npc
+    x0 = p[k]
+    y0 = p[k + 1]
+    phi = p[k + 2]
+    x = rebin(findgen((*data).siz[0]) - x0, (*data).siz[0], (*data).siz[1])
+    y = rebin(transpose(findgen((*data).siz[1])) - y0, (*data).siz[0], (*data).siz[1])
+    rot_trans, x, y, [0, 0], phi, xr, yr
+
+    iacobi = fltarr(npix, npar)
+    dmdx0 = fltarr((*data).siz[0], (*data).siz[1])
+    dmdy0 = fltarr((*data).siz[0], (*data).siz[1])
+    dmdphi = fltarr((*data).siz[0], (*data).siz[1])
+    k = -1
+    j = 0
+    for  n = 0, (*data).ncomp - 1  do begin
+       k = k + 1
+       norm = p[k]
+       deriv = (*data).mof[*,*,n]
+       if pvar[k] eq 1 then begin
+          iacobi[*, j] = reform(deriv, npix)
+          j = j + 1
+       endif
+       k = k + 1
+       rx = p[k]
+       ry = p[k + 1]
+       rone = 1 + (xr / rx)^2 + (yr / ry)^2
+       deriv = 2 * (*data).pow[n] * norm * rone^(-(*data).pow[n] - 1.0) * xr^2 / rx^3
+       if pvar[k] eq 1 then begin
+          iacobi[*, j] = reform(deriv, npix)
+          if n lt (*data).ncomp - 1 or not (*data).lmround then j = j + 1
+       endif
+       k = k + 1
+       ;ry = p[k]
+       deriv = 2 * (*data).pow[n] * norm * rone^(-(*data).pow[n] - 1.0) * yr^2 / ry^3
+       if pvar[k] eq 1 then begin
+          iacobi[*, j] = reform(deriv, npix)
+          j = j + 1
+       endif else $
+       if n eq (*data).ncomp - 1 and (*data).lmround then begin
+          iacobi[*, j] = iacobi[*, j] + reform(deriv, npix)
+          j = j + 1
+       endif
+       dmdx0 = temporary(dmdx0) + 2 * (*data).pow[n] * norm * $
+               rone^(-(*data).pow[n] - 1.0) * (xr*cos(phi)/rx^2-yr*sin(phi)/ry^2)
+       dmdy0 = temporary(dmdy0) + 2 * (*data).pow[n] * norm * $
+               rone^(-(*data).pow[n] - 1.0) * (xr*sin(phi)/rx^2+yr*cos(phi)/ry^2)
+       dmdphi = temporary(dmdphi) + 2 * (*data).pow[n] * norm * $
+                rone^(-(*data).pow[n] - 1.0) * xr * yr * (1/ry^2 - 1/rx^2)
+    endfor
+    k = k + 1
+    if pvar[k] eq 1 then begin
+       iacobi[*, j] = reform(dmdx0, npix)
+       j = j + 1
+    endif
+    k = k + 1
+    if pvar[k] eq 1 then begin
+       iacobi[*, j] = reform(dmdy0, npix)
+       j = j + 1
+    endif
+    k = k + 1
+    if pvar[k] eq 1 then begin
+       iacobi[*, j] = reform(dmdphi, npix)
+       j = j + 1
+    endif
+    k = k + 1
+    if pvar[k] eq 1 then begin
+       iacobi[*, j] = 1.0
+       j = j + 1
+    endif
+    k = k + 1
+    if pvar[k] eq 1 then begin
+       iacobi[*, j] = reform(plane(0, 1, 0, (*data).siz[0], (*data).siz[1]), npix)
+       j = j + 1
+    endif
+    k = k + 1
+    if pvar[k] eq 1 then begin
+       iacobi[*, j] = reform(plane(0, 0, 1, (*data).siz[0], (*data).siz[1]), npix)
+       j = j + 1
+    endif
+
+    return, transpose(iacobi)
+end
+
+FUNCTION mmfit_converg, p0, p1, DATA = data
+
+    on_error, 2
+    if (*data).lmround then begin
+       k = ((*data).ncomp - 1) * (*data).npc
+       p0[k + 2] = p0[k + 1]
+       p1[k + 2] = p1[k + 1]
+    endif
+    ;print, p0
+    type_p = (*data).type_p
+    wr = where(type_p, nr)
+    wa = where(not type_p, na)
+    test = 1B
+    if nr ne 0 then test = test and convergence(p0[wr], p1[wr], (*data).tol)
+    if na ne 0 then test = test and convergence(p0[wa], p1[wa], (*data).tol, /ABSOLUTE)
+    return, test
+end
+
+
+
+;;; The main routine.
+
+PRO mmfit, image, NOISE = noise, ncomp, P0 = p0_in, PVAR = pvar_in, $
+           POWER = power, LMROUND = lmround, TOL = tol, _EXTRA = extra, $
+           p, sigma_p, model, converged
+
+    catch, error
+    if  error ne 0  then begin
+       ;msg = dialog_message(/ERROR, !err_string)
+       converged = 0B
+       heap_gc
+       return
+    endif
+    ; Setup
+    if  n_elements(tol) eq 0  then  tol = 1e-2
+    siz = size(image, /DIM)
+    if  n_elements(noise) ne 0  then begin
+       var = noise
+       w = where(var gt 0)
+       var[w] = 1 / (var[w])^2
+    endif
+    npc = 3
+    ; Parameter guess
+    if n_elements(p0_in) eq 0 then begin
+       peak = max(image)
+       rc = fwhm(image) / 2
+       m = get_max(image)  &  x0 = m[0]  &  y0 = m[1]
+       npar = npc * ncomp
+       p0 = fltarr(npar)
+       for  n = 0, ncomp - 1  do begin
+          k = npc * n
+          p0[k] = peak / (n + 1)
+          p0[k + 1] = rc * (n + 1)
+          p0[k + 2] = rc * (n + 1)
+       endfor
+       p0 = [p0, x0, y0, 0.0, replicate(0.0, 3)]
+    endif else $
+       p0 = p0_in
+    npar = n_elements(p0)
+    type_p = bytarr(npar)
+    k = lindgen(ncomp) * npc
+    type_p[k] = 1B
+    if n_elements(pvar_in) eq 0 then $
+       pvar = [replicate(1, npar-3), 0, 0, 0] else $
+       pvar = pvar_in
+    k = (ncomp - 1) * npc
+    if keyword_set(lmround) then begin
+       pvar[k + 2] = 0
+       if ncomp eq 1 then pvar[k + 5] = 0
+    endif
+    ; Power law of Moffat functions
+    if n_elements(power) eq 0 then $
+       pow = replicate(1.5, ncomp) else pow = power
+    
+    ; Iterative optimization
+    data = {ncomp: ncomp, siz: siz, $
+            model: fltarr(siz[0], siz[1]), tol: tol, type_p: type_p, $
+            npc: npc, mof: fltarr(siz[0], siz[1], ncomp), $
+            pow: pow, lmround: keyword_set(lmround) and 1B}
+    data = ptr_new(data, /NO_COPY)
+    newton_gauss, "mmfit_model", "mmfit_iacobi", "mmfit_converg", $
+                  p0, PVAR = pvar, image, converged, p, sigma_p, model, $
+                  DATA = data, _EXTRA = extra, INVERSE_DATA_VAR = var
+    if  not converged  then begin
+       p = p0
+       model = fltarr(siz[0], siz[1])
+    endif
+    if n_elements(sigma_p) ne 0 then begin
+       sigma_p[where(pvar eq 0)] = 0.0
+       if keyword_set(lmround) then sigma_p[k + 2] = sigma_p[k + 1]
+    endif
+    u = lindgen(ncomp) * npc + 1
+    v = lindgen(ncomp) * npc + 2
+    p[u] = abs(p[u])
+    p[v] = abs(p[v])
+    k = npc * ncomp + 2
+    if pvar[k] eq 1 then begin
+       if abs(p[1]) lt abs(p[2]) then begin
+          temp = p[u]
+          p[u] = p[v]
+          p[v] = temp
+          p[k] = (p[k] + !pi/2) mod !pi
+          if n_elements(sigma_p) ne 0 then begin
+             temp = sigma_p[u]
+             sigma_p[u] = sigma_p[v]
+             sigma_p[v] = temp
+          endif
+       endif
+       p[k] = ((p[k] mod !pi) + 2*!pi) mod !pi
+    endif
+
+    ptr_free, data
+    return
+end
diff --git a/moffat2d.pro b/moffat2d.pro
new file mode 100644
index 0000000000000000000000000000000000000000..365d661256c2d1c50d00fbd81764ad639fdd154e
--- /dev/null
+++ b/moffat2d.pro
@@ -0,0 +1,73 @@
+; $Id: moffat2d.pro, v 1.0 March 2012 e.d. $
+;
+;+
+; NAME:
+;   MOFFAT2D
+;
+; PURPOSE:
+;   Compute a 2-dim Moffat function on a 2-dim (X, Y) reference frame.
+;
+; CATEGORY:
+;   Models.
+;
+; CALLING SEQUENCE:
+;   Result = MOFFAT2D(Nx, Ny, Cx, Cy, R1, R2, A)
+;
+; INPUTS:
+;   Nx, Ny: Size of output array (Nx columns * Ny rows).
+;
+;   Cx, Cy: Coordinates of center of Moffat function.
+;
+;   R1, R2: Radius of Moffat function along principal axes.
+;   
+; OPTIONAL INPUTS:
+;   A:  Angle of first axis (see R1) with respect to X axis; it is 
+;     measured counter-clockwise in radians. If undefined, it is set to 0.
+;
+; KEYWORD PARAMETERS:
+;   POWER:  Power law of Moffat function. Default POWER = 1.5.
+;
+;   NORMAL: Set this keyword to normalize the output Moffat function 
+;     to unit energy over the whole (X, Y) plane.
+;     Note: setting /NORMAL does not mean that the function is normalized 
+;     to unit energy over the output array.
+;
+; OUTPUTS:
+;   Result:   2D floating-point array containing the Moffat function.
+;
+; PROCEDURE:
+;   Moffat function is defined by
+;   z(x,y) = 1 / (1 + (xr/R1)^2 + (yr/R2)^2)^k,
+;   where
+;   xr and yr are coordinates in the reference frame defined by the 
+;   principal axes of the Moffat function (rotated by an angle A with 
+;   respect to the X, Y reference frame);
+;   k is the power law defined by keyword POWER.
+;   The normalization coefficient is
+;   (k-1) / (!pi*R1*R2)
+;   
+; MODIFICATION HISTORY:
+;   Written by:  Emiliano Diolaiti, March 2012.
+;-
+
+FUNCTION moffat2d, nx, ny, cx, cy, r1, r2, a, POWER = k, NORMAL = normal
+
+on_error, 2
+
+if n_elements(a) eq 0 then a = 0.0
+if n_elements(k) eq 0 then k = 3.0/2.0
+
+x = findgen(nx) - cx
+y = findgen(ny) - cy
+x = temporary(x) # make_array(ny, VALUE = 1)
+y = make_array(nx, VALUE = 1) # temporary(y)
+xtemp = x
+ytemp = y
+x =  xtemp * cos(a) + ytemp * sin(a)
+y = -xtemp * sin(a) + ytemp * cos(a)
+z = 1 / (1 + (x / r1)^2 + (y / r2)^2)^k
+
+if keyword_set(normal) then z = z * (k-1) / (!pi*r1*r2)
+
+return, z
+end
diff --git a/newton_gauss.pro b/newton_gauss.pro
new file mode 100644
index 0000000000000000000000000000000000000000..30de43d402fe27bd18f0f9f84c079854b3c9228e
--- /dev/null
+++ b/newton_gauss.pro
@@ -0,0 +1,203 @@
+; $Id: newton_gauss.pro, v 1.2 Mar 2012 e.d. $
+;
+;+
+; NAME:
+;	NEWTON_GAUSS
+;
+; PURPOSE:
+;	Optimize the parameters of parametric model in order to fit a set
+;	of measurements, by means of the Newton-Gauss iterative algorithm.
+;	This method requires the evaluation of both the model and its
+;	derivatives with respect to the parameters.
+;
+; CATEGORY:
+;	Mathematics. Optimization.
+;
+; CALLING SEQUENCE:
+;	NEWTON_GAUSS, Model_fun, Iacobi_fun, Converg_fun, Ini_x, Data, $
+;				  Converging, X, Sigma_x, Model
+;
+; INPUTS:
+;	Model_fun:	Name of a function to compute the parametric model.
+;		It must be defined as follows:
+;		FUNCTION Model_fun, X, KEYWORDS = keywords
+;		where X is a set of parameters and KEYWORDS represents a list
+;		of input keyword parameters. 
+;		The result of Model_fun must have the same size as the data to be 
+;		approximated (see below)
+;
+;	Iacobi_fun:	Name of a function to compute the derivatives of the model.
+;		It must be defined as follows:
+;		FUNCTION Iacobi_fun, X, KEYWORDS = keywords
+;		where X is a set of parameters and KEYWORDS represents a list
+;		of input keyword parameters. Among the KEYWORDS, also the keyword 
+;   PVAR should be defined if applicable (see KEYWORD PARAMETERS below). 
+;   The result of Iacobi_fun must be an array of size N*M, where N (number 
+;   of columns) is the number of parameters and M (size of rows) is the 
+;   number of elements in the input data. The element [n,m] of the result 
+;   is the derivative of the model with respect to the n-th parameter, 
+;   computed at the m-th point
+;
+;	Converg_fun:	Name of a function to check the convergence condition
+;		between to sets of parameters, corresponding to successive iterations.
+;		It must be defined as follows:
+;		FUNCTION Converg_fun, X0, X, KEYWORDS = keywords
+;		where X0 and X are two sets of parameters and KEYWORDS represents a
+;		list of input keyword parameters. It must return a logical value
+;
+;	Ini_x:	Initial guess of the set of parameters
+;
+;	Data:	Data to be approximated with the parametric model
+;
+; KEYWORD PARAMETERS:
+;	BAD_DATA:	Array of subscripts (compatible with the input Data),
+;		representing Data values to be masked
+;
+;	MASK:	Set this keyword to a nonzero value to apply the data masking
+;		mode no. 2 described in PROCEDURE description, provided an estimate
+;		of the background noise standard deviation is supplied on input
+;		(see next keyword)
+;
+;	NOISE_STD:	Estimate of the noise standard deviation. It may be a scalar
+;		("white noise" case) or an array, having the same size as Data
+;
+;	NOISE_TOL:	Fix a threshold for bad data identification in data masking
+;		mode no. 2. See PROCEDURE description. The default is NOISE_TOL = 5
+;
+; PVAR: Vector of integers with the same length as the input parameter Ini_x.
+;   The i-th value of PVAR is
+;   1, if the i-th parameter has to be considered variable in the optimization
+;   0, if the i-th parameter has to be kept fixed (to the initial value).
+;   By default all parameters are considered variable.
+;
+;	WHEN:	Iteration number when to identify bad data in data masking mode
+;		no. 2. See PROCEDURE description. The default is WHEN = 2 (i.e.
+;		2nd iteration)
+;
+;	SCALE:	Set this keyword to a nonzero value to scale the set of variables
+;		(model parameters), in order to prevent noise amplification
+;
+;	MAXIT:	Maximum number of iteration allowed. The default is 30.
+;
+;	INVERSE_DATA_VAR:	Inverse noise variance on input Data. This parameter
+;		may be either a scalar ("white noise" case) or an array, having the
+;		same size as Data.
+;
+;	_EXTRA:	Extra keywords which are accepted by NEWTON_GAUSS and passed
+;		directly to the functions Model_fun, Iacobi_fun and Converg_fun.
+;		These extra keywords may be used to handle global data, as an
+;		alternative to COMMON blocks.
+;		Extra keywords (such as SVDINV) may be also passed to Min_Norm_Inversion.
+;
+; OUTPUTS:
+;	Converging:	Logical value, true if the algorithm has converged,
+;		according to the convergence condition defined by the function
+;		Converg_fun
+;
+;	X:	Optimal set of parameters
+;
+; OPTIONAL OUTPUTS:
+;	Sigma_x:	Formal errors (at "1 sigma level") on the estimated
+;		parameters. Available only if INVERSE_DATA_VAR has been provided
+;
+;	Model:	Best fit model
+;
+;	IT:	Use this output keyword to monitor the actual number of iterations
+;		performed
+;
+;	W_BAD:	Use this output keyword to retrieve the subscripts of the bad
+;		data which have been masked. The value of this keyword concide with
+;		the input BAD_DATA if only data masking mode no. 1 is performed
+;
+; PROCEDURE:
+;	The problem may be expressed mathematically as a set of non-linear
+;	algebraic equations, in the form
+;	Model(X) - Data = 0.
+;	The algebraic system is solved by means of the iterative Newton-Gauss
+;	scheme
+;	M Dx = Data - Model(X), X' = X + Dx
+;	where M is the Iacobi matrix of the model with respect to the parameters,
+;	X is the old set of parameters, Dx a correction and X' a new estimate.
+;	At every iteration the correction vector Dx is found as the minimum norm
+;	solution of the linear system
+;	M Dx = Data - Model
+;	The vector of parameters X may be scaled (see keyword SCALE), in order to
+;	prevent noise amplification in the inversion of the matrix, due to ill
+;	conditioning.
+;	The algorithm requires an initial estimate of the solution (Ini_x) and a
+;	stopping criterion (e.g. variation of parameters smaller than a pre-fixed
+;	tolerance or upper threshold on number of iterations).
+;	Bad data masking may be performed by:
+;	1) providing an array of subscripts for the points to be masked
+;	2) providing an estimate of the background noise standard deviation (see
+;	keyword NOISE_STD), used by the algorithm to identify the points where
+;	the error between the Data and the Model (computed at the iteration
+;	specified by the keyword WHEN) is larger than  NOISE_TOL * NOISE_STD.
+;	The two data masking mode may be used together.
+;	It is possible to weigh the data by the inverse standard deviation of
+;	the error on each value (see the keyword INVERSE_DATA_VAR)
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;   1) Added keyword PVAR (E. D., March 2008)
+; 	2) Added keyword _EXTRA in call to MIN_NORM_INVERSION (E.D., March 2012).
+; 	3) Positional parameter Pvar turned into keyword in call to Iacobi_fun; 
+; 	   removed from calls to Model_fun and Converg_fun (E.D., March 2012).
+;-
+
+PRO newton_gauss, model_fun, iacobi_fun, converg_fun, ini_x, data, $
+   		  PVAR = pvar_in, BAD_DATA = bad_data, MASK = mask, NOISE_STD =	noise_std, $
+   		  NOISE_TOL = noise_tol, WHEN = mask_now, SCALE = scale,   $
+   		  MAXIT = maxit, INVERSE_DATA_VAR = inverse_var, $
+   		  converging, x, sigma_x, model, IT = it, W_BAD = w_bad, $
+   		  _EXTRA = extra
+
+	on_error, 2
+	if  n_elements(bad_data) ne 0  then  w_bad = bad_data
+	mask = keyword_set(mask) and n_elements(noise_std) ne 0
+	if  mask  then begin
+	  if  n_elements(mask_now) eq 0  then  mask_now = 2
+	  if  n_elements(noise_tol) eq 0  then  noise_tol = 5
+	endif
+	if  n_elements(maxit) eq 0  then  maxit = 30
+	n_data = n_elements(data)
+	if  n_elements(inverse_var) eq 1  then $
+	   inverse_var = replicate(inverse_var, n_data)
+	it = 0L  &  x = ini_x
+  npar = n_elements(x)
+  if n_elements(pvar_in) eq 0 then $
+     pvar = make_array(npar, VALUE = 1) else $
+     pvar = pvar_in
+  model = call_function(model_fun, x, _EXTRA = extra)
+  converging = 0B
+
+	while  it lt maxit and not converging  do begin
+
+	   it = it + 1
+	   if  mask  then  if  it eq mask_now  then  w_bad = $
+	      append_elements(w_bad, where(abs(data - model) gt noise_tol*noise_std))
+     if n_elements(pvar_in) ne 0 then $
+        iacobi = call_function(iacobi_fun, x, PVAR = pvar_in, _EXTRA = extra) else $
+        iacobi = call_function(iacobi_fun, x, _EXTRA = extra)
+	   ls_sys, iacobi, reform(data - model, n_data), MASK = w_bad, $
+	   		   WEIGHTS = inverse_var, lin_hessian, grad
+	   if  keyword_set(scale)  then $
+	      scale_ls_sys, lin_hessian, grad, lin_hessian, grad, s, $
+	      				NOCOMP = (it gt 1) and 1B
+	   dx = min_norm_inversion(lin_hessian, grad, SCALING = s, $
+	   						   INVERSE = inv_hessian, _EXTRA = extra)
+     dxv = fltarr(npar)
+     dxv[where(pvar eq 1)] = dx
+     x0 = x  &  x = x + dxv
+     model = call_function(model_fun, x, _EXTRA = extra)
+     converging = call_function(converg_fun, x0, x, _EXTRA = extra)
+
+	endwhile
+
+	if  converging  then  if  n_elements(inverse_var) ne 0  then begin
+     sigma_x = fltarr(npar)
+     sigma_x[where(pvar eq 1)] = fitting_errors(inv_hessian, SCALING = s)
+  endif
+
+	return
+end
diff --git a/noise.fits b/noise.fits
new file mode 100644
index 0000000000000000000000000000000000000000..76bcc714639afd2e8955d18858f2f385b96ed208
Binary files /dev/null and b/noise.fits differ
diff --git a/peak_area.pro b/peak_area.pro
new file mode 100644
index 0000000000000000000000000000000000000000..9b9edbd8fe1108cc16bba9b6636744822215db50
--- /dev/null
+++ b/peak_area.pro
@@ -0,0 +1,90 @@
+; $Id: peak_area.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	PEAK_AREA
+;
+; PURPOSE:
+;	Estimate the area of a peak in a given image.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = PEAK_AREA(Image)
+;
+; INPUTS:
+;	Image:	Image containing the peak whose area has to be estimated
+;
+; KEYWORD PARAMETERS:
+;	X, Y:	Coordinates of the peak. The default is the Image absolute maximum
+;
+;	ABS_THRESHOLD:	Threshold above which the area must be estimated.
+;		No default value is fixed
+;
+;	REL_THRESHOLD:	Relative threshold with respect to the peak value,
+;		used to fix the threshold above which the area must be estimated.
+;		The default is REL_THRESHOLD = 0.5, i.e. the area is estimated at
+;		half maximum. REL_THRESHOLD is neglected when ABS_THRESHOLD is
+;		defined and is used by default when ABS_THRESHOLD is undefined
+;
+;	MAG:	Integer magnification factor for array magnification. It may be
+;		useful to improve the accuracy of the measurement. The default is
+;		MAG = 1, i.e. no magnification.
+;
+;	CUBIC:	Set this keyword to a nonzero value to magnify the image with
+;		the cubic convolution interpolation implemented in the library
+;		routine CONGRID. This keyword has effect only if MAG is defined.
+;		If CUBIC is not set, the array magnification is performed with REBIN
+;		(bilinear interpolation).
+;
+; OUTPUTS:
+;	Result:	Area of the Image component connected to the peak and above the
+;		fixed threshold. The type of the result is long-integer if MAG = 1,
+;		float if MAG > 1.
+;		Return 0 if an error occurs in the extraction of the connected
+;		component.
+;
+; RESTRICTIONS:
+;	The input Image is supposed to have been background-subtracted.
+;
+; PROCEDURE:
+;	Magnify the Image if requested, threshold it with BINARY_ARRAY and use
+;	IMAGE_CORE to identify the central connected component of the resulting
+;	binary array. The area of the central connected component is an estimate
+;	of the area of the peak.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION peak_area, image, X = x, Y = y, MAG = mag_fac, CUBIC = cubic, $
+   					ABS_THRESHOLD = at, REL_THRESHOLD = rt
+
+	on_error, 2
+	if  n_elements(mag_fac) eq 0  then  mag_fac = 1
+	mag = round(mag_fac) > 1
+	if  n_elements(x) * n_elements(y) eq 0  then begin
+	   m = get_max(image)  &  x = m[0]  &  y = m[1]
+	endif
+	; Image magnification
+	siz = size52(image, /DIM) * mag  &  ima = image
+	if  mag gt 1  then $
+	   if  keyword_set(cubic)  then $
+	      ima = congrid(ima, siz[0], siz[1], CUBIC = -0.5)  else $
+	      ima = rebin(ima, siz[0], siz[1])
+	xm = round(x) * mag  &  ym = round(y) * mag
+	; Thresholding and central component extraction
+	if  n_elements(at) ne 0  then  threshold = at $
+	else begin
+	   if  n_elements(rt) eq 0  then  rt = 0.5
+	   threshold = rt * ima[xm,ym]
+	endelse
+	ima = float(binary_array(ima, threshold))
+	ima = image_core(ima, 0.5, X = xm, Y = ym, error_flag)
+	if  error_flag  then  ima = 0.
+	; Compute area
+	area = total(ima) / float(mag)^2
+	if  mag eq 1  then  area = round(area)
+	return, area
+end
diff --git a/peak_fwhm.pro b/peak_fwhm.pro
new file mode 100644
index 0000000000000000000000000000000000000000..500ee06cfb22fef055c203a67432211ea5274906
--- /dev/null
+++ b/peak_fwhm.pro
@@ -0,0 +1,52 @@
+; $Id: peak_fwhm.pro, v 1.0 Sep 1999 e.d. $
+;
+;+
+; NAME:
+;	PEAK_FWHM
+;
+; PURPOSE:
+;	Compute the FWHM (Full Width at Half Maximum) of a peak in an image.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = PEAK_FWHM(Array)
+;
+; INPUTS:
+;	Same as FWHM (see the file 'fwhm.pro')
+;
+; KEYWORD PARAMETERS:
+;	Same as FWHM (see the file 'fwhm.pro')
+;
+; OUTPUTS:
+;	Same as FWHM (see the file 'fwhm.pro')
+;
+; RESTRICTIONS:
+;	Same as FWHM (see the file 'fwhm.pro')
+;
+; PROCEDURE:
+;	Fix a guess of the FWHM. Extract a sub-array centered on the peak
+;	of size equal to 3 times the guess of the FWHM. Compute again the
+;	FWHM and repeat until the size of the sub-array is greater or equal
+;	to 3 times the current FWHM.
+;	Compute the final estimate of the FWHM applying all the detailed
+;	input options supported by the routine FWHM.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, September 1999.
+;-
+
+FUNCTION peak_fwhm, array, X = x, Y = y, _EXTRA = extra
+
+	on_error, 2
+	if  n_elements(x) * n_elements(y) ne 0  then $
+	   ref = round([x, y])  else  ref = get_max(array)
+	fw = 3.
+	repeat begin
+	   siz = round(3 * fw)
+	   peak = sub_array(array, siz, REF = ref)
+	   fw = fwhm(peak)
+	endrep until  siz ge round(3 * fw)
+	return, fwhm(peak, _EXTRA = extra)
+end
diff --git a/peak_width.pro b/peak_width.pro
new file mode 100644
index 0000000000000000000000000000000000000000..9c5f7ffc522c51abc094a0d878e34aa394135af0
--- /dev/null
+++ b/peak_width.pro
@@ -0,0 +1,60 @@
+; $Id: peak_width.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	PEAK_WIDTH
+;
+; PURPOSE:
+;	Estimate the width of a peak in a given image.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = PEAK_WIDTH(Image)
+;
+; INPUTS:
+;	Image:	Image containing the peak whose width must be measured
+;
+; KEYWORD PARAMETERS:
+;	X, Y:	Coordinates of the peak. The default is the Image absolute maximum
+;
+;	ABS_THRESHOLD:	Threshold above which the peak must be measured.
+;		No default value is fixed
+;
+;	REL_THRESHOLD:	Relative threshold with respect to the peak value,
+;		used to fix the threshold above which the peak must be measured.
+;		The default is REL_THRESHOLD = 0.5, i.e. the width is estimated at
+;		half maximum. REL_THRESHOLD is neglected when ABS_THRESHOLD is
+;		defined and is used by default when ABS_THRESHOLD is undefined
+;
+;	MAG:	Integer magnification factor for array magnification. It may be
+;		useful to improve the accuracy of the measurement. The default is
+;		MAG = 1, i.e. no magnification.
+;
+;	CUBIC:	Set this keyword to a nonzero value to magnify the image with
+;		the cubic convolution interpolation implemented in the library
+;		routine CONGRID. This keyword has effect only if MAG is defined.
+;		If CUBIC is not set, the array magnification is performed with REBIN
+;		(bilinear interpolation).
+;
+; OUTPUTS:
+;	Result:	Width of the Image component connected to the peak and above the
+;		fixed threshold.
+;
+; RESTRICTIONS:
+;	The input Image is supposed to have been background-subtracted.
+;
+; PROCEDURE:
+;	Call PEAK_AREA to estimate the area of the peak. Estimate the width
+;	as the diameter of a circle having the same section of the peak.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION peak_width, image, _EXTRA = extra
+
+	on_error, 2
+	return, sqrt(4 * peak_area(image, _EXTRA = extra) / !pi)
+end
diff --git a/phase2d.pro b/phase2d.pro
new file mode 100644
index 0000000000000000000000000000000000000000..6dbee98ec22ac4b6058b304c6d16c52b92642afc
--- /dev/null
+++ b/phase2d.pro
@@ -0,0 +1,47 @@
+; $Id: phase2d.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	PHASE2D
+;
+; PURPOSE:
+;	Compute the phase array for a 2D delta-function.
+;
+; CATEGORY:
+;	Mathematics. Transforms.
+;
+; CALLING SEQUENCE:
+;	Result = PHASE2D(X, Y, Sx, Sy)
+;
+; INPUTS:
+;	X, Y:	x- and y- position of delta-function (not necessarily integer
+;		coordinates)
+;	Sx, Sy:	x- and y- size of phase array
+;
+; KEYWORD PARAMETERS:
+;	DOUBLE_P:	Set this keyword to compute a double precision phase array
+;
+; OUTPUTS:
+;	Return a 2D complex phase array.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION phase2d, x, y, sx, sy, DOUBLE_P = double_p
+
+	on_error, 2
+	if  keyword_set(double_p)  then  pi = !Dpi  else  pi = !pi
+	arg = frequency(sx) * 2 * pi / sx
+	arg_u = arg * x
+	if  sy ne sx  then  arg = frequency(sy) * 2 * pi / sy
+	arg_v = arg * y
+	if  keyword_set(double_p)  then begin
+	   uphase = dcomplex(cos(arg_u),-sin(arg_u))
+	   vphase = dcomplex(cos(arg_v),-sin(arg_v))
+	endif else begin
+	   uphase = complex(cos(arg_u),-sin(arg_u))
+	   vphase = complex(cos(arg_v),-sin(arg_v))
+	endelse
+	return, uphase # vphase
+end
diff --git a/photon_noise.pro b/photon_noise.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0b521259eb32e392e19312455429a7db922f9448
--- /dev/null
+++ b/photon_noise.pro
@@ -0,0 +1,47 @@
+; $Id: photon_noise, v 1.2 May 2014 e.d. $
+;
+;+
+; NAME:
+;	PHOTON_NOISE
+;
+; PURPOSE:
+;	Evaluate the standard deviation of the photon noise in an image
+;	given by the sum or the mean of many exposures.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = PHOTON_NOISE(Data, El_per_adu, Nexp)
+;
+; INPUTS:
+;	Data:	Array of data affected by photon noise (in ADU)
+;
+;	El_per_adu:	Conversion constant from el. to ADU
+;		(No. of ADU = No. of el. / El_per_adu)
+;
+;	Nexp:	Number of exposures (with the same exposure time)
+;
+; KEYWORD PARAMETERS:
+;	AVG:	Set this keyword to specify that the image is the average of
+;		Nexp exposures. If AVG is not set, the routine assumes the image
+;		is the sum of Nexp exposures.
+;
+; OUTPUTS:
+;	Result:	Array with the same size as the input Data, representing the
+;		photon noise standard deviation in ADU
+;
+; MODIFICATION HISTORY:
+;	Written by: Emiliano Diolaiti, May 2000.
+;	1) Set to 0 negative data before computing SQRT!
+;	   (Emiliano Diolaiti, August 2000).
+;	2) Updated documentation (E. D., May 2014).
+;-
+
+
+FUNCTION photon_noise, data, el_per_adu, nexp, AVG = avg
+
+	on_error, 2
+	norm = 1.  &  if  keyword_set(avg)  then  norm = 1. / nexp
+	return, sqrt(norm / el_per_adu * (data > 0))
+end
diff --git a/pick_region.pro b/pick_region.pro
new file mode 100644
index 0000000000000000000000000000000000000000..af308de63d3c54222c138e3196cc7440cb82911a
--- /dev/null
+++ b/pick_region.pro
@@ -0,0 +1,56 @@
+; $Id: pick_region.pro, v 1.2 Mar 2012 e.d. $
+;
+;+
+; NAME:
+;   PICK_REGION
+;
+; PURPOSE:
+;   Given the bounds of a partition of a rectangular domain on a plane
+;   and the coordinates of a point on the same plane, compute the
+;   subscript of the sub-region containing the specified point.
+;
+; CATEGORY:
+;   Array processing.
+;
+; CALLING SEQUENCE:
+;   Result = PICK_REGION(Lx, Ux, Ly, Uy, X, Y)
+;
+; INPUTS:
+;   Lx, Ux:   Vectors of bounds of the partition along the x-axis.
+;
+;   Ly, Uy:   Vectors of bounds of the partition along the y-axis.
+;
+;   X, Y: Coordinates of the point falling on some sub-region.
+;
+; OUTPUTS:
+;   Result:   Scalar subscript of the sub-region containing the point
+;     of coordinates (X, Y).
+;
+; MODIFICATION HISTORY:
+;   Written by:  Emiliano Diolaiti, January 2000.
+;   1) Fixed bug on output Result, that was NOT scalar (E.D. August 2005).
+;   2) Modified condition for WHERE: check includes left boundary and 
+;      excludes right boundary (E.D., March 2012).
+;-
+
+FUNCTION pick_region, lx, ux, ly, uy, x, y
+
+    on_error, 2
+    nx = n_elements(lx)  &  x_rep = replicate(x, nx)
+    ny = n_elements(ly)  &  y_rep = replicate(y, ny)
+    wx = where(x_rep ge lx and x_rep lt ux)
+    wy = where(y_rep ge ly and y_rep lt uy)
+    return, wy[0] * nx + wx[0]
+end
+
+
+
+
+;    on_error, 2
+;    nx = n_elements(lx)  &  x_rep = replicate(round(x), nx)
+;    ny = n_elements(ly)  &  y_rep = replicate(round(y), ny)
+;    wx = where(x_rep ge lx and x_rep le ux)
+;    wy = where(y_rep ge ly and y_rep le uy)
+;    return, wy[0] * nx + wx[0]
+;end
+
diff --git a/plane.pro b/plane.pro
new file mode 100644
index 0000000000000000000000000000000000000000..016cdbea948b03980ec6406b9c637cc7bcab0300
--- /dev/null
+++ b/plane.pro
@@ -0,0 +1,39 @@
+; $Id: plane.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	PLANE
+;
+; PURPOSE:
+;	Compute a 3D plane, defined as
+;	P(x, y) = C + Cx * x + Cy * y
+;
+; CATEGORY:
+;	Models.
+;
+; CALLING SEQUENCE:
+;	Result = PLANE(C, Cx, Cy, Sx, Sy)
+;
+; INPUTS:
+;	C, Cx, Cy:	Coefficients of the plane
+;
+;	Sx:	First size of the output array
+;
+; OPTIONAL INPUTS:
+;	Sy:	Second size of the output array. The default is Sy = Sx
+;
+; OUTPUTS:
+;	Result:	2D floating-point array, containing the values of the plane
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION plane, c, cx, cy, sx, sy
+
+	on_error, 2
+	if  n_params() eq 4  then  sy = sx
+	p = c + cx * (findgen(sx) # (fltarr(sy) + 1))
+	p = temporary(p) + cy * ((fltarr(sx) + 1) # findgen(sy))
+	return, p
+end
diff --git a/psf.fits b/psf.fits
new file mode 100644
index 0000000000000000000000000000000000000000..528c6ff6e2efb43e4c4188db14b1ffc9c68a2174
Binary files /dev/null and b/psf.fits differ
diff --git a/psf_extract.pro b/psf_extract.pro
new file mode 100644
index 0000000000000000000000000000000000000000..16ddc704f3dc072b346304e22c86963ab970e61c
--- /dev/null
+++ b/psf_extract.pro
@@ -0,0 +1,299 @@
+; $Id: psf_extract.pro, v 1.3 Aug 2004 e.d. $
+;
+;+
+; NAME:
+;   PSF_EXTRACT
+;
+; PURPOSE:
+;   Estimate the PSF in a stellar field image by combination of a stack
+;   of user-selected stars.
+;   The "PSF stars" are cleaned from the contamination of secondary sources,
+;   background-subtracted, centered with sub-pixel accuracy, normalized and
+;   combined by median superposition.
+;   It is possible to weigh the frames in the stack before superposition and
+;   mask sub-regions above a pre-fixed threshold, which may suitably coincide
+;   with the detector saturation level. Saturated stars are approximately
+;   repaired, by replacing their core with a preliminary estimate of the PSF.
+;
+; CATEGORY:
+;   Signal processing. Stellar photometry.
+;
+; CALLING SEQUENCE:
+;   PSF_EXTRACT, X, Y, X_secondary, Y_secondary, $
+;                Image, Background, Psf_size, Psf, Psf_fwhm
+;
+; INPUTS:
+;   X, Y: Coordinates of stars to superpose
+;
+;   X_secondary, Y_secondary: Coordinates of secondary sources to subtract
+;
+;   Image:    Image of the stellar field
+;
+;   Psf_size: Size of output PSF in pixels
+;
+; OPTIONAL INPUTS:
+;   Background: Array, with the same size as Image, containing an estimate of the
+;     background emission.
+;
+; KEYWORD PARAMETERS:
+;   NOBACKGROND:  Set this keyword to specify that the image has no
+;     background (or the background in the input Image has already been
+;     subtracted).
+;
+;   N_FWHM_BACK:  Size of box for background sampling (see IMAGE_BACKGROUND
+;     for details) in units of the PSF FWHM. The default is N_FWHM_BACK = 5.
+;     For other keywords related to background estimation (e.g. SKY_MEDBOX)
+;     see the function IMAGE_BACKGROUND in the file "image_background.pro".
+;     This keyword is applied only if NOBACKGROUND is not set and the optional
+;     input Background is undefined.
+;
+;   SKY_MEDIAN: Set this keyword to estimate the background by median
+;     smoothing of the input Image, instead of using IMAGE_BACKGROUND.
+;
+;   ITER: The secondary sources around the PSF stars are fit and subtracted
+;     using a preliminary estimate of the PSF. This procedure may be repeated
+;     any number of times, as indicated  by the keyword ITER. The default is
+;     ITER = 2. Set ITER = 0 to avoid subtracting the secondary sources.
+;
+;   N_FWHM_FIT:   Width of box used to fit secondary sources.
+;     The box size must be specified in units of the PSF FWHM.
+;     The default value is N_FWHM_FIT = 2.
+;
+;   INTERP_TYPE:  Set this keyword to a string identifying the interpolation
+;     technique to use for sub-pixel centering. For details, see the function
+;     IMAGE_SHIFT in the file "image_shift.pro". Recommended values for the
+;     PSF extraction procedure are INTERP_TYPE = "S" or INTERP_TYPE = "I".
+;
+;   UPPER_LEVEL:  Use this keyword to provide the saturation threshold which
+;     is used to mask the core of bright saturated stars when performing the
+;     median superposition. Though saturated, these stars should not be
+;     rejected, because they provide useful information on the PSF halo.
+;     The value of the keyword UPPER_LEVEL may be:
+;     a) a scalar, representing the unique threshold to be used all over
+;        the frame;
+;     b) a 2D array, having the same size as the input Image, when the
+;        saturation level is not spatially uniform. This happens for
+;        example when the input Image has been background subtracted:
+;        if the removed contribution is not negligible with respect to
+;        the stellar peaks, the saturation threshold will be affected and
+;        should be defined as the original threshold minus the removed
+;        background contribution.
+;
+;   N_FWHM_MATCH: Size of "search box", expressed in units of the PSF FWHM,
+;     where the PSF must moved to optimize the correlation with a given
+;     saturated star to repair. Notice that the correlation is maximized
+;     after masking the pixels in the saturated core.
+;     The default is N_FWHM_MATCH = 1.
+;
+;   N_WIDTH:  Size of the inner portion of a saturated star to replace.
+;     It must be expressed in units of the saturated core diameter, which
+;     is computed automatically by the program.
+;     The default is N_WIDTH = 3.
+;
+;   MAG_FAC:  Integer representing the fractional sub-pixel step for
+;     accurate positioning of the PSF estimate on the core of a saturated
+;     star. This "magnification factor" is also used to optimize the
+;     correlation.
+;     The default is MAG_FAC = 2, corresponding to a positioning accuracy
+;     of 1/2 pixel.
+;
+;   MAX_NORM: Set this keyword to normalize the stars to unitary maximum
+;     before combining them in a single frame. The default is to normalize
+;     each sub-image to total unit flux.
+;
+;   RAD_NORM: Set this keyword to normalize the stars using a circular
+;     region centered on the stellar peak. The value of this keyword is the
+;      radius of the normalization region. The default is to normalize
+;     each sub-image to total unit flux.
+;
+;   AVGTYPE:  Set this keyword to choose a combination algorithm among
+;     the following possibilities:
+;     AVGTYPE = 0 [default]: pixel-by-pixel average
+;             = 1: average with sigma-rejection of outliers
+;             = 2: median
+;
+;   WEIGHTED: Set this keyword to weigh the stellar images, before averaging,
+;     according to their signal-to-noise ratio in the photon noise case.
+;
+;   NONORM:   Set this keyword to avoid normalizing the final PSF estimate.
+;
+; OUTPUTS:
+;   Image:    Same as input Image, with corrected saturated stars
+;
+;   Psf:  2D array of size Psf_size*Psf_size with the estimated PSF,
+;     normalized to unit total flux
+;
+;   Psf_fwhm: FWHM of estimated PSF
+;
+;   Background:   Estimate of the background emission
+;
+;   X, Y: If there are saturated stars among the ones to superpose, their
+;     position might slightly change after repair.
+;
+; SIDE EFFECTS:
+;   1) May create modal widgets by means of DIALOG_MESSAGE.
+;   2) Modify the input parameters Image, Clean_image, X, Y if there are
+;     saturated stars to repair among the stars to superpose.
+;
+; RESTRICTIONS:
+;   1) The PSF_EXTRACT routine is useful to extract an estimate of the PSF
+;   provided the field of view is reasonably isoplanatic.
+;   If this condition is not fulfilled, PSF_EXTRACT may still be used to
+;   extract a PSF estimate from isoplanatic sub-sections in the image.
+;   2) Centering and fitting stellar images is based on data interpolation.
+;   Interpolation techniques are not suited to undersampled data.
+;   3) Saturated stars may be useful to form a PSF estimate because they
+;   provide information on the PSF halo. If there are saturated stars in the
+;   Image, they should be repaired, to ensure proper normalization.
+;   4) Saturated stars are identified as those peaks among the selected PSF
+;   stars with an intensity greater than the saturation threshold.
+;   5) Secondary sources around PSF stars are supposed to be unsaturated.
+;
+; PROCEDURE:
+;   Before calling PSF_EXTRACT, the user has to select the candidate
+;   "PSF stars" and the contaminating sources around each of them.
+;   A preliminary estimate of the PSF is obtained superposing the unsaturated
+;   stars with the routine SUPERPOSE_STARS (see the file "superpose_stars.pro"),
+;   and is used to fit and subtract the secondary sources, thus cleaning the
+;   PSF stars. This process may be repeated iteratively: at every step the
+;   accuracy of the "fit + subtract" sequence is supposed to increase, even
+;   though in practice one iteration is often enough.
+;   A shifted scaled replica of the current PSF estimate is used to replace
+;   the core of bright saturated stars: the optimal match is found by
+;   cross-correlation maximization for the relative shift and by a least
+;   squares fitting of the PSF wings for the scaling factor.
+;   Finally all the candidate PSF stars, including the repaired ones, are
+;   superposed to form the last PSF estimate, suitably masking the core of
+;   saturated stars.
+;   In every phase described above, the stellar images are background-
+;   subtracted, centered with sub-pixel accuracy and normalized before
+;   combination.
+;
+; MODIFICATION HISTORY:
+;   Written by:  Emiliano Diolaiti, August-September 1999.
+;   Updates:
+;   1) Added keyword REFERENCE_PIX in call to IMAGE_MODEL
+;      (Emiliano Diolaiti, December 1999).
+;   2) Modified some keywords, required by called routine SUPERPOSE_STARS
+;      (Emiliano Diolaiti, September 2001).
+;   3) Added keyword NOBACKGROUND
+;      (Emiliano Diolaiti, September 2001).
+;   4) Background turned to optional input: if it is set, it is not estimated
+;      by PSF_EXTRACT (E. D., August 2004).
+;-
+
+
+
+;;; Auxiliary procedures/functions.
+
+; PSF_CLEAN: Subtract secondary sources around PSF stars.
+
+FUNCTION psf_clean, image, psf, x, y, fitbox, _EXTRA = extra
+
+    on_error, 2
+    clean_image = image  &  siz = size52(image, /DIM)
+    fitting_psf = sub_array(psf, 2*fitbox)
+    reference_pix = size52(psf, /DIM) / 2
+    fit_data = ptr_new(/ALLOCATE)  &  model_data = ptr_new(/ALLOCATE)
+    nstars = n_elements(x)
+    for  n = 0, nstars - 1  do begin
+       sub_image = sub_array(clean_image, fitbox, $
+                 REFERENCE = [x[n], y[n]], LX = lx, LY = ly)
+       fitstars, sub_image, fitting_psf, x[n] - lx, y[n] - ly, $
+                PSF_DATA = fit_data, _EXTRA = extra, xn, yn, fn, b, fit_error
+       if  fit_error ge 0  then begin
+          xn = xn + lx  &  yn = yn + ly
+          clean_image = temporary(clean_image) - $
+          image_model(xn, yn, fn, siz[0], siz[1], psf, model_data, $
+                    REFERENCE_PIX = reference_pix, _EXTRA = extra)
+       endif
+    endfor
+    ptr_free, fit_data, model_data
+    return, clean_image
+end
+
+
+
+;;; The main routine.
+
+PRO psf_extract, $
+    x, y, x_secondary, y_secondary, $
+    image, psf_size, psf, psf_fwhm, background, $
+    NOBACKGROUND = nobackground, N_FWHM_BACK = n_fwhm_back, $
+    N_FWHM_FIT = n_fwhm_fit, ITER = iter, UPPER_LEVEL = upper_lev, $
+    RAD_NORM = norm_rad, NONORM = nonorm, _EXTRA = extra
+
+    on_error, 2
+
+    ; Define unsaturated stars
+    x_unsat = x  &  y_unsat = y  &  peaks = image[x, y]
+    if  n_elements(upper_lev) ne 0  then begin
+       w = where(peaks lt upper_lev, count)
+       if  count eq 0  then begin
+          id = dialog_message(/ERROR, "Please select at least one unsaturated star.")
+       return
+    endif
+       x_unsat = x_unsat[w]  &  y_unsat = y_unsat[w]  &  peaks = peaks[w]
+    endif
+    ; Select the brightest unsaturated star
+    m = max(peaks, w)  &  x0 = x_unsat[w]  &  y0 = y_unsat[w]
+    ; Use this star to estimate the PSF FWHM
+    psf_fwhm = peak_fwhm(image, X = x0, Y = y0, MAG = 3, /CUBIC, _EXTRA = extra)
+    ; Estimate the image background, if necessary
+    if  keyword_set(nobackground)  then begin
+       siz = size52(image, /DIM)
+       background = fltarr(siz[0], siz[1])
+    endif else $
+    if n_elements(background) eq 0 then begin
+       if  n_elements(n_fwhm_back) eq 0  then  n_fwhm_back = 5
+       backbox = round(n_fwhm_back * psf_fwhm)
+       background = estimate_background(image, backbox, /CUBIC, _EXTRA = extra)
+    endif
+    if not keyword_set(nobackground) then $
+       psf_fwhm = peak_fwhm(image - background, X = x0, Y = y0, MAG = 3, /CUBIC)
+
+    ; Compute preliminary estimate of the PSF using unsaturated stars
+    if  n_elements(norm_rad) ne 0  then  rad = norm_rad * psf_fwhm
+    psf = superpose_stars(image - background, x_unsat, y_unsat, psf_size, $
+                       RAD_NORM = rad, CENTROID_BOX = round(psf_fwhm), _EXTRA = extra)
+
+    ; Fit and subtract secondary sources and refine PSF using unsaturated stars
+    if  n_elements(iter) eq 0  then  iter = 2
+    if  n_elements(x_secondary) eq 0 or n_elements(y_secondary) eq 0  then  iter = 0
+    if  n_elements(n_fwhm_fit) eq 0  then  n_fwhm_fit = 2
+    fitbox = round(n_fwhm_fit * psf_fwhm)  ; fitting box
+    if  iter eq 0  then  clean_image = image
+    for  it = 0L, iter - 1  do begin
+       clean_image = psf_clean(image, psf, x_secondary, y_secondary, $
+                               fitbox, _EXTRA = extra)
+       psf = superpose_stars(clean_image - background, x_unsat, y_unsat, $
+                             psf_size, RAD_NORM = rad, CENTROID_BOX = round(psf_fwhm), $
+                             _EXTRA = extra)
+    endfor
+    psf_fwhm = fwhm(psf, MAG = 3, /CUBIC)
+
+    ; Repair saturated stars and compute last estimate of the PSF,
+    ; using all the selected stars
+    n_satur = 0
+    if  n_elements(upper_lev) ne 0  then begin
+       w = where(image[x, y] ge upper_lev, n_satur)
+       if  n_satur ne 0  then begin
+          x_satur = x[w]  &  y_satur = y[w]
+       endif
+    endif
+    if  n_satur ne 0  then begin
+       repair_saturated, image, clean_image, background, psf, psf_fwhm, $
+                         x_satur, y_satur, upper_lev, _EXTRA = extra
+       x = [x_satur, x_unsat]
+       y = [y_satur, y_unsat]
+       psf = superpose_stars(clean_image - background, x, y, psf_size, $
+                             SATURATION = upper_lev - background, $
+                             RAD_NORM = rad, CENTROID_BOX = round(psf_fwhm), $
+                             _EXTRA = extra)
+       psf_fwhm = fwhm(psf, MAG = 3, /CUBIC)
+    endif
+
+    if not keyword_set(nonorm) then psf = psf / total(psf)
+
+    return
+end
diff --git a/psf_help.txt b/psf_help.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7e4b7e653f693875b1441c644bf3ee22a0dc4b4f
--- /dev/null
+++ b/psf_help.txt
@@ -0,0 +1,27 @@
+  'PSF' menu help page
+
+
+  The 'PSF' menu contains the following sub-menus:
+
+  'Load':
+      Load a PSF array from a FITS file.
+
+  'Extract from image':
+      Extract the PSF from the stellar field image, by superposition
+      of a set of user-selected stars (referred to as 'PSF stars'). 
+      This task may be used also to repeat the PSF extraction procedure 
+      after analyzing the image, in order to improve the PSF estimate 
+      using the available knowledge of the background emission and of 
+      the secondary sources that contaminate the 'PSF stars'. 
+ 
+  'Post process':
+      Modify the support of the retrieved PSF and smooth the PSF halo.
+
+  'Normalize':
+      Normalize the PSF array to total flux = 1. This task may be useful
+      to normalize an external PSF, loaded from a file. Notice that the
+      PSF loaded, extracted or processed within XStarFinder is always 
+      normalized automatically.
+
+  'Save':
+      Save to a FITS file the current estimate of the PSF.
diff --git a/psfstars.txt b/psfstars.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5ff352614f8d9c90a42a88c955578fe1b3a6e916
--- /dev/null
+++ b/psfstars.txt
@@ -0,0 +1,4 @@
+         141         239
+         264         245
+         231         322
+         238          89
diff --git a/radial_dist.pro b/radial_dist.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1927b070bb170c18cd049763eb563abc6cf3224c
--- /dev/null
+++ b/radial_dist.pro
@@ -0,0 +1,39 @@
+; $Id: radial_dist.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	RADIAL_DIST
+;
+; PURPOSE:
+;	Compute a 2D array of radial distances from an origin.
+;
+; CATEGORY:
+;	Models.
+;
+; CALLING SEQUENCE:
+;	Result = RADIAL_DIST(X_size, Y_size, X_center, Y_center)
+;
+; INPUTS:
+;	X_size, Y_size:	X- and y- size of output array
+;
+;	X_center, Y_center:	Coordinates of origin, not necessarily integer
+;
+; OUTPUTS:
+;	Result:	2D array of radial distances from (X_center, Y_center)
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION radial_dist, x_size, y_size, x_center, y_center
+
+	on_error, 2
+	z = findgen(x_size) - x_center  &  aux = make_array(y_size, VALUE = 1)
+	z = temporary(z) # aux
+	d = z^2
+	z = findgen(y_size) - y_center  &  aux = make_array(x_size, VALUE = 1)
+	z = aux # temporary(z)
+	d = temporary(d) + z^2
+	d = sqrt(temporary(d))
+	return, d
+end
diff --git a/read_float_data.pro b/read_float_data.pro
new file mode 100644
index 0000000000000000000000000000000000000000..25db04fa3d25b95e8c4fe445e2858205d74d65d0
--- /dev/null
+++ b/read_float_data.pro
@@ -0,0 +1,73 @@
+; $Id: read_float_data, v 1.2 Aug 2008 e.d. $
+;
+;+
+; NAME:
+;	READ_FLOAT_DATA
+;
+; PURPOSE:
+;	Read a Free Format file containing floating-point numbers,
+;	ordered by columns.
+;
+; CATEGORY:
+;	Input/Output.
+;
+; CALLING SEQUENCE:
+;	Result = READ_FLOAT_DATA(File, Ncolumns)
+;
+; INPUTS:
+;	File:	File name (string)
+;
+;	Ncolumns:	Number of columns in the input file
+;
+; KEYWORD PARAMETERS:
+;	MSG:	Set this keyword to display a dialog message in case
+;		of input error.
+;
+; OUTPUTS:
+;	Result:	Floating point array of size Ncolumns * Nrows, where Nrows
+;		is the number of rows in the input file, determined by the routine.
+;		If an error occurs, a scalar string is returned, with the message
+;		'I/O error'.
+;
+; RESTRICTIONS:
+;	The numbers in the input file MUST be written in rows of Ncolumns
+;	elements each. After the last number, only a 'carriage return' or no
+;	characters at all are allowed. If the last number in the last line is
+;	followed by one or more lines with one or more blank spaces, an error
+;	occurs.
+;	In practice this routine may be used to read data previously written by
+;	the IDL intrinsic procedure PRINTF.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, September 1999.
+;   Updates:
+;	1) Added Free_Lun instruction (Emiliano Diolaiti, March 2000).
+;	2) Modified algorithm (now faster): count line first, then read array 
+;	   of data (E. D., August 2008). 
+;-
+
+FUNCTION read_float_data, file, ncolumns, MSG = msg
+
+	catch, i_error
+	if  i_error ne 0  then begin
+	   if  keyword_set(msg)  then $
+	      m = dialog_message(/ERROR, 'Input error')
+	   if  n_elements(u) ne 0  then  free_lun, u
+	   return, 'I/O error'
+	endif
+  openr, u, file, /GET_LUN
+  data = fltarr(ncolumns)
+  n = 0L
+  while  not eof(u)  do begin
+     readf, u, data
+     n = n + 1
+  endwhile
+  if n ne 0 then begin
+     close, u
+     data = fltarr(ncolumns, n)
+     openr, u, file
+     readf, u, data
+  endif
+  close, u  &  free_lun, u
+  return, data
+end
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 0000000000000000000000000000000000000000..01de6068d6ed03c23aa9761e8c79949930e08aa3
--- /dev/null
+++ b/readme.txt
@@ -0,0 +1,67 @@
+StarFinder v 1.8.2a
+
+
+WEB PAGE
+
+http://davide2.bo.astro.it/?page_id=5128
+
+
+ARCHIVE CONTENT
+
+This archive includes the following files:
++) *.pro:
+   IDL source code (tested under IDL v 8.3)
++) *_help.txt:
+   ASCII files containing the help pages of the
+   IDL Graphical User Interface
++) list_of_modules.txt:
+   list of IDL source files with a short description of
+   each routine
++) other files (*.fits, *stars.txt):
+   simulated stellar field data to be used as a tutorial
+   example. The files are
+   synfield.fits: noisy image of the stellar field
+   psf.fits: PSF used to create the stellar field
+   background.fits: background added to the stellar field
+   noise.fits: array of noise standard deviation for
+               each pixel in the image
+   stars.txt: list of positions and fluxes of the stars
+              in the simulated stellar field
+   psfstars.txt: list of positions of the stars to be
+                 used for PSF estimation
+
+
+INSTALLATION
+
+Open the compressed archive StarFinder.zip and put all its 
+content in a new directory named 'starfinder'. Then modify the 
+IDL system variable !Path including the path to the new directory.
+
+StarFinder requires some routines of
+THE IDL ASTRONOMY USER'S LIBRARY (http://idlastro.gsfc.nasa.gov).
+
+
+INFO / BUGS REPORT
+
+Please send information requests and bug reports to:
+Emiliano Diolaiti (emiliano.diolaiti@oabo.inaf.it)
+Laura Schreiber (laura.schreiber@oabo.inaf.it)
+
+
+COPYRIGHT
+
+The StarFinder software is provided "as is" without express or implied warranty.
+It can be used freely for research and educational purposes.
+
+Please reference the authors in any publication resulting from
+the use of the StarFinder code. The references are:
+
+Diolaiti E., Bendinelli O., Bonaccini D., Close L.M., Currie D.G., 
+Parmeggiani G., Astronomy & Astrophysics Supplement Series, 147, 
+335, 2000
+
+Schreiber L., Diolaiti E., Bellazzini M., Ciliegi P., Foppiani I., 
+Greggio L., Lanzoni B., Lombini M., Second International Conference 
+on Adaptive Optics for Extremely Large Telescopes, 
+Online at http://ao4elt2.lesia.obspm.fr, id.P57, 
+Bibliographic Code 2011aoel.confP..57S, 2011
diff --git a/reciprocal_distance.pro b/reciprocal_distance.pro
new file mode 100644
index 0000000000000000000000000000000000000000..02b131655c593d32a7af28df34041a5324392c3b
--- /dev/null
+++ b/reciprocal_distance.pro
@@ -0,0 +1,44 @@
+; $Id: reciprocal_distance.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	RECIPROCAL_DISTANCE
+;
+; PURPOSE:
+;	Compute the euclidean distance for each couple of points
+;	in a set of given points on a plane.
+;
+; CATEGORY:
+;	Mathematics.
+;
+; CALLING SEQUENCE:
+;	Result = RECIPROCAL_DISTANCE(X, Y)
+;
+; INPUTS:
+;	X, Y:	Coordinates of N points
+;
+; OUTPUTS:
+;	Result:	(N-1)*(N-1) floating-point array of reciprocal distances.
+;		The elements of the array are defined as follows:
+;		Result[j,*] = vector of distances between the j-th point and
+;		              the others, for j = 0, ..., N - 2.
+;		Result is 0 if N = 1. It is set to a negative scalar if X and Y
+;		have different size.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION reciprocal_distance, x, y
+
+	on_error, 2
+	n = n_elements(x)
+	if  n_elements(y) ne n  then  return, -1
+	if  n eq 1  then  return, 0
+	d = fltarr(n - 1, n - 1)  &  s = lindgen(n)
+	for  i = 0L, n - 2  do begin
+	   other = (shift(s, -i))[1:n-1]  &  other = shift(other, +i)
+	   d[*,i] = distance(x[i], y[i], x[other], y[other])
+	endfor
+	return, transpose(d)
+end
diff --git a/relative_error.pro b/relative_error.pro
new file mode 100644
index 0000000000000000000000000000000000000000..86f9169ae26f7115595f99fe8adb3ba78da1b803
--- /dev/null
+++ b/relative_error.pro
@@ -0,0 +1,40 @@
+; $Id: relative_error.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	RELATIVE_ERROR
+;
+; PURPOSE:
+;	Compute the relative difference between two IDL variables.
+;
+; CATEGORY:
+;	Tools.
+;
+; CALLING SEQUENCE:
+;	Result = RELATIVE_ERROR(Var1, Var2)
+;
+; INPUTS:
+;	Var1:	First IDL variable
+;
+;	Var2:	Second IDL variable
+;
+; OUTPUTS:
+;	Return the relative error of Var2 with respect to Var1.
+;
+; PROCEDURE:
+;	Compute the quantity
+;	(Var2 - Var1) / Var1
+;	over the support of Var1 (set of pixels where Var1 is not 0).
+;	Outside the support of Var1, i.e. where Var1 is 0, the relative
+;	error is 1 (100%) by definition.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION relative_error, var1, var2
+
+	error = float(var1 - var1) + 1  &  w = where(var1 ne 0, count)
+	if  count ne 0  then  error[w] = (var2 - var1)[w] / var1[w]
+	return, error
+end
diff --git a/remove_coincident.pro b/remove_coincident.pro
new file mode 100644
index 0000000000000000000000000000000000000000..237a83b93ef1705ee15a9da0bb12e72fcc6ac908
--- /dev/null
+++ b/remove_coincident.pro
@@ -0,0 +1,67 @@
+; $Id: remove_coincident.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	REMOVE_COINCIDENT
+;
+; PURPOSE:
+;	Given a set of points on a plane, remove multiple occurences of
+;	coincident points.
+;
+; CATEGORY:
+;	Array manipulation.
+;
+; CALLING SEQUENCE:
+;	REMOVE_COINCIDENT, X, Y, X_distinct, Y_distinct
+;
+; INPUTS:
+;	X, Y:	X- and y- coordinates of points
+;
+; OUTPUTS:
+;	X_distinct, Y_distinct:	Coordinates of distinct points. The same
+;		variables used on input may be used for the output
+;
+; RESTRICTIONS:
+;	Apply only to points on a plane.
+;
+; PROCEDURE:
+;	Recursive procedure: given a subset made of N-1 distinct points,
+;	consider the next point in the original list and append it if
+;	distinct from the first N-1.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;	1) Removed call to obsolete routine APPEND_ELEMENTS
+;	   (Emiliano Diolaiti, June 2001).
+
+
+
+; ADD_DISTINCT: auxiliary procedure called by REMOVE_COINCIDENT.
+
+PRO add_distinct, x, y, x_out, y_out, n
+
+	on_error, 2
+	if  n eq 0  then begin
+	   ; base case
+	   x_out = x[n]  &  y_out = y[n]
+	endif else begin
+	   ; induction case
+	   add_distinct, x, y, x_out, y_out, n - 1
+	   if  min(distance(x[n], y[n], x_out, y_out)) ne 0  then begin
+	      x_out = [x_out, x[n]]
+	      y_out = [y_out, y[n]]
+	   endif
+	endelse
+	return
+end
+
+
+PRO remove_coincident, x, y, x_distinct, y_distinct
+
+	on_error, 2
+	npt = n_elements(x)
+	if  npt eq 0 or n_elements(y) ne npt  then  return
+	add_distinct, x, y, x_out, y_out, npt - 1
+	x_distinct = x_out  &  y_distinct = y_out
+	return
+end
diff --git a/repair_saturated.pro b/repair_saturated.pro
new file mode 100644
index 0000000000000000000000000000000000000000..b60017c9d1c530ffb645e9d094b307361601445b
--- /dev/null
+++ b/repair_saturated.pro
@@ -0,0 +1,185 @@
+; $Id: repair_saturated.pro, v 1.1 Jul 2000 e.d. $
+;
+;+
+; NAME:
+;	REPAIR_SATURATED
+;
+; PURPOSE:
+;	Repair saturated stars in an image, by replacing their core with a
+;	template representing an estimate of the PSF. Accurate positioning
+;	of the template onto each star is performed by correlation
+;	maximization, whereas the scaling factor is computed by fitting the
+;	wings of the saturated source.
+;	This procedure gives acceptable results when the size of the
+;	saturated region of a given star does not exceed the diameter of
+;	the central core of the PSF.
+;
+; CATEGORY:
+;	Signal processing. Stellar photometry.
+;
+; CALLING SEQUENCE:
+;	REPAIR_SATURATED, Image, Clean_image, Background, $
+;	                  Psf, Psf_fwhm, X, Y, Upper_lev
+;
+; INPUTS:
+;	Image:	Stellar field image containing saturated stars.
+;
+;	Clean_image:	Stellar field image, after subtraction of non-saturated
+;		sources. It may coincide with Image, if there are no important
+;		sources other than the saturated ones.
+;
+;	Background:	2D array, with the same size as Image, containing an
+;		estimate of the background emission.
+;
+;	Psf:	2D array, containing an estimate of the PSF, to be used as a
+;		template to repair the core of the saturated stars.
+;
+;	Psf_fwhm:	FWHM of the PSF.
+;
+;	X, Y:	X- and Y- coordinates of saturated stars.
+;
+;	Upper_lev:	Scalar, representing the presumed saturation threshold.
+;
+; KEYWORD PARAMETERS:
+;	N_FWHM_MATCH:	Size of "search box", expressed in units of the PSF FWHM,
+;		where the PSF must moved to optimize the correlation with a given
+;		saturated star to repair. Notice that the correlation is maximized
+;		after masking the pixels in the saturated core.
+;		The default is N_FWHM_MATCH = 1.
+;
+;	N_WIDTH:	Size of the inner portion of a saturated star to replace.
+;		It must be expressed in units of the saturated core diameter, which
+;		is computed automatically by the program.
+;		The default is N_WIDTH = 3.
+;		Notice that the box size for repair is limited by the size of the
+;		Psf array.
+;
+;	MAG_FAC:	Integer representing the fractional sub-pixel step for
+;		accurate positioning of the PSF estimate on the core of a saturated
+;		star. This "magnification factor" is also used to optimize the
+;		correlation.
+;		The default is MAG_FAC = 2, corresponding to a positioning accuracy
+;		of 1/2 pixel.
+;
+;	INTERP_TYPE:	Use this keyword to choose an interpolation technique
+;		for the PSF fractional shift when MAG_FAC > 1. See IMAGE_SHIFT in
+;		the file "image_shift.pro" for more details. The default is to
+;		use cubic convolution interpolation.
+;
+; OUTPUTS:
+;	Image:	Image array with repaired saturated stars.
+;
+;	Clean_image:	Input Clean_image with repaired saturated stars.
+;
+;	X, Y:	Coordinates of saturated stars after repair.
+;
+; SIDE EFFECTS:
+;	The input variables Image, Clean_image, X and Y are overwritten.
+;
+; RESTRICTIONS:
+;	It is assumed that the saturated stars are separated by a distance
+;	at least (N_WIDTH * Width), where N_WIDTH is the input keyword described
+;	above and Width is the maximum diameter in pixels of a saturated core.
+;
+; PROCEDURE:
+;	The input image is temporarily cleaned from the contamination of
+;	secondary sources and background emission. Then the saturated sources
+;	are isolated and repaired with a scaled replica of the PSF template.
+;	Accurate positioning of the template onto each star is performed by
+;	correlation maximization, whereas the scaling factor is computed by
+;	fitting the wings of the saturated source. Of course the saturated core
+;	is masked when computing the correlation coefficient and the scaling
+;	factor.
+;	When all the saturated sources specified on input have been repaired,
+;	the image is restored adding the previously subtracted stars and
+;	the background emission.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August-September 1999.
+;	Updates:
+;	1) Fixed bug on correlation maximization in module MATCH_REPLACE
+;	   (Emiliano Diolaiti, July 2000).
+;-
+
+
+
+
+;;; Auxiliary routines.
+
+; MATCH_REPLACE: repair the core of a saturated star,
+; given an unsaturated template.
+
+PRO match_replace, image, template, x, y, box, search_box, $
+				   upper_surface, MAG_FAC = mag_fac, _EXTRA = extra
+
+	on_error, 2
+	; Define saturated star, template, upper surface for matching
+	star = sub_array(image, box + 2*(search_box/2), REF = [x, y], $
+					 LX = lx, UX = ux, LY = ly, UY = uy)
+	star_ref = [x - lx, y - ly]  &  temp_ref = get_max(template)
+	upper = upper_surface[lx:ux,ly:uy]
+	if  n_elements(mag_fac) eq 0  then  mag_fac = 2
+	mag = round(mag_fac > 1)
+	if  mag gt 1  then $
+	   shifted_templates, template, mag, _EXTRA = extra, templates, dx, dy
+	; Find optimal position by cross-correlation maximization
+	w = where(star ge upper, count)
+	subs_to_coord, w, (size52(star, /DIM))[0], x_core, y_core
+	correlate_max, star, template, star_ref[0], star_ref[1], search_box, $
+   				   XT = temp_ref[0], YT = temp_ref[1], $
+   				   X_BAD = x_core, Y_BAD = y_core, $
+   				   TEMPLATES = templates, DX = dx, DY = dy, c, x, y
+	; Compute optimal scaling factor
+	if  mag gt 1  then begin
+	   dx_opt = round(mag * (x - round(x)))
+	   dy_opt = round(mag * (y - round(y)))
+	   w = where(round(mag * dx) eq dx_opt and round(mag * dy) eq dy_opt)
+	   temp = templates[*,*,w]
+	endif else  temp = template
+	extract_overlap, star, temp, round([x, y]), temp_ref, $
+					 star, temp, lxs, uxs, lys, uys
+   	x = x + lx  &  y = y + ly
+	lx = lx + lxs  &  ly = ly + lys  &  upper = upper[lxs:uxs,lys:uys]
+	w = where(star lt upper)
+	scale = total(temp[w]*star[w])/total(temp[w]^2)
+	; Repair image
+	w = where(star ge upper)
+	star[w] = scale * temp[w]
+	image[lx,ly] = star
+	return
+end
+
+
+
+;;; The main routine.
+
+PRO repair_saturated, image, clean_image, background, psf, psf_fwhm, x, y, $
+					  upper_lev, N_FWHM_MATCH = n_fwhm, N_WIDTH = n_width, $
+					  _EXTRA = extra
+
+	on_error, 2
+	; The image to use to repair saturated stars must be:
+	; 1) background removed
+	; 2) cleaned from secondary stars around saturated ones.
+	sec_sources = image - clean_image
+	clean_image = temporary(clean_image) - background
+	upper_surf = upper_lev - background - sec_sources
+	; Match and repair saturated stars in clean_image
+	n_satur = n_elements(x)
+	if  n_elements(n_fwhm) eq 0  then  n_fwhm = 1
+	if  n_elements(n_width) eq 0  then  n_width = 3
+	for  n = 0L, n_satur - 1  do begin
+	   width = peak_width(clean_image, MAG = 1, X = x[n], Y = y[n], $
+	   					  ABS_THRESH = upper_surf)
+	   box = round(n_width * width) < min(size52(psf, /DIM))
+	   search_box = round(n_fwhm * psf_fwhm)
+	   x_n = x[n]  &  y_n = y[n]
+	   match_replace, clean_image, psf, x_n, y_n, box, search_box, upper_surf, _EXTRA = extra
+	   x[n] = x_n  &  y[n] = y_n
+	endfor
+	; Define clean_image = input image with repaired stars - secondary sources
+	clean_image = temporary(clean_image) + background
+	; Define image = original image with repaired stars
+	image = clean_image + sec_sources
+	return
+end
diff --git a/replace_pix.pro b/replace_pix.pro
new file mode 100644
index 0000000000000000000000000000000000000000..4ad1e083fee945229e73045a6a944ac6b789bafe
--- /dev/null
+++ b/replace_pix.pro
@@ -0,0 +1,72 @@
+; $Id: replace_pix, v 1.0 Sep 1999 e.d. $
+;
+;+
+; NAME:
+;	REPLACE_PIX
+;
+; PURPOSE:
+;	Given a 2D array and a set of "bad" pixels, replace each bad data
+;	point with the median of the "good" data in a suitable box around.
+;	The box size is adjusted in order to have a minimum number of good
+;	points to compute the median.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = REPLACE_PIX(Data, X, Y)
+;
+; INPUTS:
+;	Data:	2D data array
+;
+;	X, Y:	Coordinates of pixels to replace
+;
+; KEYWORD PARAMETERS:
+;	BOXSIZE:	Initial value of the box size to compute the local median.
+;
+;	NGOOD_MIN:	Minimum number of good points in the box to compute the
+;		local median. The default is 3.
+;
+;	BOX_INCR:	If the box of size BOXSIZE centered on a bad pixel does
+;		not contain the minimum number of good points specified by the
+;		keyword NGOOD_MIN, its size is iteratively increased by the amount
+;		BOX_INCR until the condition is fulfilled. The default is 2.
+;
+;	MAXIT:	Maximum number of iterations to increase the box size.
+;		The default is 5.
+;
+; OUTPUTS:
+;	Result:	Array with replaced pixels
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, September 1999.
+;-
+
+FUNCTION replace_pix, data, x, y, BOXSIZE = boxsize, NGOOD_MIN = ngood_min, $
+					  BOX_INCR = box_incr, MAXIT = maxit
+
+	on_error, 2
+	if  n_elements(boxsize) eq 0  then  boxsize = 3L
+	if  n_elements(ngood_min) eq 0  then  ngood_min = 3
+	if  n_elements(box_incr) eq 0  then  box_incr = 2
+	if  n_elements(maxit) eq 0  then  maxit = 5
+	data_out = data
+	npix = n_elements(x)
+	for  n = 0L, npix - 1  do begin
+	   ; Adjust box size to have enough good points
+	   incr = 0L  &  it = 0L
+	   repeat begin
+	      box = sub_array(data, boxsize + incr, REF = [x[n],y[n]], $
+	   				      LX = lx, UX = ux, LY = ly, UY = uy)
+	   	  w = where(x ge lx and x le ux and y ge ly and y le uy, nbad)
+	   	  it = it + 1  &  incr = incr + box_incr
+	   	  large_enough = (n_elements(box) - nbad) ge ngood_min or it eq maxit
+	   endrep until  large_enough
+	   ; Replace n-th bad pixel with median of good points around
+	   bin = make_array(ux - lx + 1, uy - ly + 1, VALUE = 1B, /BYTE)
+	   bin[x[w] - lx, y[w] - ly] = 0
+	   w = where(bin eq 1, ngood)
+	   if  ngood ne 0  then  data_out[x[n],y[n]] = median(box[w], /EVEN)
+	endfor
+	return, data_out
+end
diff --git a/resample.pro b/resample.pro
new file mode 100644
index 0000000000000000000000000000000000000000..6abaf8e786f1739d109b43026a7f8d8b6a9cdb6d
--- /dev/null
+++ b/resample.pro
@@ -0,0 +1,107 @@
+; $Id: resample.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	RESAMPLE
+;
+; PURPOSE:
+;	Resample a bivariate function defined on a rectangular domain by
+;	integrating it over square regions, defining pixels of the resampled
+;	array. The integration is performed by means of IDL REBIN or with
+;	the Simpson rule. The size of the input array need not be an integer
+;	multiple of the resampling factor.
+;	This routine is particularly useful to integrate over pixels an
+;	oversampled PSF.
+;
+; CATEGORY:
+;	Mathematics. Integration routines.
+;
+; CALLING SEQUENCE:
+;	Result = RESAMPLE(F, N_sub)
+;
+; INPUTS:
+;	F:	Sampled bivariate function to be resampled
+;
+;	N_sub:	Resampling factor
+;
+; KEYWORD PARAMETERS:
+;	X_SHIFT, Y_SHIFT:	X- and Y- fractional offsets, expressed in pixel
+;		units after resampling. The default is X_SHIFT = Y_SHIFT = 0.
+;
+;	X_REF, Y_REF:	Use this keyword to provide the position of a pixel
+;		in the input array to be used as a reference for centering.
+;		In general the pixel of interest is the array maximum.
+;		Suppose that X_SHIFT = 0. and Y_SHIFT = 0. and that the keywords
+;		X_REF and Y_REF are not supplied: the maximum of the resampled array
+;		may appear "not well centered", i.e. it may present a visual
+;		off-centering different from X_SHIFT, Y_SHIFT.
+;		In practice all the relative positions in the output array are always
+;		preserved. X_REF and Y_REF should be provided when the visual
+;		appearance of the resampled array is important.
+;
+;	SIMP:	Set this keyword to a nonzero value to perform the integration
+;		by means of the Simpson rule instead of REBIN (neighbor averaging).
+;		The results is much more accurate.
+;
+; OUTPUTS:
+;	Result:	Resampled array
+;
+; RESTRICTIONS:
+;	1) When the input array has to be shifted to realize the desired offset,
+;	missing values at the array edges are actually replaced with 0s.
+;	2) The actual off-centering of the resampled array can only be an
+;	integer multiple of the smallest "theoretical" shift, given by
+;	(1. / N_sub).
+;	In practice the input offsets X_SHIFT and Y_SHIFT are rounded.
+;	For example, if N_sub = 4 and X_SHIFT = 0.4, the actual shift will be
+;	0.5; if N_sub = 5 and X_SHIFT = 0.5, the actual shift will be 0.6
+;	pixels of the resampled array.
+;	Of course this rounding effect is more and more negligible as the
+;	oversampling factor of the input array and the resampling factor
+;	N_sub increase.
+;
+; PROCEDURE:
+;	Suitably resize the input array, according to the initial size and the
+;	resampling factor. Apply the desired shift and then resample with REBIN
+;	or SIMPSON_PIX_INTEGRAL.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION resample, f, n_sub, X_SHIFT = x_shift, Y_SHIFT = y_shift, $
+				   SIMP = simp, X_REF = x_ref, Y_REF = y_ref
+
+	on_error, 2
+	nsub = round(n_sub)
+	if  n_elements(x_shift) eq 0  then  x_shift = 0.
+	if  n_elements(y_shift) eq 0  then  y_shift = 0.
+	xshift = round(x_shift*nsub)  &  yshift = round(y_shift*nsub)
+	; Shift the array in order to:
+	;	1) apply the requested shift (x_shift, y_shift)
+	;	2) prevent spurious off-centering due to resampling
+	;	   when a reference pixel is provided
+	size_f = size52(f, /DIM)  &  e = 1 - nsub mod 2
+	if  n_elements(x_ref) * n_elements(y_ref) ne 0  then begin
+	   xr = round(x_ref)  &  yr = round(y_ref)
+	   xshift = xshift + (xr/n_sub) * nsub + (nsub + e)/2 - xr
+	   yshift = yshift + (yr/n_sub) * nsub + (nsub + e)/2 - yr
+	endif
+	a = extend_shift(f, xshift, yshift)
+	; Resize the array, if necessary
+	if  not keyword_set(simp)  then  e = 0
+	size_a = (size_f / nsub) * nsub + e
+	if  size_a[0] lt size_f[0]  then $
+	   a = a[0:size_a[0]-1,*]  else $
+	if  size_a[0] gt size_f[0]  then $
+	   a = extend_array(a, size_a[0], size_f[1], /NO_OFF)
+	if  size_a[1] lt size_f[1]  then $
+	   a = a[*,0:size_a[1]-1]  else $
+	if  size_a[1] gt size_f[1]  then $
+	   a = extend_array(a, size_a[0], size_a[1], /NO_OFF)
+	; Integrate over pixels
+	if  keyword_set(simp)  then $
+	   a = simpson_pix_integral(a, nsub)  else $
+	   a = rebin(a, size_f[0]/nsub, size_f[1]/nsub)
+	return, a
+end
diff --git a/reverse_class.pro b/reverse_class.pro
new file mode 100644
index 0000000000000000000000000000000000000000..e1ec2bdfd5809d23547a984c49227b783d8972f2
--- /dev/null
+++ b/reverse_class.pro
@@ -0,0 +1,40 @@
+; $Id: reverse_class.pro, v 1.1 Mar 2012 e.d. $
+;
+;+
+; NAME:
+;	REVERSE_CLASS
+;
+; PURPOSE:
+;	Reverse classification (star/not star) of an element in a list.
+;
+; CATEGORY:
+;	STARFINDER auxiliary procedures.
+;
+; CALLING SEQUENCE:
+;	Result = REVERSE_CLASS(List, SUBSCRIPTS = S)
+;
+; INPUTS:
+;	List:	list of stars and presumed stars
+;
+; KEYWORD PARAMETERS:
+;	SUBSCRIPTS:	subscripts of elements whose classification
+;		must be reversed. If undefined, reverse classification
+;		of all elements in the list
+;
+; OUTPUTS:
+;	Return list where the classification of the subscripted elements;
+;	is reversed
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, June 2001.
+; 	1) Created this file (E.D., March 2012).
+;-
+
+FUNCTION reverse_class, list, SUBSCRIPTS = s
+
+    on_error, 2
+    if  n_elements(s) eq 0  then  s = lindgen(n_elements(list))
+    l = list
+    l[s].is_a_star = (not l[s].is_a_star) and 1B
+    return, l
+end
diff --git a/rot_trans.pro b/rot_trans.pro
new file mode 100644
index 0000000000000000000000000000000000000000..c22a20469257e25e389a8a8a8fbaef08f1bcf93b
--- /dev/null
+++ b/rot_trans.pro
@@ -0,0 +1,45 @@
+; $Id: rot_trans.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	ROT_TRANS
+;
+; PURPOSE:
+;	Rotate and translate a set of points on a plane.
+;
+; CATEGORY:
+;	Mathematics.
+;
+; CALLING SEQUENCE:
+;	ROT_TRANS, X, Y, Origin, Angle, Rtx, Rty
+;
+; INPUTS:
+;	X:	X- coordinates of points
+;
+;	Y:	Y- coordinates of points
+;
+;	Origin:	2-components vector, containing the x- and y-
+;		coordinates of the origin of the new set of coordinates
+;		with respect to the old one
+;	Angle:	Angle (in radians) between the x-axes of the old and the
+;		new reference frames
+;
+; OUTPUTS:
+;	Rtx, Rty:	X- and y- coordinates of points in the translated
+;		rotated reference frame
+;
+; PROCEDURE:
+;	Transform the input coordinates according to the following rules:
+;	Rtx = -Origin[0] + X * cos(angle) + Y * sin(angle)
+;	Rty = -Origin[1] - X * sin(angle) + Y * cos(angle)
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+PRO rot_trans, x, y, origin, angle, rtx, rty
+
+	on_error, 2
+	rtx = -origin[0] + x * cos(angle[0]) + y * sin(angle[0])
+	rty = -origin[1] - x * sin(angle[0]) + y * cos(angle[0])
+	return
+end
diff --git a/sampling_grid.pro b/sampling_grid.pro
new file mode 100644
index 0000000000000000000000000000000000000000..9517406ef5cdd6e08a8c8d89edd1ade909f0e9df
--- /dev/null
+++ b/sampling_grid.pro
@@ -0,0 +1,45 @@
+; $Id: sampling_grid.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	SAMPLING_GRID
+;
+; PURPOSE:
+;	Define a set of sampling points along an axis.
+;
+; CATEGORY:
+;	Mathematics. Interpolation.
+;
+; CALLING SEQUENCE:
+;	Result = SAMPLING_GRID(N, Dx, Lx, Ux)
+;
+; INPUTS:
+;	N:	Number of sampling points
+;
+;	Dx:	Sampling step
+;
+; OUTPUTS:
+;	Result:	N-components vector of equispaced points
+;
+; OPTIONAL OUTPUTS:
+;	Lx, Ux:	Lower and upper bounds of sampling region, useful for
+;		spline interpolation
+;
+; PROCEDURE:
+;	Call FINDGEN to define a set of pixels along a 1D axis. Each pixel
+;	has a physical step size and corresponds to a sampling point, ideally
+;	located in the middle of the pixel itself.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION sampling_grid, n, dx, lx, ux
+
+	on_error, 2
+	x = findgen(n) * dx + dx / 2.
+	lx = min(x) - dx/2.  &  ux = max(x) + dx/2.
+	return, x
+end
+
+
diff --git a/scale_ls_sys.pro b/scale_ls_sys.pro
new file mode 100644
index 0000000000000000000000000000000000000000..7d00f1b0b8765b69364c59d663bbda07c5dd52de
--- /dev/null
+++ b/scale_ls_sys.pro
@@ -0,0 +1,79 @@
+; $Id: scale_ls_sys.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	SCALE_LS_SYS
+;
+; PURPOSE:
+;	Scale a linear system of normal equations in order to improve the
+;	eigenvalue ratio.
+;
+; CATEGORY:
+;	Mathematics. Linear systems.
+;
+; CALLING SEQUENCE:
+;	SCALE_LS_SYS, A, B, A_scaled, B_scaled, Scaling
+;
+; INPUTS:
+;	A:	Linear system matrix. It must be symmetric
+;
+;	B:	Right-hand side term of linear system
+;
+; OPTIONAL INPUTS
+;	Scaling:	Vector of scaling factors released on output in a
+;		previous call. Used with the keyword NOCOMP indicates that
+;		the scaling factors must not be computed again: nly the
+;		scaling operations must be performed
+;
+; KEYWORD PARAMETERS:
+;	NOCOMP:	Set this keyword to a nonzero value to indicate that
+;		the scaling factors must not be computed because they are
+;		being passed on input as Scaling
+;
+; OUTPUTS:
+;	A_scaled:	Scaled matrix. Its diagonal elements are equal to 1
+;
+;	B_scaled:	Scaled right-hand side term
+;
+;	Scaling:	Vector of scaling factors
+;
+; SIDE EFFECTS:
+;	Scaling the linear system
+;	Ax = b
+;	involves scaling the vector of variables x.
+;	After inversion of the system, the solution vector must be multiplied
+;	component-wise (e.g. using the * operator) by the output vector Scaling.
+;
+; RESTRICTIONS:
+;	The system matrix A must be symmetric and positive (semi-) definite.
+;	No check on the properties of the input array A is performed.
+;	In practice the procedure SCALE_LS_SYS can be safely applied to the
+;	output of LS_SYS (see the file 'ls_sys.pro').
+;
+; PROCEDURE:
+;	Compute scaling factors in order to have the diagonal elements of the
+;	scaled matrix A all equal to 1. If s is the vector of scaling factors,
+;	let's define S = diag{s} the diagonal matrix having these factors on
+;	the main diagonal. The scaled version of the linear system
+;	Ax = b  is
+;	(SAS)x = Sb.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+PRO scale_ls_sys, a, b, a_scaled, b_scaled, scaling, NOCOMP = nocomp
+
+	on_error, 2
+	if  not keyword_set(nocomp)  then begin
+	   ; compute scaling factors
+	   n = size52(a, /DIM)  &  n = n[0]
+	   d = lindgen(n)  &  scaling = make_array(n, /FLOAT, VALUE = 1.)
+	   w = where(a[d,d] ne 0, n)
+	   if  n ne 0  then  scaling[w] = 1 / sqrt(a[d[w],d[w]])
+	endif
+	; scale a and b
+	a_scaled = diag_mult(diag_mult(a, scaling), scaling, /PREMULT)
+	b_scaled = b * scaling
+	return
+end
diff --git a/search_objects.pro b/search_objects.pro
new file mode 100644
index 0000000000000000000000000000000000000000..4ed3bd2ecdbb78fb94dcd8ddcc95e2b144f8ed35
--- /dev/null
+++ b/search_objects.pro
@@ -0,0 +1,100 @@
+; $Id: search_objects.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	SEARCH_OBJECTS
+;
+; PURPOSE:
+;	Search objects in a given image as relative maxima above a pre-fixed
+;	threshold. The image can be suitably smoothed to reduce the number
+;	of spurious detections, due to noise spikes.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	SEARCH_OBJECTS, Image, Threshold, N, X, Y, I
+;
+; INPUTS:
+;	Image:	2D array to search
+;
+;	Threshold:	Scalar or array threshold for detection.
+;		It must be of the same type as Image.
+;
+; KEYWORD PARAMETERS:
+;	LOW_SURFACE:	2D array, with the same size as Image, containing the
+;		background emission. If this keyword is defined, a lower detection
+;		surface is defined, as the sum of the background emission and the
+;		detection Threshold. In this case, Threshold may suitably represent
+;		a multiple of the noise standard deviation.
+;
+;	PRE_SMOOTH:	Set this keyword to smooth the image before searching for
+;		relative maxima.
+;
+;	MINIF:	Integer resampling factor, used to minify the Image with the
+;		IDL function REBIN. This will smooth many noise spikes.
+;		This keyword has effect only if PRE_SMOOTH is set.
+;		If PRE_SMOOTH is set but MINIF is undefined, a standard smoothing
+;		is applied, by convolving the input Image with the low-pass filter
+;		   1  2  1
+;		   2  4  2
+;		   1  2  1
+;		Notice that when the keyword BACKGROUND is defined, the same type of
+;		smoothing is applied to the lower detection surface.
+;
+;	FOUR:	Set this keyword to identify relative maxima as pixels brigher
+;		than their 4-neighbors. The default is to use 8-neighbors.
+;
+; OUTPUTS:
+;	N:	Number of detected objects
+;
+;	X, Y:	Coordinates of objects
+;
+;	I:	Central intensity of detected objects in the background-removed
+;		Image. If the keyword BACKGROUND is undefined, this output variable
+;		represent the intensity of the objects in the input Image.
+;		The detected objects are sorted in order of decreasing intensity
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+PRO search_objects, image, LOW_SURFACE = background, threshold, $
+	                PRE_SMOOTH = pre_smooth, MINIF = minif, $
+	                _EXTRA = extra, n, x, y, i
+
+	on_error, 2
+	ima = image
+	; Define lower surface for detection
+	if  n_elements(background) eq 0  then  background = 0
+	low = background + threshold
+	; Smooth image and lower surface
+	if  keyword_set(pre_smooth)  then $
+	   if  n_elements(minif) ne 0  then begin
+	      ima = resample(ima, minif)
+	      if  size52(low, /N_DIM) eq 2  then $
+	         low = resample(low, minif)
+	   endif else begin
+	      mask = float([[1, 2, 1], [2, 4, 2], [1, 2, 1]])
+	      mask = mask / total(mask)
+	      ima = convol(ima, mask, /EDGE_TRUNCATE)
+	      if  size52(low, /N_DIM) eq 2  then $
+	         low = convol(low, mask, /EDGE_TRUNCATE)
+	   endelse
+	; Search image maxima above lower surface
+	all_max, ima, x, y, n, _EXTRA = extra
+	if  n eq 0  then  return
+	if  size52(low, /N_DIM) eq 2  then $
+	   w = where(ima[x, y] gt low[x, y], n)  else $
+	   w = where(ima[x, y] gt low, n)
+	if  n eq 0  then  return
+	x = x[w]  &  y = y[w]
+	if  keyword_set(pre_smooth)  then $
+	   if  n_elements(minif) ne 0  then begin
+	      x = x * round(minif)  &  y = y * round(minif)
+	   endif
+	i = (image - background)[x,y]
+	sorted = reverse(sort(i))
+	x = x[sorted]  &  y = y[sorted]  &  i = i[sorted]
+	return
+end
diff --git a/shifted_templates.pro b/shifted_templates.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1321063cc4462b72480f803509f598cfa9dda819
--- /dev/null
+++ b/shifted_templates.pro
@@ -0,0 +1,69 @@
+; $Id: shifted_templates.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	SHIFTED_TEMPLATES
+;
+; PURPOSE:
+;	Shift a template image by an integer multiple of pre-fixed sub-pixel
+;	shift. The basic fractional offset is defined by a magnification factor
+;	(> 1). All the possible fractional shifts whose absolute value is < 1/2
+;	pixel are applied to the input array and the resulting shifted templates
+;	are collected into an output stack.
+;
+; CATEGORY:
+;	Image processing, spatial transformations
+;
+; CALLING SEQUENCE:
+;	SHIFTED_TEMPLATES, Template, Magfac, Templates, Dx, Dy
+;
+; INPUTS:
+;	Template:	image to be shifted
+;
+;	Magfac:	magnification factor (integer, > 1)
+;
+;	EDGE:	width (in pixel units) of a frame around the shifted template
+;		which is excluded after applying the shift. This is useful to
+;		reject possible edge effects due to interpolation.
+;		All the shifted templates will have x- and y- size given by
+;		(sx - 2*edge) and (sy - 2*edge) respectively.
+;		The default is EDGE = 0.
+;
+;	_EXTRA: keyword parameters of IMAGE_SHIFT (see file 'image_shift.pro')
+;
+; OUTPUTS:
+;	Templates:	stack of shifted templates
+;
+;	Dx, Dy:	1D arrays of fractional shifts. Templates[*,*,n] is the
+;		input template shifted by (Dx[n], Dy[n])
+;
+; RESTRICTIONS:
+;	The shift of the input template is performed by IMAGE_SHIFT applying
+;	some interpolation techniques. Undersampled data should not be shifted
+;	by interpolation. For details, see IMAGE_SHIFT
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999
+;-
+
+PRO shifted_templates, template, magfac, _EXTRA = extra, EDGE = edge, $
+					   templates, dx, dy
+
+	on_error, 2
+	mag = round(magfac) > 1
+	; define shifts
+	nshift = mag + 1L - mag mod 2  &  one = make_array(nshift, VALUE = 1)
+	dx = ((findgen(nshift) - nshift/2) / mag) # one
+	dy = one # ((findgen(nshift) - nshift/2) / mag)
+	nshift = nshift^2  &  dx = reform(dx, nshift)  &  dy = reform(dy, nshift)
+	; define stack of templates
+	if  n_elements(edge) eq 0  then  edge = 0
+	s = size52(template, /DIM) - 2*edge  &  l = [edge, edge]  &  u = l + s - 1
+	templates = make_array(s[0], s[1], nshift, TYPE = size52(template, /TYPE))
+	; compute shifted templates
+	for  n = 0L, nshift - 1  do begin
+	   template_n = image_shift(template, dx[n], dy[n], aux, _EXTRA = extra)
+	   templates[*,*,n] = template_n[l[0]:u[0],l[1]:u[1]]
+	endfor
+	return
+end
diff --git a/simpson_pix_integral.pro b/simpson_pix_integral.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0691d67b0fa444fd873cefd866b455a9bdf7c810
--- /dev/null
+++ b/simpson_pix_integral.pro
@@ -0,0 +1,118 @@
+; $Id: simpson_pix_integral.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	SIMPSON_PIX_INTEGRAL
+;
+; PURPOSE:
+;	Resample a bivariate function defined on a rectangular domain by
+;	integrating it over square regions. The integration is performed
+;	by means of the Simpson rule.
+;
+; CATEGORY:
+;	Mathematics. Integration routines.
+;
+; CALLING SEQUENCE:
+;	Result = SIMPSON_PIX_INTEGRAL(F, Nsteps)
+;
+; INPUTS:
+;	F:	2D array containing the values of the bivariate function
+;
+;	Nsteps:	Number of samples / size of integration interval. The following
+;		relationship must exist between Nsteps and the size S of the input
+;		array (we consider only one dimension for simplicity):
+;		S = FIX(S / Nsteps) * Nsteps + e, where
+;		e = 1 - Nsteps MOD 2.
+;
+; KEYWORD PARAMETERS:
+;	PIX_SIZE:	Set this keyword to the physical value of the pixel size.
+;		The default is PIX_SIZE = 1.
+;
+; OUTPUTS:
+;	Result:	2D array containing the input function integrated
+;		over square sub-regions.
+;
+; PROCEDURE:
+;	Integrate the input function over square sub-domains of N*N points, where
+;	N is related to the input parameter Nsteps by the following relation:
+;	N = Nsteps, if Nsteps is odd
+;	N = Nsteps + 1, if Nsteps is even.
+;	The output array may be thought of as the input function integrated over
+;	larger pixels. The value of each output pixel is the result of the integral
+;	computed over N*N points. If Nsteps is even, two adjacent output pixels
+;	will share one input point: this strategy is necessary when using Simpson
+;	rule (at least its simplest version), which requires an odd number of
+;	points per integration interval.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+
+
+; SIMPSON_COEFF: auxiliary function, compute coefficients for Simpson rule.
+
+FUNCTION simpson_coeff, n, l
+
+	on_error, 2
+	w = fltarr(n)  &  s = lindgen((n - 1)/2)
+	w[2*s] = 2.  &  w[2*s+1] = 4.
+	w[0] = 1.  &  w[n-1] = 1.
+	w = w / 3. * float(l) / (n - 1)
+	return, w
+end
+
+
+FUNCTION simpson_pix_integral, f, nsteps, PIX_SIZE = pixsize
+
+	on_error, 2
+	s = size52(f, /DIM)  &  nstep = round(nsteps)
+	nx = s[0]/nstep  &  ny = s[1]/nstep  &  e = 1 - nstep mod 2
+	if  s[0] ne (nx*nstep + e) or s[1] ne (ny*nstep + e)  then $
+	   message, 'wrong array size'
+	if  n_elements(pixsize) eq 0  then  pixsize = 1.
+	npt = nstep + e  &  half = npt/2
+	w = simpson_coeff(npt, pixsize)  &  wt = transpose(w)
+	lx = half  &  ly = half  &  ux = s[0]-1-half  &  uy = s[1]-1-half
+	intf = fltarr(nx, ny)
+	i = -1L
+	for  y = ly, uy, nstep  do begin
+	   i = i + 1  &  j = -1L
+	   for  x = lx, ux, nstep  do begin
+	      j = j + 1
+		  intf[j,i] = wt # f[x-half:x+half,y-half:y+half] # w
+	   endfor
+	endfor
+	return, intf
+end
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Matrix implementation (for nstep even). More beautiful but slower!
+
+;   FUNCTION simp_coeff_array, nstep, nint
+;
+;	c = simpson_coeff(nstep+1, 1.)
+;	a = fltarr( nstep*nint+1, nint )
+;	for  n = 0, nint-1  do  a[n*nstep,n] = c
+;	return, a
+;  end
+
+;   FUNCTION simpson_pix_integral, f, nstep
+
+;	s = size52(f, /DIM)  &  nstep = round(nstep)
+;	nx = s[0]/nstep  &  ny = s[1]/nstep
+;	if  size52(f, /N_DIM) ne 2  or $
+;		s[0] mod 2 eq 0 or s[1] mod 2 eq 0  or $
+;		nstep mod 2 ne 0  or nx mod 2 ne 0 or ny mod 2 ne 0 $
+;		then return, f
+;	cx = simp_coeff_array( nstep, nx )
+;	if  ny ne nx  then $
+;	   cy = simp_coeff_array( nstep, ny )  else  cy = cx
+;	return, transpose(cx) # f # cy
+;  end
+
+
+
diff --git a/size52.pro b/size52.pro
new file mode 100644
index 0000000000000000000000000000000000000000..a3cc138de217347ff01d057b5611ed2f4c60e086
--- /dev/null
+++ b/size52.pro
@@ -0,0 +1,46 @@
+; $Id: size52.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	SIZE52
+;
+; PURPOSE:
+;	Alias of IDL 5.2 intrinsic SIZE function for previous versions.
+;
+; CATEGORY:
+;	Array informational routines.
+;
+; CALLING SEQUENCE:
+;	Result = SIZE52(X)
+;
+; INPUTS:
+;	X:	IDL variable
+;
+; KEYWORD PARAMETERS:
+;	N_DIMENSION:	Set this keyword to a nonzero value to retrieve the
+;		number of dimensions of X
+;
+;	DIMENSION:	Set this keyword to a nonzero value to retrieve a
+;		long-integer vector containing the size of each dimension of X
+;
+;	TYPE:	Set this keyword to a nonzero value to retrieve the IDL
+;		type code of X
+;
+; OUTPUTS:
+;	Result:	Same as output of SIZE if no keyword is set. Otherwise return
+;		the result specified by the KEYWORD.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION size52, x, N_DIMENSION = ndim, DIMENSION = dim, TYPE = type
+
+	s = size(x)
+	if  keyword_set(ndim)  then  s = s[0]  else $
+	if  keyword_set(dim)  then  begin
+	   if  s[0] le 1  then  s = s[0]  else  s = s[1:s[0]]
+	endif  else $
+	if  keyword_set(type)  then  s = s[s[0] + 1]
+	return, s
+end
diff --git a/sort_list.pro b/sort_list.pro
new file mode 100644
index 0000000000000000000000000000000000000000..7b4f0e0a27ae40ec8b408f2d1099617a831db4a2
--- /dev/null
+++ b/sort_list.pro
@@ -0,0 +1,37 @@
+; $Id: sort_list.pro, v 1.1 Mar 2012 e.d. $
+;
+;+
+; NAME:
+;	SORT_LIST
+;
+; PURPOSE:
+;	Sort stars by decreasing flux.
+;
+; CATEGORY:
+;	STARFINDER auxiliary procedures.
+;
+; CALLING SEQUENCE:
+;	Result = SORT_LIST(List, SUBSCRIPTS = S)
+;
+; INPUTS:
+;	List:	list of stars
+;
+; KEYWORD PARAMETERS:
+;	SUBSCRIPTS:	subscripts of stars to be sorted. If undefined, sort
+;		all stars in the list
+;
+; OUTPUTS:
+;	Return sorted list of sublist, if SUBSCRIPTS is set.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, June 2001.
+;   1) Created this file (E. D., March 2012).
+;-
+
+FUNCTION sort_list, list, SUBSCRIPTS = s
+
+    on_error, 2
+    if  n_tags(list) eq 0  then  return, list
+    s = reverse(sort(list.f))
+    return, list[s]
+end
diff --git a/spline_coeff.pro b/spline_coeff.pro
new file mode 100644
index 0000000000000000000000000000000000000000..59d1f039eeb78404903ff4b4906be22d352650a1
--- /dev/null
+++ b/spline_coeff.pro
@@ -0,0 +1,218 @@
+; $Id: spline_coeff.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	SPLINE_COEFF
+;
+; PURPOSE:
+;	Given a set of observations on a rectangular grid of points,
+;	compute the coefficients of the 2D interpolating spline.
+;
+; CATEGORY:;
+;	Mathematics. Interpolation
+;
+; CALLING SEQUENCE:
+;	SPLINE_COEFF, Data, Coefficients, X_knots, Y_knots, $
+;	              X, Y, Lo_x, Up_x, Lo_y, Up_y
+;
+; INPUTS:
+;	Data:	2D array of data to be interpolated
+;
+; OPTIONAL INPUTS:
+;	X, Y:	Vectors of abscissae and ordinates, in increasing order.
+;		If not provided, a default grid is defined by the function
+;		SAMPLING_GRID
+;
+;	Lo_x, Up_x, Lo_y, Up_y:	Lower and Upper, X- and Y- bounds of
+;		rectangular domain where the observations are assigned.
+;		The following conditions must be fulfilled:
+;		Lo_x <= X <= Up_x, Lo_y <= Y <= Up_y
+;
+; KEYWORD PARAMETERS:
+;	DEGREE:	Integer odd degree of spline. The default is DEGREE = 3.
+;
+; OUTPUTS:
+;	Coefficients:	2D array of spline coefficients, with the same size
+;		size as the input Data. Return a scalar if an error occurs or
+;		if the input parameters are not acceptable.
+;
+;	X_knots, Y_knots:	Vectors of spline knots
+;
+; OPTIONAL OUTPUTS:
+;	X, Y:	Vectors of abscissae and ordinates
+;
+;	Lo_x, Up_x, Lo_y, Up_y:	Lower and Upper, X- and Y- bounds of
+;		rectangular domain where the observations are assigned
+;
+; RESTRICTIONS:
+;	Apply only to 2D data.
+;
+; PROCEDURE:
+;	Apply the procedures described in
+;	Paul Dierckx, "Curve and surface fitting with splines",
+;		Clarendon Press, Oxford (1995)
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;	Adapted in IDL from the sofware FITPACK, written in FORTRAN by P.Dierckx.
+;	Complete references may be found in
+;	Paul Dierckx, "Curve and surface fitting with splines",
+;		Clarendon Press, Oxford (1995)
+;-
+
+
+
+;;; Auxiliary procedures/functions.
+
+; SPL_ASCENDING: given the vector x of size n, check the condition
+; x[i] < x[i+1], for i = 0, n - 2.
+
+FUNCTION spl_ascending, x
+
+	on_error, 2
+	if  size52(x, /N_DIM) gt 1  then  return, 0B
+	n = n_elements(x)
+	check = (x lt shift(x, -1) )[0:n-2] and 1B
+	return, min(check)
+end
+
+; SPL_CHECK_DATA: check input coordinates. If not set, define a default grid.
+
+PRO spl_check_data, data, x, y, lo_x, up_x, lo_y, up_y, error
+
+	on_error, 2
+	error = size52(data, /N_DIM) ne 2  &  if  error  then  return
+	sx = n_elements(x)  &  sy = n_elements(y)
+	if  sx eq 0 or sy eq 0 or $
+	    n_elements(lo_x) eq 0 or n_elements(up_x) eq 0 or $
+	    n_elements(lo_y) eq 0 or n_elements(up_y) eq 0  then begin
+	   s = size52(data, /DIM)  &  sx = s[0]  &  sy = s[1]
+	   x = sampling_grid(sx, 1, lo_x, up_x)
+	   y = sampling_grid(sy, 1, lo_y, up_y)
+	endif else $
+	   error = min(x) lt lo_x  or  max(x) gt up_x  or $
+	   		   min(y) lt lo_y  or  max(y) gt up_y  or $
+	   		   not spl_ascending(x) or not spl_ascending(y)
+	return
+end
+
+; SPL_COMPUTE_KNOTS: 1-D set of knots for spline interpolation of odd degree.
+
+FUNCTION spl_compute_knots, x, a, b, degree, error
+
+	on_error, 2
+	n = n_elements(x)
+	error = n le degree or degree mod 2 eq 0  &  if  error  then  return, 0
+	k = fltarr(n + degree + 1)
+	k[0:degree] = a  &  k[n:n+degree] = b	; additional knots
+	if  n gt degree + 1  then $				; interior knots
+	   k[degree + 1:n - 1] = x[degree/2 + 1:degree/2 + n - degree - 1]
+	return, k
+end
+
+; SPL_GIVPAR: compute parameters for a Givens transformation.
+
+PRO spl_givpar, piv, r, c, s
+
+	on_error, 2
+	abs_piv = abs(piv)
+	if  abs_piv ge r  then $
+	   aux_r = abs_piv * sqrt(1 + (r/piv)^2)  else $
+	   aux_r = r * sqrt(1 + (piv/r)^2)
+	c = r / aux_r  &  s = piv / aux_r  &  r = aux_r
+	return
+end
+
+; SPL_G_ROTATE: rotate vectors v1 and v2 applying a Givens rotation (c,s).
+
+PRO spl_g_rotate, c, s, v1, v2
+
+	on_error, 2
+	u1 = v1  &  u2 = v2
+	v1 = c * u1 - s * u2
+	v2 = s * u1 + c * u2
+	return
+end
+
+; SPL_GIV_TRANSFORM: rotate observation array a and data array d
+; applying Givens rotations.
+
+PRO spl_giv_transform, a, npt, d, degree
+
+	on_error, 2
+	n_points = n_elements(npt)
+	aux_a = a  &  a = a - a
+	aux_d = transpose(d)  &  d = aux_d - aux_d
+	for  n = 0L, n_points - 1  do begin
+	   this = npt[n]  &  va = aux_a[*,n]  &  vd = aux_d[*,n]
+	   for  i = 0, degree  do begin
+	      piv = va[i]
+	      if  piv ne 0  then begin
+	         temp = a[0,this]  &  spl_givpar, piv, temp, c, s   &  a[0,this] = temp
+	         temp = d[*,this]  &  spl_g_rotate, c, s, vd, temp  &  d[*,this] = temp
+	         if  i lt degree  then begin
+	            temp = va[i+1:degree]  &  temp1 = a[1:degree-i,this]
+	            spl_g_rotate, c, s, temp, temp1
+	            va[i+1:degree] = temp  &  a[1:degree-i,this] = temp1
+	         endif
+	      endif
+	      this = this + 1
+	   endfor
+	endfor
+	return
+end
+
+; SPL_BACK_SUB: solve the set of m linear algebraic systems  a x = b,
+; where a is an n*n upper triangular matrix of bandwidth w,
+; x and b are m*n arrays.
+
+FUNCTION spl_back_sub, a, b, w
+
+	on_error, 2
+	s = size52(b, /DIM)  &  m = s[0]  &  n = s[1]
+	x = fltarr(m, n + w - 1)
+	for  i = n - 1, 0, -1  do $
+	   x[*,i] = (b[*,i] -  x[*,i+1:i+w-1] # a[1:w-1,i]) / a[0,i]
+	return, x[*,0:n-1]
+end
+
+; SPL_SOLVE_SYS: compute the coefficients of the interpolating spline
+; as the solution of the linear system  (ay) c (ax)' = data
+
+FUNCTION spl_solve_sys, ax, nptx, ay, npty, data, degree
+
+	on_error, 2
+	d = data
+	; Reduce (ax) to upper triangular form. Apply the same transformation
+	; to the data.
+	spl_giv_transform, ax, nptx, d, degree
+	; Reduce (ay) to upper triangular form. Apply the same transformation
+	; to the data.
+	spl_giv_transform, ay, npty, d, degree
+	; Solve the linear system  (ay) c (ax)' = d
+	temp = spl_back_sub(ay, d, degree + 1)
+	c = spl_back_sub(ax, transpose(temp), degree + 1)
+	return, transpose(c)	; c is (nx) * (ny)
+end
+
+;;; The main routine.
+
+PRO spline_coeff, data, DEGREE = degree, coefficients, $
+   				  x_knots, y_knots, x, y, lo_x, up_x, lo_y, up_y
+
+	on_error, 2
+	coefficients = 0
+	spl_check_data, data, x, y, lo_x, up_x, lo_y, up_y, error
+	if  error  then  return
+	if  n_elements(degree) eq 0  then  degree = 3
+	if  degree mod 2 eq 0  then  degree = degree + 1
+	x_knots = spl_compute_knots(x, lo_x, up_x, degree, error)
+	if  error  then  return
+	y_knots = spl_compute_knots(y, lo_y, up_y, degree, error)
+	if  error  then  return
+	b_splines, x, x_knots, degree, ax, nptx
+	b_splines, y, y_knots, degree, ay, npty			; delta_t = 2.6
+	coefficients = spl_solve_sys(ax, nptx, ay, npty, data, degree)
+													; delta_t = 10.6
+	return
+end
diff --git a/spline_interp.pro b/spline_interp.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2888e2eb6108ef63ef48dec396eadeb12d47646a
--- /dev/null
+++ b/spline_interp.pro
@@ -0,0 +1,66 @@
+; $Id: spline_interp.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	SPLINE_INTERP
+;
+; PURPOSE:
+;	Given the coefficients of a 2D spline, as returned by SPLINE_COEFF,
+;	evaluate the spline on a grid of points.
+;
+; CATEGORY:
+;	Mathematics. Interpolation.
+;
+; CALLING SEQUENCE:
+;	Result = SPLINE_INTERP(C, X_knots, Y_knots, X, Y)
+;
+; INPUTS:
+;	C:	2D array of spline coefficients, returned by SPLINE_COEFF
+;
+;	X_knots, Y_knots:	Vector of spline knots, returned by SPLINE_COEFF
+;
+;	X, Y:	Coordinates of points where the spline function must be
+;		evaluated. The following conditions must be hold:
+;		MIN(X_knots) <= X <= MAX(X_knots)
+;		MIN(Y_knots) <= Y <= MAX(Y_knots)
+;		If some X or Y does not fulfills these conditions, it is replaced
+;		by the corresponding bound on X_knots and Y_knots
+;
+; KEYWORD PARAMETERS:
+;	DEGREE:	Degree of spline. It must be the same as that used in the call
+;		to SPLINE_COEFF. The default value (strongly recommended) is
+;		DEGREE = 3.
+;
+; OUTPUTS:
+;	Result:	2D array of spline evaluations, of size Nx*Ny, where Nx and Ny
+;		are the number of elements in the input vectors X and Y
+;
+; RESTRICTIONS:
+;	Apply only to 2D data.
+;
+; PROCEDURE:
+;	Apply the procedures described in
+;	Paul Dierckx, "Curve and surface fitting with splines",
+;		Clarendon Press, Oxford (1995)
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;	Adapted in IDL from the sofware FITPACK, written in FORTRAN by P.Dierckx.
+;	Complete references may be found in
+;	Paul Dierckx, "Curve and surface fitting with splines",
+;		Clarendon Press, Oxford (1995)
+;-
+
+FUNCTION spline_interp, c, x_knots, y_knots, x, y, DEGREE = degree
+
+	on_error, 2
+	if  n_elements(degree) eq 0  then  degree = 3
+	x_points = (x > min( x_knots)) < max(x_knots)
+	y_points = (y > min( y_knots)) < max(y_knots)
+	b_splines, x_points, x_knots, degree, bx, kx, /BOUNDS, /FULL
+	b_splines, y_points, y_knots, degree, by, ky, /BOUNDS, /FULL
+											; delta_t = 2.7
+	return, transpose(bx) # c # by		; delta_t = 336
+			; NOTE: the array implementation is faster than the
+			; component-wise by a factor of 2 for an array 128*128
+end
diff --git a/stack_combine.pro b/stack_combine.pro
new file mode 100644
index 0000000000000000000000000000000000000000..843302dbeab2fbfae20ef6cd28b06ba69f56bca6
--- /dev/null
+++ b/stack_combine.pro
@@ -0,0 +1,106 @@
+; $Id: stack_combine.pro, v 1.2 July 2006 e.d. $
+;
+;+
+; NAME:
+;   STACK_COMBINE
+;
+; PURPOSE:
+;   Combine frames in a 3D stack by average, average with sigma-rejection
+;  or median.
+;
+; CATEGORY:
+;   Signal processing.
+;
+; CALLING SEQUENCE:
+;   Result = STACK_COMBINE(Stack)
+;
+; INPUTS:
+;   Stack:    3D array, representing the stack of frames to be combined
+;
+; KEYWORD PARAMETERS:
+;   AVGTYPE:  Set this keyword to choose a combination algorithm among
+;     the following possibilities:
+;     AVGTYPE = 0 [default]: pixel-by-pixel average
+;             = 1: pixel-by-pixel minimum
+;             = 2: pixel-by-pixel median
+;
+;   MASK: 3D binary array used to mask the frames in the Stack.
+;     The n-th frame of the 3D array Mask passed with this keyword may
+;     be defined as follows:
+;     Mask[j, i, n] = 1, if  Stack[j, i, n] is a valid pixel
+;                   = 0, if  Stack[j, i, n] must be rejected
+;     The default is no masking.
+;
+;   WEIGHTS:  Set this keyword to a N-components vector, where N is the
+;     number of frames in the Stack. The n-th component is the weight to
+;     apply to the n-th input frame. The weights must be positive and
+;     non-zero.
+;     If the median is used, then the weights are divided by their minimum
+;     value and rounded to integers. Every plane in the Stack is then
+;     replicated a number of times equal to the corresponding weight.
+;     This keyword has no effect when AVGTYPE = 1.
+;
+;   NSTDEV:   when the average with sigma-clipping is used, the outliers to
+;     be excluded from the computation are defined as those values whose
+;     absolute distance from the median of the sample is larger than NSTDEV
+;     times the standard deviation of the sample.
+;
+; OUTPUTS:
+;   Result:   2D array, given by the combination of the planes in the Stack.
+;
+; MODIFICATION HISTORY:
+;   Written by:  Emiliano Diolaiti, September 2001.
+;   1) Mean and median average only (E.D. May 2005)
+;   2) Added option for combination with MIN operator (E.D. July 2006)
+;-
+
+FUNCTION stack_combine, stack, MASK = mask, WEIGHTS = weights, $
+                         AVGTYPE = avgtype, _EXTRA = extra
+
+    on_error, 2
+    ; Default average type
+    if  n_elements(avgtype) eq 0  then  avgtype = 0
+    ; Stack size
+    if  size52(stack, /N_DIM) ne 3  then  return, stack
+    s = size52(stack, /DIM)  &  s0 = s[0]  &  s1 = s[1]  &  n_frames = s[2]
+    ; Mask some frames?
+    masked = n_elements(mask) ne 0
+    ; Weighted average?
+    weighted = n_elements(weights) ne 0
+    if  weighted  then  weighted = min(weights) gt 0
+    if  weighted  then  w = weights  else  w = replicate(1, n_frames)
+    w = w / total(w)
+    if  weighted and avgtype eq 2  then  w = round(w / min(w))
+    ; Combine planes of the stack
+    if  avgtype eq 0  then begin
+       wstack = replicate(w[0], s0, s1)
+       for  n = 1, n_frames - 1  do  $
+          wstack = [[[wstack]], [[replicate(w[n], s0, s1)]]]
+       m = total(wstack * stack, 3)
+    endif else begin
+       m = make_array(s0, s1, TYPE = size52(stack, /TYPE))
+       for  i = 0L, s1 - 1  do  for  j = 0L, s0 - 1  do begin
+          slice = stack[j,i,*]  &  w_ji = w  &  n = n_frames
+          ; Mask undesired frames
+          if  masked  then begin
+             accept = where(mask[j,i,*] ne 0, n)
+             if  n ne 0  then begin
+                slice = slice[accept]  &  w_ji = w_ji[accept]
+             endif
+          endif
+          ; If median is applied, replicate frames according to their weight
+          if  avgtype eq 2 and weighted and n ne 0  then begin
+             temp = replicate(slice[0], w_ji[0])
+             for  k = 1L, n - 1  do $
+                temp = [temp, replicate(slice[k], w_ji[k])]
+             slice = temp
+          endif
+          ; Compute average of pixel [j,i]
+          if  n ne 0  then $
+             if  avgtype eq 1  then $
+                m[j,i] = min(slice)  else $
+                m[j,i] = median(slice, /EVEN)
+       endfor
+    endelse
+    return, m
+end
diff --git a/star.pro b/star.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f6cb4b0944b0acde525cedb506d396028e119cf4
--- /dev/null
+++ b/star.pro
@@ -0,0 +1,34 @@
+; $Id: star.pro, v 1.1 Mar 2012 e.d. $
+;
+;+
+; NAME:
+;	STAR
+;
+; PURPOSE:
+;	Create named structure, called "starlet", representing a star.
+;	This structure is the basic element of a list of stars, which
+;	might both accepted stars and still presumed ones.
+;
+; CATEGORY:
+;	STARFINDER auxiliary procedures.
+;
+; CALLING SEQUENCE:
+;	Result = STAR()
+;
+; OUTPUTS:
+;	Return "starlet" structure
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, June 2001.
+; 	1) Created this file (E. D., March 2012).
+;-
+
+FUNCTION star
+
+    return, {starlet, $
+             x: 0., sigma_x: 0., $   ; x- coordinate and error
+             y: 0., sigma_y: 0., $   ; y- coordinate and error
+             f: 0., sigma_f: 0., $   ; flux and error
+             c: -1., $              ; correlation
+             is_a_star: 0B}            ; flag
+end
diff --git a/star_param.pro b/star_param.pro
new file mode 100644
index 0000000000000000000000000000000000000000..4a4ac9e2d5a76fb2f49310916f30c57dd4865c5c
--- /dev/null
+++ b/star_param.pro
@@ -0,0 +1,57 @@
+; $Id: star_param.pro, v 1.1 Mar 2012 e.d. $
+;
+;+
+; NAME:
+;	STAR_PARAM
+;
+; PURPOSE:
+;	Extract stars parameters from star list, possibly including
+;	presumed stars.
+;
+; CATEGORY:
+;	STARFINDER auxiliary procedures.
+;
+; CALLING SEQUENCE:
+;	STAR_PARAM, List, SUBSCRIPTS = S, $
+;	            N, X, Y, F, C, Sigma_X, Sigma_Y, Sigma_F
+;
+; INPUTS:
+;	List:	list of stars
+;
+; KEYWORD PARAMETERS:
+;	SUBSCRIPTS:	1D vector of subscript of stars to be extracted.
+;		If undefined, extract parameters of all true stars in the list.
+;
+; OUTPUTS:
+;	N:	number of extracted stars
+;
+;	X, Y, F:	position and flux of stars
+;
+;	C:	correlation coefficienf
+;
+;	Sigma_X, Sigma_Y, Sigma_F:	errors on position and flux
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, June 2001.
+;   1) Created this file (E. D., March 2012).
+;-
+
+PRO star_param, list, SUBSCRIPTS = s, $
+                 n, x, y, f, c, sigma_x, sigma_y, sigma_f
+
+    on_error, 2
+    if  n_tags(list) eq 0  then begin
+       n = 0L  &  s = -1L  &  return
+    endif
+    n = n_elements(s)
+    if  n eq 0  then begin
+       n = n_elements(list)  &  s = lindgen(n) ; extract all elements
+    endif
+    if  s[0] lt 0  then  n = 0  else begin $
+       x = list[s].x  &  sigma_x = list[s].sigma_x
+       y = list[s].y  &  sigma_y = list[s].sigma_y
+       f = list[s].f  &  sigma_f = list[s].sigma_f
+       c = list[s].c
+    endelse
+    return
+end
diff --git a/starfinder.pro b/starfinder.pro
new file mode 100644
index 0000000000000000000000000000000000000000..d6482d8290eded33ac37019cba9f454f0d86f78d
--- /dev/null
+++ b/starfinder.pro
@@ -0,0 +1,1197 @@
+; $Id: starfinder.pro, v 1.8.2a May 2014 e.d. $
+;
+;+
+; NAME:
+;   STARFINDER
+;
+; PURPOSE:
+;   Given a stellar field and an approximation of the Point Spread Function
+;   (PSF), detect the stellar sources and estimate their position and flux.
+;   The image may be contaminated by a smooth non-uniform background emission.
+;   If the imaged field is not isoplanatic, it is possible to partition it
+;   into approximately isoplanatic sub-regions, provided a local estimate of
+;   the PSF is available. In this case, the field is analyzed as a whole as
+;   in the constant PSF case, with the only difference that the local PSF is
+;   used to analyze each star. 
+;   A spatially variable PSF may also be handled by providing a parametric 
+;   PSF model variable across the imaged field.
+;
+; CATEGORY:
+;   Signal processing. Stellar fields astrometry and photometry.
+;
+; CALLING SEQUENCE:
+;   STARFINDER, Image, Psf, Threshold, Min_correlation, $
+;               X, Y, Fluxes, Sigma_x, Sigma_y, Sigma_f, Correlation
+;
+; INPUTS:
+;   Image:    2D image of the stellar field
+;
+;   Psf:  2D array, representing the Point Spread Function of the stellar
+;     field. If the PSF is space-variant, Psf is a 3D stack of local
+;     PSF measurements, relative to a partition of the imaged field into
+;     sub-regions arranged in a regular grid. In this case it is necessary
+;     to supply the bounds of the partition (see keyword SV_PAR).
+;
+;   Threshold:    Vector of lower detection levels (above the local background,
+;     which is temporarly removed before detection). These levels are
+;     assumed to be "absolute" levels by default. If the keyword
+;     REL_THRESHOLD (see below) is set and the noise standard deviation is
+;     defined (see the keyword NOISE_STD) below, then the threshold levels
+;     are assumed to be "relative", i.e. expressed in units of the noise
+;     standard deviation.
+;     Example 1: let Threshold be = [10., 3.]
+;      If the keyword REL_THRESHOLD is not defined or the keyword
+;      parameter NOISE_STD is undefined, the threshold levels 10 and 3
+;      are absolute intensity levels, i.e. all the peaks brighter than 10
+;      and 3 counts are considered as presumed stars. If REL_THRESHOLD is
+;      set and NOISE_STD is defined, the intensity levels for detection
+;      are respectively (10 * NOISE_STD) and (3 * NOISE_STD).
+;     The number of elements of the vector Threshold establishes the number
+;     of iterations of the "basic step" (see PROCEDURE below).
+;     The components of the vector Threshold may be all equal or decreasing.
+;
+;   Min_correlation:  Minimum value of correlation between an acceptable
+;     stellar image and the Psf. It must be > 0 and < 1.
+;
+; KEYWORD PARAMETERS:
+;   SV_PAR:   Set this keyword to a structure defining the bounds of the
+;     imaged field partition when the PSF is not isoplanatic.
+;     Let the imaged field be partitioned into Nx*Ny sub-regions, such
+;     that the (j, i)-th region is bounded by
+;     Lx[j] < x < Ux[j], Ly[i] < y < Uy[i], where
+;     j = 0, ..., Nx - 1; i = 0, ..., Ny - 1.
+;     The structure must be defined as follows:
+;     SV_PAR = {Lx: Lx, Ux: Ux, Ly: Ly, Uy: Uy}.
+;     The (j, i)-th sub-region must correspond to the k-th psf in the 3D
+;     stack, where k = i*Nx + j.
+;     
+;   PSF_TYPE: Set this keyword to a string indicating the name of a PSF 
+;     model. Available PSF models are defined in the documentation of the 
+;     routine IMAGE_MODEL (see documentation of the input parameter Psf in 
+;     the file IMAGE_MODEL.PRO). This keyword has to be used together with 
+;     the keyword PSF_DATA.
+;     The keywords PSF_TYPE and PSF_DATA are useful to define a parametric 
+;     PSF model, that can be made variable across the field of view, 
+;     depending on how it is defined in IMAGE_MODEL.PRO.
+;     When PSF_TYPE and PSF_DATA are used, the input parameter Psf and the 
+;     keyword parameter SV_PAR described above have to be supplied anyway, 
+;     as they are used in the preliminary phases of the analysis.
+;   
+;   PSF_DATA: Use this keyword to provide a pointer to the auxiliary data
+;     required by the PSF model defined by the keyword PSF_TYPE, when it is 
+;     used. Auxiliary data are defined according to the documentation of the 
+;     input parameter Data in the file IMAGE_MODEL.PRO.
+;
+;   REL_THRESHOLD:    Set this keyword to specify that the detection levels
+;     contained in the input parameter Threshold have to be considered as
+;     "relative" levels, i.e. they must be multiplied by the noise standard
+;     deviation. This keyword is effective only if the NOISE_STD is defined
+;     (see below).
+;
+;   X_BAD, Y_BAD: Coordinates of bad pixels to be excluded.
+;     It is important to mask bad pixels, especially in the following phases
+;     of the analysis:
+;     1) search for presumed stars
+;     2) correlation check
+;     3) local fitting.
+;
+;   BACKGROUND:   2D array, containing an initial guess of the image background
+;     emission. If the keyword is undefined, the background is estimated
+;     automatically, provided the box size BACK_BOX (see below) is defined.
+;     The background estimate is subtracted before searching for presumed
+;     stars in the image and before computing the correlation coefficient.
+;
+;   BACK_BOX: Set this keyword to a scalar value specifying the box size
+;     to estimate the background emission. For more details see the routine
+;     ESTIMATE_BACKGROUND in the file "estimate_background.pro".
+;     The value of this keyword may be conveniently defined as a multiple
+;     of the PSF Full Width at Half Maximum (e.g. 5 * FWHM).
+;     If if is not supplied, the program uses the argument of the keyword
+;     BACKGROUND (if defined of course!) as a background estimate. However
+;     this will prevent any improvements in the background knowledge in the
+;     course of iterations. If the stellar field is supposed to have no
+;     background emission, the keywords BACKGROUND and BACK_BOX should be
+;     left undefined.
+;
+;   For other keywords concerning background estimation see the routines
+;   IMAGE_BACKGROUND and ESTIMATE_BACKGROUND.
+;
+;   FOUR: Set this keyword to identify relative maxima referring only to
+;     the 4-neighbors of each pixel. The default is to use 8-neighbors.
+;
+;   PRE_SMOOTH:   Set this keyword to smooth the image with a standard low-pass
+;     filter before searching for local maxima. This reduces the probability
+;     to pick up noise spikes, which would increase the computation time for
+;     further checks and the probability of false detections.
+;     For more details see the procedure SEARCH_OBJECTS, in the file
+;     "search_objects.pro".
+;
+;   MINIF:    If PRE_SMOOTH is set, the keyword MINIF may be used to enter the
+;     integer minification factor used to down-sample the image before
+;     searching for local maxima, as an alternative smoothing strategy to
+;     the standard low-pass filter used by default when PRE_SMOOTH is set.
+;
+;   CORREL_MAG:   Set this keyword to an integer scalar specifying the sub-pixel
+;     accuracy with which the template PSF should be superposed to a given
+;     object when computing the correlation coefficient.
+;     If CORREL_MAG = 1, the PSF is superposed to the
+;     object just taking the maximum intensity pixel as a reference.
+;     If CORREL_MAG is > 1, all the possible fractional shifts of the PSF,
+;     with step size of 1/CORREL_MAG, are considered.
+;     The default value is CORREL_MAG = 2 (half pixel positioning).
+;
+;   DEBLEND:  Set this keyword to a nonzero value to perform de-blending
+;     of the objects detected iterating the basic step (see PROCEDURE).
+;     This de-blending strategy allows the algorithm to detect secondary
+;     components of crowded groups, whose principal component has previously
+;     been detected as a single star. This strategy may be referred to as
+;     'partial de-blending'.
+;
+;   DEBLOST:  Set this keyword to a nonzero value to recover all the
+;     significant intensity enhancement lost in the course of the analysis,
+;     in order to search for possible blends. This strategy allows the
+;     algorithm to re-analyze the blended objects whose principal component
+;     has not been previously found as a single star (see DEBLEND above).
+;     This strategy, applied after the 'partial de-blending' described with
+;     the keyword DEBLEND above, may be referred to as 'full de-blending'.
+;     More details can be found in the PROCEDURE description below.
+;
+;   CUT_THRESHOLD:    Set this keyword to a scalar value in the range ]0, 1[
+;     to specify the relative threshold to use when "cutting" a given
+;     object to measure its area. The default is CUT_THRESHOLD = 0.5,
+;     i.e. the object is cut at 50% of the peak height. Notice that the
+;     background is subtracted beforehands. Notice also that if the
+;     absolute value of the threshold for binary detection is comparable
+;     to the gaussian noise level (see also keywords GAUSSIAN_NOISE and
+;     BIN_N_STDEV), the estimated area of the object is not reliable: thus
+;     deblending is not applied. This check on the threshold value is
+;     performed only if the gaussian noise standard deviation is defined
+;     (see the keyword GAUSSIAN_NOISE).
+;     For more details on the determination of the area, see the routine
+;     PEAK_AREA in the file "peak_area.pro".
+;
+;   BIN_N_STDEV:  Set this keyword to a positive scalar to specify the
+;     minimum cutting threshold for binary detection, in units of the
+;     gaussian noise standard deviation. The default value is
+;     BIN_N_STDEV = 3.
+;
+;   BIN_THRESHOLD:    When a crowded group (in the simplest case a close binary
+;     star) is analyzed, the deblending algorithm searches for residuals
+;     representing secondary components by subtracting the known sources:
+;     The brightest local maximum in the residual sub-image is taken as a
+;     candidate secondary star. In principle the detection threshold used
+;     for isolated objects, set by the parameter Threshold described above,
+;     should not be applied in this case, because the residual is affected
+;     by the poor knowledge about the subtracted components.
+;     BIN_THRESHOLD specifies the relative threshold, in units of the
+;     parameter Threshold, to use for the detection of candidate secondary
+;     sources in crowded groups. The default is BIN_THRESHOLD = 0, i.e. all
+;     the positive residuals (remember that the local background level has
+;     been removed!) are considered. Their intensity is compared to the
+;     detection threshold after fitting: if the fitted intensity happens to;
+;     be below the value set by Threshold, the new secondary component is
+;     rejected.
+;
+;   BIN_TOLERANCE:    An object is classified as "blend" if the relative error;
+;     between its area and the area of the PSF is greater than the threshold
+;     fixed by this keyword. The default is BIN_TOLERANCE = 0.2, i.e. 20%.
+;
+;   NOISE_STD:    Set this keyword to a 2D array, with the same size as Image,
+;     representing the noise standard deviation in each pixel of the input
+;     data. This array is used to compute the formal errors on astrometry
+;     and photometry.
+;
+;   NO_SLANT: Set this keyword to avoid fitting the local background with
+;     a slanting plane. In this case the background to use for the local
+;     fit of the stars is derived from the 2D background array and it is
+;     kept fixed in the fitting. This option should be used only if the
+;     (input) estimate of the image background is very accurate.
+;
+;   MIN_DISTANCE: Minimum distance, expressed in units of the PSF FWHM, to
+;     consider two sources as separated. This parameter is used to check the
+;     outcome of the fitting of a group of neighboring sources: if two sources
+;     are closer than this limit, the fit is considered unacceptable and the
+;     last detected source is rejected as a false detection.
+;     The default value is 1 (which means 1 PSF FWHM).
+;
+;   N_ITER:   At the end of the analysis, the detected stars are fitted again
+;     a number of times equal to the value specified with this keyword.
+;     The default is N_ITER = 1. To avoid re-fitting, set N_ITER = 0.
+;     Notice that the final number of re-fitting iterations includes also
+;     the extra re-fitting which is normally performed after each basic
+;     step (see also the keyword NO_INTERMEDIATE_ITER).
+;
+;   NO_INTERMEDIATE_ITER: The currently detected stars are re-fitted after
+;     each basic step. Set NO_INTERMEDIATE_ITER to avoid this re-fitting.
+;
+;   ASTROMETRIC_TOL, PHOTOMETRIC_TOL: When the last re-fitting is iterated
+;     a lot of times, it is possible to stop the iterations when convergence
+;     on stellar positions and fluxes is achieved. The default values for
+;     convergence are ASTROMETRIC_TOL = 0.01 pixels and
+;     PHOTOMETRIC_TOL = 0.01 (i.e. 1%).
+;     In practice setting N_ITER = 1 or 2 is generally enough to obtain
+;     reliable astrometry and photometry, without having to iterate a lot.
+;
+;   X_INPUT, Y_INPUT, F_INPUT: vectors with positions and fluxes of the stars,
+;     when these are already known. When these parameters are defined, no
+;     search is performed: the known sources are just fitted a pre-fixed number
+;     of times (see N_ITER) or until convergence (see ASTROMETRIC_TOL and
+;     PHOTOMETRIC_TOL). The sources are sorted by decreasing flux. 
+;     Usual checks applied in fitting procedure are applied (minimum flux 
+;     above threshold, minimum distance between any two stars). 
+;     When this option is used, single-component fitting is performed, i.e. 
+;     stars closer than the fitting box width are fit one at a time.
+;     Input sources for which the fit fails are rejected.
+;     *** Recommendation. When this option is used, the following keyword 
+;         should be set: 
+;         MIN_DISTANCE = 0.0
+;     In order to avoid optimizing the input positions set the keyword /FLUXOPT 
+;     (see below). In this case, the positions are kept fixed to the input values, 
+;     only fluxes are optimized.
+;     
+;   FLUXOPT: Set this binary keyword to keep the positions of the sources 
+;     fixed in the optimization process when an input list of sources is given 
+;     (see keywords X_INPUT, Y_INPUT, F_INPUT above).
+;
+;   C_INPUT: when an input list of sources is given (see keywords X_INPUT, 
+;     Y_INPUT, F_INPUT above), the keyword C_INPUT may be used to provide the 
+;     correlation coefficients of the sources (detemined in a previous detection 
+;     run). These correlation coefficients are just retained on output, associated 
+;     to the sources for which the fit process is successful.
+;
+;   SVDINV: The fitting process is performed by a Newton-Gauss method. 
+;     This method requires a matrix inversion at every iteration. 
+;     Set this keyword to perform this matrix inversion by SVD (Singular 
+;     Value Decomposition). The default is matrix inversion by Moore-Penrose 
+;     Generalized Inverse (see routine 'ginv.pro').
+;     
+;   SILENT: Set this keyword to avoid printing messaged to the output window.
+;     If not set, STARFINDER prints messages about the current analysis step and 
+;     about the candidate and detected stars. "Candidate stars" are the peaks 
+;     found in the image; "Detected stars" are the peaks which are confirmed to be 
+;     stars in the analysis. The number of "Candidate stars" does not account for 
+;     the additional candidate peaks found with the deblending procedure. 
+;
+; OUTPUTS:
+;   X, Y: Coordinates of detected stars in pixel units.
+;     The origin is at (0, 0).
+;
+;   Fluxes:   Vector of stellar fluxes, referred to the normalization of the Psf.
+;
+;   Sigma_x, Sigma_y, Sigma_f:    Vector of formal errors on positions and
+;     fluxes, estimated by the fitting procedure.
+;     These vectors have all components equal to zero if no information is
+;     supplied about noise: in this case it has no meaning to estimate the
+;     error propagation in the fit.
+;
+;   Correlation:  Vector of correlation coefficients for accepted stars.
+;     Stars belonging to crowded groups detected with the de-blending
+;     procedure have a correlation coefficient of -1.
+;
+; OPTIONAL OUTPUTS:
+;   BACKGROUND:   Last estimate of the image background, computed by the
+;     program after the iteration corresponding to the lowest
+;     detection level.
+;
+;   STARS:    2D array, containing one shifted scaled replica of the PSF for
+;     each detected star.
+;
+; SIDE EFFECTS:
+;   If the keyword NOISE_STD is set to a scalar value it is transformed into
+;   a 2D constant array with the same size as the input image.
+;
+; RESTRICTIONS:
+;   1) The algorithm is based on the assumption that the input Image may
+;   be considered as a superpositions of stellar sources and a smooth
+;   background.
+;   2) Saturated stars should have been approximately repaired beforehands.
+;   This is especially important for the reliable detection and analysis of
+;   fainter sources in their surrounding.
+;   3) High accuracy astrometry and photometry are based on sub-pixel
+;   positioning of the input PSF. In this version of the algorithm this
+;   relies on interpolation techniques, which are not suited to undersampled
+;   data. Thus the algorithm, at least in its present form, should not be
+;   used with poorly sampled data.
+;   4) The keyword /FLUXOPT should be used only when a list of input sources 
+;   is given and the input position estimates are very accurate.
+;
+; PROCEDURE:
+;     The standard analysis is accomplished as a sequence of "basic steps".
+;   One of these steps consists of 3 phases:
+;   1) detection of presumed stars above a given threshold
+;   2) check and analysis of detected objects, sorted by decreasing
+;      intensity
+;   3) re_fitting
+;   Pixel (x,y) is the approximate center of a presumed star if
+;   a) Image(x,y) is a local maximum
+;   b) Image(x,y) > Background(x,y) + Stars(x,y) + Threshold,
+;   where Image is the stellar field, Background is an approximation of
+;   the background emission, Stars is a sum of shifted scaled replicas
+;   of the PSF (one for each detected star) and Threshold is the
+;   minimum central intensity of a detectable star. In practice the user
+;   provides a set of Threshold levels (generally decreasing!): the
+;   number of these levels fixes the number of times the basic step is
+;   repeated.
+;   At the first iteration of the basic step, the "image model" called
+;   Stars is identically zero; in later iterations it contains the detected
+;   sources. Subtraction of these stars simplifies the detection of fainter
+;   objects and allows a better estimation of the image Background.
+;   It should be noticed that the model of detected stars (Stars) is
+;   subtracted only in order to detecte new presumed stars and refine the
+;   background, whereas the subsequent astrometric and photometric analysis
+;   is performed on the original Image.
+;     Let us describe in detail how the presumed stars are analyzed (Phase
+;   2 of each basic step).
+;   First of all each object in the newly formed list is "re-identified",
+;   i.e. searched again after subtraction of other brighter sources: this
+;   allows to reject many spurious detections associated to PSF features
+;   of bright stars. The object is compared with the PSF by a correlation
+;   check and accepted only if a sufficient similarity is found. Then it is
+;   fitted to estimate its position and flux. The local fitting is performed
+;   by FITSTARS (see the file "fitstars.pro" for more details), which takes
+;   into consideration all the following contributions:
+;   a) other known stars in the fitting box, which are fitted along with
+;   the object under examination (multiple fitting)
+;   b) known stars lying outside the fitting box: this term is extracted
+;   from the image model Stars and considered as a fixed contribution
+;   c) the local background, which may be approximated either with a
+;   slanting plane (whose coefficients are optimized as well) or with a
+;   sub-image extracted from the image Background (kept fixed).
+;   If the fit is successful, the parameters of the stars are saved and
+;   the image model Stars is updated.
+;     The basic step (phases 1 + 2 + 3) may be iterated: a new list of
+;   objects is formed by searching in the image after subtraction of the
+;   previously detected stars. Then the analysis proceeds on the original
+;   frame. This iteration is very useful to detect hidden objects, e.g.
+;   close binaries down to separations comparable to 1 PSF FWHM.
+;     An optional deblending strategy is available, consisting of two
+;   separate phases. The first step (see keyword DEBLEND) consists of a search
+;   for secondary sources around the objects detected in the earlier phases of
+;   the analysis; in the second step (see keyword DEBLOST) all the significant
+;   intensity enhancement previously discarded are recovered and a check is
+;   performed in order to find among these some possible blends. Blends are
+;   recognized on the basis of their larger extension as compared to the PSF.
+;   The area of a given object is measured by a thresholding technique, applied
+;   at a specified threshold below the peak. When an object is recognized as a
+;   blend, deblending is attempted iteratively by searching for a new residual
+;   and subsequent fitting. The iteration is stopped when no more residual is
+;   found or the fitting of the last residual is not successful. The deblending
+;   procedure is applied at the end of the last iteration of the basic step
+;   described above, i.e. when all the "resolved" objects are supposed to have
+;   been detected.
+;     It should be stressed that step 3 (re-fitting) has the goal to improve 
+;   the astrometric and photometric measurement of the detected stars. If the 
+;   fit of a given source fails, however, the source (which has already been 
+;   identified as a true one) is not rejected: its parameters are simply 
+;   set to their previous value, without any update.
+;
+; MODIFICATION HISTORY:
+;   Written by:  Emiliano Diolaiti, August-September 1999.
+;   Updates:
+;   1) New partial deblending strategy (Emiliano Diolaiti, October 1999).
+;   2) Full deblending strategy (Emiliano Diolaiti, February 2000).
+;   3) Added PSF stack option; this version might not handle properly
+;      very close groups of objects lying on the boundary of two adjacent
+;      sub-regions (Emiliano Diolaiti, February 2000).
+;   4) Modified keyword parameters in auxiliary routines to avoid trouble
+;      under IDL 5.0 (Emiliano Diolaiti, May 2000).
+;   5) Modified STARFINDER_FIT module. Now faster.
+;      (Emiliano Diolaiti, December 2000).
+;   6) Moved auxiliary routines to handle the list of stars in the
+;      program module STARLIST. (Emiliano Diolaiti, June 2001).
+;   7) Modified STARFINDER_DEBLEND module. Now faster.
+;      (Emiliano Diolaiti, June 2001).
+;   8) PSF stack option (see modification no. 3): fixed problem with stars
+;      lying close to boundary between adjacent sub-regions
+;      (E.D., December 2004). DEBLEND option not checked with PSF stack option.
+;   9) Increased minimum distance between two stars to 1 FWHM.
+;   10) Increased box width for distance check in STARFINDER_CHECK module
+;      (after suggestion by Jessica Lu, May 2005).
+;   11) Temporarily removed modification no. 10 and restored previous version
+;       for trouble at image edge.
+;   12) Added keywords X_INPUT, Y_INPUT, F_INPUT for fitting a set of known
+;       stars. Not yet tested with space-variant PSF (E. D., February 2006).
+;   13) Added keyword MIN_DISTANCE, to set minimum acceptable distance between
+;       two stars (E. D., August 2006).
+;   14) Fixed parameter value: fitting box size was not properly set with 
+;       keywords X_INPUT, Y_INPUT, F_INPUT (E. D., March 2012).
+;   15) When an input list of sources is given (keywords X_INPUT, Y_INPUT, 
+;       F_INPUT), the sources for which the fit fails are rejected
+;       (E. D., March 2012).
+;   16) Keyword "re_fitting" turned into a positional parameters in modules 
+;       STARFINDER_FIT, STARFINDER_DEBLEND, STARFINDER_ANALYZE (E. D., March 2012).
+;   17) Fixed bug about keyword MIN_DIST: 0 value was not accepted before
+;       (E. D., March 2012).
+;   18) Added keyword SVDINV (E. D., March 2012).
+;   19) Changed some output messages in VERBOSE mode (E.D., March 2012).
+;   20) Created separate source files for all auxiliary routines described 
+;       at point 6) (E. D., March 2012).
+;   21) Changed default value of keyword CUT_THRESHOLD = 0.5 (E.D., March 2012).
+;   22) Added keyword MAG=3 in call to PEAK_WIDTH in module 
+;       STARFINDER_DEB_PAR (E.D., March 2012).
+;   23) Added keyword FLUXOPT (E.D., April 2012).
+;   24) Removed check MAX_DIST in module STARFINDER_DEBLEND (E.D., April 2012).
+;   25) Set default value of keyword CORREL_MAG = 2 (E.D., April 2012).
+;   26) Removed bug in STARFINDER_FIT module: sometimes very close sources 
+;       were swapped by call to COMPARE_LISTS (E.D., April 2012).
+;   27) Updated documentation (E. D., May 2014).
+;-
+
+
+
+;;; Auxiliary procedures/functions to handle list of stars data structure.
+
+
+;FUNCTION star
+;
+;PRO update_list, list, SUBSCRIPTS = s, x, y, f, c, $
+;                  sigma_x, sigma_y, sigma_f, IS_STAR = is_star
+;
+;FUNCTION create_element, x, y, f
+;
+;FUNCTION merge_list, l1, l2
+;
+;FUNCTION add_subscript, subscripts, s
+;
+;FUNCTION delete_element, list
+;
+;PRO star_param, list, SUBSCRIPTS = s, $
+;                 n, x, y, f, c, sigma_x, sigma_y, sigma_f
+;
+;FUNCTION where_stars, list, LX = lx, UX = ux, LY = ly, UY = uy, n
+;
+;FUNCTION extract_stars, list, n
+;
+;FUNCTION sort_list, list, SUBSCRIPTS = s
+;
+;FUNCTION reverse_class, list, SUBSCRIPTS = s
+;
+;FUNCTION starlist, n, x, y, f, c
+;
+
+
+
+;;; Auxiliary procedures/functions to define the program's parameters.
+
+; STARFINDER_FWHM: compute PSF FWHM.
+
+FUNCTION starfinder_fwhm, psf, n_psf
+
+    on_error, 2
+    fw = fltarr(n_psf)
+    for  n = 0L, n_psf - 1  do  fw[n] = fwhm(psf[*,*,n], /CUBIC, MAG = 3)
+    return, fw
+end
+
+; DEFINE_CORR_BOX: define correlation box size.
+
+FUNCTION define_corr_box, psf_fwhm
+
+    on_error, 2
+    box = round(1.5 * psf_fwhm)
+    box = box + 1 - box mod 2
+    return, box
+end
+
+; DEFINE_FIT_BOX: define fitting box size.
+
+FUNCTION define_fit_box, psf_fwhm, WIDER = wider
+
+    on_error, 2
+    if  keyword_set(wider)  then  b = 2.  else  b = 1.
+    box = round(define_corr_box(psf_fwhm) > 5 + b * psf_fwhm)
+    box = box + 1 - box mod 2
+    return, box
+end
+
+; STARFINDER_ID_PAR: define parameters to re-identify presumed stars.
+
+FUNCTION starfinder_id_par, psf_fwhm, FOUR = four
+
+    on_error, 2
+    box = define_fit_box(psf_fwhm)
+    neigh4 = keyword_set(four) and 1B
+    return, {box: box, neigh4: neigh4}
+end
+
+; STARFINDER_CORR_PAR: define parameters for correlation.
+
+FUNCTION starfinder_corr_par, psf, psf_fwhm, n_psf, CORREL_MAG = correl_mag, $
+                              _EXTRA = extra
+
+    on_error, 2
+    correlation_box = define_corr_box(psf_fwhm)
+    search_box = correlation_box / 2
+    search_box = search_box + 1 - search_box mod 2
+    if  n_elements(correl_mag) eq 0  then  correl_mag = 2
+    if  correl_mag gt 1  then  edge = 2  else  edge = 0
+    temp_siz = correlation_box + 2 * edge
+    template = ptrarr(n_psf, /ALLOCATE)
+    if  correl_mag gt 1  then  templates = ptrarr(n_psf, /ALLOCATE) $
+    else begin
+       templates = 0  &  dx = 0  &  dy = 0
+    endelse
+    for  n = 0L, n_psf - 1  do begin
+       temp = sub_array(psf[*,*,n], temp_siz[n])
+       if  correl_mag gt 1  then begin
+          shifted_templates, temp, correl_mag, _EXTRA = extra, EDGE = edge, $
+                             templs, dx, dy
+          temp = sub_array(temp, correlation_box[n])
+          *templates[n] = templs
+       endif
+       *template[n] = temp
+    endfor
+    return, {correl_mag: correl_mag, $
+             correlation_box: correlation_box, $
+             search_box: search_box, $
+             template: template, $
+             templates: templates, dx: dx, dy: dy}
+end
+
+; STARFINDER_FIT_PAR: define parameters for fitting.
+
+FUNCTION starfinder_fit_par, psf, psf_fwhm, n_psf, MIN_DISTANCE = min_dist, _EXTRA = extra
+
+    on_error, 2
+    fitting_box = define_fit_box(psf_fwhm, _EXTRA = extra)
+    psf_size = 2 * max(fitting_box) < (max((size52(psf, /DIM))[0:1]) - 2)
+;   edge = round((fitting_box - psf_fwhm) / 2.0) > 1
+    edge = 0.5
+    if n_elements(min_dist) eq 0 then min_dist = 1.0
+    min_distance = min_dist * psf_fwhm
+    fitting_psf = fltarr(psf_size, psf_size, n_psf)
+    psf_max = fltarr(n_psf)
+    for  n = 0L, n_psf - 1  do begin
+       fitting_psf[*,*,n] = sub_array(psf[*,*,n], psf_size)
+       psf_max[n] = max(psf[*,*,n])
+    endfor
+    return, {fitting_box: fitting_box, edge: edge, $
+             min_distance: min_distance, $
+             fitting_psf: fitting_psf, psf: psf, $
+             psf_max: psf_max, psf_fwhm: psf_fwhm}
+end
+
+; STARFINDER_DEB_PAR: define parameters for deblending.
+
+FUNCTION starfinder_deb_par, psf, psf_fwhm, n_psf, $
+                             BIN_THRESHOLD = bin_threshold, $
+                             CUT_THRESHOLD = cut, $
+                             BIN_N_STDEV = n_std, BIN_TOLERANCE = tol
+
+    on_error, 2
+    if  n_elements(bin_threshold) eq 0  then  bin_threshold = 0.
+    if  n_elements(cut) eq 0  then  cut = 0.5  &  cut = cut > 0 < 1 ;cut = cut > 0.2 < 1
+    if  n_elements(n_std) eq 0  then  n_std = 3
+    if  n_elements(tol) eq 0  then  tol = 0.2  &  tol = tol > 0 < 1
+    box = lonarr(n_psf)  &  area = fltarr(n_psf)
+    for  n = 0L, n_psf - 1  do begin
+       box[n] = round(3 * peak_width(psf[*,*,n], REL = cut, MAG = 3))
+       area[n] = peak_area(psf[*,*,n], REL = cut, MAG = 3)
+    endfor
+    return, {bin_threshold: bin_threshold, n_std: n_std, $
+             box: box, cut: cut, tol: tol, psf_area: area}
+end
+
+; STARFINDER_DEALLOC: de-allocate heap variables.
+
+PRO starfinder_dealloc, corr_par, fit_data, model_data
+
+    on_error, 2
+    if  n_elements(corr_par) eq 0  then  return
+    if  (ptr_valid(corr_par.template))[0]  then  ptr_free, corr_par.template
+    if  (ptr_valid(corr_par.templates))[0]  then  ptr_free, corr_par.templates
+    if  ptr_valid(fit_data)  then  ptr_free, fit_data
+    if  ptr_valid(model_data)  then  ptr_free, model_data
+    return
+end
+
+
+
+;;; Other auxiliary procedures/functions.
+
+; STARFINDER_BAD: find bad pixels in the sub-image [lx:ux,ly:uy].
+
+PRO starfinder_bad, x_bad, y_bad, lx, ux, ly, uy, x_bad_here, y_bad_here
+
+    on_error, 2
+    w = where(x_bad ge lx and x_bad le ux and $
+              y_bad ge ly and y_bad le uy, n)
+    if  n ne 0  then begin
+       x_bad_here = x_bad[w] - lx  &  y_bad_here = y_bad[w] - ly
+    endif
+    return
+end
+
+; STARFINDER_BOXES: extract boxes from image, background and image model.
+
+PRO starfinder_boxes, image, background, stars, x, y, boxsize, $
+                      lx, ux, ly, uy, i_box, b_box, s_box, $
+                      x_bad, y_bad, x_bad_here, y_bad_here
+
+    on_error, 2
+    i_box = sub_array(image, boxsize, REFERENCE = [x, y], $
+                      LX = lx, UX = ux, LY = ly, UY = uy)
+    s_box = stars[lx:ux,ly:uy]  &  b_box = background[lx:ux,ly:uy]
+    if  n_elements(x_bad) ne 0 and n_elements(y_bad) ne 0  then $
+       starfinder_bad, x_bad, y_bad, lx, ux, ly, uy, x_bad_here, y_bad_here
+    return
+end
+
+; STARFINDER_ID: re-identification of a presumed star.
+
+PRO starfinder_id, image, background, stars, sv_par, id_par, $
+                   min_intensity, x, y, found
+
+    on_error, 2
+    if  n_elements(sv_par) ne 0  then $
+       r = pick_region(sv_par.lx, sv_par.ux, sv_par.ly, sv_par.uy, x, y) $
+    else  r = 0
+    ; Extract boxes
+    starfinder_boxes, image, background, stars, x, y, id_par.box[r], $
+                      lx, ux, ly, uy, i_box, b_box, s_box
+    ; Search
+    max_search, i_box - b_box - s_box, min_intensity[lx:ux,ly:uy], $
+                X0 = x - lx, Y0 = y - ly, n, x, y, $
+                /NEAREST, /MAXIMUM, FOUR = id_par.neigh4
+    found = n ne 0
+    if  found  then begin
+       x = x[0] + lx  &  y = y[0] + ly
+    endif
+    return
+end
+
+; STARFINDER_CORRELATE: correlation check.
+
+PRO starfinder_correlate, image, background, stars, sv_par, x_bad, y_bad, $
+                          corr_par, min_correlation, x, y, correl, accepted
+
+    on_error, 2
+    if  n_elements(sv_par) ne 0  then $
+       r = pick_region(sv_par.lx, sv_par.ux, sv_par.ly, sv_par.uy, x, y) $
+    else  r = 0
+    ; Extract boxes
+    boxsize = corr_par.correlation_box[r] + corr_par.search_box[r] + 1
+    starfinder_boxes, image, background, stars, x, y, boxsize, $
+                      lx, ux, ly, uy, i_box, b_box, s_box, x_bad, y_bad, xb, yb
+    ; Compute correlation
+    if  corr_par.correl_mag gt 1  then begin
+       templates = *corr_par.templates[r]  &  dx = corr_par.dx  &  dy = corr_par.dy
+    endif
+    correlate_max, i_box - b_box - s_box, *corr_par.template[r], x - lx, y - ly, $
+                   corr_par.search_box[r], X_BAD = xb, Y_BAD = yb, $
+                   TEMPLATES = templates, DX = dx, DY = dy, correl, x, y
+    x = x + lx  &  y = y + ly
+    accepted = correl ge min_correlation and $
+               x ge lx and x le ux and y ge ly and y le uy
+    return
+end
+
+; STARFINDER_CHECK: check outcome of local fitting.
+
+FUNCTION starfinder_check, fit_error, x_fit, y_fit, f_fit, $
+                           lx, ux, ly, uy, list, min_intensity, fit_par, r
+
+    on_error, 2
+    ; Check convergence of fit, minimum acceptable value of fluxes,
+    ; range of positions
+;    padd = 2.0   ; added after suggestion by Jessica Lu
+    padd = 0.0
+    good = fit_error ge 0 and $
+           min(x_fit) ge lx-padd and max(x_fit) le ux+padd and $
+           min(y_fit) ge ly-padd and max(y_fit) le uy+padd
+    if  good  then begin
+       threshold = min_intensity[round(x_fit),round(y_fit)] / fit_par.psf_max[r]
+       good = min(f_fit - threshold) ge 0
+       good = min(f_fit - threshold) ge 0
+    endif
+    if  good  then begin
+       ; Consider the subset of stars in a neighborhood of [lx:ux,ly:uy]
+       ; and check their reciprocal distances
+       s = where_stars(LX = lx - fit_par.min_distance[r], $
+                       UX = ux + fit_par.min_distance[r], $
+                       LY = ly - fit_par.min_distance[r], $
+                       UY = uy + fit_par.min_distance[r], list, n)                
+       star_param, list, SUBSCRIPTS = s, n, x, y, f
+       if  n gt 1  then $
+          good = min(reciprocal_distance(x, y)) ge fit_par.min_distance[r]
+    endif
+    return, good
+end
+
+; STARFINDER_FIT: local fitting.
+
+PRO starfinder_fit, list, this_max, image, siz, background, stars, noise_std, $
+                    sv_par, x_bad, y_bad, fit_par, fit_data, model_data, $
+                    min_intensity, NO_SLANT = no_slant, $
+                    re_fitting, _EXTRA = extra, star_here, $
+                    PSF_TYPE = psf_type, PSF_DATA = psf_data
+
+    on_error, 2
+    star_param, list, SUBSCRIPTS = this_max, n, x, y
+    if  n_elements(sv_par) ne 0  then $
+       r = pick_region(sv_par.lx, sv_par.ux, sv_par.ly, sv_par.uy, x, y) $
+    else  r = 0
+    ; Extract boxes
+    starfinder_boxes, image, background, stars, x, y, fit_par.fitting_box[r], $
+                      lx, ux, ly, uy, i_box, b_box, s_box, x_bad, y_bad, xb, yb
+    if  n_elements(xb) ne 0 and n_elements(yb) ne 0  then $
+       w_bad = coord_to_subs(xb, yb, (size52(i_box, /DIM))[0])
+    ; Select known stars into i_box and subtract them from the image model
+    s = where_stars(LX = lx + fit_par.edge, UX = ux - fit_par.edge, $
+                    LY = ly + fit_par.edge, UY = uy - fit_par.edge, list, n)
+    if  re_fitting ne 0  then begin
+;       if  n eq 0  then  s = this_max  ; edge star
+;       Modified March 2012
+;       if  n eq 0  then begin
+       if n eq 0 or re_fitting eq 2 then begin
+          s = this_max  ; edge star or single-component fitting
+          n = 1
+       endif
+       s_and_this = s
+    endif else  s_and_this = add_subscript(s, this_max)
+    star_param, list, SUBSCRIPTS = s, n, x_add, y_add, f_add, c
+    if  n ne 0  then $
+       if keyword_set(psf_type) then $
+          stars = image_model(x_add, y_add, -f_add, siz[0], siz[1], psf_type, $
+                              psf_data, _EXTRA = extra, MODEL = stars) else $
+       if n_elements(sv_par) ne 0 then $
+          stars = image_model(x_add, y_add, -f_add, siz[0], siz[1], fit_par.psf, $
+                              LX = sv_par.lx, UX = sv_par.ux, LY = sv_par.ly, UY = sv_par.uy, $
+                              model_data, _EXTRA = extra, MODEL = stars) else $
+          stars = image_model(x_add, y_add, -f_add, siz[0], siz[1], fit_par.psf, $
+                              model_data, _EXTRA = extra, MODEL = stars)
+    ; Fixed contribution for local fitting
+    contrib = stars[lx:ux,ly:uy]   ; stars outside fitting box
+    if  keyword_set(no_slant)  then begin
+       contrib = contrib + b_box  &  b_box = 0
+    endif
+    ; Local fitting
+    if  re_fitting ne 0  then begin
+       x = x_add  &  y = y_add  &  f0 = f_add
+    endif else $
+; Modified March 2012: n is the number of known sources in the box
+       star_param, list, SUBSCRIPTS = s_and_this, n_and_this, x, y, f, c
+;       star_param, list, SUBSCRIPTS = s_and_this, n, x, y, f, c
+    x0 = x - lx  &  y0 = y - ly
+    if n_elements(noise_std) ne 0 then noise = noise_std[lx:ux,ly:uy]
+    if n_elements(sv_par) ne 0 then begin
+       sv_lx = sv_par.lx - lx
+       sv_ux = sv_par.ux - lx
+       sv_ly = sv_par.ly - ly
+       sv_uy = sv_par.uy - ly
+    endif
+    if keyword_set(psf_type) then begin
+    xori = (*psf_data).xori
+    yori = (*psf_data).yori
+    (*psf_data).xori = lx
+    (*psf_data).yori = ly
+    fitstars, i_box, FIXED = contrib, psf_type, $
+              PSF_DATA = psf_data, x0, y0, F0 = f0, BACKGROUND = b_box, $
+              NO_SLANT = no_slant, NOISE_STD = noise, _EXTRA = extra, $
+              BAD_DATA = w_bad, x, y, f, b, fit_error, sigma_x, sigma_y, sigma_f
+    (*psf_data).xori = xori
+    (*psf_data).yori = yori
+    endif else $
+    fitstars, i_box, FIXED = contrib, fit_par.fitting_psf, $
+              PSF_DATA = fit_data, x0, y0, F0 = f0, BACKGROUND = b_box, $
+              NO_SLANT = no_slant, NOISE_STD = noise, _EXTRA = extra, $
+              BAD_DATA = w_bad, LX = sv_lx, UX = sv_ux, LY = sv_ly, UY = sv_uy, $
+              x, y, f, b, fit_error, sigma_x, sigma_y, sigma_f
+;    Modified April 2012
+;    x_out = x  &  y_out = y
+;    compare_lists, x0, y0, x_out, y_out, x0_out, y0_out, x, y, SUBSCRIPTS_2 = w
+    compare_lists, x0, y0, x, y, SUBSCRIPTS_2 = w
+    x = x[w] + lx  &  y = y[w] + ly  &  f = f[w]
+    if  n_elements(sigma_f) ne 0  then begin
+       sigma_x = sigma_x[w]
+       sigma_y = sigma_y[w]
+       sigma_f = sigma_f[w]
+    endif
+    ; Is the examined max a star? Assume it is, then perform checks
+    temp_list = list
+    update_list, temp_list, SUB = s_and_this, x, y, f, c, $
+                 sigma_x, sigma_y, sigma_f, /IS_STAR
+    star_here = starfinder_check(fit_error, x, y, f, lx, ux, ly, uy, $
+                                 temp_list, min_intensity, fit_par, r)
+    ; Update list of stars and image model
+    if  star_here  then begin
+       list = temp_list
+       x_add = x  &  y_add = y  &  f_add = f
+    endif else if re_fitting eq 2 then begin
+       list = reverse_class(list, SUBSCRIPT = this_max)
+       n = n - 1
+       if n gt 0 then begin
+          w = where(s_and_this ne this_max[0])
+          star_param, list, SUBSCRIPTS = s_and_this[w], n, x_add, y_add, f_add, c
+       endif
+    endif
+    if n gt 0 or re_fitting eq 0 then $ ; should be equivalent to "n gt 0 or re_fitting lt 2"
+    if keyword_set(psf_type) then $
+       stars = image_model(x_add, y_add, f_add, siz[0], siz[1], psf_type, $
+                           psf_data, _EXTRA = extra, MODEL = stars) else $
+    if n_elements(sv_par) ne 0 then $
+       stars = image_model(x_add, y_add, f_add, siz[0], siz[1], fit_par.psf, $
+                           LX = sv_par.lx, UX = sv_par.ux, LY = sv_par.ly, UY = sv_par.uy, $
+                           model_data, _EXTRA = extra, MODEL = stars) else $
+       stars = image_model(x_add, y_add, f_add, siz[0], siz[1], fit_par.psf, $
+                           model_data, _EXTRA = extra, MODEL = stars)
+    return
+end
+
+; STARFINDER_BLEND: check the area of a presumed star to identify blends.
+
+FUNCTION starfinder_blend, image, background, stars, noise_std, $
+                           deb_par, x, y, r
+
+    on_error, 2
+    starfinder_boxes, image, background, stars, x, y, deb_par.box[r], $
+                      lx, ux, ly, uy, i_box, b_box, s_box
+    ima = i_box - b_box - s_box      ; after this, it should be positive!
+    x0 = x - lx  &  y0 = y - ly
+    threshold = ima[x0,y0] * deb_par.cut
+    check = 1B
+    if  n_elements(noise_std) ne 0  then $
+       check = threshold gt deb_par.n_std * noise_std[x,y]
+    if  check  then begin
+       area = peak_area(ima, X = x0, Y = y0, MAG = 3, ABS_THRESHOLD = threshold)
+       check = relative_error(deb_par.psf_area[r], area) gt deb_par.tol
+    endif
+    return, check
+end
+
+; STARFINDER_DEBLEND: de-blend a crowded group of stars
+; (partial or full de-blending).
+
+PRO starfinder_deblend, list, this_max, image, siz, background, stars, $
+                        noise_std, sv_par, x_bad, y_bad, id_par, fit_par, $
+                        deb_par, fit_data, model_data, min_intensity, $
+                        re_fitting, AROUND = around, _EXTRA = extra, $
+                        PSF_TYPE = psf_type, PSF_DATA = psf_data
+
+    on_error, 2
+    star_param, list, SUB = this_max, n, x, y, f
+    x0 = round(x)  &  y0 = round(y)
+    if  n_elements(sv_par) ne 0  then $
+       r = pick_region(sv_par.lx, sv_par.ux, sv_par.ly, sv_par.uy, x, y) $
+    else  r = 0
+    ; Is the present object a blend?
+    if  keyword_set(around)  then $
+       if keyword_set(psf_type) then $
+          stars = image_model(x, y, -f, siz[0], siz[1], psf_type, $
+                              psf_data, _EXTRA = extra, MODEL = stars) else $
+       if n_elements(sv_par) ne 0 then $
+          stars = image_model(x, y, -f, siz[0], siz[1], fit_par.psf, $
+                              LX = sv_par.lx, UX = sv_par.ux, LY = sv_par.ly, UY = sv_par.uy, $
+                              model_data, _EXTRA = extra, MODEL = stars) else $
+          stars = image_model(x, y, -f, siz[0], siz[1], fit_par.psf, $
+                              model_data, _EXTRA = extra, MODEL = stars)
+;       stars = image_model(x, y, -f, siz[0], siz[1], fit_par.psf[*,*,r], $
+;                        model_data, _EXTRA = extra, MODEL = stars)
+    blended = starfinder_blend(image, background, stars, noise_std, $
+                               deb_par, x0, y0, r)
+    if  keyword_set(around)  then $
+       if keyword_set(psf_type) then $
+          stars = image_model(x, y, f, siz[0], siz[1], psf_type, $
+                              psf_data, _EXTRA = extra, MODEL = stars) else $
+       if n_elements(sv_par) ne 0 then $
+          stars = image_model(x, y, f, siz[0], siz[1], fit_par.psf, $
+                              LX = sv_par.lx, UX = sv_par.ux, LY = sv_par.ly, UY = sv_par.uy, $
+                              model_data, _EXTRA = extra, MODEL = stars) else $
+          stars = image_model(x, y, f, siz[0], siz[1], fit_par.psf, $
+                              model_data, _EXTRA = extra, MODEL = stars)
+;       stars = image_model(x, y, f, siz[0], siz[1], fit_par.psf[*,*,r], $
+;                         model_data, _EXTRA = extra, MODEL = stars)
+    if  not blended  then  return  ; not a blend
+    ncomp = 0L  &  found = ncomp eq 0  &  star_here = found
+    if  keyword_set(around)  then  ncomp = ncomp + 1
+;    max_dist = 1.25 * fit_par.psf_fwhm[r]
+    while  star_here  do begin
+       x = x0  &  y = y0
+       if  ncomp ne 0  then begin
+          ; Identify another component of the blend
+          starfinder_boxes, image, background, stars, x, y, deb_par.box[r], $
+                            lx, ux, ly, uy, i_box, b_box, s_box
+          max_search, i_box - b_box - s_box, $
+                      deb_par.bin_threshold * min_intensity[lx:ux,ly:uy], $
+                      X0 = x - lx, Y0 = y - ly, CHECK_DIST = max_dist, $
+                      /MAXIMUM, FOUR = id_par.neigh4, n, x, y
+          found = n ne 0  &  star_here = found
+          if  found  then begin
+             x = x[0] + lx  &  y = y[0] + ly
+          endif
+       endif
+       if  found  then begin
+          ; Fit the new detected component
+          if  ncomp ne 0  then begin
+             list = merge_list(list, create_element(x, y, 0))
+             index = n_elements(list) - 1
+          endif else  index = this_max
+          starfinder_fit, list, index, image, siz, background, stars, $
+                          noise_std, sv_par, x_bad, y_bad, fit_par, fit_data, $
+                          model_data, min_intensity, re_fitting, _EXTRA = extra, $
+                          star_here, PSF_TYPE = psf_type, PSF_DATA = psf_data
+       endif
+       if  star_here  then  ncomp = ncomp + 1
+    endwhile
+    if  ncomp eq 1 and not keyword_set(around)  then begin
+       ; The object was mis-recognized as a blend: it is single
+       star_param, list, SUB = this_max, n, x, y, f
+       if keyword_set(psf_type) then $
+          stars = image_model(x, y, -f, siz[0], siz[1], psf_type, $
+                              psf_data, _EXTRA = extra, MODEL = stars) else $
+       if n_elements(sv_par) ne 0 then $
+          stars = image_model(x, y, -f, siz[0], siz[1], fit_par.psf, $
+                              LX = sv_par.lx, UX = sv_par.ux, LY = sv_par.ly, UY = sv_par.uy, $
+                              model_data, _EXTRA = extra, MODEL = stars) else $
+          stars = image_model(x, y, -f, siz[0], siz[1], fit_par.psf, $
+                              model_data, _EXTRA = extra, MODEL = stars)
+;       stars = image_model(x, y, -f, siz[0], siz[1], fit_par.psf[*,*,r], $
+;                         model_data, _EXTRA = extra)
+       list = reverse_class(list, SUBSCRIPT = this_max)
+    endif
+    return
+end
+
+; STARFINDER_ANALYZE: analyze the object list[this_max].
+
+PRO starfinder_analyze, list, this_max, image, siz, background, stars, $
+                        noise_std, sv_par, x_bad, y_bad, id_par, corr_par, $
+                        fit_par, fit_data, model_data, $
+                        min_intensity, min_correlation, re_fitting, _EXTRA = extra
+
+    on_error, 2
+    star_param, list, SUB = this_max, n, x, y
+    ; Is the maximum list[this_max] a feature of an already detected star?
+    starfinder_id, image, background, stars, sv_par, id_par, $
+                   min_intensity, x, y, check
+    if  not check  then  return           ; yes, it is
+    ; Correlation check
+    starfinder_correlate, image, background, stars, sv_par, x_bad, y_bad, $
+                          corr_par, min_correlation, x, y, c, check
+    if  not check  then  return   ; too low correlation
+    ; Fit
+    update_list, list, SUB = this_max, x, y, 0, c
+    starfinder_fit, list, this_max, image, siz, background, stars, noise_std, $
+                    sv_par, x_bad, y_bad, fit_par, fit_data, model_data, $
+                    min_intensity, re_fitting, _EXTRA = extra
+    return
+end
+
+; STARFINDER_CONVERG: check convergence of positions and fluxes for Phase 3.
+
+FUNCTION starfinder_converg, list0, list, $
+        ASTROMETRIC_TOL = a_tol, PHOTOMETRIC_TOL = ph_tol
+
+    on_error, 2
+    if  n_elements(a_tol)  eq 0  then  a_tol  = 1e-2;1e-4;0.01
+    if  n_elements(ph_tol) eq 0  then  ph_tol = 1e-2;1e-4;0.01
+    s = where_stars(list, n)
+    if  n eq 0  then  return, n eq 0
+    star_param, list0, SUB = s, n, x0, y0, f0
+    star_param, list,  SUB = s, n, x,  y,  f
+    check = convergence(x0, x, a_tol, /ABSOLUTE) and $
+         convergence(y0, y, a_tol, /ABSOLUTE) and $
+         convergence(f0, f, ph_tol)
+    return, check
+end
+
+
+
+;;; The main routine.
+
+PRO starfinder, $
+    image, psf, SV_PAR = sv_par, $
+    X_BAD = x_bad, Y_BAD = y_bad, $
+    BACKGROUND = background, BACK_BOX = back_box, $
+    threshold, REL_THRESHOLD = rel_threshold, NOISE_STD = noise_std, $
+    min_correlation, DEBLEND = deblend, DEBLOST = deblost, _EXTRA = extra, $
+    N_ITER = n_iter, NO_INTERMEDIATE_ITER = no_intermediate, SILENT = silent, $
+    x, y, fluxes, sigma_x, sigma_y, sigma_f, correlation, STARS = stars, $
+    X_INPUT = x_in, Y_INPUT = y_in, F_INPUT = f_in, C_INPUT = c_in, $
+    PSF_TYPE = psf_type, PSF_DATA = psf_data
+
+    catch, error
+    if  error ne 0  then begin
+       starfinder_dealloc, corr_par, fit_data, model_data
+       return
+    endif
+
+    ; Define background and image model
+    siz = size52(image, /DIM)
+    if  n_elements(background) eq 0  then $
+       if  n_elements(back_box) eq 0  then $
+          background = fltarr(siz[0], siz[1])  else $
+          background = estimate_background(image, back_box, _EXTRA = extra)
+    if  n_elements(noise_std) ne 0  then $
+       if  n_elements(noise_std) ne n_elements(image)  then $
+          noise_std = replicate(noise_std[0], siz[0], siz[1])
+    stars = fltarr(siz[0], siz[1])
+
+    ; Define some program parameters and default values
+    re_fitting = 0 ; re_fitting = 0 --> normal mode
+    if  n_elements(x_in) ne 0 and n_elements(y_in) ne 0 and n_elements(f_in) ne 0 then $
+       re_fitting = 2 ; re_fitting = 2 --> fit of input list of sources
+    if  n_elements(n_iter) eq 0  then  n_iter = 1
+    if  size52(psf, /N_DIM) eq 3  then $
+       n_psf = (size52(psf, /DIM))[2]  else  n_psf = 1
+    psf_fwhm = starfinder_fwhm(psf, n_psf)
+    id_par = starfinder_id_par(psf_fwhm, _EXTRA = extra)
+    corr_par = starfinder_corr_par(psf, psf_fwhm, n_psf, _EXTRA = extra)
+    ; modified March 2012
+    if re_fitting eq 2 then $
+        fit_par = starfinder_fit_par(psf, psf_fwhm, n_psf, /WIDER, _EXTRA = extra) else $
+        fit_par = starfinder_fit_par(psf, psf_fwhm, n_psf, _EXTRA = extra)
+;    fit_par = starfinder_fit_par(psf, psf_fwhm, n_psf, _EXTRA = extra)
+    if  keyword_set(deblend) or keyword_set(deblost)  then $
+       deb_par = starfinder_deb_par(psf, psf_fwhm, n_psf, _EXTRA = extra)
+    if  n_elements(sv_par) eq 0  then begin
+       fit_data = ptr_new(/ALLOCATE)  &  model_data = ptr_new(/ALLOCATE)
+    endif
+
+    ; Iterative search for suspected stars and subsequent analysis
+    n_levels = n_elements(threshold)
+    n_stars = 0L  &  n_presumed = 0L  &  n_max = 0L
+    if re_fitting eq 2 then begin
+       n_levels = 1
+       n_stars = n_elements(f_in)
+       list_of_stars = sort_list(reverse_class(starlist(n_stars, x_in, y_in, f_in)))
+       if keyword_set(psf_type) then $
+       stars = image_model(x_in, y_in, f_in, siz[0], siz[1], psf_type, $
+                           psf_data, _EXTRA = extra) else $
+       if n_elements(sv_par) ne 0 then $
+       stars = image_model(x_in, y_in, f_in, siz[0], siz[1], psf, $
+                           LX = sv_par.lx, UX = sv_par.ux, LY = sv_par.ly, UY = sv_par.uy, $
+                           _EXTRA = extra) else $
+       stars = image_model(x_in, y_in, f_in, siz[0], siz[1], psf, _EXTRA = extra)
+    endif
+
+    for  n_lev = 0L, n_levels - 1  do begin
+
+    ; Update detection threshold
+    threshold_n = float(threshold[n_lev])
+    if  keyword_set(rel_threshold) and n_elements(noise_std) ne 0  then $
+       threshold_n = threshold_n * noise_std
+    if  n_elements(threshold_n) eq 1  then $
+       threshold_n = replicate(threshold_n[0], siz[0], siz[1])
+
+    ; Phase 1: find local maxima having
+    ; central intensity > known stars + background + threshold
+    if re_fitting eq 0 then begin
+    if  not keyword_set(silent)  then $
+       print, "STARFINDER: search for candidate stars"
+    search_objects, image - stars, LOW_SURFACE = background, threshold_n, $
+                    _EXTRA = extra, n_max, x0, y0, i0
+    n_presumed = n_presumed + n_max
+    endif
+
+    ; Phase 2: analyze presumed stars with correlation and fitting,
+    ;      estimating positions and fluxes.
+    if n_max ne 0 and re_fitting eq 0 then begin
+       if  not keyword_set(silent)  then $
+          print, "STARFINDER: analysis of candidate stars"
+       list_of_max = starlist(n_max, x0, y0, i0)
+       list_of_stars = merge_list(list_of_stars, sort_list(list_of_max))
+       for  n = n_stars, n_stars - 1 + n_max  do $
+          starfinder_analyze, list_of_stars, n, image, siz, background, stars, $
+                              noise_std, sv_par, x_bad, y_bad, id_par, $
+                              corr_par, fit_par, fit_data, model_data, $
+                              threshold_n, min_correlation, re_fitting, _EXTRA = extra, $
+                              PSF_TYPE = psf_type, PSF_DATA = psf_data
+       list_of_stars = sort_list(extract_stars(list_of_stars, n_stars))
+       ; Update background estimate
+       if  n_elements(back_box) ne 0  then $
+          background = estimate_background(image - stars, back_box, _EXTRA = extra)
+       ; Modify fitting parameters for subsequent operations
+       fit_par = starfinder_fit_par(psf, psf_fwhm, n_psf, /WIDER, _EXTRA = extra)
+       if  ptr_valid(fit_data)  then  ptr_free, fit_data
+    endif  ; n_max ne 0
+
+    ; Phase 2b: de-blend detected objects.
+    if keyword_set(deblend) and n_lev eq n_levels - 1 and n_stars ne 0 and re_fitting eq 0 then begin
+       if  not keyword_set(silent)  then $
+          print, "STARFINDER: deblending of detected stars"
+       ; Check each detected star: is it a blend?
+       for  n = 0L, n_stars - 1  do $
+          starfinder_deblend, list_of_stars, n, image, siz, background, stars, $
+                              noise_std, sv_par, x_bad, y_bad, id_par, $
+                              fit_par, deb_par, fit_data, model_data, $
+                              threshold_n, re_fitting, _EXTRA = extra, /AROUND, $
+                              PSF_TYPE = psf_type, PSF_DATA = psf_data
+       list_of_stars = sort_list(extract_stars(list_of_stars, n_stars))
+       ; Update background estimate
+       if  n_elements(back_box) ne 0  then $
+          background = estimate_background(image - stars, back_box, _EXTRA = extra)
+    endif
+
+    ; Phase 2c: recover lost objects to search for blends.
+;    if keyword_set(deblost) and n_lev eq n_levels - 1 and n_stars ne 0 and re_fitting eq 0 then begin
+    if keyword_set(deblost) and n_lev eq n_levels - 1 and re_fitting eq 0 then begin
+       if  not keyword_set(silent)  then $
+          print, "STARFINDER: search for blends among lost objects"
+       search_objects, image - stars, LOW_SURFACE = background, threshold_n, $
+                       _EXTRA = extra, n_max, x0, y0, i0
+       if  n_max ne 0  then begin
+          list_of_max = starlist(n_max, x0, y0, i0)
+          list_of_stars = merge_list(list_of_stars, sort_list(list_of_max))
+          for  n = n_stars, n_stars - 1 + n_max  do $
+             starfinder_deblend, list_of_stars, n, image, siz, background, stars, $
+                                 noise_std, sv_par, x_bad, y_bad, id_par, fit_par, $
+                                 deb_par, fit_data, model_data, threshold_n, $
+                                 re_fitting, _EXTRA = extra, $
+                                 PSF_TYPE = psf_type, PSF_DATA = psf_data
+          list_of_stars = sort_list(extract_stars(list_of_stars, n_stars))
+          ; Update background estimate
+          if  n_elements(back_box) ne 0  then $
+             background = estimate_background(image - stars, back_box, _EXTRA = extra)
+       endif
+    endif
+
+    ; Phase 3: re-determination of positions and fluxes by iterative
+    ;      fitting of detected stars.
+    if  n_lev eq n_levels - 1  then  maxit = n_iter  else $
+    if  keyword_set(no_intermediate)  then  maxit = 0  else  maxit = 1
+    if  n_stars ne 0  then  list0 = list_of_stars
+    if re_fitting eq 0 then re_fitting = 1
+    iter = 0L  &  converging = n_stars eq 0
+    while  iter lt maxit and not converging  do begin
+       if  not keyword_set(silent)  then $
+          if  n_lev lt n_levels - 1  then $
+             print, "STARFINDER: re-fitting"  else $
+             print, "STARFINDER: re-fitting: iteration", iter + 1
+;         Modified March 2012
+;          if  n_lev lt n_levels - 1  then $
+;             print, "STARFINDER: intermediate re-fitting"  else $
+;             print, "STARFINDER: final re-fitting: iteration", iter + 1
+       for  n = 0L, n_stars - 1  do $
+          ; modified March 2012
+          if list_of_stars[n].is_a_star or re_fitting eq 1 then $   ;;; if list_of_stars[n].is_a_star or re_fitting eq 1 or iter eq 0 then $
+          starfinder_fit, list_of_stars, n, image, siz, background, stars, $
+                          noise_std, sv_par, x_bad, y_bad, fit_par, fit_data, $
+                          model_data, threshold_n, re_fitting, _EXTRA = extra, $
+                          PSF_TYPE = psf_type, PSF_DATA = psf_data
+       if  maxit gt 1  then $
+          converging = starfinder_converg(list0, list_of_stars, _EXTRA = extra)
+       iter = iter + 1  &  list0 = list_of_stars
+    endwhile
+    if re_fitting eq 1 then re_fitting = 0
+    fit_par = starfinder_fit_par(psf, psf_fwhm, n_psf, _EXTRA = extra)
+    if  ptr_valid(fit_data)  then  ptr_free, fit_data
+
+    endfor ; end of cycle on threshold levels
+
+    ; De-allocate pointer heap variables
+    starfinder_dealloc, corr_par, fit_data, model_data
+
+    ; Save results
+    if  n_stars ne 0  then begin
+       list_of_stars = sort_list(extract_stars(list_of_stars, n_stars))
+       star_param, list_of_stars, n_stars, $
+                   x, y, fluxes, correlation, sigma_x, sigma_y, sigma_f
+    endif
+    if  not keyword_set(silent)  then begin
+       if re_fitting ne 2 then $
+       print, "STARFINDER", n_presumed,   "   candidate stars"
+       print, "STARFINDER", n_stars, "   detected stars"
+    endif
+    return
+end
diff --git a/starlist.pro b/starlist.pro
new file mode 100644
index 0000000000000000000000000000000000000000..11994b1f5a0b7d7cc56f5fe2617617dd8138964d
--- /dev/null
+++ b/starlist.pro
@@ -0,0 +1,42 @@
+; $Id: starlist.pro, v 1.1 Mar 2012 e.d. $
+;
+;+
+; NAME:
+;	STARLIST
+;
+; PURPOSE:
+;	Create a new list of elements representing either
+;	true or presumed stars.
+;
+; CATEGORY:
+;	STARFINDER auxiliary procedures.
+;
+; CALLING SEQUENCE:
+;	Result = STARLIST(N, X, Y, F, C)
+;
+; INPUTS:
+;	N:	number of elements in the list
+;
+; OPTIONAL INPUTS:
+;	X, Y, F:	1D vectors with position and flux of new elements
+;	
+;	C: 1D vector with correlation coefficients of new elements (if available)
+;
+; OUTPUTS:
+;	Return possibly initialized list of N elements
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, June 2001.
+; 	1) Added optional input C in STARLIST (E.D., March 2012).
+; 	2) Created this file (E. D., March 2012).
+;-
+
+FUNCTION starlist, n, x, y, f, c
+
+    on_error, 2
+    element = star()
+    list = replicate(element, n)
+    if  n_elements(x) ne 0 and n_elements(y) ne 0  then $
+       update_list, list, x, y, f, c
+    return, list
+end
diff --git a/stars.txt b/stars.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e6ca708d3fb4450e3895409c2666fbddcfbb8195
--- /dev/null
+++ b/stars.txt
@@ -0,0 +1,1000 @@
+      141.444      239.065 1.00000e+007     0.000000     0.000000     0.000000     0.000000
+      263.880      245.285 7.47086e+006     0.000000     0.000000     0.000000     0.000000
+      231.020      322.379 6.59129e+006     0.000000     0.000000     0.000000     0.000000
+      238.198      88.8366 3.32472e+006     0.000000     0.000000     0.000000     0.000000
+      278.154      274.961 1.83254e+006     0.000000     0.000000     0.000000     0.000000
+      29.2396      101.448 1.59408e+006     0.000000     0.000000     0.000000     0.000000
+      102.241      189.381 1.21068e+006     0.000000     0.000000     0.000000     0.000000
+      92.1810      178.633      773162.     0.000000     0.000000     0.000000     0.000000
+      302.978      15.4805      737351.     0.000000     0.000000     0.000000     0.000000
+      248.226      279.705      704095.     0.000000     0.000000     0.000000     0.000000
+      141.675      175.461      676584.     0.000000     0.000000     0.000000     0.000000
+      340.424      329.580      661287.     0.000000     0.000000     0.000000     0.000000
+      256.130      5.77905      638781.     0.000000     0.000000     0.000000     0.000000
+      99.0782      359.178      519881.     0.000000     0.000000     0.000000     0.000000
+      230.265      63.1091      506067.     0.000000     0.000000     0.000000     0.000000
+      160.545      357.701      500177.     0.000000     0.000000     0.000000     0.000000
+      87.1833      35.7546      479293.     0.000000     0.000000     0.000000     0.000000
+      181.326      21.0803      457698.     0.000000     0.000000     0.000000     0.000000
+      193.221      151.761      437480.     0.000000     0.000000     0.000000     0.000000
+      331.626      281.044      421626.     0.000000     0.000000     0.000000     0.000000
+      196.967      215.621      411944.     0.000000     0.000000     0.000000     0.000000
+      332.888      67.3763      396346.     0.000000     0.000000     0.000000     0.000000
+      301.842      183.755      377396.     0.000000     0.000000     0.000000     0.000000
+      14.9324      100.224      356474.     0.000000     0.000000     0.000000     0.000000
+      188.292      324.556      344011.     0.000000     0.000000     0.000000     0.000000
+      79.8033      20.1347      340647.     0.000000     0.000000     0.000000     0.000000
+      203.205      292.668      340602.     0.000000     0.000000     0.000000     0.000000
+      4.08286      251.532      336837.     0.000000     0.000000     0.000000     0.000000
+      89.6078      216.392      308973.     0.000000     0.000000     0.000000     0.000000
+      153.712      171.918      296011.     0.000000     0.000000     0.000000     0.000000
+      248.966      195.936      266923.     0.000000     0.000000     0.000000     0.000000
+      117.632      48.2569      260607.     0.000000     0.000000     0.000000     0.000000
+      308.253      29.6234      260248.     0.000000     0.000000     0.000000     0.000000
+      203.769      56.2594      250214.     0.000000     0.000000     0.000000     0.000000
+      238.393      363.804      237712.     0.000000     0.000000     0.000000     0.000000
+      316.437      357.973      236734.     0.000000     0.000000     0.000000     0.000000
+      306.785      152.560      235881.     0.000000     0.000000     0.000000     0.000000
+      342.694      277.907      233065.     0.000000     0.000000     0.000000     0.000000
+      54.1969      292.909      231872.     0.000000     0.000000     0.000000     0.000000
+      68.3034      347.885      222287.     0.000000     0.000000     0.000000     0.000000
+      94.0176      60.6761      221532.     0.000000     0.000000     0.000000     0.000000
+      102.126      156.966      221122.     0.000000     0.000000     0.000000     0.000000
+      328.504      50.0842      219851.     0.000000     0.000000     0.000000     0.000000
+      323.204      36.2747      212618.     0.000000     0.000000     0.000000     0.000000
+      61.5537      54.2696      205046.     0.000000     0.000000     0.000000     0.000000
+      167.366      142.279      197444.     0.000000     0.000000     0.000000     0.000000
+      129.178      170.515      193344.     0.000000     0.000000     0.000000     0.000000
+      80.7047      345.043      190810.     0.000000     0.000000     0.000000     0.000000
+      214.974      206.928      186916.     0.000000     0.000000     0.000000     0.000000
+      75.1124      331.121      186550.     0.000000     0.000000     0.000000     0.000000
+      219.742      57.2710      181822.     0.000000     0.000000     0.000000     0.000000
+      275.859      227.410      178175.     0.000000     0.000000     0.000000     0.000000
+      93.2953      151.123      176123.     0.000000     0.000000     0.000000     0.000000
+      231.419      322.719      173074.     0.000000     0.000000     0.000000     0.000000
+      238.244      107.443      172252.     0.000000     0.000000     0.000000     0.000000
+      152.464      347.544      170346.     0.000000     0.000000     0.000000     0.000000
+      143.542      295.029      168789.     0.000000     0.000000     0.000000     0.000000
+      169.870      248.333      168593.     0.000000     0.000000     0.000000     0.000000
+      292.060      261.347      164718.     0.000000     0.000000     0.000000     0.000000
+      35.8475      94.3537      162842.     0.000000     0.000000     0.000000     0.000000
+      48.4971      310.308      161867.     0.000000     0.000000     0.000000     0.000000
+      161.854      258.059      155129.     0.000000     0.000000     0.000000     0.000000
+      261.010      315.584      149634.     0.000000     0.000000     0.000000     0.000000
+      270.759      170.260      149466.     0.000000     0.000000     0.000000     0.000000
+      161.598      80.8070      146634.     0.000000     0.000000     0.000000     0.000000
+      118.249      347.903      144433.     0.000000     0.000000     0.000000     0.000000
+      188.792      324.297      142534.     0.000000     0.000000     0.000000     0.000000
+      150.565      319.440      142475.     0.000000     0.000000     0.000000     0.000000
+      294.201      322.857      139912.     0.000000     0.000000     0.000000     0.000000
+      40.3396      231.383      138934.     0.000000     0.000000     0.000000     0.000000
+      300.716      321.223      136407.     0.000000     0.000000     0.000000     0.000000
+      313.770      53.2494      131038.     0.000000     0.000000     0.000000     0.000000
+      165.575      116.979      125809.     0.000000     0.000000     0.000000     0.000000
+      37.1321      265.568      122559.     0.000000     0.000000     0.000000     0.000000
+      179.508      9.89236      114837.     0.000000     0.000000     0.000000     0.000000
+      225.502      251.722      113258.     0.000000     0.000000     0.000000     0.000000
+      363.681      80.0904      111222.     0.000000     0.000000     0.000000     0.000000
+      171.779      278.806      111141.     0.000000     0.000000     0.000000     0.000000
+      58.4512      258.920      110230.     0.000000     0.000000     0.000000     0.000000
+      316.804      304.948      107616.     0.000000     0.000000     0.000000     0.000000
+      302.164      91.1036      107397.     0.000000     0.000000     0.000000     0.000000
+      26.5350      219.965      106188.     0.000000     0.000000     0.000000     0.000000
+      283.449      155.508      105731.     0.000000     0.000000     0.000000     0.000000
+      211.195      185.650      105438.     0.000000     0.000000     0.000000     0.000000
+      188.711      82.2072      104895.     0.000000     0.000000     0.000000     0.000000
+      72.2484      105.537      101507.     0.000000     0.000000     0.000000     0.000000
+      289.912      3.21481      98803.0     0.000000     0.000000     0.000000     0.000000
+      254.344      7.08516      98763.3     0.000000     0.000000     0.000000     0.000000
+      302.036      52.2602      98698.9     0.000000     0.000000     0.000000     0.000000
+      274.811      359.645      95523.1     0.000000     0.000000     0.000000     0.000000
+      118.079      32.5073      93886.7     0.000000     0.000000     0.000000     0.000000
+      285.718      23.3751      93222.0     0.000000     0.000000     0.000000     0.000000
+      59.9410      178.202      92600.3     0.000000     0.000000     0.000000     0.000000
+      61.3693      269.778      91754.5     0.000000     0.000000     0.000000     0.000000
+      202.962      100.187      90361.8     0.000000     0.000000     0.000000     0.000000
+      256.779      96.4422      88950.8     0.000000     0.000000     0.000000     0.000000
+      95.8379      144.879      87336.5     0.000000     0.000000     0.000000     0.000000
+      231.668      118.223      86284.7     0.000000     0.000000     0.000000     0.000000
+      192.931      254.259      85762.4     0.000000     0.000000     0.000000     0.000000
+      232.133      31.2530      84899.0     0.000000     0.000000     0.000000     0.000000
+      94.6659      174.799      83423.6     0.000000     0.000000     0.000000     0.000000
+      136.477      188.531      83193.9     0.000000     0.000000     0.000000     0.000000
+      298.921      278.288      82613.9     0.000000     0.000000     0.000000     0.000000
+      39.6911      230.275      82228.0     0.000000     0.000000     0.000000     0.000000
+      115.177      244.697      82011.5     0.000000     0.000000     0.000000     0.000000
+      191.734      189.689      81725.9     0.000000     0.000000     0.000000     0.000000
+      255.640      247.122      79493.9     0.000000     0.000000     0.000000     0.000000
+      148.062      143.007      75975.5     0.000000     0.000000     0.000000     0.000000
+      122.010      119.083      75621.7     0.000000     0.000000     0.000000     0.000000
+      200.155      190.028      75504.5     0.000000     0.000000     0.000000     0.000000
+      169.312      285.975      74337.4     0.000000     0.000000     0.000000     0.000000
+      357.948      307.675      73702.0     0.000000     0.000000     0.000000     0.000000
+      359.127      274.367      71515.1     0.000000     0.000000     0.000000     0.000000
+      45.3947      57.2922      71148.6     0.000000     0.000000     0.000000     0.000000
+      204.018      10.9722      70522.5     0.000000     0.000000     0.000000     0.000000
+      244.906      334.343      65969.8     0.000000     0.000000     0.000000     0.000000
+      258.525      297.974      65360.8     0.000000     0.000000     0.000000     0.000000
+      258.209      214.108      64573.3     0.000000     0.000000     0.000000     0.000000
+      199.392      61.8723      64532.7     0.000000     0.000000     0.000000     0.000000
+      61.0304      229.297      63913.4     0.000000     0.000000     0.000000     0.000000
+      160.626      164.319      62196.8     0.000000     0.000000     0.000000     0.000000
+      329.092      248.683      61878.7     0.000000     0.000000     0.000000     0.000000
+      127.118      169.217      61871.3     0.000000     0.000000     0.000000     0.000000
+      191.067      240.918      61298.6     0.000000     0.000000     0.000000     0.000000
+      250.683      28.4992      61234.0     0.000000     0.000000     0.000000     0.000000
+      40.4708      4.53567      60880.9     0.000000     0.000000     0.000000     0.000000
+      259.064      80.9131      60770.4     0.000000     0.000000     0.000000     0.000000
+      143.693      92.0707      58822.8     0.000000     0.000000     0.000000     0.000000
+      27.1328      110.225      57835.5     0.000000     0.000000     0.000000     0.000000
+      142.263      303.959      57615.0     0.000000     0.000000     0.000000     0.000000
+      22.9556      296.589      57282.7     0.000000     0.000000     0.000000     0.000000
+      23.7486      312.086      56885.8     0.000000     0.000000     0.000000     0.000000
+      103.904      211.577      56217.2     0.000000     0.000000     0.000000     0.000000
+      122.554      167.526      56121.2     0.000000     0.000000     0.000000     0.000000
+      275.144      70.9676      56078.2     0.000000     0.000000     0.000000     0.000000
+      181.944      342.399      56035.8     0.000000     0.000000     0.000000     0.000000
+      248.900      264.279      55127.5     0.000000     0.000000     0.000000     0.000000
+      179.764      48.4617      54755.7     0.000000     0.000000     0.000000     0.000000
+      64.7956      190.716      54361.8     0.000000     0.000000     0.000000     0.000000
+      168.035      354.381      53846.0     0.000000     0.000000     0.000000     0.000000
+      305.555      13.5973      53464.5     0.000000     0.000000     0.000000     0.000000
+      254.125      164.183      52782.5     0.000000     0.000000     0.000000     0.000000
+      129.826      82.6673      52045.7     0.000000     0.000000     0.000000     0.000000
+      175.487      96.5041      51705.9     0.000000     0.000000     0.000000     0.000000
+      131.850      5.19465      49549.7     0.000000     0.000000     0.000000     0.000000
+      251.157      47.6331      48155.6     0.000000     0.000000     0.000000     0.000000
+      156.185      297.552      44830.9     0.000000     0.000000     0.000000     0.000000
+      32.7849      347.404      44548.8     0.000000     0.000000     0.000000     0.000000
+      139.296      359.265      44434.4     0.000000     0.000000     0.000000     0.000000
+      78.6520      224.699      43521.3     0.000000     0.000000     0.000000     0.000000
+      93.3061      340.185      42670.1     0.000000     0.000000     0.000000     0.000000
+      181.422      158.919      42212.9     0.000000     0.000000     0.000000     0.000000
+      196.592      280.650      41965.6     0.000000     0.000000     0.000000     0.000000
+      84.1532      66.5267      41632.9     0.000000     0.000000     0.000000     0.000000
+      280.767      87.3626      41607.4     0.000000     0.000000     0.000000     0.000000
+      271.622      166.118      41468.1     0.000000     0.000000     0.000000     0.000000
+      13.6983      304.871      41131.6     0.000000     0.000000     0.000000     0.000000
+      48.1051      227.197      40753.8     0.000000     0.000000     0.000000     0.000000
+      20.1975      354.705      40607.0     0.000000     0.000000     0.000000     0.000000
+      345.646      132.836      40481.6     0.000000     0.000000     0.000000     0.000000
+      183.484      238.597      40418.5     0.000000     0.000000     0.000000     0.000000
+      238.737      121.789      40295.7     0.000000     0.000000     0.000000     0.000000
+      263.596      281.672      40224.8     0.000000     0.000000     0.000000     0.000000
+      162.429      177.789      40063.9     0.000000     0.000000     0.000000     0.000000
+      95.0396      86.2365      40052.7     0.000000     0.000000     0.000000     0.000000
+      354.378      190.422      39998.6     0.000000     0.000000     0.000000     0.000000
+      114.971      15.8472      39566.9     0.000000     0.000000     0.000000     0.000000
+      26.5936      16.1287      39319.5     0.000000     0.000000     0.000000     0.000000
+      77.1282      249.081      39219.6     0.000000     0.000000     0.000000     0.000000
+      306.809      9.47797      38975.8     0.000000     0.000000     0.000000     0.000000
+      83.0219      60.7900      38736.6     0.000000     0.000000     0.000000     0.000000
+      137.099      162.847      38704.7     0.000000     0.000000     0.000000     0.000000
+      64.8679      167.281      38437.0     0.000000     0.000000     0.000000     0.000000
+      211.216      148.011      38358.8     0.000000     0.000000     0.000000     0.000000
+      40.9717      155.190      38339.0     0.000000     0.000000     0.000000     0.000000
+      182.266      28.3910      38258.6     0.000000     0.000000     0.000000     0.000000
+      244.444      255.625      38151.2     0.000000     0.000000     0.000000     0.000000
+      32.2430      98.1823      38130.0     0.000000     0.000000     0.000000     0.000000
+      143.451      292.529      38101.9     0.000000     0.000000     0.000000     0.000000
+      180.375      259.875      37821.1     0.000000     0.000000     0.000000     0.000000
+      107.606      156.024      37788.5     0.000000     0.000000     0.000000     0.000000
+      210.998      81.1154      37774.4     0.000000     0.000000     0.000000     0.000000
+      340.622      133.712      37698.4     0.000000     0.000000     0.000000     0.000000
+      197.761      163.981      37594.1     0.000000     0.000000     0.000000     0.000000
+      93.8015      156.494      37421.5     0.000000     0.000000     0.000000     0.000000
+      260.590      350.815      37192.3     0.000000     0.000000     0.000000     0.000000
+      317.750      64.7870      37074.9     0.000000     0.000000     0.000000     0.000000
+      70.4437      190.468      37004.9     0.000000     0.000000     0.000000     0.000000
+      221.623      90.9939      36930.1     0.000000     0.000000     0.000000     0.000000
+      128.444      186.987      36916.6     0.000000     0.000000     0.000000     0.000000
+      26.0331      290.122      36763.0     0.000000     0.000000     0.000000     0.000000
+      87.0650      258.033      36545.5     0.000000     0.000000     0.000000     0.000000
+      279.910      342.241      36502.7     0.000000     0.000000     0.000000     0.000000
+      121.926      276.727      36382.9     0.000000     0.000000     0.000000     0.000000
+      265.246      137.480      36338.4     0.000000     0.000000     0.000000     0.000000
+      292.552      86.9713      36232.1     0.000000     0.000000     0.000000     0.000000
+      338.423      108.581      35388.8     0.000000     0.000000     0.000000     0.000000
+      196.687      304.196      35296.3     0.000000     0.000000     0.000000     0.000000
+      148.693      99.0690      35194.9     0.000000     0.000000     0.000000     0.000000
+      158.453      231.067      35136.4     0.000000     0.000000     0.000000     0.000000
+      300.064      115.489      35068.0     0.000000     0.000000     0.000000     0.000000
+      15.3618      355.783      34731.0     0.000000     0.000000     0.000000     0.000000
+      259.877      313.889      34655.6     0.000000     0.000000     0.000000     0.000000
+      344.235      60.4770      34556.6     0.000000     0.000000     0.000000     0.000000
+      171.975      216.563      34190.5     0.000000     0.000000     0.000000     0.000000
+      255.588      17.8280      34086.0     0.000000     0.000000     0.000000     0.000000
+      141.199      363.133      34003.9     0.000000     0.000000     0.000000     0.000000
+      198.494      316.173      33991.7     0.000000     0.000000     0.000000     0.000000
+      14.4216      269.120      33928.2     0.000000     0.000000     0.000000     0.000000
+      245.228      160.431      33848.2     0.000000     0.000000     0.000000     0.000000
+      359.424      72.3061      33841.2     0.000000     0.000000     0.000000     0.000000
+      11.2306      35.1264      33807.8     0.000000     0.000000     0.000000     0.000000
+      278.206      274.896      33586.8     0.000000     0.000000     0.000000     0.000000
+      12.5086      30.9141      33398.5     0.000000     0.000000     0.000000     0.000000
+      312.332      26.9308      33267.9     0.000000     0.000000     0.000000     0.000000
+      185.655      59.1044      32918.2     0.000000     0.000000     0.000000     0.000000
+      61.2724      190.277      32798.8     0.000000     0.000000     0.000000     0.000000
+      220.191      189.604      32750.6     0.000000     0.000000     0.000000     0.000000
+      127.860      121.978      32729.5     0.000000     0.000000     0.000000     0.000000
+      355.378      252.497      32705.5     0.000000     0.000000     0.000000     0.000000
+      214.552      255.179      32384.5     0.000000     0.000000     0.000000     0.000000
+      57.5893      181.740      32368.8     0.000000     0.000000     0.000000     0.000000
+      14.4280      335.523      32204.1     0.000000     0.000000     0.000000     0.000000
+      21.6336      118.752      31321.7     0.000000     0.000000     0.000000     0.000000
+      162.314      205.696      30852.6     0.000000     0.000000     0.000000     0.000000
+      223.611      243.805      30825.2     0.000000     0.000000     0.000000     0.000000
+      340.626      15.6565      30613.5     0.000000     0.000000     0.000000     0.000000
+      255.144      184.321      30606.3     0.000000     0.000000     0.000000     0.000000
+      150.121      63.3999      30459.8     0.000000     0.000000     0.000000     0.000000
+      233.868      252.369      30407.8     0.000000     0.000000     0.000000     0.000000
+      91.4964      11.0882      30184.1     0.000000     0.000000     0.000000     0.000000
+      140.221      260.644      30161.7     0.000000     0.000000     0.000000     0.000000
+      285.664      310.042      30151.7     0.000000     0.000000     0.000000     0.000000
+      83.0180      341.710      30018.8     0.000000     0.000000     0.000000     0.000000
+      259.472      335.211      29964.9     0.000000     0.000000     0.000000     0.000000
+      104.117      221.599      29905.0     0.000000     0.000000     0.000000     0.000000
+      158.391      195.846      29880.7     0.000000     0.000000     0.000000     0.000000
+      194.507      176.202      29819.0     0.000000     0.000000     0.000000     0.000000
+      47.3849      327.727      29782.1     0.000000     0.000000     0.000000     0.000000
+      223.476      102.402      29754.3     0.000000     0.000000     0.000000     0.000000
+      238.197      4.73843      29652.0     0.000000     0.000000     0.000000     0.000000
+      86.1274      125.202      29535.9     0.000000     0.000000     0.000000     0.000000
+      218.689      39.0515      29162.9     0.000000     0.000000     0.000000     0.000000
+      103.693      162.297      29135.5     0.000000     0.000000     0.000000     0.000000
+      178.188      153.348      28962.6     0.000000     0.000000     0.000000     0.000000
+      76.0960      337.107      28841.5     0.000000     0.000000     0.000000     0.000000
+      279.589      313.014      28506.7     0.000000     0.000000     0.000000     0.000000
+      152.271      293.573      28390.0     0.000000     0.000000     0.000000     0.000000
+      188.247      256.592      28375.0     0.000000     0.000000     0.000000     0.000000
+      354.740      209.341      28323.1     0.000000     0.000000     0.000000     0.000000
+      193.396      114.306      28163.6     0.000000     0.000000     0.000000     0.000000
+      334.937      23.8380      28114.4     0.000000     0.000000     0.000000     0.000000
+      24.7114      292.980      27856.0     0.000000     0.000000     0.000000     0.000000
+      156.112      316.887      27722.5     0.000000     0.000000     0.000000     0.000000
+      209.919      209.652      27519.5     0.000000     0.000000     0.000000     0.000000
+      280.987      171.985      27475.0     0.000000     0.000000     0.000000     0.000000
+      143.491      296.094      27402.2     0.000000     0.000000     0.000000     0.000000
+      297.004      322.017      27159.2     0.000000     0.000000     0.000000     0.000000
+      61.5556      102.870      27043.6     0.000000     0.000000     0.000000     0.000000
+      328.340      320.377      27039.4     0.000000     0.000000     0.000000     0.000000
+      190.481      154.634      27030.4     0.000000     0.000000     0.000000     0.000000
+      342.294      54.8700      26940.8     0.000000     0.000000     0.000000     0.000000
+      37.8107      29.3057      26879.3     0.000000     0.000000     0.000000     0.000000
+      246.564      238.117      26846.3     0.000000     0.000000     0.000000     0.000000
+      64.6574      259.351      26589.7     0.000000     0.000000     0.000000     0.000000
+      280.739      212.330      26546.6     0.000000     0.000000     0.000000     0.000000
+      54.7320      320.027      26357.3     0.000000     0.000000     0.000000     0.000000
+      141.126      125.049      26310.2     0.000000     0.000000     0.000000     0.000000
+      314.045      320.963      26281.7     0.000000     0.000000     0.000000     0.000000
+      122.404      229.985      26176.5     0.000000     0.000000     0.000000     0.000000
+      232.309      157.823      26172.8     0.000000     0.000000     0.000000     0.000000
+      133.826      56.8797      26135.3     0.000000     0.000000     0.000000     0.000000
+      251.216      339.756      26089.7     0.000000     0.000000     0.000000     0.000000
+      248.913      178.616      26077.4     0.000000     0.000000     0.000000     0.000000
+      183.376      354.064      26073.6     0.000000     0.000000     0.000000     0.000000
+      165.715      273.441      26047.2     0.000000     0.000000     0.000000     0.000000
+      150.352      177.678      25951.7     0.000000     0.000000     0.000000     0.000000
+      313.176      331.037      25901.4     0.000000     0.000000     0.000000     0.000000
+      270.414      49.7428      25779.4     0.000000     0.000000     0.000000     0.000000
+      73.8670      60.6083      25582.7     0.000000     0.000000     0.000000     0.000000
+      355.293      350.701      25541.3     0.000000     0.000000     0.000000     0.000000
+      262.530      141.016      25468.6     0.000000     0.000000     0.000000     0.000000
+      255.002      111.344      25217.2     0.000000     0.000000     0.000000     0.000000
+      289.411      71.4270      25216.9     0.000000     0.000000     0.000000     0.000000
+      219.648      180.555      24981.3     0.000000     0.000000     0.000000     0.000000
+      175.428      132.120      24967.6     0.000000     0.000000     0.000000     0.000000
+      125.422      289.734      24945.9     0.000000     0.000000     0.000000     0.000000
+      183.006      123.685      24945.5     0.000000     0.000000     0.000000     0.000000
+      176.200      116.606      24915.3     0.000000     0.000000     0.000000     0.000000
+      291.452      243.735      24911.3     0.000000     0.000000     0.000000     0.000000
+      326.645      303.884      24786.9     0.000000     0.000000     0.000000     0.000000
+      214.429      143.610      24659.9     0.000000     0.000000     0.000000     0.000000
+      311.426      47.9050      24614.0     0.000000     0.000000     0.000000     0.000000
+      98.3522      320.341      24601.9     0.000000     0.000000     0.000000     0.000000
+      220.412      139.228      24593.1     0.000000     0.000000     0.000000     0.000000
+      42.7167      59.2701      24578.4     0.000000     0.000000     0.000000     0.000000
+      107.204      289.952      24508.6     0.000000     0.000000     0.000000     0.000000
+      46.9480      118.741      24437.0     0.000000     0.000000     0.000000     0.000000
+      159.269      55.3080      24427.0     0.000000     0.000000     0.000000     0.000000
+      170.868      74.5069      24309.4     0.000000     0.000000     0.000000     0.000000
+      168.355      155.541      24229.1     0.000000     0.000000     0.000000     0.000000
+      306.077      303.947      23994.5     0.000000     0.000000     0.000000     0.000000
+      232.098      108.789      23993.4     0.000000     0.000000     0.000000     0.000000
+      136.224      253.386      23847.3     0.000000     0.000000     0.000000     0.000000
+      276.501      30.7327      23746.8     0.000000     0.000000     0.000000     0.000000
+      273.140      298.849      23502.5     0.000000     0.000000     0.000000     0.000000
+      262.615      40.7531      23376.4     0.000000     0.000000     0.000000     0.000000
+      21.2239      153.017      23342.0     0.000000     0.000000     0.000000     0.000000
+      357.514      138.104      23264.1     0.000000     0.000000     0.000000     0.000000
+      340.214      29.6600      23083.4     0.000000     0.000000     0.000000     0.000000
+      139.031      303.849      23011.2     0.000000     0.000000     0.000000     0.000000
+      127.348      191.829      22954.2     0.000000     0.000000     0.000000     0.000000
+      241.219      266.692      22941.1     0.000000     0.000000     0.000000     0.000000
+      170.164      68.4117      22927.0     0.000000     0.000000     0.000000     0.000000
+      242.757      102.877      22885.0     0.000000     0.000000     0.000000     0.000000
+      346.583      148.389      22865.2     0.000000     0.000000     0.000000     0.000000
+      196.090      346.828      22838.0     0.000000     0.000000     0.000000     0.000000
+      123.187      21.0655      22802.1     0.000000     0.000000     0.000000     0.000000
+      218.130      205.490      22747.1     0.000000     0.000000     0.000000     0.000000
+      129.180      235.133      22601.7     0.000000     0.000000     0.000000     0.000000
+      323.108      7.16255      22454.3     0.000000     0.000000     0.000000     0.000000
+      161.937      162.696      22281.2     0.000000     0.000000     0.000000     0.000000
+      342.856      196.480      22150.8     0.000000     0.000000     0.000000     0.000000
+      245.465      153.179      22044.6     0.000000     0.000000     0.000000     0.000000
+      262.846      119.758      21830.1     0.000000     0.000000     0.000000     0.000000
+      247.060      44.7340      21737.1     0.000000     0.000000     0.000000     0.000000
+      14.6492      242.304      21586.9     0.000000     0.000000     0.000000     0.000000
+      305.187      298.337      21354.4     0.000000     0.000000     0.000000     0.000000
+      136.872      92.1575      21351.5     0.000000     0.000000     0.000000     0.000000
+      243.913      241.775      21328.0     0.000000     0.000000     0.000000     0.000000
+      61.8279      334.386      21259.3     0.000000     0.000000     0.000000     0.000000
+      316.777      211.091      21234.2     0.000000     0.000000     0.000000     0.000000
+      5.01734      304.795      21216.3     0.000000     0.000000     0.000000     0.000000
+      229.980      73.8202      21105.5     0.000000     0.000000     0.000000     0.000000
+      45.3229      129.853      21087.7     0.000000     0.000000     0.000000     0.000000
+      305.763      76.3401      20793.4     0.000000     0.000000     0.000000     0.000000
+      144.351      350.475      20430.6     0.000000     0.000000     0.000000     0.000000
+      312.433      208.532      20342.0     0.000000     0.000000     0.000000     0.000000
+      217.491      36.1401      20095.0     0.000000     0.000000     0.000000     0.000000
+      234.536      101.352      20022.5     0.000000     0.000000     0.000000     0.000000
+      66.6876      14.9143      20022.5     0.000000     0.000000     0.000000     0.000000
+      239.775      184.169      19979.0     0.000000     0.000000     0.000000     0.000000
+      207.392      300.690      19873.1     0.000000     0.000000     0.000000     0.000000
+      285.473      86.7142      19870.3     0.000000     0.000000     0.000000     0.000000
+      103.209      329.003      19788.0     0.000000     0.000000     0.000000     0.000000
+      144.329      5.52987      19689.5     0.000000     0.000000     0.000000     0.000000
+      163.591      48.8786      19684.6     0.000000     0.000000     0.000000     0.000000
+      41.1080      347.128      19634.7     0.000000     0.000000     0.000000     0.000000
+      265.919      176.901      19627.3     0.000000     0.000000     0.000000     0.000000
+      3.01452      70.8604      19596.9     0.000000     0.000000     0.000000     0.000000
+      45.7414      212.730      19592.9     0.000000     0.000000     0.000000     0.000000
+      245.358      361.263      19494.8     0.000000     0.000000     0.000000     0.000000
+      129.773      175.180      19375.8     0.000000     0.000000     0.000000     0.000000
+      193.050      236.955      19369.1     0.000000     0.000000     0.000000     0.000000
+      255.570      133.309      19365.4     0.000000     0.000000     0.000000     0.000000
+      349.580      288.906      19270.6     0.000000     0.000000     0.000000     0.000000
+      212.150      126.407      19262.1     0.000000     0.000000     0.000000     0.000000
+      284.457      50.2993      19110.8     0.000000     0.000000     0.000000     0.000000
+      108.445      343.947      19101.5     0.000000     0.000000     0.000000     0.000000
+      98.5429      75.6392      19093.8     0.000000     0.000000     0.000000     0.000000
+      243.557      29.4193      18852.6     0.000000     0.000000     0.000000     0.000000
+      41.2816      282.126      18554.4     0.000000     0.000000     0.000000     0.000000
+      252.426      363.544      18528.4     0.000000     0.000000     0.000000     0.000000
+      303.026      44.1925      18521.4     0.000000     0.000000     0.000000     0.000000
+      52.4907      278.827      18517.0     0.000000     0.000000     0.000000     0.000000
+      80.0980      104.970      18348.4     0.000000     0.000000     0.000000     0.000000
+      104.881      127.866      18244.3     0.000000     0.000000     0.000000     0.000000
+      44.3451      255.037      18238.5     0.000000     0.000000     0.000000     0.000000
+      131.637      122.596      18158.9     0.000000     0.000000     0.000000     0.000000
+      83.7545      59.7327      18156.9     0.000000     0.000000     0.000000     0.000000
+      80.2236      239.321      18130.3     0.000000     0.000000     0.000000     0.000000
+      317.533      47.1217      18119.6     0.000000     0.000000     0.000000     0.000000
+      145.036      140.407      17989.1     0.000000     0.000000     0.000000     0.000000
+      141.051      298.051      17982.8     0.000000     0.000000     0.000000     0.000000
+      156.464      319.885      17979.6     0.000000     0.000000     0.000000     0.000000
+      209.453      326.082      17946.1     0.000000     0.000000     0.000000     0.000000
+      307.757      229.041      17879.8     0.000000     0.000000     0.000000     0.000000
+      266.524      99.1295      17779.1     0.000000     0.000000     0.000000     0.000000
+      289.194      129.046      17714.1     0.000000     0.000000     0.000000     0.000000
+      93.9559      222.648      17696.6     0.000000     0.000000     0.000000     0.000000
+      160.844      104.638      17464.8     0.000000     0.000000     0.000000     0.000000
+      133.751      51.1189      17409.9     0.000000     0.000000     0.000000     0.000000
+      116.573      303.190      17376.9     0.000000     0.000000     0.000000     0.000000
+      87.7180      49.7890      17363.9     0.000000     0.000000     0.000000     0.000000
+      350.731      48.4579      17213.3     0.000000     0.000000     0.000000     0.000000
+      137.892      58.0751      16926.9     0.000000     0.000000     0.000000     0.000000
+      323.030      59.8720      16855.2     0.000000     0.000000     0.000000     0.000000
+      32.3589      338.198      16854.7     0.000000     0.000000     0.000000     0.000000
+      9.42043      273.939      16851.0     0.000000     0.000000     0.000000     0.000000
+      302.530      311.379      16790.2     0.000000     0.000000     0.000000     0.000000
+      48.4972      292.222      16781.3     0.000000     0.000000     0.000000     0.000000
+      283.278      14.4937      16676.5     0.000000     0.000000     0.000000     0.000000
+      46.3838      261.815      16664.5     0.000000     0.000000     0.000000     0.000000
+      88.9964      85.2222      16607.6     0.000000     0.000000     0.000000     0.000000
+      359.077      74.4421      16590.0     0.000000     0.000000     0.000000     0.000000
+      19.4328      83.3369      16540.7     0.000000     0.000000     0.000000     0.000000
+      152.302      28.6130      16520.8     0.000000     0.000000     0.000000     0.000000
+      223.018      76.2170      16514.7     0.000000     0.000000     0.000000     0.000000
+      316.030      77.9975      16510.2     0.000000     0.000000     0.000000     0.000000
+      138.917      160.170      16484.3     0.000000     0.000000     0.000000     0.000000
+      223.953      12.3861      16482.4     0.000000     0.000000     0.000000     0.000000
+      214.474      271.793      16481.6     0.000000     0.000000     0.000000     0.000000
+      78.1325      205.277      16481.3     0.000000     0.000000     0.000000     0.000000
+      235.625      52.7153      16471.8     0.000000     0.000000     0.000000     0.000000
+      354.783      139.073      16457.8     0.000000     0.000000     0.000000     0.000000
+      3.56808      198.879      16424.3     0.000000     0.000000     0.000000     0.000000
+      168.668      14.9409      16395.3     0.000000     0.000000     0.000000     0.000000
+      245.260      133.896      16380.6     0.000000     0.000000     0.000000     0.000000
+      301.882      353.278      16377.0     0.000000     0.000000     0.000000     0.000000
+      139.618      291.032      16321.1     0.000000     0.000000     0.000000     0.000000
+      165.128      297.489      16320.5     0.000000     0.000000     0.000000     0.000000
+      122.781      239.530      16265.7     0.000000     0.000000     0.000000     0.000000
+      188.373      64.3559      16263.2     0.000000     0.000000     0.000000     0.000000
+      177.580      235.027      16250.7     0.000000     0.000000     0.000000     0.000000
+      32.4557      306.842      16226.1     0.000000     0.000000     0.000000     0.000000
+      164.661      168.512      16198.5     0.000000     0.000000     0.000000     0.000000
+      262.112      211.318      16193.5     0.000000     0.000000     0.000000     0.000000
+      147.116      327.635      16180.3     0.000000     0.000000     0.000000     0.000000
+      102.228      72.9018      16147.2     0.000000     0.000000     0.000000     0.000000
+      306.166      263.748      16089.4     0.000000     0.000000     0.000000     0.000000
+      52.4548      171.662      16079.3     0.000000     0.000000     0.000000     0.000000
+      358.891      189.852      16043.8     0.000000     0.000000     0.000000     0.000000
+      253.507      229.634      16041.5     0.000000     0.000000     0.000000     0.000000
+      164.988      279.357      16041.2     0.000000     0.000000     0.000000     0.000000
+      128.062      338.965      15973.2     0.000000     0.000000     0.000000     0.000000
+      172.024      74.8392      15963.1     0.000000     0.000000     0.000000     0.000000
+      167.933      188.467      15961.1     0.000000     0.000000     0.000000     0.000000
+      350.253      289.588      15956.4     0.000000     0.000000     0.000000     0.000000
+      363.672      203.275      15932.4     0.000000     0.000000     0.000000     0.000000
+      129.272      93.8611      15904.2     0.000000     0.000000     0.000000     0.000000
+      234.879      123.706      15904.1     0.000000     0.000000     0.000000     0.000000
+      23.2646      210.800      15896.7     0.000000     0.000000     0.000000     0.000000
+      209.357      241.943      15882.7     0.000000     0.000000     0.000000     0.000000
+      180.687      117.996      15872.5     0.000000     0.000000     0.000000     0.000000
+      336.864      75.7837      15860.1     0.000000     0.000000     0.000000     0.000000
+      308.564      307.915      15824.9     0.000000     0.000000     0.000000     0.000000
+      224.627      296.561      15812.1     0.000000     0.000000     0.000000     0.000000
+      181.376      224.835      15749.0     0.000000     0.000000     0.000000     0.000000
+      138.004      248.014      15697.7     0.000000     0.000000     0.000000     0.000000
+      148.405      208.206      15648.6     0.000000     0.000000     0.000000     0.000000
+      43.0012      147.090      15624.2     0.000000     0.000000     0.000000     0.000000
+      55.4895      222.495      15589.3     0.000000     0.000000     0.000000     0.000000
+      138.836      206.598      15544.2     0.000000     0.000000     0.000000     0.000000
+      64.8731      72.5455      15533.4     0.000000     0.000000     0.000000     0.000000
+      271.611      227.078      15531.5     0.000000     0.000000     0.000000     0.000000
+      91.9145      103.725      15495.1     0.000000     0.000000     0.000000     0.000000
+      286.411      41.6308      15488.2     0.000000     0.000000     0.000000     0.000000
+      34.2647      312.923      15454.5     0.000000     0.000000     0.000000     0.000000
+      290.567      362.981      15416.5     0.000000     0.000000     0.000000     0.000000
+      360.258      354.323      15388.4     0.000000     0.000000     0.000000     0.000000
+      201.375      213.505      15383.9     0.000000     0.000000     0.000000     0.000000
+      201.298      354.240      15378.6     0.000000     0.000000     0.000000     0.000000
+      195.002      25.7019      15360.8     0.000000     0.000000     0.000000     0.000000
+      71.6831      255.232      15359.9     0.000000     0.000000     0.000000     0.000000
+      174.469      266.665      15340.3     0.000000     0.000000     0.000000     0.000000
+      158.528      317.745      15337.3     0.000000     0.000000     0.000000     0.000000
+      168.200      249.695      15314.3     0.000000     0.000000     0.000000     0.000000
+      310.647      263.492      15264.3     0.000000     0.000000     0.000000     0.000000
+      219.865      24.4243      15258.7     0.000000     0.000000     0.000000     0.000000
+      345.731      55.9484      15249.6     0.000000     0.000000     0.000000     0.000000
+      296.935      156.008      15244.2     0.000000     0.000000     0.000000     0.000000
+      63.8222      105.283      15238.0     0.000000     0.000000     0.000000     0.000000
+      291.241      239.914      15237.0     0.000000     0.000000     0.000000     0.000000
+      361.177      337.150      15235.1     0.000000     0.000000     0.000000     0.000000
+      161.663      116.349      15229.4     0.000000     0.000000     0.000000     0.000000
+      244.247      238.389      15214.8     0.000000     0.000000     0.000000     0.000000
+      194.193      163.689      15150.9     0.000000     0.000000     0.000000     0.000000
+      36.8054      104.885      15141.2     0.000000     0.000000     0.000000     0.000000
+      335.458      241.595      15082.1     0.000000     0.000000     0.000000     0.000000
+      251.383      315.676      15032.2     0.000000     0.000000     0.000000     0.000000
+      205.569      171.467      14991.4     0.000000     0.000000     0.000000     0.000000
+      334.390      332.674      14980.3     0.000000     0.000000     0.000000     0.000000
+      4.37845      242.829      14932.3     0.000000     0.000000     0.000000     0.000000
+      213.486      218.862      14926.5     0.000000     0.000000     0.000000     0.000000
+      11.6138      188.180      14915.5     0.000000     0.000000     0.000000     0.000000
+      62.7144      111.802      14906.5     0.000000     0.000000     0.000000     0.000000
+      341.116      122.965      14904.4     0.000000     0.000000     0.000000     0.000000
+      167.098      201.155      14879.8     0.000000     0.000000     0.000000     0.000000
+      119.749      258.761      14867.7     0.000000     0.000000     0.000000     0.000000
+      141.900      174.599      14859.6     0.000000     0.000000     0.000000     0.000000
+      76.6127      189.811      14852.7     0.000000     0.000000     0.000000     0.000000
+      306.080      36.0436      14843.5     0.000000     0.000000     0.000000     0.000000
+      149.521      114.137      14827.3     0.000000     0.000000     0.000000     0.000000
+      62.8410      93.3785      14818.4     0.000000     0.000000     0.000000     0.000000
+      65.2576      150.670      14817.8     0.000000     0.000000     0.000000     0.000000
+      192.994      235.970      14812.7     0.000000     0.000000     0.000000     0.000000
+      24.7471      67.3128      14800.1     0.000000     0.000000     0.000000     0.000000
+      352.101      307.515      14763.7     0.000000     0.000000     0.000000     0.000000
+      246.477      140.334      14759.9     0.000000     0.000000     0.000000     0.000000
+      192.727      123.419      14728.5     0.000000     0.000000     0.000000     0.000000
+      31.2353      69.5522      14725.5     0.000000     0.000000     0.000000     0.000000
+      106.922      61.6365      14697.9     0.000000     0.000000     0.000000     0.000000
+      123.972      120.534      14677.2     0.000000     0.000000     0.000000     0.000000
+      347.941      234.537      14637.1     0.000000     0.000000     0.000000     0.000000
+      3.60083      167.327      14623.2     0.000000     0.000000     0.000000     0.000000
+      16.6035      61.7953      14620.6     0.000000     0.000000     0.000000     0.000000
+      321.528      121.160      14609.6     0.000000     0.000000     0.000000     0.000000
+      130.912      105.016      14597.9     0.000000     0.000000     0.000000     0.000000
+      65.3000      39.6274      14567.7     0.000000     0.000000     0.000000     0.000000
+      297.005      220.434      14561.1     0.000000     0.000000     0.000000     0.000000
+      18.1205      82.5609      14554.5     0.000000     0.000000     0.000000     0.000000
+      69.7734      245.039      14532.6     0.000000     0.000000     0.000000     0.000000
+      204.297      199.394      14505.1     0.000000     0.000000     0.000000     0.000000
+      94.8972      14.2587      14481.6     0.000000     0.000000     0.000000     0.000000
+      63.3900      138.389      14448.9     0.000000     0.000000     0.000000     0.000000
+      234.641      358.762      14448.7     0.000000     0.000000     0.000000     0.000000
+      358.741      327.191      14407.8     0.000000     0.000000     0.000000     0.000000
+      349.905      62.7117      14396.1     0.000000     0.000000     0.000000     0.000000
+      22.7864      87.4560      14391.4     0.000000     0.000000     0.000000     0.000000
+      230.120      339.082      14390.1     0.000000     0.000000     0.000000     0.000000
+      108.111      321.511      14373.6     0.000000     0.000000     0.000000     0.000000
+      317.026      276.578      14356.8     0.000000     0.000000     0.000000     0.000000
+      272.134      337.203      14335.5     0.000000     0.000000     0.000000     0.000000
+      180.295      97.3230      14329.0     0.000000     0.000000     0.000000     0.000000
+      281.363      326.638      14265.0     0.000000     0.000000     0.000000     0.000000
+      227.063      311.070      14255.6     0.000000     0.000000     0.000000     0.000000
+      183.418      258.732      14254.3     0.000000     0.000000     0.000000     0.000000
+      56.3467      286.487      14240.1     0.000000     0.000000     0.000000     0.000000
+      283.491      28.8608      14220.0     0.000000     0.000000     0.000000     0.000000
+      199.402      279.639      14204.6     0.000000     0.000000     0.000000     0.000000
+      344.018      302.872      14203.2     0.000000     0.000000     0.000000     0.000000
+      362.073      85.5142      14187.5     0.000000     0.000000     0.000000     0.000000
+      63.8054      71.4535      14186.8     0.000000     0.000000     0.000000     0.000000
+      21.7488      355.081      14132.3     0.000000     0.000000     0.000000     0.000000
+      191.489      321.967      14125.4     0.000000     0.000000     0.000000     0.000000
+      201.271      147.150      14124.7     0.000000     0.000000     0.000000     0.000000
+      251.122      111.121      14123.2     0.000000     0.000000     0.000000     0.000000
+      222.080      273.185      14113.5     0.000000     0.000000     0.000000     0.000000
+      331.818      105.101      14108.4     0.000000     0.000000     0.000000     0.000000
+      88.1360      294.219      14081.4     0.000000     0.000000     0.000000     0.000000
+      200.960      198.588      14062.9     0.000000     0.000000     0.000000     0.000000
+      251.984      283.924      14059.0     0.000000     0.000000     0.000000     0.000000
+      138.533      353.062      14052.4     0.000000     0.000000     0.000000     0.000000
+      256.849      328.732      14044.8     0.000000     0.000000     0.000000     0.000000
+      111.828      241.685      14041.4     0.000000     0.000000     0.000000     0.000000
+      126.877      90.7269      14037.3     0.000000     0.000000     0.000000     0.000000
+      243.825      42.6837      14036.3     0.000000     0.000000     0.000000     0.000000
+      347.499      78.8332      14031.4     0.000000     0.000000     0.000000     0.000000
+      29.3669      256.523      14025.3     0.000000     0.000000     0.000000     0.000000
+      199.751      150.531      13989.7     0.000000     0.000000     0.000000     0.000000
+      150.995      272.232      13966.1     0.000000     0.000000     0.000000     0.000000
+      203.903      142.845      13905.4     0.000000     0.000000     0.000000     0.000000
+      166.491      62.0418      13870.6     0.000000     0.000000     0.000000     0.000000
+      176.796      328.800      13868.2     0.000000     0.000000     0.000000     0.000000
+      170.432      98.9300      13842.3     0.000000     0.000000     0.000000     0.000000
+      130.904      139.211      13839.8     0.000000     0.000000     0.000000     0.000000
+      144.127      50.9461      13831.6     0.000000     0.000000     0.000000     0.000000
+      72.1932      342.729      13821.6     0.000000     0.000000     0.000000     0.000000
+      61.3450      361.764      13801.0     0.000000     0.000000     0.000000     0.000000
+      140.029      161.223      13781.2     0.000000     0.000000     0.000000     0.000000
+      236.984      14.6743      13755.7     0.000000     0.000000     0.000000     0.000000
+      105.077      335.650      13703.9     0.000000     0.000000     0.000000     0.000000
+      325.066      194.209      13689.6     0.000000     0.000000     0.000000     0.000000
+      29.3006      215.859      13669.1     0.000000     0.000000     0.000000     0.000000
+      32.8177      62.4512      13665.8     0.000000     0.000000     0.000000     0.000000
+      266.401      99.9594      13658.5     0.000000     0.000000     0.000000     0.000000
+      211.166      312.198      13620.0     0.000000     0.000000     0.000000     0.000000
+      93.5192      105.553      13600.6     0.000000     0.000000     0.000000     0.000000
+      45.2959      81.0646      13587.3     0.000000     0.000000     0.000000     0.000000
+      288.607      351.075      13583.5     0.000000     0.000000     0.000000     0.000000
+      181.065      54.7112      13570.8     0.000000     0.000000     0.000000     0.000000
+      147.589      201.483      13567.4     0.000000     0.000000     0.000000     0.000000
+      202.244      199.902      13561.9     0.000000     0.000000     0.000000     0.000000
+      262.522      178.621      13515.2     0.000000     0.000000     0.000000     0.000000
+      248.962      152.616      13502.7     0.000000     0.000000     0.000000     0.000000
+      352.888      357.563      13500.1     0.000000     0.000000     0.000000     0.000000
+      213.718      302.877      13470.8     0.000000     0.000000     0.000000     0.000000
+      149.837      113.488      13460.0     0.000000     0.000000     0.000000     0.000000
+      189.020      138.238      13445.2     0.000000     0.000000     0.000000     0.000000
+      249.078      108.727      13444.3     0.000000     0.000000     0.000000     0.000000
+      294.594      208.276      13404.0     0.000000     0.000000     0.000000     0.000000
+      75.3453      333.563      13380.6     0.000000     0.000000     0.000000     0.000000
+      92.1763      151.808      13355.2     0.000000     0.000000     0.000000     0.000000
+      130.025      62.1811      13343.6     0.000000     0.000000     0.000000     0.000000
+      363.235      123.166      13310.2     0.000000     0.000000     0.000000     0.000000
+      7.02267      98.4354      13292.4     0.000000     0.000000     0.000000     0.000000
+      300.030      32.7445      13276.7     0.000000     0.000000     0.000000     0.000000
+      142.064      18.6700      13266.9     0.000000     0.000000     0.000000     0.000000
+      206.554      35.7591      13243.2     0.000000     0.000000     0.000000     0.000000
+      154.639      316.345      13235.1     0.000000     0.000000     0.000000     0.000000
+      189.662      60.7627      13227.4     0.000000     0.000000     0.000000     0.000000
+      10.8179      250.801      13220.2     0.000000     0.000000     0.000000     0.000000
+      174.230      175.471      13207.5     0.000000     0.000000     0.000000     0.000000
+      296.718      280.390      13149.6     0.000000     0.000000     0.000000     0.000000
+      306.943      244.012      13145.3     0.000000     0.000000     0.000000     0.000000
+      170.516      49.9658      13140.1     0.000000     0.000000     0.000000     0.000000
+      287.901      24.3702      13130.4     0.000000     0.000000     0.000000     0.000000
+      337.564      277.880      13118.5     0.000000     0.000000     0.000000     0.000000
+      77.8025      240.561      13113.7     0.000000     0.000000     0.000000     0.000000
+      238.540      185.863      13109.5     0.000000     0.000000     0.000000     0.000000
+      214.278      252.369      13075.2     0.000000     0.000000     0.000000     0.000000
+      106.459      289.293      13067.1     0.000000     0.000000     0.000000     0.000000
+      78.3597      109.804      13064.1     0.000000     0.000000     0.000000     0.000000
+      205.993      356.052      13062.6     0.000000     0.000000     0.000000     0.000000
+      359.209      334.555      13027.5     0.000000     0.000000     0.000000     0.000000
+      331.500      146.132      13022.4     0.000000     0.000000     0.000000     0.000000
+      354.290      97.9034      13014.3     0.000000     0.000000     0.000000     0.000000
+      171.987      4.87055      13012.6     0.000000     0.000000     0.000000     0.000000
+      185.807      324.935      12929.9     0.000000     0.000000     0.000000     0.000000
+      232.712      336.225      12910.3     0.000000     0.000000     0.000000     0.000000
+      236.602      287.362      12874.8     0.000000     0.000000     0.000000     0.000000
+      46.3189      10.3655      12847.5     0.000000     0.000000     0.000000     0.000000
+      357.498      154.141      12795.4     0.000000     0.000000     0.000000     0.000000
+      304.459      344.493      12771.7     0.000000     0.000000     0.000000     0.000000
+      34.3393      248.134      12766.2     0.000000     0.000000     0.000000     0.000000
+      349.093      18.0188      12753.9     0.000000     0.000000     0.000000     0.000000
+      327.095      68.1273      12752.3     0.000000     0.000000     0.000000     0.000000
+      139.162      283.033      12739.8     0.000000     0.000000     0.000000     0.000000
+      36.9341      344.077      12716.8     0.000000     0.000000     0.000000     0.000000
+      133.703      218.410      12697.8     0.000000     0.000000     0.000000     0.000000
+      214.902      274.618      12679.1     0.000000     0.000000     0.000000     0.000000
+      316.714      300.312      12660.2     0.000000     0.000000     0.000000     0.000000
+      298.096      264.712      12645.9     0.000000     0.000000     0.000000     0.000000
+      152.851      363.386      12645.7     0.000000     0.000000     0.000000     0.000000
+      306.643      168.527      12587.3     0.000000     0.000000     0.000000     0.000000
+      216.967      327.614      12585.2     0.000000     0.000000     0.000000     0.000000
+      284.660      351.667      12571.5     0.000000     0.000000     0.000000     0.000000
+      42.3146      165.977      12543.2     0.000000     0.000000     0.000000     0.000000
+      158.357      220.813      12527.9     0.000000     0.000000     0.000000     0.000000
+      153.702      257.090      12492.0     0.000000     0.000000     0.000000     0.000000
+      313.976      153.479      12473.8     0.000000     0.000000     0.000000     0.000000
+      148.738      252.439      12422.9     0.000000     0.000000     0.000000     0.000000
+      326.491      270.312      12413.9     0.000000     0.000000     0.000000     0.000000
+      156.401      267.468      12409.7     0.000000     0.000000     0.000000     0.000000
+      297.961      269.814      12406.8     0.000000     0.000000     0.000000     0.000000
+      121.527      229.707      12373.6     0.000000     0.000000     0.000000     0.000000
+      55.7035      85.5249      12286.2     0.000000     0.000000     0.000000     0.000000
+      348.916      88.4967      12284.8     0.000000     0.000000     0.000000     0.000000
+      96.4374      231.709      12284.0     0.000000     0.000000     0.000000     0.000000
+      300.548      154.692      12256.9     0.000000     0.000000     0.000000     0.000000
+      160.314      13.0360      12218.8     0.000000     0.000000     0.000000     0.000000
+      219.159      138.652      12211.3     0.000000     0.000000     0.000000     0.000000
+      248.748      76.2700      12198.8     0.000000     0.000000     0.000000     0.000000
+      20.4236      234.168      12198.2     0.000000     0.000000     0.000000     0.000000
+      31.4977      286.610      12175.5     0.000000     0.000000     0.000000     0.000000
+      243.974      278.342      12151.7     0.000000     0.000000     0.000000     0.000000
+      103.561      197.281      12130.3     0.000000     0.000000     0.000000     0.000000
+      152.034      122.094      12102.1     0.000000     0.000000     0.000000     0.000000
+      90.5346      9.32374      12085.4     0.000000     0.000000     0.000000     0.000000
+      305.691      194.666      12066.6     0.000000     0.000000     0.000000     0.000000
+      256.903      261.281      12047.2     0.000000     0.000000     0.000000     0.000000
+      311.221      81.2428      12035.9     0.000000     0.000000     0.000000     0.000000
+      273.788      297.322      12023.1     0.000000     0.000000     0.000000     0.000000
+      129.700      76.6173      12020.7     0.000000     0.000000     0.000000     0.000000
+      199.615      317.206      12019.1     0.000000     0.000000     0.000000     0.000000
+      115.028      92.0918      12006.0     0.000000     0.000000     0.000000     0.000000
+      287.003      147.767      11966.7     0.000000     0.000000     0.000000     0.000000
+      275.602      343.999      11957.1     0.000000     0.000000     0.000000     0.000000
+      100.723      327.139      11941.4     0.000000     0.000000     0.000000     0.000000
+      266.488      79.2946      11939.1     0.000000     0.000000     0.000000     0.000000
+      353.888      330.321      11889.3     0.000000     0.000000     0.000000     0.000000
+      210.325      49.9941      11853.8     0.000000     0.000000     0.000000     0.000000
+      114.017      57.2840      11840.9     0.000000     0.000000     0.000000     0.000000
+      302.389      179.064      11832.5     0.000000     0.000000     0.000000     0.000000
+      172.789      130.951      11802.4     0.000000     0.000000     0.000000     0.000000
+      254.915      299.850      11800.5     0.000000     0.000000     0.000000     0.000000
+      102.401      13.9669      11772.8     0.000000     0.000000     0.000000     0.000000
+      58.9761      281.184      11749.5     0.000000     0.000000     0.000000     0.000000
+      128.119      61.4088      11736.1     0.000000     0.000000     0.000000     0.000000
+      352.178      208.087      11697.3     0.000000     0.000000     0.000000     0.000000
+      162.070      152.026      11697.0     0.000000     0.000000     0.000000     0.000000
+      7.49861      251.724      11671.1     0.000000     0.000000     0.000000     0.000000
+      168.642      207.709      11644.3     0.000000     0.000000     0.000000     0.000000
+      136.068      121.350      11621.5     0.000000     0.000000     0.000000     0.000000
+      320.275      213.144      11586.3     0.000000     0.000000     0.000000     0.000000
+      227.644      62.5805      11585.6     0.000000     0.000000     0.000000     0.000000
+      78.8221      27.6432      11573.0     0.000000     0.000000     0.000000     0.000000
+      214.251      127.613      11568.7     0.000000     0.000000     0.000000     0.000000
+      163.459      15.5157      11561.8     0.000000     0.000000     0.000000     0.000000
+      61.6744      331.132      11556.6     0.000000     0.000000     0.000000     0.000000
+      264.949      294.568      11520.6     0.000000     0.000000     0.000000     0.000000
+      265.972      107.224      11509.7     0.000000     0.000000     0.000000     0.000000
+      93.5120      254.407      11477.7     0.000000     0.000000     0.000000     0.000000
+      125.181      56.6061      11467.5     0.000000     0.000000     0.000000     0.000000
+      53.8462      190.002      11451.9     0.000000     0.000000     0.000000     0.000000
+      186.376      251.675      11431.4     0.000000     0.000000     0.000000     0.000000
+      64.9942      344.878      11417.0     0.000000     0.000000     0.000000     0.000000
+      123.082      235.587      11390.1     0.000000     0.000000     0.000000     0.000000
+      150.701      210.810      11357.8     0.000000     0.000000     0.000000     0.000000
+      253.085      184.330      11351.2     0.000000     0.000000     0.000000     0.000000
+      253.276      258.162      11328.3     0.000000     0.000000     0.000000     0.000000
+      276.483      268.743      11313.8     0.000000     0.000000     0.000000     0.000000
+      189.279      187.865      11305.3     0.000000     0.000000     0.000000     0.000000
+      215.193      201.435      11265.0     0.000000     0.000000     0.000000     0.000000
+      69.5529      153.028      11248.0     0.000000     0.000000     0.000000     0.000000
+      44.8571      141.318      11246.3     0.000000     0.000000     0.000000     0.000000
+      255.785      257.613      11224.9     0.000000     0.000000     0.000000     0.000000
+      247.608      88.8264      11202.4     0.000000     0.000000     0.000000     0.000000
+      156.177      67.7048      11186.5     0.000000     0.000000     0.000000     0.000000
+      13.5149      239.654      11168.9     0.000000     0.000000     0.000000     0.000000
+      187.392      112.795      11138.0     0.000000     0.000000     0.000000     0.000000
+      14.8975      47.6641      11105.0     0.000000     0.000000     0.000000     0.000000
+      70.7366      188.308      11103.1     0.000000     0.000000     0.000000     0.000000
+      271.378      230.490      11090.4     0.000000     0.000000     0.000000     0.000000
+      168.597      53.0663      11074.7     0.000000     0.000000     0.000000     0.000000
+      285.365      155.739      11057.2     0.000000     0.000000     0.000000     0.000000
+      263.262      200.536      11031.6     0.000000     0.000000     0.000000     0.000000
+      290.855      229.283      11019.5     0.000000     0.000000     0.000000     0.000000
+      21.7265      11.0327      11001.5     0.000000     0.000000     0.000000     0.000000
+      211.312      193.496      10977.8     0.000000     0.000000     0.000000     0.000000
+      354.942      344.677      10969.7     0.000000     0.000000     0.000000     0.000000
+      179.984      250.949      10963.5     0.000000     0.000000     0.000000     0.000000
+      89.9879      102.486      10933.5     0.000000     0.000000     0.000000     0.000000
+      13.4885      49.8407      10925.8     0.000000     0.000000     0.000000     0.000000
+      293.170      296.958      10915.3     0.000000     0.000000     0.000000     0.000000
+      268.678      275.276      10914.3     0.000000     0.000000     0.000000     0.000000
+      11.4741      236.882      10905.5     0.000000     0.000000     0.000000     0.000000
+      216.674      117.140      10900.9     0.000000     0.000000     0.000000     0.000000
+      118.744      317.341      10900.8     0.000000     0.000000     0.000000     0.000000
+      93.5018      139.083      10898.7     0.000000     0.000000     0.000000     0.000000
+      17.3496      250.851      10896.2     0.000000     0.000000     0.000000     0.000000
+      192.690      4.16211      10893.5     0.000000     0.000000     0.000000     0.000000
+      28.9853      267.572      10889.8     0.000000     0.000000     0.000000     0.000000
+      225.422      299.069      10885.0     0.000000     0.000000     0.000000     0.000000
+      11.2046      101.703      10845.9     0.000000     0.000000     0.000000     0.000000
+      299.357      82.8579      10814.0     0.000000     0.000000     0.000000     0.000000
+      338.334      302.286      10798.6     0.000000     0.000000     0.000000     0.000000
+      288.247      291.015      10777.2     0.000000     0.000000     0.000000     0.000000
+      25.2908      249.434      10775.6     0.000000     0.000000     0.000000     0.000000
+      357.118      208.553      10770.1     0.000000     0.000000     0.000000     0.000000
+      107.145      312.038      10762.6     0.000000     0.000000     0.000000     0.000000
+      88.8668      141.845      10754.3     0.000000     0.000000     0.000000     0.000000
+      340.480      270.378      10745.8     0.000000     0.000000     0.000000     0.000000
+      322.660      238.161      10706.5     0.000000     0.000000     0.000000     0.000000
+      261.030      125.355      10705.9     0.000000     0.000000     0.000000     0.000000
+      5.36683      177.624      10684.8     0.000000     0.000000     0.000000     0.000000
+      84.5028      253.255      10636.6     0.000000     0.000000     0.000000     0.000000
+      69.3425      316.810      10602.1     0.000000     0.000000     0.000000     0.000000
+      214.932      127.791      10571.5     0.000000     0.000000     0.000000     0.000000
+      53.2043      143.702      10536.8     0.000000     0.000000     0.000000     0.000000
+      127.327      129.746      10529.5     0.000000     0.000000     0.000000     0.000000
+      199.281      325.606      10518.3     0.000000     0.000000     0.000000     0.000000
+      91.0923      32.7281      10478.6     0.000000     0.000000     0.000000     0.000000
+      290.000      104.865      10455.9     0.000000     0.000000     0.000000     0.000000
+      110.150      39.1507      10432.3     0.000000     0.000000     0.000000     0.000000
+      73.3965      209.015      10425.8     0.000000     0.000000     0.000000     0.000000
+      334.666      82.5704      10415.4     0.000000     0.000000     0.000000     0.000000
+      119.569      103.891      10405.2     0.000000     0.000000     0.000000     0.000000
+      5.51266      129.989      10404.5     0.000000     0.000000     0.000000     0.000000
+      352.328      322.056      10373.6     0.000000     0.000000     0.000000     0.000000
+      118.789      357.245      10365.4     0.000000     0.000000     0.000000     0.000000
+      189.231      338.293      10314.9     0.000000     0.000000     0.000000     0.000000
+      146.456      199.104      10311.6     0.000000     0.000000     0.000000     0.000000
+      275.953      350.132      10297.5     0.000000     0.000000     0.000000     0.000000
+      211.655      119.536      10295.0     0.000000     0.000000     0.000000     0.000000
+      107.430      252.205      10264.6     0.000000     0.000000     0.000000     0.000000
+      298.279      95.8443      10245.1     0.000000     0.000000     0.000000     0.000000
+      73.7256      317.953      10223.7     0.000000     0.000000     0.000000     0.000000
+      241.150      105.953      10203.3     0.000000     0.000000     0.000000     0.000000
+      289.573      235.203      10180.7     0.000000     0.000000     0.000000     0.000000
+      177.092      133.147      10170.5     0.000000     0.000000     0.000000     0.000000
+      66.4591      33.4103      10161.2     0.000000     0.000000     0.000000     0.000000
+      167.121      221.529      10147.7     0.000000     0.000000     0.000000     0.000000
+      150.614      217.315      10116.1     0.000000     0.000000     0.000000     0.000000
+      349.168      220.736      10114.9     0.000000     0.000000     0.000000     0.000000
+      189.201      327.360      10105.4     0.000000     0.000000     0.000000     0.000000
+      356.941      292.278      10071.5     0.000000     0.000000     0.000000     0.000000
+      159.444      350.615      10066.7     0.000000     0.000000     0.000000     0.000000
+      153.628      37.9686      10030.9     0.000000     0.000000     0.000000     0.000000
+      224.064      40.6913      10016.4     0.000000     0.000000     0.000000     0.000000
+      119.818      42.4017      10012.7     0.000000     0.000000     0.000000     0.000000
+      121.470      215.858      10010.6     0.000000     0.000000     0.000000     0.000000
+      184.875      289.720      9994.10     0.000000     0.000000     0.000000     0.000000
+      46.6822      362.316      9969.35     0.000000     0.000000     0.000000     0.000000
+      286.563      89.0843      9927.89     0.000000     0.000000     0.000000     0.000000
+      147.549      316.635      9833.91     0.000000     0.000000     0.000000     0.000000
+      140.216      239.690      9810.08     0.000000     0.000000     0.000000     0.000000
+      218.380      212.227      9791.60     0.000000     0.000000     0.000000     0.000000
+      185.957      95.6876      9773.53     0.000000     0.000000     0.000000     0.000000
+      250.300      140.294      9763.96     0.000000     0.000000     0.000000     0.000000
+      211.091      310.549      9754.13     0.000000     0.000000     0.000000     0.000000
+      300.558      138.689      9746.11     0.000000     0.000000     0.000000     0.000000
+      257.092      215.141      9744.90     0.000000     0.000000     0.000000     0.000000
+      246.171      47.4282      9728.41     0.000000     0.000000     0.000000     0.000000
+      102.151      37.6587      9726.53     0.000000     0.000000     0.000000     0.000000
+      234.644      320.442      9706.42     0.000000     0.000000     0.000000     0.000000
+      209.105      208.744      9681.31     0.000000     0.000000     0.000000     0.000000
+      19.1231      99.7509      9678.07     0.000000     0.000000     0.000000     0.000000
+      38.0761      219.821      9671.93     0.000000     0.000000     0.000000     0.000000
+      30.9910      211.942      9605.70     0.000000     0.000000     0.000000     0.000000
+      46.4823      149.956      9603.90     0.000000     0.000000     0.000000     0.000000
+      98.9956      300.200      9558.20     0.000000     0.000000     0.000000     0.000000
+      189.435      348.322      9497.54     0.000000     0.000000     0.000000     0.000000
+      229.480      91.6102      9487.79     0.000000     0.000000     0.000000     0.000000
+      218.761      291.812      9487.13     0.000000     0.000000     0.000000     0.000000
+      141.428      284.746      9474.41     0.000000     0.000000     0.000000     0.000000
+      26.3322      214.819      9446.11     0.000000     0.000000     0.000000     0.000000
+      20.0580      339.197      9418.89     0.000000     0.000000     0.000000     0.000000
+      98.2980      240.850      9417.25     0.000000     0.000000     0.000000     0.000000
+      54.2404      295.567      9409.39     0.000000     0.000000     0.000000     0.000000
+      306.913      202.034      9403.31     0.000000     0.000000     0.000000     0.000000
+      83.5711      209.601      9402.86     0.000000     0.000000     0.000000     0.000000
+      49.9428      186.438      9373.70     0.000000     0.000000     0.000000     0.000000
+      141.370      45.4081      9334.23     0.000000     0.000000     0.000000     0.000000
+      187.359      251.220      9330.72     0.000000     0.000000     0.000000     0.000000
+      256.338      255.339      9330.37     0.000000     0.000000     0.000000     0.000000
+      47.4843      242.818      9320.21     0.000000     0.000000     0.000000     0.000000
+      299.883      105.716      9308.30     0.000000     0.000000     0.000000     0.000000
+      347.525      73.1966      9299.82     0.000000     0.000000     0.000000     0.000000
+      127.778      51.4150      9285.16     0.000000     0.000000     0.000000     0.000000
+      243.152      87.5172      9252.12     0.000000     0.000000     0.000000     0.000000
+      18.7177      289.625      9248.86     0.000000     0.000000     0.000000     0.000000
+      111.025      107.977      9247.44     0.000000     0.000000     0.000000     0.000000
+      48.9049      321.713      9229.70     0.000000     0.000000     0.000000     0.000000
+      49.1277      22.6012      9189.48     0.000000     0.000000     0.000000     0.000000
+      7.74438      341.231      9186.96     0.000000     0.000000     0.000000     0.000000
+      114.374      319.487      9181.88     0.000000     0.000000     0.000000     0.000000
+      356.844      58.7305      9181.26     0.000000     0.000000     0.000000     0.000000
+      197.970      42.8118      9167.81     0.000000     0.000000     0.000000     0.000000
+      308.839      51.4067      9159.38     0.000000     0.000000     0.000000     0.000000
+      29.2213      234.074      9158.70     0.000000     0.000000     0.000000     0.000000
+      241.482      85.2010      9157.08     0.000000     0.000000     0.000000     0.000000
+      251.966      16.5346      9070.71     0.000000     0.000000     0.000000     0.000000
+      61.7394      162.858      9055.08     0.000000     0.000000     0.000000     0.000000
+      135.239      315.640      9036.42     0.000000     0.000000     0.000000     0.000000
+      66.3842      282.122      9028.25     0.000000     0.000000     0.000000     0.000000
+      84.6350      140.990      9007.93     0.000000     0.000000     0.000000     0.000000
+      222.329      342.022      9006.42     0.000000     0.000000     0.000000     0.000000
+      42.9745      341.749      8977.87     0.000000     0.000000     0.000000     0.000000
+      197.206      182.702      8977.56     0.000000     0.000000     0.000000     0.000000
+      69.5008      239.540      8968.93     0.000000     0.000000     0.000000     0.000000
+      72.0435      75.5923      8967.49     0.000000     0.000000     0.000000     0.000000
+      136.074      185.496      8946.40     0.000000     0.000000     0.000000     0.000000
+      6.45282      119.214      8940.80     0.000000     0.000000     0.000000     0.000000
+      264.851      274.553      8934.76     0.000000     0.000000     0.000000     0.000000
+      126.041      181.148      8927.69     0.000000     0.000000     0.000000     0.000000
+      235.483      54.1305      8853.71     0.000000     0.000000     0.000000     0.000000
+      113.735      351.481      8850.05     0.000000     0.000000     0.000000     0.000000
+      182.225      58.8718      8844.37     0.000000     0.000000     0.000000     0.000000
+      281.007      213.040      8785.75     0.000000     0.000000     0.000000     0.000000
+      280.136      298.103      8785.29     0.000000     0.000000     0.000000     0.000000
+      154.780      212.224      8738.26     0.000000     0.000000     0.000000     0.000000
+      362.577      358.870      8687.21     0.000000     0.000000     0.000000     0.000000
+      79.9677      223.692      8684.84     0.000000     0.000000     0.000000     0.000000
+      281.464      343.100      8642.57     0.000000     0.000000     0.000000     0.000000
+      227.974      93.5333      8642.12     0.000000     0.000000     0.000000     0.000000
+      225.162      179.988      8603.52     0.000000     0.000000     0.000000     0.000000
+      363.955      187.390      8573.78     0.000000     0.000000     0.000000     0.000000
+      304.473      145.395      8560.22     0.000000     0.000000     0.000000     0.000000
+      329.204      340.733      8548.99     0.000000     0.000000     0.000000     0.000000
+      3.46966      252.491      8542.90     0.000000     0.000000     0.000000     0.000000
+      350.219      184.647      8540.27     0.000000     0.000000     0.000000     0.000000
+      331.809      108.234      8527.97     0.000000     0.000000     0.000000     0.000000
+      3.84361      36.1200      8526.37     0.000000     0.000000     0.000000     0.000000
+      113.516      189.622      8513.15     0.000000     0.000000     0.000000     0.000000
+      135.314      328.291      8510.13     0.000000     0.000000     0.000000     0.000000
+      207.372      110.136      8501.20     0.000000     0.000000     0.000000     0.000000
+      120.626      11.9419      8493.59     0.000000     0.000000     0.000000     0.000000
+      39.2559      283.713      8484.60     0.000000     0.000000     0.000000     0.000000
+      20.0342      213.709      8476.63     0.000000     0.000000     0.000000     0.000000
+      281.907      63.6222      8470.19     0.000000     0.000000     0.000000     0.000000
+      271.525      171.649      8465.58     0.000000     0.000000     0.000000     0.000000
+      260.969      349.726      8421.75     0.000000     0.000000     0.000000     0.000000
+      244.879      352.469      8410.74     0.000000     0.000000     0.000000     0.000000
+      231.957      163.764      8396.27     0.000000     0.000000     0.000000     0.000000
+      57.4121      69.9200      8393.76     0.000000     0.000000     0.000000     0.000000
+      339.282      345.389      8380.26     0.000000     0.000000     0.000000     0.000000
+      58.7499      176.551      8376.42     0.000000     0.000000     0.000000     0.000000
+      296.630      179.301      8372.55     0.000000     0.000000     0.000000     0.000000
+      20.4299      219.358      8363.85     0.000000     0.000000     0.000000     0.000000
+      24.8150      354.064      8342.90     0.000000     0.000000     0.000000     0.000000
+      98.5372      185.151      8342.33     0.000000     0.000000     0.000000     0.000000
+      333.657      45.6321      8330.16     0.000000     0.000000     0.000000     0.000000
+      224.090      156.503      8324.05     0.000000     0.000000     0.000000     0.000000
+      99.2796      293.111      8322.83     0.000000     0.000000     0.000000     0.000000
+      85.1664      140.326      8302.26     0.000000     0.000000     0.000000     0.000000
+      212.479      238.727      8295.13     0.000000     0.000000     0.000000     0.000000
+      349.170      28.4832      8288.76     0.000000     0.000000     0.000000     0.000000
+      212.064      100.364      8282.41     0.000000     0.000000     0.000000     0.000000
+      116.647      297.652      8244.60     0.000000     0.000000     0.000000     0.000000
+      140.094      252.549      8239.89     0.000000     0.000000     0.000000     0.000000
+      3.73455      218.219      8234.69     0.000000     0.000000     0.000000     0.000000
+      41.0175      236.134      8216.58     0.000000     0.000000     0.000000     0.000000
+      130.661      14.6804      8215.85     0.000000     0.000000     0.000000     0.000000
+      157.922      249.381      8207.19     0.000000     0.000000     0.000000     0.000000
+      361.029      103.031      8201.34     0.000000     0.000000     0.000000     0.000000
+      25.1080      304.053      8196.51     0.000000     0.000000     0.000000     0.000000
+      251.132      226.503      8184.33     0.000000     0.000000     0.000000     0.000000
+      262.140      262.829      8179.95     0.000000     0.000000     0.000000     0.000000
+      112.822      234.655      8176.15     0.000000     0.000000     0.000000     0.000000
+      362.972      130.027      8170.37     0.000000     0.000000     0.000000     0.000000
+      286.230      214.833      8117.50     0.000000     0.000000     0.000000     0.000000
+      347.297      45.7254      8096.95     0.000000     0.000000     0.000000     0.000000
+      89.8166      132.465      8078.18     0.000000     0.000000     0.000000     0.000000
+      188.795      172.561      8077.90     0.000000     0.000000     0.000000     0.000000
+      96.6791      135.688      8063.67     0.000000     0.000000     0.000000     0.000000
+      317.930      159.719      8055.87     0.000000     0.000000     0.000000     0.000000
+      333.854      148.828      8055.59     0.000000     0.000000     0.000000     0.000000
+      189.200      301.279      8055.36     0.000000     0.000000     0.000000     0.000000
+      151.986      311.486      8039.44     0.000000     0.000000     0.000000     0.000000
+      317.173      97.2851      8026.74     0.000000     0.000000     0.000000     0.000000
+      223.548      211.624      8024.90     0.000000     0.000000     0.000000     0.000000
+      9.04450      340.864      8020.38     0.000000     0.000000     0.000000     0.000000
+      349.144      213.470      8005.95     0.000000     0.000000     0.000000     0.000000
+      109.896      313.486      8000.23     0.000000     0.000000     0.000000     0.000000
+      350.389      211.508      7988.00     0.000000     0.000000     0.000000     0.000000
+      206.645      123.713      7979.93     0.000000     0.000000     0.000000     0.000000
+      266.411      347.247      7978.76     0.000000     0.000000     0.000000     0.000000
+      80.1159      330.520      7976.54     0.000000     0.000000     0.000000     0.000000
+      214.298      176.375      7969.72     0.000000     0.000000     0.000000     0.000000
+      13.5541      204.100      7969.38     0.000000     0.000000     0.000000     0.000000
+      328.562      10.8260      7964.38     0.000000     0.000000     0.000000     0.000000
+      84.1033      121.227      7954.34     0.000000     0.000000     0.000000     0.000000
+      44.5995      201.531      7926.02     0.000000     0.000000     0.000000     0.000000
+      39.7059      73.2695      7919.54     0.000000     0.000000     0.000000     0.000000
+      353.915      95.5096      7878.12     0.000000     0.000000     0.000000     0.000000
+      257.584      7.33578      7860.87     0.000000     0.000000     0.000000     0.000000
+      69.1357      135.115      7856.97     0.000000     0.000000     0.000000     0.000000
+      189.035      357.202      7854.36     0.000000     0.000000     0.000000     0.000000
+      176.125      133.910      7851.27     0.000000     0.000000     0.000000     0.000000
+      86.8012      128.032      7816.09     0.000000     0.000000     0.000000     0.000000
+      281.446      330.991      7811.29     0.000000     0.000000     0.000000     0.000000
+      178.094      182.133      7805.46     0.000000     0.000000     0.000000     0.000000
+      303.274      229.602      7781.67     0.000000     0.000000     0.000000     0.000000
+      127.928      163.923      7739.83     0.000000     0.000000     0.000000     0.000000
+      193.399      224.266      7730.48     0.000000     0.000000     0.000000     0.000000
+      345.658      223.740      7708.36     0.000000     0.000000     0.000000     0.000000
+      184.026      65.1665      7692.67     0.000000     0.000000     0.000000     0.000000
+      105.698      64.8980      7649.95     0.000000     0.000000     0.000000     0.000000
+      130.572      14.4292      7648.34     0.000000     0.000000     0.000000     0.000000
+      315.749      17.0102      7646.99     0.000000     0.000000     0.000000     0.000000
+      224.948      199.281      7644.45     0.000000     0.000000     0.000000     0.000000
+      3.71182      140.943      7637.17     0.000000     0.000000     0.000000     0.000000
+      297.735      341.078      7624.77     0.000000     0.000000     0.000000     0.000000
+      184.381      266.513      7612.73     0.000000     0.000000     0.000000     0.000000
+      74.0777      76.6774      7610.14     0.000000     0.000000     0.000000     0.000000
+      229.994      327.230      7607.33     0.000000     0.000000     0.000000     0.000000
+      300.324      41.7404      7592.34     0.000000     0.000000     0.000000     0.000000
+      86.5110      250.161      7587.75     0.000000     0.000000     0.000000     0.000000
+      219.749      166.493      7586.91     0.000000     0.000000     0.000000     0.000000
+      140.995      54.3545      7578.47     0.000000     0.000000     0.000000     0.000000
+      222.102      27.6615      7564.80     0.000000     0.000000     0.000000     0.000000
+      166.091      60.8323      7560.70     0.000000     0.000000     0.000000     0.000000
+      54.0243      249.656      7560.08     0.000000     0.000000     0.000000     0.000000
+      86.2203      294.304      7551.22     0.000000     0.000000     0.000000     0.000000
+      230.635      13.7741      7551.03     0.000000     0.000000     0.000000     0.000000
+      42.3630      219.880      7520.25     0.000000     0.000000     0.000000     0.000000
+      223.474      5.85404      7506.76     0.000000     0.000000     0.000000     0.000000
+      339.768      78.3322      7496.85     0.000000     0.000000     0.000000     0.000000
+      181.819      318.912      7456.63     0.000000     0.000000     0.000000     0.000000
+      344.929      107.100      7451.92     0.000000     0.000000     0.000000     0.000000
+      194.012      110.977      7450.68     0.000000     0.000000     0.000000     0.000000
+      96.0159      87.0652      7448.98     0.000000     0.000000     0.000000     0.000000
+      309.907      201.304      7422.60     0.000000     0.000000     0.000000     0.000000
+      352.607      207.636      7407.49     0.000000     0.000000     0.000000     0.000000
+      10.0850      74.6048      7402.71     0.000000     0.000000     0.000000     0.000000
+      314.108      4.39326      7366.84     0.000000     0.000000     0.000000     0.000000
+      92.7798      301.844      7344.09     0.000000     0.000000     0.000000     0.000000
+      178.008      104.544      7342.37     0.000000     0.000000     0.000000     0.000000
+      190.225      328.578      7330.94     0.000000     0.000000     0.000000     0.000000
+      135.999      57.5390      7314.04     0.000000     0.000000     0.000000     0.000000
+      97.0393      5.48788      7313.27     0.000000     0.000000     0.000000     0.000000
+      165.200      159.932      7299.78     0.000000     0.000000     0.000000     0.000000
+      251.944      324.406      7278.26     0.000000     0.000000     0.000000     0.000000
+      68.5419      82.1139      7270.03     0.000000     0.000000     0.000000     0.000000
+      63.0529      52.6903      7243.15     0.000000     0.000000     0.000000     0.000000
+      330.566      190.512      7232.62     0.000000     0.000000     0.000000     0.000000
+      88.1024      155.162      7225.92     0.000000     0.000000     0.000000     0.000000
+      252.150      154.943      7196.68     0.000000     0.000000     0.000000     0.000000
+      296.441      217.759      7175.80     0.000000     0.000000     0.000000     0.000000
+      202.838      311.159      7156.54     0.000000     0.000000     0.000000     0.000000
+      231.353      84.4772      7150.01     0.000000     0.000000     0.000000     0.000000
+      28.1829      44.0445      7137.31     0.000000     0.000000     0.000000     0.000000
+      155.559      158.616      7136.71     0.000000     0.000000     0.000000     0.000000
+      158.502      360.723      7135.93     0.000000     0.000000     0.000000     0.000000
+      297.945      207.397      7135.41     0.000000     0.000000     0.000000     0.000000
+      174.532      275.227      7131.25     0.000000     0.000000     0.000000     0.000000
+      276.590      73.3019      7096.64     0.000000     0.000000     0.000000     0.000000
+      4.98168      226.570      7078.55     0.000000     0.000000     0.000000     0.000000
+      353.974      244.802      7064.15     0.000000     0.000000     0.000000     0.000000
+      238.717      285.406      7024.70     0.000000     0.000000     0.000000     0.000000
+      123.122      252.534      7004.02     0.000000     0.000000     0.000000     0.000000
+      341.752      234.903      6998.35     0.000000     0.000000     0.000000     0.000000
+      163.600      12.4996      6996.43     0.000000     0.000000     0.000000     0.000000
+      39.9085      188.847      6970.39     0.000000     0.000000     0.000000     0.000000
+      58.6450      126.128      6965.15     0.000000     0.000000     0.000000     0.000000
+      54.7612      220.406      6937.47     0.000000     0.000000     0.000000     0.000000
+      283.937      55.5230      6900.33     0.000000     0.000000     0.000000     0.000000
+      57.7399      307.712      6881.11     0.000000     0.000000     0.000000     0.000000
+      179.116      140.159      6871.33     0.000000     0.000000     0.000000     0.000000
+      163.289      332.439      6869.44     0.000000     0.000000     0.000000     0.000000
+      193.545      304.415      6863.99     0.000000     0.000000     0.000000     0.000000
+      112.087      266.857      6863.63     0.000000     0.000000     0.000000     0.000000
+      93.9835      13.9360      6862.43     0.000000     0.000000     0.000000     0.000000
+      336.524      204.765      6843.78     0.000000     0.000000     0.000000     0.000000
+      296.890      17.8750      6842.42     0.000000     0.000000     0.000000     0.000000
+      66.1222      217.429      6834.09     0.000000     0.000000     0.000000     0.000000
+      359.721      279.081      6816.87     0.000000     0.000000     0.000000     0.000000
+      92.6921      141.503      6810.39     0.000000     0.000000     0.000000     0.000000
+      9.90257      16.4829      6810.06     0.000000     0.000000     0.000000     0.000000
+      150.675      196.338      6804.06     0.000000     0.000000     0.000000     0.000000
+      326.662      361.814      6796.60     0.000000     0.000000     0.000000     0.000000
+      154.145      194.495      6790.79     0.000000     0.000000     0.000000     0.000000
+      24.1808      199.348      6788.36     0.000000     0.000000     0.000000     0.000000
+      262.393      133.538      6786.13     0.000000     0.000000     0.000000     0.000000
+      6.97511      116.572      6760.88     0.000000     0.000000     0.000000     0.000000
+      69.1432      42.7144      6760.76     0.000000     0.000000     0.000000     0.000000
+      195.255      84.6974      6742.48     0.000000     0.000000     0.000000     0.000000
+      333.503      187.364      6720.80     0.000000     0.000000     0.000000     0.000000
+      222.436      355.739      6710.22     0.000000     0.000000     0.000000     0.000000
diff --git a/sub_array.pro b/sub_array.pro
new file mode 100644
index 0000000000000000000000000000000000000000..2b8c80a5d243ce1e960c147f26453253ca3edf8d
--- /dev/null
+++ b/sub_array.pro
@@ -0,0 +1,54 @@
+; $Id: sub_array.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	SUB_ARRAY
+;
+; PURPOSE:
+;	Given a 2D array, extract a sub-array centered at a pre-fixed position
+;	and of given size.
+;
+; CATEGORY:
+;	Array manipulation.
+;
+; CALLING SEQUENCE:
+;	Result = SUB_ARRAY(Array, Bx, By)
+;
+; INPUTS:
+;	Array:	2D array
+;
+;	Bx:	X- size of sub-array to extract
+;
+; OPTIONAL INPUTS:
+;	By:	Y- size of sub-array. The default is By = Bx
+;
+; KEYWORD PARAMETERS:
+;	REFERENCE:	2-components vector, coordinates of pixel where the
+;		sub-array must be centered. The default is the Array maximum.
+;
+; OUTPUTS:
+;	Result:	Sub-array of size Bx*By and having the reference pixel specified
+;		by the keyword R at the relative position (Bx/2, By/2).
+;		If it is not possible to extract such a sub-array, the extracted
+;		sub-array may not have the reference pixel at (Bx/2, By/2) or its
+;		size may be different from Bx*By.
+;
+; OPTIONAL OUTPUTS:
+;	LX, UX, LY, UY:	Output keywords containing the Lower and Upper,
+;		X- and Y- bounds of the sub-array in Array
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+FUNCTION sub_array, array, bx, by, REFERENCE = r, $
+					LX = lx, UX = ux, LY = ly, UY = uy
+
+	on_error, 2
+	if  n_params() eq 2  then  by = bx
+	if  n_elements(r) ne 2  then  r = get_max(array)
+	bsize = round([bx, by])
+	array_overlap, size52(array, /DIM), bsize, $
+				   round(r), bsize/2, lx, ux, ly, uy
+	return, array[lx:ux,ly:uy]
+end
diff --git a/sub_arrays.pro b/sub_arrays.pro
new file mode 100644
index 0000000000000000000000000000000000000000..94af203f225ec7c2e71c058e375fb84d310782c6
--- /dev/null
+++ b/sub_arrays.pro
@@ -0,0 +1,58 @@
+; $Id: sub_arrays.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	SUB_ARRAYS
+;
+; PURPOSE:
+;	Given a 2D array, extract a stack of sub-arrays centered at specified
+;	positions and having a fixed size.
+;	Sub-arrays corresponding to positions next to the array border are
+;	suitably padded with 0s.
+;
+; CATEGORY:
+;	Array manipulation.
+;
+; CALLING SEQUENCE:
+;	SUB_ARRAYS, Array, X, Y, Boxsize, Stack, Masks
+;
+; INPUTS:
+;	Array:	2D array
+;
+;	X, Y:	Coordinates of reference positions
+;
+;	Boxsize:	Scalar, representing the size of each square sub-array
+;
+; OUTPUTS:
+;	Stack:	3D array of size Boxsize*Boxsize*N, where N is the number
+;		of reference points. Each reference point is ensured to be at
+;		the position (Boxsize/2, Boxsize/2) in the corresponding plane;
+;		of the output Stack
+;
+;	Masks:	Cube of byte type, having the same size as the previous Stack.
+;		The n-th plane in this cube is defined as follows:
+;		Masks[j, i, n] = 1, if Stack[j, i, n] is an Array pixel
+;		               = 0, if Stack[j, i, n] is a padding pixel
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+PRO sub_arrays, array, x, y, boxsize, stack, masks
+
+	on_error, 2
+	nframes = n_elements(x)
+	stack = fltarr(boxsize, boxsize, nframes)
+	masks = bytarr(boxsize, boxsize, nframes)
+	for  n = 0L, nframes - 1  do begin
+	   box = sub_array(array, boxsize, REF = [x[n], y[n]], $
+	   				   LX = lx, UX = ux, LY = ly, UY = uy)
+	   offset = [boxsize/2, boxsize/2] - [x[n] - lx, y[n] - ly]
+	   box = extend_array(box, boxsize, /NO_OFF)
+	   box = shift(box, offset[0], offset[1])
+	   stack[*,*,n] = box
+	   lo = offset  &  up = lo + [ux - lx, uy - ly]
+	   masks[lo[0]:up[0],lo[1]:up[1],n] = 1B
+	endfor
+	return
+end
diff --git a/subs_to_coord.pro b/subs_to_coord.pro
new file mode 100644
index 0000000000000000000000000000000000000000..cbcb99137d0dbfd45679479dbb0331488e8a1750
--- /dev/null
+++ b/subs_to_coord.pro
@@ -0,0 +1,37 @@
+; $Id: subs_to_coord.pro, v 1.0 Aug 1999 e.d. $
+;
+;+
+; NAME:
+;	SUBS_TO_COORD
+;
+; PURPOSE:
+;	Convert array subscripts to pixel coordinates.
+;
+; CATEGORY:
+;	Array manipulation.
+;
+; CALLING SEQUENCE:
+;	SUBS_TO_COORD, Subs, N_columns, X, Y
+;
+; INPUTS:
+;	Subs:	Long integer vector of array subscripts
+;
+;	N_columns:	Number of columns in the 2D array
+;
+; OUTPUTS:
+;	X, Y:	Column and row coordinates of pixels subscripted by Subs
+;
+; RESTRICTIONS:
+;	Apply only to 2D arrays.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;-
+
+PRO subs_to_coord, subs, n_columns, x, y
+
+	on_error, 2
+	s = round(subs)  &  n = round(n_columns)
+	x = s mod n  &  y = s / n
+	return
+end
diff --git a/superpose_stars.pro b/superpose_stars.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0317485b19b596f7eb2d47516bf83c074e82f282
--- /dev/null
+++ b/superpose_stars.pro
@@ -0,0 +1,261 @@
+; $Id: superpose_stars.pro, v 1.4 Mar 2020 l.s. $
+;
+;+
+; NAME:
+;	SUPERPOSE_STARS
+;
+; PURPOSE:
+;	Given the coordinates of a set of stars in an image, extract sub-images
+;	centered on the stars and combine them by a simple pixel-by-pixel average
+; or average with sigma-clipping or median operation. This routine may be
+; used to estimate the PSF in a stellar field image.
+;	If the stars are known, e.g. after analyzing the field with a preliminary
+;	PSF estimate, then it is possible to clean each selected star from all
+;	the other point sources around before deriving a new PSF estimate.
+;
+; CATEGORY:
+;	Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = SUPERPOSE_STARS(Image, X, Y, Siz, Stack, Masks)
+;
+; INPUTS:
+;	Image:	2D image of the stellar field
+;
+;	X, Y:	Coordinates of the stars to extract
+;
+;	Siz:	Scalar, representing the size of the output combined image
+;
+; KEYWORD PARAMETERS:
+;	NO_SUB_PIX:	Set this keyword to avoid centering each star with sub-pixel
+;		accuracy. For details on centering, see the function CENTROIDER in
+;		the file 'centroider.pro'.
+;
+;	INTERP_TYPE:	Set this keyword to a string identifying the interpolation
+;		technique to use for sub-pixel centering. For details, see the function
+;		IMAGE_SHIFT in the file 'image_shift.pro'
+;
+;	NOISE_LEVEL:	Scalar, representing the background noise above the local
+;		sky level. It may be expressed as N * Sigma, where N is any number > 0
+;		and Sigma is the overall standard deviation of the Image gaussian noise.
+;
+;	SATURATION:	Use this keyword to provide the saturation threshold which
+;		is used to mask the core of bright saturated stars when computing the
+;		median superposition. Though saturated, these stars should not be
+;		rejected, because they provide useful information on the PSF halo.
+;		The value of the keyword SATURATION may be:
+;		a) a scalar, representing the unique threshold to be used all over
+;		   the frame;
+;		b) a 2D array, having the same size as the input Image, when the
+;		   saturation level is not spatially uniform. This happens for
+;		   example when the input Image has been background subtracted:
+;		   if the removed contribution is not negligible with respect to
+;		   the stellar peaks, the saturation threshold will be affected and
+;		   should be defined as the original threshold minus the removed
+;		   background contribution.
+;
+;	MAX_NORM:	Set this keyword to normalize the stars to unitary maximum
+;		before combining them in a single frame. The default is to normalize
+;     each sub-image to total unit flux.
+;
+;	RAD_NORM:	Set this keyword to normalize the stars using a circular
+;     region centered on the stellar peak. The value of this keyword is the
+;	   radius of the normalization region. The default is to normalize
+;     each sub-image to total unit flux.
+;
+;	AVGTYPE:	Set this keyword to choose a combination algorithm among
+;		the following possibilities:
+;		AVGTYPE = 0 [default]: pixel-by-pixel average
+;		        = 1: average with sigma-rejection of outliers
+;		        = 2: median
+;
+;	WEIGHTED:	Set this keyword to weigh the stellar images, before averaging,
+;		according to their signal-to-noise ratio in the photon noise case.
+;
+;	STARS:	Stellar field model, including a replica of the PSF for each known
+;		star. This keyword, along with X, Y, FLUX, PSF, must be supplied when
+;		the selected stars, identified by the positions X and Y (see INPUTS)
+;		have to be cleaned from the contamination of secondary sources. This
+;		will produce a better PSF estimate.
+;
+;	X_STARS, Y_STARS, FLUXES:	Positions and fluxes of the known stars
+;		appearing in the image model supplied by the keyword STARS.
+;
+;	PSF:	Point Spread Function used to create the image model STARS.
+;		It may be either a 2D array or a 3D stack of local PSF images, when
+;		PSF is space-variant. In the latter case, it is necessary to supply
+;		the bounds of the image domain partition (see LX, UX, LY, UY).
+;
+;	LX, UX, LY, UY:	Vectors specifying the bounds of the image domain
+;		partition when the "space-variant PSF" option is used. In this case
+;		the sub-domain  [LX[j]: Ux[j], LY[i]: UY[i]]  must correspond to the
+;		(i * X_size + j)-th  PSF in the input stack. For more details, see
+;		the documentation on the routine ARRAY_PARTITION.
+;		
+;	LOCAL_BKG: Set this keyword to calculate and remove the local background, 
+;	  modelled as a tilted plane, from each sub-image. 
+;	  The parameters of the local tilted plane are computed using only the pixels 
+;	  at the corners of the sub-image square domain of size Siz*Siz (the corners are 
+;	  defined as the pixels outside the circle inscribed in the square domain itself).
+;
+; OUTPUTS:
+;	Result:	2D array of size Siz*Siz containing the median combination of
+;		the extracted stars, after suitable processing
+;
+; OPTIONAL OUTPUTS:
+;	Stack:	Cube of stellar images, optionally centered and normalized,
+;		before masking
+;
+;	Masks:	Cube of byte type, having the same size as the previous Stack.
+;		The n-th plane in this cube is defined as follows:
+;		Masks[j, i, n] = 1, if the pixel Stack[j, i, n] has been used to
+;	                        form the output image
+;		               = 0, if the same pixel has been masked
+;		The Masks cube is used in median superposition
+;
+; RESTRICTIONS:
+;	1) The input Image should be background subtracted.
+;	2) Sub-pixel centering is based on interpolation and should be avoided
+;	with undersampled data.
+;	3) The extracted stellar images are normalized before superposition.
+;  Saturated stars should have been previously repaired to ensure proper
+;  normalization. However previous repair of saturated stars should not
+;  prevent the use of the keyword SATURATION.
+;
+; PROCEDURE:
+;	Extract a box centered on each star, suitably padded with 0 if the
+;	source is near the Image edge. Additional 0-padded pixels will be
+;	masked.
+;	Optionally compute weights for median superposition, as the square root
+;  of the peak of each star. Center each sub-image with sub-pixel accuracy,
+;	then optionally mask pixels below the noise threshold and above the
+;	saturation level. Notice that if a noise level is defined, the pixels
+;	below this level are masked (set to 0!) and the central connected
+;	component of the resulting image (see IMAGE_CORE for details) is
+;	extracted.
+;	Combine the frames in the stack by average or average with sigma-rejection
+;  or median or weighted median.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, August 1999.
+;	Updates:
+;	1) Fixed bug on normalization (Emiliano Diolaiti, January 2000).
+;	2) Secondary stars subtraction (Emiliano Diolaiti, January 2000).
+;	3) NOISE_LEVEL keyword (Emiliano Diolaiti, February 2000).
+;	4) Renamed keyword NORM_MAX to MAX_NORM (Emiliano Diolaiti, September 2001).
+;	5) Added keyword RAD_NORM (Emiliano Diolaiti, September 2001).
+;	6) Replaced keyword UNWEIGHTED with WEIGHTED
+;     (Emiliano Diolaiti, September 2001).
+; 7) Added keyword LOCAL_BKG (Laura Schreiber, March 2020).
+;-
+
+
+
+; CLEAN_EXTRACT: extract stellar images after removing secondary sources.
+
+PRO clean_extract, image, x_psf, y_psf, siz, _EXTRA = extra, $
+                   stars, x_stars, y_stars, f_stars, psf, stack, masks
+
+	on_error, 2
+	imasiz = size52(image, /DIM)  &  nframes = n_elements(x_psf)
+	stack = fltarr(siz, siz, nframes)  &  masks = bytarr(siz, siz, nframes)
+	for  n = 0L, nframes - 1  do begin
+	   compare_lists, x_psf[n], y_psf[n], x_stars, y_stars, $
+	                  aux1, aux2, x, y, SUBSCRIPTS_2 = w
+	   f = f_stars[w]
+	   sub_arrays, image - stars + image_model(x, y, f, $
+	               imasiz[0], imasiz[1], psf, _EXTRA = extra), $
+	               x_psf[n], y_psf[n], siz, frame_n, mask_n
+	   stack[*,*,n] = frame_n  &  masks[*,*,n] = mask_n
+	endfor
+	return
+end
+
+;;; The main routine.
+
+FUNCTION superpose_stars, image, x, y, siz, stack, masks, _EXTRA = extra, $
+                          NO_SUB_PIX = no_sub_pix, NOISE_LEVEL = noise_lev, $
+                          SATURATION = satur_lev, MAX_NORM = max_norm, $
+                          RAD_NORM = rad_norm, WEIGHTED = weighted, $
+                          STARS = stars, PSF = psf, $
+                          X_STARS = x_stars, Y_STARS = y_stars, FLUXES = f_stars, $
+                          LOCAL_BKG = local_bkg
+
+	on_error, 2
+
+	; Extract sub-images
+	if  n_elements(stars) ne 0 and n_elements(psf) ne 0 and $
+	    n_elements(x_stars) ne 0 and n_elements(y_stars) ne 0 and $
+	    n_elements(f_stars) ne 0  then $
+	   clean_extract, image, x, y, siz, _EXTRA = extra, $
+                      stars, x_stars, y_stars, f_stars, psf, stack, masks  else $
+       sub_arrays, image, x, y, siz, stack, masks
+	var_satur = n_elements(satur_lev) ne 0
+	if  var_satur  then $
+	   var_satur = max(abs(size52(satur_lev, /DIM) - size52(image, /DIM))) eq 0
+	if  var_satur  then $	; define a stack of non-uniform saturation levels
+	   sub_arrays, satur_lev, x, y, siz, satur_stack
+	if  size52(stack, /N_DIM) eq 2  then $
+	   nframes = 1  else  nframes = (size52(stack, /DIM))[2]
+
+  ; Calculation and removal of local background from sub-images
+  if keyword_set(local_bkg) then begin
+     wbkg = where(radial_dist(siz, siz, siz/2, siz/2) gt siz/2)
+     one = plane(1, 0, 0, siz, siz)
+     xp = plane(0, 1, 0, siz, siz)
+     yp = plane(0, 0, 1, siz, siz)
+     ainv = ginv([transpose(one[wbkg]), transpose(xp[wbkg]), transpose(yp[wbkg])])
+     for n = 0L, nframes - 1 do begin
+        c = ainv ## transpose((stack[*,*,n])[wbkg])
+        p = c[0] + c[1]*xp + c[2]*yp
+        stack[*,*,n] = stack[*,*,n] - p
+     endfor
+  endif
+
+	; Sub-pixel centering
+	if  not keyword_set(no_sub_pix)  then  for  n = 0L, nframes - 1  do $
+	   stack[*,*,n] = centroider(stack[*,*,n], XC = siz/2, YC = siz/2, _EXTRA = extra)
+
+	; Define weights
+	if  keyword_set(weighted)  then begin
+	   w = fltarr(nframes)
+	   for  n = 0L, nframes - 1  do  w[n] = sqrt(stack[siz/2,siz/2,n] > 0)
+	endif
+
+	; For each star, mask pixels above saturation threshold
+	if  n_elements(satur_lev) ne 0  then begin
+	   satur = satur_lev
+	   for  n = 0L, nframes - 1  do begin
+	      if  var_satur  then  satur = satur_stack[*,*,n]
+	      exclude = where(stack[*,*,n] gt satur, n_ex)
+	      mask_n = make_array(siz, siz, /BYTE, VALUE = 1B)
+	      if  n_ex ne 0  then  mask_n[exclude] = 0B
+	      masks[*,*,n] = masks[*,*,n] and mask_n
+	   endfor
+	endif
+
+	; For each star, extract central connected component above noise level
+	if  n_elements(noise_lev) ne 0  then begin
+	   eps = 1e-12
+	   for  n = 0L, nframes - 1  do $
+	      stack[*,*,n] = image_core(binary_array(stack[*,*,n], noise_lev) * $
+	                                stack[*,*,n], eps, X = siz/2, Y = siz/2)
+	endif
+
+	; Normalize sub-images
+	if  keyword_set(rad_norm)  then $
+	   peak = where(radial_dist(siz, siz, siz/2, siz/2) le rad_norm)
+	for  n = 0L, nframes - 1  do $
+	   if  keyword_set(max_norm)  then $
+	      stack[*,*,n] = stack[*,*,n] / stack[siz/2,siz/2,n]  else $
+	   if  keyword_set(rad_norm)  then $
+	      stack[*,*,n] = stack[*,*,n] / total((stack[*,*,n])[peak])  else $
+	      stack[*,*,n] = stack[*,*,n] / total(stack[*,*,n])
+
+	; Compute stack median
+	if  nframes eq 1  then $
+	   avg = stack[*,*,0] * masks[*,*,0]  else $
+	   avg = stack_combine(stack, WEIGHTS = w, MASK = masks, _EXTRA = extra)
+
+	return, avg
+end
diff --git a/svpsf_extract.pro b/svpsf_extract.pro
new file mode 100644
index 0000000000000000000000000000000000000000..b7c92b131f0b0aed35e5945766e1addae4b61649
--- /dev/null
+++ b/svpsf_extract.pro
@@ -0,0 +1,194 @@
+; $Id: svpsf_extract.pro, v 1.0 Dec 2004 e.d. $
+;
+;+
+; NAME:
+;	SVPSF_EXTRACT
+;
+; PURPOSE:
+;	Partition an image into a regular grid and derive a PSF estimate
+;	for each sub-region by combining a set of point sources.
+;	The PSF stars are found automatically as significant peaks above
+;	a detection threshold or may be selected among a set supplied by
+;	the user. The extracted set of PSFs may be used for the identification
+;	and the analysis of the stars in the field by the procedure STARFINDER.
+;	After this analysis, SVPSF_EXTRACT may be iterated using the information
+;	retrieved by STARFINDER in order to improve the PSF estimate.
+;
+; CATEGORY:
+;	Stellar field photometry.
+;
+; CALLING SEQUENCE:
+;	SVPSF_EXTRACT, Image, Background, Threshold, Nx, Ny, Psfsize, Stack, Sv_par
+;
+;
+; INPUTS:
+;	Image:	2D image array
+;
+;	Background:	2D array, with the same size of Image, representing the
+;		background contribution
+;
+;	Threshold:	Scalar, representing the detection threshold for the
+;		presumed stellar peaks.
+;
+;	Nx, Ny:	Number of sub-regions along the X- and Y- axis respectively.
+;		The higher these numbers, the finer the partitioning of the image.
+;
+;	Psfsize:	Scalar, giving the size of each local PSF.
+;
+; KEYWORD PARAMETERS:
+;	SMOOTHBOX:	Size of box for median smoothing before search for local peaks.
+;
+;	SEARCHBOX:	Define the size of the box where each significant stellar
+;		peak is the relative image maximum. The default is 9.
+;
+;	NSTAR:	Number of stars to combine for each sub-region. By definition,
+;		the NSTAR brightest stars in a given sub-region are selected.
+;
+;	SATUR_LEV:	Upper linearity threshold of the detector. The stars whose
+;		peak is higher than this level are not included in the PSF estimation.
+;
+;	NORMRAD:	The stars in a given sub-region, before being combined to
+;		estimate the local PSF, are normalized to the same flux integrated
+;		over a circular region of radius given by the value of this keyword.
+;		The default is 3.
+;
+;	NOISE_LEVEL:	Each stellar image, selected for PSF estimation, may be
+;		"cleaned" by masking the pixels below some threshold related to the
+;		noise level. A useful choice of this parameter is a few times the
+;		background noise standard deviation.
+;
+;	X_STARS, Y_STARS:	Input coordinates of stars to use for PSF extraction.
+;		If set, no search for local peaks is performed. The stars to use for
+;		the estimation of the PSF are selected among these positions, according
+;		to the constraints set by the keywords NSTAR and SATUR_LEV.
+;
+;	FLUXES, STARS, PSF, SV_PAR:	When this procedure is used after a run of
+;		STARFINDER, the available information on the image may be used
+;		to improve the PSF estimate. The new stack of PSF estimates is obtained
+;		by removing from each used star the contamination due to the surrounding
+;		sources previously identified by STARFINDER. In order to apply this
+;		option, the coordinates of the known stars must be supplied with the
+;		keywords X_STARS, Y_STARS described above and, in addition, it is
+;		necessary to supply also the fluxes, the image model, the previously
+;		used PSF and corresponding SV_PAR. The input PSF may also be a 2D array,
+;		if the previous analysis has been performed assuming a space-invariant
+;		PSF; in this case, the input SV_PAR must not be supplied.
+;
+; OUTPUTS:
+;	Stack:	3D array, of size  Psfsize * Psfsize * (Nx * Ny), with the
+;		local PSF estimates.
+;
+;	Sv_par:	Structure to use as input parameter of the STARFINDER procedure
+;		to make photometry with spatially variable PSF.
+;		This structure has four fields: Lx, Ux, Ly, Uy. The value of each
+;		field is a vector containing the lower (Lx and Ly) and upper (Ux and
+;		Uy) bounds of the image sub-regions, along the X- and Y- directions.
+;		The k-th PSF in the Stack corresponds to the sub-region bounded by
+;		j*Nx + i, where i = k MOD Nx and j = k / Nx.
+;
+; RESTRICTIONS:
+;
+; PROCEDURE:
+;	Find all the significant peaks in the image, defined as the relative
+;	maxima above the detection threshold and not saturated. Each peak is the
+;	relative maximum within a certain sub-region of size given by the keyword
+;	parameter SEARCHBOX. The larger this figure, the lower the probability of
+;	selecting two close stars, whose images might be spatially overlapped.
+;	The image is then partitioned into a grid of sub-region and for each
+;	region the local PSF is estimated considering the brightest stars among
+;	the previously identified peaks.
+;	If the keywords X_STARS, Y_STARS are supplied, then the peaks are chosen
+;	among those defined by these keywords.
+;	If ALL the keywords X_STARS, Y_STARS, FLUXES, STARS, PSF, SV_PAR are supplied,
+;	then the peaks are chosen among those defined by X_STARS, Y_STARS and each
+;	stellar image selected for PSF extraction is cleaned from the contamination
+;	of the already known surrounding stars.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, December 2004.
+;	Updates:
+;-
+
+
+PRO svpsf_extract, image, background, threshold, nx, ny, psfsize, $
+	               stack, sv_par, $
+	               SMOOTHBOX = smoothbox, SEARCHBOX = searchbox, NSTAR = nstar, $
+	               SATUR_LEV = satur, NORMRAD = norm_rad, $
+	               NOISE_LEVEL = noise, CCTHRESHOLD = ccthreshold, _EXTRA = extra, $
+	               X_STARS = x_in, Y_STARS = y_in, FLUXES = f_in, $
+	               STARS = stars_in, PSF = psf_in, SV_PAR = sv_par_in, $
+	               SILENT = silent
+
+	; Default values of keywords
+	if n_elements(smoothbox) eq 0 then smoothbox = 3
+;	if n_elements(searchbox) eq 0 then searchbox = 9
+	if n_elements(nstar) eq 0 then nstar = 20
+	if n_elements(norm_rad) eq 0 then norm_rad = 3
+
+	; Find peaks
+	s = size(image, /DIM)  &  sx = s[0]  &  sy = s[1]
+	if n_elements(x_in) ne 0 and n_elements(y_in) ne 0 then begin
+	   x = round(x_in) > 0 < (sx - 1)
+	   y = round(y_in) > 0 < (sy - 1)
+	endif else $
+	   all_max, median_filter(image - background, smoothbox), x, y, BOX = searchbox
+	f = image[x,y] - background[x,y]
+	; Reject peaks below detection threshold
+	w = where(f gt threshold)
+	x = x[w]  &  y = y[w]  &  f = f[w]
+	; Reject peaks above saturation threshold
+	if  n_elements(satur) ne 0  then begin
+	   w = where(image[x,y] lt satur)
+	   x = x[w]  &  y = y[w]  &  f = f[w]
+	endif
+
+	; Define sub-regions
+	array_partition, sx, nx, lx, ux
+	array_partition, sy, ny, ly, uy
+	sv_par = {lx: lx, ux: ux, ly: ly, uy: uy}
+	if n_elements(sv_par_in) ne 0 then begin
+	   sv_lx = sv_par_in.lx
+	   sv_ux = sv_par_in.ux
+	   sv_ly = sv_par_in.ly
+	   sv_uy = sv_par_in.uy
+	endif
+
+	; For each sub-region, estimate PSF
+	stack = fltarr(psfsize, psfsize, nx*ny)
+	for  i = 0L, ny - 1  do for  j = 0L, nx - 1  do begin
+	   if not keyword_set(silent) then begin
+	      print, ""
+	      print, "Estimating PSF in sub-region centered at ", $
+	             (lx[j] + ux[j]) / 2, (ly[i] + uy[i]) / 2
+	   endif
+	   ; Find stars in sub-region
+	   w = where(x gt lx[j] and x lt ux[j] and y gt ly[i] and y lt uy[i], n_ji)
+	   if  n_ji eq 0  then $
+	      message, "No star in sub-region " + $
+	      strcompress(string(j), /REMOVE_ALL) + ", " + strcompress(string(i), /REMOVE_ALL)
+	   x_ji = x[w] ;- lx[j]  &
+	   y_ji = y[w] ;- ly[i]  &
+	   f_ji = f[w]
+	   ; Select brightest stars
+	   n_ji = min([n_ji, nstar])
+	   s = (reverse(sort(f_ji)))[0:n_ji-1]
+	   x_ji = x_ji[s]  &  y_ji = y_ji[s]  &  f_ji = f_ji[s]
+	   ; Estimate local PSF
+	   psf_extract, x_ji, y_ji, dummy1, dummy2, $
+	                image, psfsize, psf, fw, background, $
+	                RAD_NORM = norm_rad, AVGTYPE = 2, $
+	                NOISE_LEVEL = noise, /NONORM, _EXTRA = extra, $
+	                X_STARS = x_in, Y_STARS = y_in, FLUXES = f_in, $
+	                STARS = stars_in, PSF = psf_in, LX = sv_lx, UX = sv_ux, LY = sv_ly, UY = sv_uy
+	   if not keyword_set(silent) then begin
+	      print, "Used ", n_ji, " stars"
+;	      print, "Stars magnitudes between ", -2.5*alog10(max(f_ji)), " and ", -2.5*alog10(min(f_ji))
+	      print, "PSF FWHM = ", fw
+	   endif
+	   if n_elements(ccthreshold) ne 0 then psf = image_core(psf, X = psfsize/2, Y = psfsize/2, ccthreshold)
+	   psf = psf / total(psf)
+	   stack[*,*,i*nx+j] = psf
+	endfor
+
+	return
+end
diff --git a/synfield.fits b/synfield.fits
new file mode 100644
index 0000000000000000000000000000000000000000..7eaf55eadbe18909832d08b8b8917a8237b946a2
Binary files /dev/null and b/synfield.fits differ
diff --git a/update_list.pro b/update_list.pro
new file mode 100644
index 0000000000000000000000000000000000000000..aa694b46f17d2ab71a6c31249148ffc71ee46e11
--- /dev/null
+++ b/update_list.pro
@@ -0,0 +1,58 @@
+; $Id: update_list.pro, v 1.1 Mar 2012 e.d. $
+;
+;+
+; NAME:
+;	UPDATE_LIST
+;
+; PURPOSE:
+;	Update list of stars.
+;
+; CATEGORY:
+;	STARFINDER auxiliary procedures.
+;
+; CALLING SEQUENCE:
+;	UPDATE_LIST, List, SUBSCRIPTS = S, X, Y, F, C, $
+;	             Sigma_X, Sigma_Y, Sigma_F, IS_STAR = Is_Star
+;
+; INPUTS:
+;	List:	list of stars.
+;
+;	X, Y:	1D vectors with x- and y- position of stars to update.
+;
+; OPTIONAL INPUTS:
+;	F, C:	1D vectors with flux and correlation coefficient of stars to update.
+;
+;	Sigma_X, Sigma_Y, Sigma_F:	errors on position and flux.
+;
+; KEYWORD PARAMETERS:
+;	SUBSCRIPTS:	1D vector of subscripts of stars to update. If not defined,
+;		update all the stars in the list.;
+;
+;	IS_STAR:	set this keyword to say that the stars to update have already
+;		been accepted as true stars.
+;
+; OUTPUTS:
+;	List:	updated list.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, June 2001.
+; 	1) Created this file (E. D., March 2012).
+;-
+
+PRO update_list, list, SUBSCRIPTS = s, x, y, f, c, $
+                  sigma_x, sigma_y, sigma_f, IS_STAR = is_star
+
+    on_error, 2
+    n = n_elements(s)
+    if  n eq 0  then  s = lindgen(n_elements(x))
+    if  s[0] ge 0  then begin
+       list[s].x = x  &  list[s].y = y
+       if  n_elements(f) ne 0  then  list[s].f = f
+       if  n_elements(c) ne 0  then  list[s].c = c
+       if  n_elements(sigma_x) ne 0  then  list[s].sigma_x = sigma_x
+       if  n_elements(sigma_y) ne 0  then  list[s].sigma_y = sigma_y
+       if  n_elements(sigma_f) ne 0  then  list[s].sigma_f = sigma_f
+       list[s].is_a_star = keyword_set(is_star) and 1B
+    endif
+    return
+end
diff --git a/where_stars.pro b/where_stars.pro
new file mode 100644
index 0000000000000000000000000000000000000000..82c50b6e924f6158f8ecb34531ef21876c8a56cb
--- /dev/null
+++ b/where_stars.pro
@@ -0,0 +1,71 @@
+; $Id: where_stars.pro, v 1.1 Mar 2012 e.d. $
+;
+;+
+; NAME:
+;	WHERE_STARS
+;
+; PURPOSE:
+;	Find subscripts of stars in a given star list, which might also
+;	include presumed stars.
+;
+; CATEGORY:
+;	STARFINDER auxiliary procedures.
+;
+; CALLING SEQUENCE:
+;	Result = WHERE_STARS(List, LX = Lx, UX = Ux, LY = Ly, UY = Uy, N)
+;
+; INPUTS:
+;	List:	star list
+;
+; KEYWORD PARAMETERS:
+;	LX, UX, LY, UY:	fix lower and upper x- and y- bounds of image
+;		region where the stars in the list have to searched
+;
+; OUTPUTS:
+;	Return subscripts of stars, possibly falling within specified
+;	region
+;
+; OPTIONAL OUTPUTS:
+;	N:	number of found stars
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, June 2001.
+;   1) Created this file (E. D., March 2012).
+;-
+
+FUNCTION where_stars, list, LX = lx, UX = ux, LY = ly, UY = uy, n
+
+    on_error, 2
+    if  n_tags(list) eq 0  then begin
+       n = 0L  &  return, -1L
+    endif
+    flag = list.is_a_star
+    if  n_elements(lx) ne 0  then $
+       flag = flag and list.x ge lx and list.x le ux $
+                   and list.y ge ly and list.y le uy
+    return, where(flag and 1B, n)
+end
+
+;FUNCTION where_stars, list, LX = lx, UX = ux, LY = ly, UY = uy, n
+;
+;  on_error, 2
+;  if  n_tags(list) eq 0 then begin
+;    n = 0L  &  return, -1L
+;  endif
+;  flag = list.is_a_star
+;  if  n_elements(lx) ne 0 then begin 
+;    wf = where(flag, n)
+;    if n eq 0 then return, -1L
+;    wlx = where((list.x)[wf] ge lx, n) 
+;    if n eq 0 then return, -1L
+;    wux = where((list.x)[wf[wlx]] le ux, n)
+;    if n eq 0 then return, -1L
+;    wly = where((list.y)[wf[wlx[wux]]] ge ly, n)
+;    if n eq 0 then return, -1L
+;    wuy = where((list.y)[wf[wlx[wux[wly]]]] le uy, n)
+;    if n eq 0 then return, -1L 
+;    return, [wf[wlx[wux[wly[wuy]]]]]
+;  endif else begin
+;    return, where(flag and 1B, n)
+;  endelse
+;end
diff --git a/xcompare_lists.pro b/xcompare_lists.pro
new file mode 100644
index 0000000000000000000000000000000000000000..9c90b5e453c4eb1c193069e02409636fcc364531
--- /dev/null
+++ b/xcompare_lists.pro
@@ -0,0 +1,368 @@
+; $Id: xcompare_lists, v 1.4 Apr 2012 e.d. $
+;
+;+
+; NAME:
+;	XCOMPARE_LISTS
+;
+; PURPOSE:
+;	Widget interface to read and compare two lists of objects.
+;	Each list is supposed to include floating point data ordered in rows
+;	of 7 elements. Such a list is produced by XStarFinder, as a result
+;	of the analysis of a stellar field. XCOMPARE_LISTS may be used to
+;	compare the results obtained for two images of the same field, observed
+;	at different wavelenghts. This task requires matching the coordinates,
+;	which are assumed to be reciprocally translated and rotated, and finding
+;	the common objects in the two lists.
+;	The output lists may be saved to a file. It is possible to plot the
+;	magnitudes of the common objects, producing a Color Magnitude Diagram.
+;
+; CATEGORY:
+;	Widgets. Stellar astrometry and photometry.
+;
+; CALLING SEQUENCE:
+;	XCOMPARE_LISTS, Wnum
+;
+; OPTIONAL INPUTS:
+;	Wnum:	Number of an existing graphic window where the widget must
+;		produce a Color Magnitude Diagram.
+;		If undefined, the plot is displayed on a new graphic window.
+;
+; KEYWORD PARAMETERS:
+;	PATH:	Initial path for file browsing when reading lists or saving
+;		results. If the argument of the keyword is a named variable,
+;		its value is overwritten.
+;
+;	GROUP: XCompare_Lists group leader.
+;
+;	UVALUE: XCompare_Lists user value.
+;
+; SIDE EFFECTS:
+;	1) Initiates the XMANAGER if it is not already running.
+;	2) If the window number Wnum is undefined and the user wants to plot the
+;	Color Magnitude Diagram, a new window is created.
+;
+; RESTRICTIONS:
+;	The Help menu opens the file
+;	'/starfinder/xcompare_lists_help.txt'.
+;
+; PROCEDURE:
+;	Create and register the widget as a modal widget.
+;
+; MODIFICATION HISTORY:
+;	Written by: Emiliano Diolaiti, September 1999
+;	Updates:
+;	1) Fixed bug on output roto-translated coordinates
+;	   (Emiliano Diolaiti, March 2000)
+;	2) Enhanced error handling in event-handler
+;	   (Emiliano Diolaiti, April 2000).
+;	3) Reviewed handling of lists (Emiliano Diolaiti, June 2000).
+;	4) Output file on 7 columns (E. D., April 2012).
+;-
+
+; XCOMPARE_LISTS_EVENT: XCompare_Lists event handler.
+
+PRO xcompare_lists_event, event
+
+	catch, error
+	if  error ne 0  then begin
+	   msg = dialog_message(/ERROR, !err_string)
+	   child = widget_info(event.top, /CHILD)
+	   widget_control, child, SET_UVALUE = data, /NO_COPY
+	   close, /ALL
+	   return
+	endif
+	; Get user value
+	child = widget_info(event.top, /CHILD)
+	widget_control, child, GET_UVALUE = data, /NO_COPY
+	; Event case
+	event_id = event.id  &  id = (*data).id
+	case  event_id  of
+	   id.fil: $
+	      case  event.value  of
+	         'File.Load.List 1': begin
+	            file = dialog_pickfile(/READ, FILTER = '*.txt', $
+	            					   PATH = *(*data).path, GET_PATH = path)
+	            if  file ne ''  then begin
+	               widget_control, /HOURGLASS
+	               *(*data).path = path
+	               in = transpose(read_float_data(file, 7))
+	               *(*data).x1 = in[*,0]  &  *(*data).sx1 = in[*,3]
+	               *(*data).y1 = in[*,1]  &  *(*data).sy1 = in[*,4]
+	               *(*data).f1 = in[*,2]  &  *(*data).sf1 = in[*,5]
+	               *(*data).c1 = in[*,6]
+	               ptr_free, (*data).x1c, (*data).sx1c, (*data).y1c, (*data).sy1c, $
+	                         (*data).f1c, (*data).sf1c, (*data).c1c, $
+	                         (*data).x_ref, (*data).y_ref
+	               (*data).x1c = ptr_new(/ALLOCATE)
+	               (*data).sx1c = ptr_new(/ALLOCATE)
+	               (*data).y1c = ptr_new(/ALLOCATE)
+	               (*data).sy1c = ptr_new(/ALLOCATE)
+	               (*data).f1c = ptr_new(/ALLOCATE)
+	               (*data).sf1c = ptr_new(/ALLOCATE)
+	               (*data).c1c = ptr_new(/ALLOCATE)
+	               (*data).x_ref = ptr_new(/ALLOCATE)
+	               (*data).y_ref = ptr_new(/ALLOCATE)
+	            endif
+	            end
+	         'File.Load.List 2': begin
+	            file = dialog_pickfile(/READ, FILTER = '*.txt', $
+	            					   PATH = *(*data).path, GET_PATH = path)
+	            if  file ne ''  then begin
+	               widget_control, /HOURGLASS
+	               *(*data).path = path
+	               in = transpose(read_float_data(file, 7))
+	               *(*data).x2 = in[*,0]  &  *(*data).sx2 = in[*,3]
+	               *(*data).y2 = in[*,1]  &  *(*data).sy2 = in[*,4]
+	               *(*data).f2 = in[*,2]  &  *(*data).sf2 = in[*,5]
+	               *(*data).c2 = in[*,6]
+	               ptr_free, (*data).x2c, (*data).sx2c, (*data).y2c, (*data).sy2c, $
+	                         (*data).f2c, (*data).sf2c, (*data).c2c, $
+	                         (*data).x2rt, (*data).y2rt
+	               (*data).x2c = ptr_new(/ALLOCATE)
+	               (*data).sx2c = ptr_new(/ALLOCATE)
+	               (*data).y2c = ptr_new(/ALLOCATE)
+	               (*data).sy2c = ptr_new(/ALLOCATE)
+	               (*data).f2c = ptr_new(/ALLOCATE)
+	               (*data).sf2c = ptr_new(/ALLOCATE)
+	               (*data).c2c = ptr_new(/ALLOCATE)
+	               (*data).x2rt = ptr_new(/ALLOCATE)
+	               (*data).y2rt = ptr_new(/ALLOCATE)
+	            endif
+	            end
+	         'File.Load.Reference list': begin
+	            file = dialog_pickfile(/READ, FILTER = '*.txt', $
+	            					   PATH = *(*data).path, GET_PATH = path)
+	            if  file ne ''  then begin
+	               widget_control, /HOURGLASS
+	               *(*data).path = path
+	               in = transpose(read_float_data(file, 2))
+	               *(*data).x_ref = in[*,0]  &  *(*data).y_ref = in[*,1]
+	            endif
+	            end
+	         'File.Save.List 1': begin
+	            if  n_elements(*(*data).f1c) ne 0  then begin
+	               file = dialog_pickfile(/WRITE, FILTER = '*.txt', $
+	            					      PATH = *(*data).path, GET_PATH = path)
+	               if  file ne ''  then begin
+	                  widget_control, /HOURGLASS
+	                  if  strpos(file, '.txt') lt 0  then  file = file + '.txt'
+	                  *(*data).path = path
+	                  out = [transpose(*(*data).x1c), $
+	               		     transpose(*(*data).y1c), $
+	               		     transpose(*(*data).f1c), $
+	               		     transpose(*(*data).sx1c), $
+	               		     transpose(*(*data).sy1c), $
+	            	         transpose(*(*data).sf1c), $
+	            	         transpose(*(*data).c1c)]
+	                  openw, lun, file, /GET_LUN, WIDTH = 200
+	                  printf, lun, out  &  free_lun, lun
+	               endif
+	            endif
+	            end
+	         'File.Save.List 2': begin
+	            if  n_elements(*(*data).f2c) ne 0 or $
+	                n_elements(*(*data).x2rt) ne 0  then begin
+	               file = dialog_pickfile(/WRITE, FILTER = '*.txt', $
+	            					      PATH = *(*data).path, GET_PATH = path)
+	               if  file ne ''  then begin
+	                  widget_control, /HOURGLASS
+	                  if  strpos(file, '.txt') lt 0  then  file = file + '.txt'
+	                  *(*data).path = path
+	                  if  n_elements(*(*data).f2c) ne 0  then begin
+	                     x = *(*data).x2c  &  sx = *(*data).sx2c
+	                     y = *(*data).y2c  &  sy = *(*data).sy2c
+	                     f = *(*data).f2c  &  sf = *(*data).sf2c
+	                     c = *(*data).c2c
+	                  endif else $
+	                  if  n_elements(*(*data).x2rt) ne 0  then begin
+	                     x = *(*data).x2rt  &  sx = *(*data).sx2
+	                     y = *(*data).y2rt  &  sy = *(*data).sy2
+	                     f = *(*data).f2  &  sf = *(*data).sf2
+	                     c = *(*data).c2
+	                  endif
+	                  out = [transpose(x), transpose(y), transpose(f), $
+	               	  	     transpose(sx), transpose(sy), transpose(sf), $
+	            	         transpose(c)]
+	                  openw, lun, file, /GET_LUN, WIDTH = 200
+	                  printf, lun, out  &  free_lun, lun
+	               endif
+	            endif
+	            end
+	      end
+	   id.match: begin
+	      if  n_elements(*(*data).x1) eq 0 or n_elements(*(*data).y1) eq 0  then $
+	         msg = dialog_message(/ERROR, 'Load list 1.')  else $
+	      if  n_elements(*(*data).x2) eq 0 or n_elements(*(*data).y2) eq 0  then $
+	         msg = dialog_message(/ERROR, 'Load list 2.')  else $
+	      if  n_elements(*(*data).x_ref) eq 0 or n_elements(*(*data).y_ref) eq 0  then $
+	         msg = dialog_message(/ERROR, 'Load reference points for list 1.') $
+	      else begin
+	         xmatch_coord, *(*data).x1, *(*data).y1, *(*data).x2, *(*data).y2, $
+	         			   *(*data).x_ref, *(*data).y_ref, x2_out, y2_out, $
+	         			   GROUP = event.top
+	         if  n_elements(x2_out) ne 0 and n_elements(y2_out) ne 0  then begin
+	            *(*data).x2rt = x2_out  &  *(*data).y2rt = y2_out
+	         endif
+	      endelse
+	      end
+	   id.find: begin
+	      if  n_elements(*(*data).x1) eq 0 or n_elements(*(*data).y1) eq 0  then $
+	         msg = dialog_message(/ERROR, 'Load list 1.')  else $
+	      if  n_elements(*(*data).x2) eq 0 or n_elements(*(*data).y2) eq 0  then $
+	         msg = dialog_message(/ERROR, 'Load list 2.')  $
+	      else begin
+	         if  n_elements(*(*data).x2rt) le 1  then begin
+	            *(*data).x2rt = *(*data).x2  &  *(*data).y2rt = *(*data).y2
+	         endif
+	         form = cw_form(['0,FLOAT,1,LABEL_LEFT=Distance,TAG=dist,WIDTH=12', $
+	         				 '2, BUTTON,OK,QUIT,NO_RELEASE'], TITLE = 'Matching distance')
+	         widget_control, /HOURGLASS
+	         compare_lists, *(*data).x1, *(*data).y1, *(*data).x2rt, *(*data).y2rt, $
+	      				    MAX_DISTANCE = form.dist, x1c, y1c, x2c, y2c, $
+						    SUBSCRIPTS_1 = sub1, SUBSCRIPTS_2 = sub2
+			 if  n_elements(sub1) ne 0  then  begin
+	            *(*data).x1c = x1c  &  *(*data).y1c = y1c
+	            *(*data).x2c = x2c  &  *(*data).y2c = y2c
+	            *(*data).f1c = (*(*data).f1)[sub1]
+	            *(*data).sx1c = (*(*data).sx1)[sub1]
+	            *(*data).sy1c = (*(*data).sy1)[sub1]
+	            *(*data).sf1c = (*(*data).sf1)[sub1]
+	            *(*data).c1c = (*(*data).c1)[sub1]
+	            *(*data).f2c = (*(*data).f2)[sub2]
+	            *(*data).sx2c = (*(*data).sx2)[sub2]
+	            *(*data).sy2c = (*(*data).sy2)[sub2]
+	            *(*data).sf2c = (*(*data).sf2)[sub2]
+	            *(*data).c2c = (*(*data).c2)[sub2]
+	         endif
+	         msg = dialog_message(/INFO, 'Found ' + $
+	         					  strcompress(string(n_elements(sub1)), /REMOVE_ALL) + ' common stars.')
+	      endelse
+	      end
+	   id.cmd: begin
+	      if  n_elements(*(*data).f1c) ne 0 and n_elements(*(*data).f2c) ne 0  then begin
+	         mag1 = *(*data).f1c  &  mag2 = *(*data).f2c
+	      endif else $
+	      if  n_elements(*(*data).f1) ne 0 and n_elements(*(*data).f2) ne 0  then begin
+	         mag1 = *(*data).f1  &  mag2 = *(*data).f2
+	      endif else $
+	         msg = dialog_message(/ERROR, 'No data to plot.')
+	      if  n_elements(mag1) ne 0 and n_elements(mag2) ne 0  then begin
+	         w = where(mag1 gt 0 and mag2 gt 0, count)
+	         if  count ne 0  then begin
+	            mag1 = -2.5*alog10(mag1[w])  &  mag2 = -2.5*alog10(mag2[w])
+	            form = cw_form(TITLE = 'Magnitude zero point: set 1', $
+	         				['0,FLOAT,0,LABEL_LEFT=Magnitude zero point,TAG=z,WIDTH=12', $
+	         				 '2, BUTTON,OK,QUIT,NO_RELEASE'])
+	            mag1 = mag1 + form.z
+	            form = cw_form(TITLE = 'Magnitude zero point: set 2', $
+	         				['0,FLOAT,0,LABEL_LEFT=Magnitude zero point,TAG=z,WIDTH=12', $
+	         				 '2, BUTTON,OK,QUIT,NO_RELEASE'])
+	            mag2 = mag2 + form.z
+	            xplot, mag1, mag1 - mag2, WNUM = (*data).wnum, $
+	            	   PATH = *(*data).path, DEFAULT_PAR = *(*data).plot_par
+	         endif
+	      endif
+	      end
+	   id.hlp: $
+	      xdispfile, file_name('starfinder', 'xcompare_lists_help.txt'), $
+	      		 TITLE = 'XCompare_Lists help', /MODAL
+	   id.done: begin
+	      widget_control, child, SET_UVALUE = data, /NO_COPY
+	      widget_control, event.top, /DESTROY
+	      end
+	endcase
+	if  event_id ne id.done  then $
+	   widget_control, child, SET_UVALUE = data, /NO_COPY
+	return
+end
+
+; XCOMPARE_LISTS_DEF: define data structure.
+
+FUNCTION xcompare_lists_def, wnum, path, id
+
+	on_error, 2
+	if  n_elements(wnum) eq 0  then  w = -1  else  w = wnum
+	data = {x1: ptr_new(/ALLOCATE), sx1: ptr_new(/ALLOCATE), $
+			y1: ptr_new(/ALLOCATE), sy1: ptr_new(/ALLOCATE), $
+			f1: ptr_new(/ALLOCATE), sf1: ptr_new(/ALLOCATE), $
+			c1: ptr_new(/ALLOCATE), $	; input parameters of set 1
+			x2: ptr_new(/ALLOCATE), sx2: ptr_new(/ALLOCATE), $
+			y2: ptr_new(/ALLOCATE), sy2: ptr_new(/ALLOCATE), $
+			f2: ptr_new(/ALLOCATE), sf2: ptr_new(/ALLOCATE), $
+			c2: ptr_new(/ALLOCATE), $	; input parameters of set 2
+			x_ref: ptr_new(/ALLOCATE), y_ref: ptr_new(/ALLOCATE), $
+			x2rt: ptr_new(/ALLOCATE), y2rt: ptr_new(/ALLOCATE), $
+			id: id, wnum: w, path: ptr_new(path), $ ; other parameters
+			x1c: ptr_new(/ALLOCATE), sx1c: ptr_new(/ALLOCATE), $
+			y1c: ptr_new(/ALLOCATE), sy1c: ptr_new(/ALLOCATE), $
+			f1c: ptr_new(/ALLOCATE), sf1c: ptr_new(/ALLOCATE), $
+			c1c: ptr_new(/ALLOCATE), $	; output parameters of set 1
+			x2c: ptr_new(/ALLOCATE), sx2c: ptr_new(/ALLOCATE), $
+			y2c: ptr_new(/ALLOCATE), sy2c: ptr_new(/ALLOCATE), $
+			f2c: ptr_new(/ALLOCATE), sf2c: ptr_new(/ALLOCATE), $
+			c2c: ptr_new(/ALLOCATE), $	; output parameters of set 2
+			plot_par: ptr_new(/ALLOCATE)}
+	return, data
+end
+
+; XCOMPARE_LISTS_DEL: de-reference and de-allocate heap variables.
+
+PRO xcompare_lists_del, data, path
+
+	if  n_elements(*(*data).path) ne 0  then  path = *(*data).path
+	ptr_free, (*data).x1, (*data).sx1, (*data).y1, (*data).sy1, $
+	   		  (*data).f1, (*data).sf1, (*data).c1, $
+	   		  (*data).x2, (*data).sx2, (*data).y2, (*data).sy2, $
+	   		  (*data).f2, (*data).sf2, (*data).c2, $
+	   		  (*data).x_ref, (*data).y_ref, (*data).x2rt, (*data).y2rt, $
+	   		  (*data).x1c, (*data).sx1c, (*data).y1c, (*data).sy1c, $
+	   		  (*data).f1c, (*data).sf1c, (*data).c1c, $
+	   		  (*data).x2c, (*data).sx2c, (*data).y2c, (*data).sy2c, $
+	   		  (*data).f2c, (*data).sf2c, (*data).c2c, $
+	   		  (*data).path, (*data).plot_par
+	ptr_free, data
+	return
+end
+
+; XCOMPARE_LISTS: XCompare_Lists widget definition module.
+
+PRO xcompare_lists, wnum, PATH = path, GROUP = group, UVALUE = uvalue
+
+	on_error, 2
+	; Create group leader if necessary
+	if  n_elements(group) eq 0  then $
+	   group_id = widget_base()  else  group_id = group
+	; Create modal base
+	if  n_elements(uvalue) eq 0  then  uvalue = 0B
+	base = widget_base(TITLE = 'XCompare_Lists', /MODAL, UVALUE = uvalue, $
+					   GROUP_LEADER = group_id, /COLUMN)
+	; Define child of top level base to store data
+	child = widget_base(base)
+	; Define File menu
+	desc = ['1\File', '1\Load', '0\List 1', '0\List 2', $
+			'2\Reference list', '3\Save', '0\List 1', '2\List 2']
+	fil = cw_pdmenu(base, desc, /RETURN_FULL_NAME)
+	; Define 'processing' buttons
+	pbase = widget_base(base, /COLUMN)
+	match = widget_button(pbase, VALUE = 'Match coordinates', /NO_RELEASE)
+	find = widget_button(pbase, VALUE = 'Find coincident', /NO_RELEASE)
+	cmd = widget_button(pbase, VALUE = 'Color Magnitude Diagram', /NO_RELEASE)
+	; Define other buttons
+	ubase = widget_base(base, /ROW)
+	hlp = widget_button(ubase, VALUE = 'Help', /NO_RELEASE)
+	done = widget_button(ubase, VALUE = 'Exit', /NO_RELEASE)
+	; Define pointer to auxiliary/output data
+	id = {fil: fil, match: match, find: find, cmd: cmd, hlp: hlp, done: done}
+	data = xcompare_lists_def(wnum, path, id)
+	data = ptr_new(data, /NO_COPY)
+	widget_control, child, SET_UVALUE = data
+	; Realize, register, etc.
+	widget_control, base, /REALIZE
+	xmanager, 'xcompare_lists', base, EVENT_HANDLER = 'xcompare_lists_event'
+	; De-reference output data and de-allocate heap variables
+	xcompare_lists_del, data, path
+	; Destroy group leader if necessary
+	if  n_elements(group) eq 0  then $
+	   widget_control, group_id, /DESTROY
+	return
+end
diff --git a/xcompare_lists_help.txt b/xcompare_lists_help.txt
new file mode 100644
index 0000000000000000000000000000000000000000..73f95ad81e09b6714f9242163532ef81a6a672e8
--- /dev/null
+++ b/xcompare_lists_help.txt
@@ -0,0 +1,69 @@
+  XCompare_Lists help page
+
+
+
+  GENERAL DESCRIPTION
+
+  The XCompare_Lists widget compares two lists of stars,
+  resulting for instance from the analysis of two images of
+  the same field observed at different wavelenghts.
+  In general the two frames are translated and rotated one
+  another: the proper transformation must be determined, in
+  order to map one set of coordinates onto the other.
+  After matching the reference frames, the common points
+  can be found.
+  The input lists of stars must have the same format as the
+  outputs produced by XStarFinder_Run; the data must be
+  stored on rows of 7 columns each, in the following order:
+
+  x  y  flux  sigma_x  sigma_y  sigma_flux  correlation
+
+  The reference list used to match the reference frames (see
+  the 'File' menu below) must contain only the coordinates
+  of the reference stars, in the following order:
+
+  x  y
+
+
+
+  CONTROLS/BUTTONS
+
+  'File':
+      The 'File' pull-down menu includes two sub-menus for
+      lists input/output.
+      The 'Load' sub-menu allows the user to read
+      - the lists to compare, named List 1 and List 2;
+      - a reference list (coordinates only!), containing a subset
+        of the objects in List 1, which is used to find the
+        coordinate transformation between the two reference frames.
+      The 'Save' sub-menu allows the user to save the processed
+      Lists 1 and 2, either after matching the reference frames
+      or after finding the common objects.
+ 
+  'Match coordinates':
+      Find the optimal transformation to map coordinates of
+      List 2 onto the reference frame of List 1. This is done
+      by the widget application XMatch_Coord.
+
+  'Find coincident':
+      Find coincident points in the two lists. The user is
+      requested to supply a 'matching distance', which
+      represents a tolerance to identify coincident points.
+
+  'Color Magnitude Diagram':
+      Create a simple color-magnitude diagram, plotting Mag1
+      on the vertical axis vs. (Mag1 - Mag2) on the horizontal
+      axis, where Mag1 and Mag2 are the magnitudes of the
+      stars in Lists 1 and 2 respectively. Magnitudes are
+      defined as
+      Mag = -2.5 * Log10(Flux);
+      the user is requested to enter a zero-point for the
+      magnitude scale.
+      The plot is created by means of the XPlot widget
+      application and can be saved as a PostScript file.
+
+  'Help':
+      Display this help page.
+
+  'Exit':
+      Quit XCompare_Lists.
\ No newline at end of file
diff --git a/xdispfile.pro b/xdispfile.pro
new file mode 100644
index 0000000000000000000000000000000000000000..4fcb5f8aadb814b35fb41b3d902151f12273e4f6
--- /dev/null
+++ b/xdispfile.pro
@@ -0,0 +1,110 @@
+; $Id: xdispfile.pro, v 1.1 Apr 2000 e.d. $
+;
+;+
+; NAME:
+;	XDISPFILE
+;
+; PURPOSE:
+;	Display an ASCII text file.
+;	This is a simplified version of the IDL library routine
+;	XDisplayFile, with the only additional feature that it
+;	can be called by other modal widgets.
+;
+; CATEGORY:
+;	Widgets.
+;
+; CALLING SEQUENCE:
+;	XDISPFILE, Filename
+;
+; INPUTS:
+;     Filename:	String, containing the name of the file.
+;
+; KEYWORD PARAMETERS:
+;	BLOCK:	Set this keyword to have XMANAGER block the IDL
+;		command line when this application is registered.
+;		The default is 'not blocked'.
+;
+;	GROUP:	The widget identifier of the group leader of the widget.
+;		If this keyword is specified and the keyword MODAL (see
+;		below) is not set, the death of the group leader results
+;		in the death of XDispFile.
+;
+;	MODAL:	Set this keyword to any nonzero value to create the widget
+;		as a modal widget, blocking the IDL command line and every
+;		other previously created widget applications.
+;
+;	TITLE:	Widget title. The default is Filename.
+;
+;	WIDTH:	Width of the text widget in characters. The default is 80.
+;
+;	HEIGHT:	Number of lines to be displayed in the text widget.
+;		Scroll bars are available to see the hidden text.
+;		The default height is 24 lines.
+;
+; OUTPUTS:
+;	None. Text is displayed on the widget.
+;
+; SIDE EFFECTS:
+;	Initiates the XMANAGER if it is not already running.
+;
+; PROCEDURE:
+;	Read the specified ASCII file and display its content
+;	on a text widget.
+;
+; MODIFICATION HISTORY:
+; 	Written by:	Emiliano Diolaiti, November 1999.
+;	Updates:
+;	1) Enhanced error handling (Emiliano Diolaiti, April 2000).
+;-
+
+; XDISPFILE_EVENT: XDispFile event handler.
+
+PRO xdispfile_event, event
+
+	widget_control, event.id, GET_UVALUE = ev_type
+	if  strlowcase(ev_type) eq 'quit'  then $
+	   widget_control, event.top, /DESTROY
+	return
+end
+
+; XDISPFILE: XDispFile widget definition module.
+
+PRO xdispfile, filename, GROUP = group, MODAL = modal, BLOCK = block, $
+	           TITLE = title, WIDTH = width, HEIGHT = height
+
+	catch, error
+	if  error ne 0  then begin
+	   msg = dialog_message(/ERROR, !err_string)
+	   close, /ALL
+	   return
+	endif
+	; Open file and read its content
+	openr, unit, filename, /GET_LUN
+	text = ''  &  line = text
+	while  not eof(unit)  do begin
+	   readf, unit, line  &  text = [text, line]
+	endwhile
+	free_lun, unit
+	; Define default values
+	if  n_elements(title) eq 0  then  title = filename
+	if  n_elements(group) ne 0  then  group_leader = group
+	if  keyword_set(modal)  then $
+	   if  n_elements(group) eq 0  then  group_leader = widget_base()
+	if  n_elements(width) eq 0  then  width = 80
+	if  n_elements(height) eq 0  then  height = 24
+	; Define widget
+    base = widget_base(TITLE = title, /COLUMN, $
+                       MODAL = modal, GROUP_LEADER = group_leader)
+	text_id = widget_text(base, /SCROLL, VALUE = text, $
+	                      XSIZE = width, YSIZE = height)
+	lo_base = widget_base(base)
+	quit_id = widget_button(lo_base, VALUE = 'Close', UVALUE = 'quit')
+	; Realize widget, register it, etc.
+	widget_control, base, /REALIZE
+	xmanager, 'xdispfile', base, $
+                  EVENT_HANDLER = 'xdispfile_event', $
+                  NO_BLOCK = (not keyword_set(block)) and 1B
+	if  keyword_set(modal)  then  if  n_elements(group) eq 0  then $
+	   widget_control, group_leader, /DESTROY
+	return
+end
diff --git a/xdisplayopt.pro b/xdisplayopt.pro
new file mode 100644
index 0000000000000000000000000000000000000000..4b7ce41f3cfd619580e8f100d554056c7dd86168
--- /dev/null
+++ b/xdisplayopt.pro
@@ -0,0 +1,177 @@
+; $Id: xdisplayopt.pro, v 1.1 Apr 2000 e.d. $
+;
+;+
+; NAME:
+;	XDISPLAYOPT
+;
+; PURPOSE:
+;	Modify display options for a 2D image.
+;
+; CATEGORY:
+;	Widgets. Data visualization.
+;
+; CALLING SEQUENCE:
+;	Result = XDISPLAYOPT(Image, Wnum)
+;
+; INPUTS:
+;	Image: 2D data array
+;
+; OPTIONAL INPUT PARAMETERS:
+;	Wnum: window number of an existing window
+;
+; KEYWORD PARAMETERS:
+;	OPTIONS: structure of current display options; the structure must be
+;		defined as in DEFAULT_DISPLAY_OPT
+;
+;	GROUP: group leader of top level base
+;
+;	NODISPLAY: avoid first image display. This keyword should be set only
+;		if the image is already displayed in its window (as in a call from
+;		DISPLAY_IMAGE)
+;
+;	UVALUE: xdisplayopt user value
+;
+; OUTPUTS:
+;	Return structure of modified display options
+;
+; OPTIONAL OUTPUT PARAMETERS:
+;	Wnum: window number of new window, if undefined on input
+;
+; SIDE EFFECTS:
+;	1) Initiates the XMANAGER if it is not already running.
+;	2) Use WSET to activate the graphic window identified by Wnum.
+;	3) Create a new graphic window if the input parameter Wnum is undefined.
+;
+; RESTRICTIONS:
+;	1) If the parameter Wnum is a window number < 32 but the corresponding
+;	window does not exist (or has been deleted), the new window size is set
+;	by IDL and may not fit the image x- and y size. If Wnum >=32 and the
+;	corresponding window does not exists, an error occurs.
+;	2) The Help menu opens the file '/starfinder/xdisplay_opt_help.txt'.
+;
+; PROCEDURE:
+;	Create and register the widget as a modal widget.
+;	Then let the user modify the image display options.
+;
+; MODIFICATION HISTORY:
+;	Written by: Emiliano Diolaiti, August 1999
+;	Updates:
+;	1) Enhanced error handling in event-handler
+;	   (Emiliano Diolaiti, April 2000).
+;-
+
+
+; XDISPLAYOPT_EVENT: XDisplayOpt event handler.
+
+PRO xdisplayopt_event, event
+
+	catch, error
+	if  error ne 0  then begin
+	   msg = dialog_message(/ERROR, !err_string)
+	   child = widget_info(event.top, /CHILD)
+	   widget_control, child, SET_UVALUE = info, /NO_COPY
+	   return
+	endif
+	; Get user value
+	child = widget_info(event.top, /CHILD)
+	widget_control, child, GET_UVALUE = info, /NO_COPY
+	; Event case
+	event_id = event.id  &  id = (*info).id
+	case event_id of
+	   id.min_level: (*info).options.range[0] = event.value
+	   id.max_level: (*info).options.range[1] = event.value
+	   id.stretch: (*info).options.stretch = event.value
+	   id.reverse: (*info).options.reverse = not (*info).options.reverse and 1B
+	   id.chop: (*info).options.chop = event.value
+	   id.ct: (*info).options.color_table = event.index
+	   id.apply: begin
+	      widget_control, /HOURGLASS
+	      display_image, (*info).image, (*info).wnum, OPTIONS = (*info).options
+	      end
+	   id.hlp: $
+	      xdispfile, file_name('starfinder', 'xdisplayopt_help.txt'), $
+	                 TITLE = 'XDisplayOpt help', /MODAL
+	   id.done: begin
+	      widget_control, child, SET_UVALUE = info, /NO_COPY
+	      widget_control, event.top, /DESTROY
+	      end
+	endcase
+	; Set user value
+	if  event_id ne id.done  then $
+	   widget_control, child, SET_UVALUE = info, /NO_COPY
+	return
+end
+
+
+; XDISPLAYOPT: XDisplayOpt widget definition module.
+
+FUNCTION xdisplayopt, image, wnum, OPTIONS = options, NODISPLAY = nodisplay, $
+					  GROUP = group, UVALUE = uvalue
+
+	catch, display_error
+	if  display_error ne 0  then begin
+	   if  n_elements(options) eq 0  then  options = 0
+	   return, options
+	endif
+	; Display image, retrieving default options if undefined
+	if  not keyword_set(nodisplay)  then $
+	   display_image, image, wnum, OPTIONS = options  else $
+	if  n_elements(options) eq 0  then $
+	   options = default_display_opt(image)
+	; Define group leader, if necessary
+	if  n_elements(group) eq 0  then $
+	   group_id = widget_base()  else  group_id = group
+	; Define modal top level base
+	if  n_elements(uvalue) eq 0  then  uvalue = 0B
+	base = widget_base(TITLE = 'XDisplayOpt', GROUP_LEADER = group_id, $
+					   /MODAL, /COLUMN, UVALUE = uvalue)
+	; Define child, to store data structure
+	child = widget_base(base)
+	; Define 'Intensity range' input fields
+	min_level = cw_form(base, '0, FLOAT,,WIDTH=12,LABEL_LEFT=Minimum intensity ')
+	widget_control, min_level, SET_VALUE = $
+					{tag0: strcompress(string(options.range[0]), /REMOVE_ALL)}
+	max_level = cw_form(base, '0, FLOAT,,WIDTH=12,LABEL_LEFT=Maximum intensity ')
+	widget_control, max_level, SET_VALUE = $
+					{tag0: strcompress(string(options.range[1]), /REMOVE_ALL)}
+	; Define Stretch buttons
+	slabel = widget_label(base, VALUE = 'Stretch:', /ALIGN_LEFT)
+	stretch_opt = ['square', 'linear', 'square root', 'logarithm']
+	stretch = cw_bgroup(base, stretch_opt, /EXCLUSIVE, /NO_RELEASE, $
+			    SET_VALUE = (where(stretch_opt eq options.stretch))[0], $
+			    BUTTON_UVALUE = stretch_opt)
+	reverse = cw_bgroup(base, ['reverse scale'], /NONEXCLUSIVE, $
+						SET_VALUE = options.reverse and 1B,	$
+						BUTTON_UVALUE = 'reverse')
+	; Define 'Chopping threshold' input field
+	chop = cw_form(base, '0, FLOAT,,WIDTH=12,LABEL_LEFT=Chopping threshold ')
+	widget_control, chop, SET_VALUE = $
+					{tag0: strcompress(string(options.chop), /REMOVE_ALL)}
+	; Define 'Color Table' list
+	ct_names = ''	; define ct_names for LoadCT
+	loadct, GET_NAMES = ct_names, /SILENT
+	ctlabel = widget_label(base, VALUE = 'Color Table:', /ALIGN_LEFT)
+	ct = widget_list(base, VALUE = ct_names, YSIZE = 5)
+	; Define other buttons
+	base2 = widget_base(base, /ROW)
+	apply = widget_button(base2, VALUE = 'Apply options', /NO_RELEASE)
+	base3 = widget_base(base, /ROW)
+	hlp = widget_button(base3, VALUE = 'Help', /NO_RELEASE)
+	done = widget_button(base3, VALUE = 'Exit', /NO_RELEASE)
+	; Realize widget, set user value, register, etc.
+	id = {min_level: min_level, max_level: max_level, $
+		  stretch: stretch, reverse: reverse, chop: chop, ct: ct, $
+		  apply: apply, hlp: hlp, done: done} ; IDs structure
+	data = {id: id, wnum: wnum, image: image, options: options}	; data structure
+	data = ptr_new(data, /NO_COPY)	; pointer to data structure
+	widget_control, child, SET_UVALUE = data
+		; NOTE: /NO_COPY is not set here, to avoid losing the pointer to
+		; the global data stored in the user-value of the 'child' base
+	widget_control, base, /REALIZE
+	xmanager, 'xdisplayopt', base, EVENT_HANDLER = 'xdisplayopt_event'
+	options = (*data).options  &  ptr_free, data
+	; Destroy group leader base, if necessary
+	if  n_elements(group) eq 0  then $
+	   widget_control, group_id, /DESTROY
+	return, options
+end
diff --git a/xdisplayopt_help.txt b/xdisplayopt_help.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c56477717d30a6f25654d765d106311984054270
--- /dev/null
+++ b/xdisplayopt_help.txt
@@ -0,0 +1,56 @@
+  XDisplay_Opt help page
+
+
+
+  GENERAL DESCRIPTION
+
+  The XDisplay_Opt widget allows the user to define the
+  options to display a given image.
+
+ 
+ 
+  PARAMETERS
+
+  'Minimum intensity':
+      Minimum intensity level to display. Values lower than
+      this bound are set to 'Minimum intensity' before display.
+
+  'Maximum intensity':
+      Maximum intensity level to display.
+
+  'Stretch':
+      Define display scale. Possible choices are
+      - square (maximum contrast)
+      - linear
+      - square root
+      - logarithm (minimum contrast)
+
+  'Reverse scale':
+      Reverse gray level scale: the brightest pixels will be
+      represented by the lowest gray level.
+
+  'Chopping threshold':
+      Pixels above this threshold are set to the minimum gray
+      level. This options is useful to highlight saturated
+      regions in the image.
+
+  'Color Table':
+      Select a pre-defined color table. A suitable choice is
+      'STERN SPECIAL'.
+      This option might not work properly if the screen is not
+      set to 256 colors.
+
+
+
+  CONTROLS/BUTTONS
+
+  'Apply options':
+      Display the input array with the currently defined
+      options. The options are applied to a copy of the input
+      array, which of course is not modified.
+
+  'Help':
+      Display this help page.
+
+  'Exit':
+      Quit XDisplay_Opt.
\ No newline at end of file
diff --git a/ximage_support.pro b/ximage_support.pro
new file mode 100644
index 0000000000000000000000000000000000000000..394a90bac5c6b8d8cb436026779e9fcb62216321
--- /dev/null
+++ b/ximage_support.pro
@@ -0,0 +1,198 @@
+; $Id: ximage_support, v 1.1 Apr 1999 e.d. $
+;
+;+
+; NAME:
+;	XIMAGE_SUPPORT
+;
+; PURPOSE:
+;	Widget interface for the CIRC_MASK and IMAGE_CORE functions.
+;	Modify the support of an image by applying a circular mask and/or
+;	extracting the principal connected component above a pre-fixed threshold.
+;	The reference pixel for CIRC_MASK and IMAGE_CORE is assumed to be the
+;	maximum intensity pixel of the input array.
+;
+; CATEGORY:
+;	Widgets. Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = XIMAGE_SUPPORT(Psf, Wnum, Display_opt)
+;
+; INPUTS:
+;	Psf: 2D data array, containing the image of the point source to smooth
+;
+; OPTIONAL INPUTS:
+;	Wnum: Window number of an existing window
+;
+;	Display_opt:	Structure of current display options;
+;		the structure must be defined as in DEFAULT_DISPLAY_OPT
+;
+; KEYWORD PARAMETERS:
+;	DEFAULT_PAR:	Structure of default parameters for the widget's form.
+;
+;	GROUP: XImage_Support group leader.
+;
+;	UVALUE: XImage_Support user value.
+;
+; OUTPUTS:
+;	Result:	Input Image with processed support
+;
+; OPTIONAL OUTPUTS:
+;	Wnum: window number of new window, if undefined on input
+;
+;	Display_opt:	Display options, as defined and/or modified by
+;		X_Psf_smooth
+;
+;	DEFAULT_PAR:	Set this keyword to a named variable to get the
+;		structure of parameters set by the widget's user.
+;
+; SIDE EFFECTS:
+;	1) Initiates the XMANAGER if it is not already running.
+;	2) Call DISPLAY_IMAGE to activate the graphic window identified by Wnum.
+;	3) Create a new graphic window if not defined on input (see DISPLAY_IMAGE
+;	and XDISPLAYOPT for details).
+;	4) Any image displayed on the window Wnum is overwritten first by the
+;	input image and then by the processed array.
+;
+; RESTRICTIONS:
+;	The Help menu opens the file
+;	'/starfinder/ximage_support_help.txt'.
+;
+; PROCEDURE:
+;	Create and register the widget as a modal widget.
+;	Then let the user define and or/modify the support options and apply
+;	them to the input image. As a new processed image is obtained applying
+;	the current options, it is displayed on the graphic window.
+;
+; MODIFICATION HISTORY:
+;	Written by: Emiliano Diolaiti, September 1999
+;	Updates:
+;	1) Enhanced error handling in event-handler
+;	   (Emiliano Diolaiti, April 2000).
+;-
+
+; XIMAGE_SUPPORT_EVENT: XImage_Support event handler.
+
+PRO ximage_support_event, event
+
+	catch, error
+	if  error ne 0  then begin
+	   msg = dialog_message(/ERROR, !err_string)
+	   widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	   return
+	endif
+	widget_control, event.id, GET_UVALUE = data, /NO_COPY
+	event_type = strlowcase(event.tag)
+	case  event_type  of
+	   'mask': $
+	      widget_control, (*data).ids[0], SENSITIVE = (event.value eq 1) and 1B
+	   'comp': $
+	      widget_control, (*data).ids[1], SENSITIVE = (event.value eq 1) and 1B
+	   'proc': begin
+	      widget_control, /HOURGLASS
+	      widget_control, event.id, GET_VALUE = form
+	      (*data).par.mask = form.mask
+	      (*data).par.rad = form.rad
+	      (*data).par.comp = form.comp
+	      (*data).par.thresh = form.thresh
+	      mask = (form.mask eq 1) and 1B
+	      if  mask  then  rad = form.rad
+	      comp = (form.comp eq 1) and 1B
+	      if  comp  then  thresh = form.thresh
+	      (*data).image_out = (*data).image_in
+	      m = get_max((*data).image_out)
+	      if  mask  then $
+	         (*data).image_out = circ_mask((*data).image_out, m[0], m[1], rad)
+	      if  comp  then $
+	         (*data).image_out = image_core((*data).image_out, thresh, X = m[0], Y = m[1])
+	      display_image, (*data).image_out, (*data).wnum, OPT = (*data).display_opt
+	      end
+	   'display': $
+	      (*data).display_opt = xdisplayopt((*data).image_out, (*data).wnum, $
+	      		/NODISPLAY, OPTIONS = (*data).display_opt, GROUP = event.top)
+	   'help': $
+	      xdispfile, file_name('starfinder', 'ximage_support_help.txt'), $
+	      		 TITLE = 'XImage_Support help', /MODAL
+	   'exit': begin
+	      widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	      widget_control, event.top, /DESTROY
+	      end
+	   else:
+	endcase
+	if  event_type ne 'exit'  then $
+	   widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	return
+end
+
+; XIMAGE_SUPPORT_PAR: define default parameters.
+
+PRO ximage_support_par, id, maxsiz, par
+
+	if  n_elements(par) ne 0  then begin
+	   mask = par.mask
+	   rad = par.rad
+	   comp = par.comp
+	   thresh = par.thresh
+	endif else begin
+	   mask = 0
+	   rad = maxsiz
+	   comp = 0
+	   thresh = 0
+	   par = {mask: mask, rad: rad, comp: comp, thresh: thresh}
+	endelse
+	init = {mask: mask, rad: strcompress(string(rad), /REMOVE_ALL), $
+			comp: comp, thresh: strcompress(string(thresh), /REMOVE_ALL)}
+	widget_control, id, SET_VALUE = init
+	return
+end
+
+; XIMAGE_SUPPORT: XImage_Support widget definition module.
+
+FUNCTION ximage_support, image, wnum, display_opt, DEFAULT_PAR = par, $
+						 GROUP = group, UVALUE = uvalue
+
+	on_error, 2
+	; Display image and define display options
+	display_image, image, wnum, OPTIONS = display_opt
+	; Create group leader if necessary
+	if  n_elements(group) eq 0  then $
+	   group_id = widget_base()  else  group_id = group
+	; Create modal base
+	if  n_elements(uvalue) eq 0  then  uvalue = 0B
+	base = widget_base(TITLE = 'XImage_Support', /MODAL, UVALUE = uvalue, $
+					   GROUP_LEADER = group_id)
+	; Define form
+	desc = [ $
+	'0, LABEL,Circular mask:', $
+	'1, BASE,,COLUMN,FRAME', $
+	'0, BUTTON,No|Yes,EXCLUSIVE,TAG=mask,ROW', $
+	'2, INTEGER,,LABEL_LEFT=Circular mask radius,TAG=rad', $
+	'0, LABEL,Principal component extraction:', $
+	'1, BASE,,COLUMN,FRAME', $
+	'0, BUTTON,No|Yes,EXCLUSIVE,TAG=comp,ROW', $
+	'2, FLOAT,,LABEL_LEFT=Threshold for principal component extraction,TAG=thresh', $
+	'1, BASE,,ROW', $
+	'0, BUTTON,Processing...,NO_RELEASE,TAG=proc', $
+	'2, BUTTON,Display Options,NO_RELEASE,TAG=display', $
+	'1, BASE,,ROW', $
+	'0, BUTTON,Help,NO_RELEASE,TAG=help', $
+	'2, BUTTON,Exit,QUIT,NO_RELEASE,TAG=exit']
+	form = cw_form(base, desc, IDS = ids, /COLUMN)
+	ximage_support_par, form, max(size52(image, /DIM)), par
+	widget_control, ids[3], SENSITIVE = par.mask eq 1 and 1B
+	widget_control, ids[7], SENSITIVE = par.comp eq 1 and 1B
+	; Define pointer to auxiliary/output data
+	data = {par: par, image_in: image, image_out: image, $
+			wnum: wnum, display_opt: display_opt, ids: [ids[3], ids[7]]}
+	data = ptr_new(data, /NO_COPY)
+	widget_control, form, SET_UVALUE = data
+	; Realize, register, etc.
+	widget_control, base, /REALIZE
+	xmanager, 'ximage_support', base, EVENT_HANDLER = 'ximage_support_event'
+	; De-reference output data
+	par = (*data).par  &  image_out = (*data).image_out  &  display_opt = (*data).display_opt
+	ptr_free, data
+	; Destroy group leader if necessary
+	if  n_elements(group) eq 0  then $
+	   widget_control, group_id, /DESTROY
+	return, image_out
+end
diff --git a/ximage_support_help.txt b/ximage_support_help.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e02e3b0c30dd4cca50cfe03b3030a5e4a71a8241
--- /dev/null
+++ b/ximage_support_help.txt
@@ -0,0 +1,41 @@
+  XImage_Support help page
+
+
+  GENERAL DESCRIPTION
+
+  The XImage_Support widget modifies the support of the input
+  image by either applying a circular mask centered on the
+  image maximum or extracting the principal connected component,
+  i.e. the set of pixels above a pre-fixed intensity threshold
+  and connected by a path to the maximum intensity pixel.
+    
+ 
+ 
+  PARAMETERS
+
+  'Circular mask radius':
+      Mask radius in pixel units.
+
+  'Threshold for principal component extraction':
+      Threshold representing the lower value to identify the region
+      of pixels connected by a path to the maximum intensity pixel.
+
+
+
+  CONTROLS/BUTTONS
+
+  'Processing...':
+      Apply the currently defined options to the input image.
+      Whenever the 'Processing...' button is pressed, the previous
+      result is overwritten by the input image and the processing
+      is performed with the current options. The result of the
+      last processing is returned on output.
+
+  'Display Options':
+      Modify the display options of the displayed image.
+
+  'Help':
+      Display this help page.
+
+  'Exit':
+      Quit XImage_Support.
\ No newline at end of file
diff --git a/xmatch_coord.pro b/xmatch_coord.pro
new file mode 100644
index 0000000000000000000000000000000000000000..fd0daf51f9b41965dfa21f7f5229795e4b542e61
--- /dev/null
+++ b/xmatch_coord.pro
@@ -0,0 +1,187 @@
+; $Id: xmatch_coord, v 1.1 Apr 2000 e.d. $
+;
+;+
+; NAME:
+;	XMATCH_COORD
+;
+; PURPOSE:
+;	Widget interface for the MATCH_COORD procedure.
+;	Given two sets of coordinates on a plane, representing the same points
+;	in two different reference frames supposed to be reciprocally translated
+;	and rotated, find the optimal transformation between the two sets and
+;	map one of them onto the other.
+;
+; CATEGORY:
+;	Widgets. Spatial transformations.
+;
+; CALLING SEQUENCE:
+;	XMATCH_COORD, X1, Y1, X2, Y2, X_ref, Y_ref, X2_out, Y2_out
+;
+; INPUTS:
+;	X1, Y1:	Coordinates of points in reference frame no. 1
+;
+;	X2, Y2:	Coordinates of points in reference frame no. 2
+;
+;	X_ref, Y_ref:	Coordinates of reference points, used to find the
+;		optimal transformation. (X_ref, Y_ref) may be a subset of (X1, Y1).
+;
+; KEYWORD PARAMETERS:
+;	GROUP: XMatch_Coord group leader.
+;
+;	UVALUE: XMatch_Coord user value.
+;
+; OUTPUTS:
+;	X2_out, Y2_out:	Coordinates (X2, Y2) mapped onto reference frame 1.
+;		These coordinates may be directly compared to (X1, Y1).
+;		A negative scalar value indicates an error condition
+;
+; OPTIONAL OUTPUTS:
+;	ORIGIN:	Set this keyword to a named variable to retrieve a 2-components
+;		vector, representing the estimated position of the origin of reference
+;		frame 2 in reference frame 1.
+;
+;	ANGLE:	Set this keyword to a named variable to retrieve a scalar,
+;		representing the estimated angle (in radians) between the x- axis of
+;		reference frame 1 and the x- axis of reference frame 2, measured
+;		counter-clockwise from 1 to 2.
+;
+; SIDE EFFECTS:
+;	Initiates the XMANAGER if it is not already running.
+;
+; RESTRICTIONS:
+;	The Help menu opens the file
+;	'/starfinder/xmatch_coord_help.txt'.
+;
+; PROCEDURE:
+;	Create and register the widget as a modal widget.
+;
+; MODIFICATION HISTORY:
+;	Written by: Emiliano Diolaiti, September 1999
+;	Updates:
+;	1) Enhanced error handling in event-handler
+;	   (Emiliano Diolaiti, April 2000).
+;-
+
+; XMATCH_COORD_EVENT: XMatch_Coord event handler.
+
+PRO xmatch_coord_event, event
+
+	catch, error
+	if  error ne 0  then begin
+	   msg = dialog_message(/ERROR, !err_string)
+	   widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	   return
+	endif
+	widget_control, event.id, GET_UVALUE = data, /NO_COPY
+	event_type = strlowcase(event.tag)
+	case  event_type  of
+	   'match': begin
+	      widget_control, /HOURGLASS
+	      ; Match coordinates
+	      widget_control, event.id, GET_VALUE = form
+	      origin = [form.ox, form.oy]
+	      angle = form.angle * !pi/180.
+	      match_coord, (*data).x1, (*data).y1, (*data).x2, (*data).y2, $
+	      			   (*data).x_ref, (*data).y_ref, x2_out, y2_out, $
+	      			   ORIGIN_0 = origin, ANGLE_0 = angle, origin, angle
+	      ; Save results
+	      if  n_elements(x2_out) eq n_elements((*data).x2)  then begin
+	         msg = dialog_message(['The parameters of the transformation are: ', $
+	         					   'x-shift = ' + strcompress(string(origin[0])), $
+	         					   'y-shift = ' + strcompress(string(origin[1])), $
+	         					   'rotation angle (deg.) = ' + $
+	         					   strcompress(string(angle/!pi*180))], /INFO)
+	         *(*data).x2_out = x2_out  &  *(*data).y2_out = y2_out
+	         (*data).origin = origin  &  (*data).angle = angle
+	      endif else $
+		     msg = dialog_message('Unsuccessful matching', /ERROR)
+	      end
+	   'help': $
+	      xdispfile, file_name('starfinder', 'xmatch_coord_help.txt'), $
+	      		 TITLE = 'XMatch_Coord help', /MODAL
+	   'exit': begin
+	      widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	      widget_control, event.top, /DESTROY
+	      end
+	   else:
+	endcase
+	if  event_type ne 'exit'  then $
+	   widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	return
+end
+
+; XMATCH_COORD_DEF: define data structure.
+
+FUNCTION xmatch_coord_def, x1, y1, x2, y2, x_ref, y_ref
+
+	data = {x1: x1, y1: y1, x2: x2, y2: y2, $
+			x_ref: x_ref, y_ref: y_ref, $
+			x2_out: ptr_new(/ALLOCATE), y2_out: ptr_new(/ALLOCATE), $
+			origin: [0., 0.], angle: 0.}
+	return, data
+end
+
+; XMATCH_COORD_DEL: de-reference and de-allocate heap variables.
+
+PRO xmatch_coord_del, data, x2_out, y2_out, origin, angle
+
+	if  n_elements(*(*data).x2_out) ne 0 and n_elements(*(*data).y2_out) ne 0  then begin
+	   x2_out = *(*data).x2_out  &  y2_out = *(*data).y2_out
+	endif
+	origin = (*data).origin  &  angle = (*data).angle
+	ptr_free, (*data).x2_out, (*data).y2_out
+	ptr_free, data
+	return
+end
+
+; XMATCH_COORD: XMatch_Coord widget definition module.
+
+PRO xmatch_coord, x1, y1, x2, y2, x_ref, y_ref, x2_out, y2_out, $
+				  ORIGIN = origin, ANGLE = angle, $
+				  GROUP = group, UVALUE = uvalue
+
+	on_error, 2
+	if  n_elements(x1) eq 0 or n_elements(y1) eq 0 or $
+		n_elements(x2) eq 0 or n_elements(y2) eq 0  then begin
+	   msg = dialog_message('XMatch_Coord: missing data', /ERROR)
+	   return
+	endif
+	if  n_elements(x_ref) lt 2 or n_elements(y_ref) lt 2  then begin
+	   msg = dialog_message('XMatch_Coord: at least 2 reference ' + $
+	   						'points must be supplied.', /ERROR)
+	   return
+	endif
+	; Create group leader if necessary
+	if  n_elements(group) eq 0  then $
+	   group_id = widget_base()  else  group_id = group
+	; Create modal base
+	if  n_elements(uvalue) eq 0  then  uvalue = 0B
+	base = widget_base(TITLE = 'XMatch_Coord', /MODAL, UVALUE = uvalue, $
+					   GROUP_LEADER = group_id)
+	; Define form
+	desc = [ $
+	'0, LABEL,Initial guess:,LEFT', $
+	'1, BASE,,COLUMN,FRAME', $
+	'0, FLOAT,0,LABEL_LEFT=x-axis translation,TAG=ox', $
+	'0, FLOAT,0,LABEL_LEFT=y-axis translation,TAG=oy', $
+	'2, FLOAT,0,LABEL_LEFT=rotation angle (deg.),TAG=angle', $
+	'1, BASE,,ROW', $
+	'2, BUTTON,Match,NO_RELEASE,TAG=match', $
+	'1, BASE,,ROW', $
+	'0, BUTTON,Help,NO_RELEASE,TAG=help', $
+	'2, BUTTON,Exit,QUIT,NO_RELEASE,TAG=exit']
+	form = cw_form(base, desc, /COLUMN)
+	; Define pointer to auxiliary/output data
+	data = xmatch_coord_def(x1, y1, x2, y2, x_ref, y_ref)
+	data = ptr_new(data, /NO_COPY)
+	widget_control, form, SET_UVALUE = data
+	; Realize, register, etc.
+	widget_control, base, /REALIZE
+	xmanager, 'xmatch_coord', base, EVENT_HANDLER = 'xmatch_coord_event'
+	; De-reference output data and de-allocate heap variables
+	xmatch_coord_del, data, x2_out, y2_out, origin, angle
+	; Destroy group leader if necessary
+	if  n_elements(group) eq 0  then $
+	   widget_control, group_id, /DESTROY
+	return
+end
diff --git a/xmatch_coord_help.txt b/xmatch_coord_help.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c7315a93866947c42ba9eb96885714bd5068d0c8
--- /dev/null
+++ b/xmatch_coord_help.txt
@@ -0,0 +1,46 @@
+  XMatch_Coord help page
+
+
+
+  GENERAL DESCRIPTION
+
+  Given two lists of points, referred to reciprocally translated and
+  rotated reference frames on a plane (x, y), the XMatch_Coord
+  application estimates the relative shift and rotation and applies
+  an inverse transformation to the points in list 2, in order to
+  map them onto list 1.
+  The estimation is performed by means of a Newton-like algorithm.
+  A list of reference points, representing a sub-set of list 1, must
+  be supplied, along with a guess of the relative shift and rotation
+  between the reference frames.
+    
+ 
+ 
+  PARAMETERS
+
+  'x-axis translation':
+      Guess of the x-coordinate of the origin of reference frame 2
+      with respect to reference frame 1.
+
+  'y-axis translation':
+      Guess of the y-coordinate of the origin of reference frame 2
+      with respect to reference frame 1.
+
+  'rotation angle':
+      Guess of the angle between the x-axis of reference frame 1
+      and the x-axis of reference frame 2. It must be expressed in
+      degrees, measured counter-clockwise from 1 to 2. 
+
+
+
+  CONTROLS/BUTTONS
+
+  'Match':
+      Estimate shift and rotation angle between reference frames
+      and apply an inverse transformation to the points in list 2.
+
+  'Help':
+      Display this help page.
+
+  'Exit':
+      Quit XMatch_Coord.
\ No newline at end of file
diff --git a/xnoise.pro b/xnoise.pro
new file mode 100644
index 0000000000000000000000000000000000000000..d5537a1a973180edb3a096f84740e0016f1a8578
--- /dev/null
+++ b/xnoise.pro
@@ -0,0 +1,344 @@
+; $Id: xnoise, v 1.2 May 2014 e.d. $
+;
+;+
+; NAME:
+;	XNOISE
+;
+; PURPOSE:
+;	Widget interface to estimate the noise standard deviation for each
+;	pixel of a given image.
+;	The overall variance is the sum of the photon noise and of the
+;	variances due to the following noise sources:
+;	1) read-out noise
+;	2) dark current
+;	3) thermal background
+;	4) sky
+;	Noise source 1) follows a gaussian distribution of 0 mean.
+;	Noise sources 2), 3) and 4) strictly follow a Poisson distribution,
+;	but since they may be often considered roughly constant over the frame
+;	the Poisson distribution may be approximated by a gaussian one,
+;	spatially uniform across the frame itself.
+;	While noise source 1) introduces no positive bias in the recorded signal,
+;	sources 2), 3) and 4) have nonzero mean. In general the mean dark
+;	current level, the overall thermal background and the mean sky are
+;	subtracted in the pre-processing phase.
+;	The photon noise is estimated on the basis of the recorded signal:
+;	for this reason, the dark current level and the thermal background
+;	should be removed beforehand. The gaussian noise standard deviation is
+;	estimated as a function of the noise parameters 1) to 4), but it may be
+;	optionally computed by means of the XNoise_StDev widget program.
+;	The simplest way to use this widget program is to estimate the gaussian
+;	noise in the data, by means of XNoise_StDev, without considering the
+;	contribution of Poisson noise: in this way no other parameters must be
+;	supplied on input in the widget form. The retrieved noise estimate
+;	roughly represents the standard deviation of the 'mean intensity level'
+;	in the image: in a crowded stellar field this quantity is the major
+;	source of noise and may be associated to the background emission due
+;	to nebulosities, bright stars haloes and light from faint unresolved
+;	sources.
+;
+; CATEGORY:
+;	Widgets. Signal processing.
+;
+; CALLING SEQUENCE:
+;	XNOISE, Image, Noise_std
+;
+; INPUTS:
+;	Image: 2D data array
+;
+; KEYWORD PARAMETERS:
+;	WNUM: Window number of an existing window used by XNoise_StDev
+;		when the gaussian noise standard deviation must be computed
+;		since no input estimate is available (see keyword STDEV).
+;
+;	PATH:	Initial path for file browsing. If the argument is a named
+;		variable, its value is overwritten.
+;
+;	DEFAULT_PAR:	Structure of default parameters for the widget's form.
+;
+;	G_NOISE_PAR:	Structure of default parameters to compute the gaussian
+;		noise standard deviation (see XNoise_StDev for details).
+;
+;	PLOT_PAR:	Structure of default parameters to plot the data histogram
+;		(see XNoise_StDev and XPlot for details).
+;
+;	GROUP: XNoise group leader.
+;
+;	UVALUE: XNoise user value.
+;
+; OUTPUTS:
+;	Noise_std:	2D array, with the same size as the input Image, containing
+;		the noise standard deviation for each Image pixel.
+;
+; OPTIONAL OUTPUTS:
+;	STDEV:	Standard deviation of gaussian noise, computed by XNoise,
+;		either as a function of the input values of read-out noise, dark
+;		current, etc. or as computed by means of XNoise_StDev.
+;
+;	WNUM: Window number of new graphic window, created by XNoise_StDev if
+;		undefined on input.
+;
+;	DEFAULT_PAR:	Set this keyword to a named variable to get the
+;		structure of parameters set by the widget's user.
+;
+;	G_NOISE_PAR:	Set this keyword to a named variable to get the
+;		structure of default parameters used by XNoise_StDev.
+;
+;	PLOT_PAR:	Set this keyword to a named variable to get the
+;		structure of parameters used by XPlot through XNoise_StDev.
+;
+; SIDE EFFECTS:
+;	1) Initiates the XMANAGER if it is not already running.
+;	2) Might create a new graphic window, if WNUM is undefined on input
+;	   (see XNoise_StDev for details).
+;
+; RESTRICTIONS:
+;	The Help menu opens the file
+;	'/starfinder/xnoise_help.txt'.
+;
+; PROCEDURE:
+;	Create and register the widget as a modal widget.
+;	Then let the user define the parameters used to estimate the noise
+;	standard deviation. The resulting array of noise may be saved to a
+;	FITS file.
+;
+; MODIFICATION HISTORY:
+;	Written by: Emiliano Diolaiti, October 1999
+;	1) Enhanced error handling in event-handler
+;	   (Emiliano Diolaiti, April 2000).
+;	2) Modified units of field "Sky" in GUI from ADU to electrons
+;	   (E. D., May 2014).
+;-
+
+; XNOISE_EVENT: XNoise event handler.
+
+PRO xnoise_event, event
+
+	catch, error
+	if  error ne 0  then begin
+	   msg = dialog_message(/ERROR, !err_string)
+	   widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	   return
+	endif
+	widget_control, event.id, GET_UVALUE = data, /NO_COPY
+	event_type = strlowcase(event.tag)
+	case  event_type  of
+	   'eval': begin
+	      widget_control, event.id, GET_VALUE = form
+	      for  id = 3, 6  do $
+	         widget_control, (*data).ids[id], $
+	         SENSITIVE = (form.eval eq 0) and 1B
+	      for  id = 12, 14  do $
+	         widget_control, (*data).ids[id], $
+	         SENSITIVE = (form.eval eq 0 or form.phnoise eq 1) and 1B
+	      end
+	   'phnoise': begin
+	      widget_control, event.id, GET_VALUE = form
+	      for  id = 3, 6  do $
+	         widget_control, (*data).ids[id], $
+	         SENSITIVE = (form.eval eq 0) and 1B
+	      for  id = 12, 14  do $
+	         widget_control, (*data).ids[id], $
+	         SENSITIVE = (form.eval eq 0 or form.phnoise eq 1) and 1B
+	      end
+	   'compute': begin
+	      ; Read out form
+	      widget_control, event.id, GET_VALUE = form
+	      nexp = form.nexp > 1
+	      el_per_adu = form.el_per_adu > 0
+	      ron = form.ron > 0
+	      dark = form.dark > 0
+	      therm = form.therm > 0
+	      sky = form.sky > 0
+	      avg = form.avg eq 0 and 1B
+	      norm = 1.  &  if  avg  then  norm = norm/nexp
+	      eval = form.eval eq 1 and 1B
+	      phnoise = (form.phnoise eq 1) and 1B
+	      ; Store parameters
+	      (*(*data).par).nexp = form.nexp
+	      (*(*data).par).el_per_adu = form.el_per_adu
+	      (*(*data).par).ron = form.ron
+	      (*(*data).par).dark = form.dark
+	      (*(*data).par).therm = form.therm
+	      (*(*data).par).sky = form.sky
+	      (*(*data).par).avg = form.avg
+	      (*(*data).par).eval = form.eval
+	      (*(*data).par).phnoise = form.phnoise
+	      ; Compute noise
+	      if  eval  then begin
+	         msg = dialog_message(/INFO, $
+	         ['Calling XNnoise_StDev to estimate gaussian noise.', $
+	         							  'Press OK to continue.'])
+	         xnoise_stdev, *(*data).image, stdev, WNUM = *(*data).wnum, $
+	         			   DEFAULT_PAR = *(*data).g_noise_par, $
+	         			   PLOT_PAR = *(*data).plot_par, $
+	         			   PATH = *(*data).path, GROUP = event.top
+	      endif else $
+	         stdev = instr_noise(ron, dark, therm, sky, el_per_adu, nexp, AVG = avg)
+	      if  n_elements(stdev) ne 0  then  *(*data).stdev = stdev  else  stdev = 0.
+	      if  phnoise  then begin
+	         widget_control, /HOURGLASS
+	         phn = photon_noise(*(*data).image, el_per_adu, nexp, AVG = avg)
+	         *(*data).noise_std = sqrt(phn^2 + stdev^2)
+	         if  not eval  then  msg = dialog_message(/INFO, 'Done.')
+	      endif else $
+	      if  n_elements(*(*data).stdev) ne 0  then begin
+	         widget_control, /HOURGLASS
+	         siz = size52(*(*data).image, /DIM)
+	         *(*data).noise_std = replicate(stdev[0], siz[0], siz[1])
+	         if  not eval  then  msg = dialog_message(/INFO, 'Done.')
+	      endif
+	      end
+	   'save': $
+	      if  n_elements(*(*data).noise_std) ne 0  then begin
+	         file = dialog_pickfile(/WRITE, FILTER = '*.fits', $
+	      						    PATH = *(*data).path, GET_PATH = path)
+	         if  file ne ''  then begin
+	            widget_control, /HOURGLASS
+	            if  strpos(file, '.fits') lt 0  then  file = file + '.fits'
+	            *(*data).path = path
+	            writefits, file, *(*data).noise_std
+	         endif
+	      endif
+	   'help': $
+	      xdispfile, file_name('starfinder', 'xnoise_help.txt'), $
+	                 TITLE = 'XNoise help', /MODAL
+	   'exit': begin
+	      widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	      widget_control, event.top, /DESTROY
+	      end
+	   else:
+	endcase
+	if  event_type ne 'exit'  then $
+	   widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	return
+end
+
+; XNOISE_DEF: define XNoise data structure.
+
+FUNCTION xnoise_def, par, g_noise_par, plot_par, ids, image, wnum, path
+
+	return, {par: ptr_new(par, /NO_COPY), $
+			 g_noise_par: ptr_new(g_noise_par, /NO_COPY), $
+			 plot_par: ptr_new(plot_par, /NO_COPY), $
+			 image: ptr_new(image, /NO_COPY), $
+			 wnum: ptr_new(wnum, /NO_COPY), $
+			 path: ptr_new(path, /NO_COPY), $
+			 stdev: ptr_new(/ALLOCATE), $
+			 noise_std: ptr_new(/ALLOCATE), $
+			 ids: ids}
+end
+
+; XNOISE_DEL: de-reference XNoise data structure.
+
+PRO xnoise_del, data, par, g_noise_par, plot_par, image, wnum, stdev, noise_std, path
+
+	if  n_elements(*(*data).par) ne 0  then  par = *(*data).par
+	if  n_elements(*(*data).g_noise_par) ne 0  then  g_noise_par = *(*data).g_noise_par
+	if  n_elements(*(*data).plot_par) ne 0  then  plot_par = *(*data).plot_par
+	if  n_elements(*(*data).image) ne 0  then  image = *(*data).image
+	if  n_elements(*(*data).wnum) ne 0  then  wnum = *(*data).wnum
+	if  n_elements(*(*data).stdev) ne 0  then  stdev = *(*data).stdev
+	if  n_elements(*(*data).noise_std) ne 0  then  noise_std = *(*data).noise_std
+	if  n_elements(*(*data).path) ne 0  then  path = *(*data).path
+	ptr_free, (*data).par, (*data).g_noise_par, (*data).plot_par, $
+			  (*data).image, (*data).wnum, (*data).stdev, $
+			  (*data).noise_std, (*data).path
+	ptr_free, data
+	return
+end
+
+; XNOISE_PAR: define default parameters.
+
+PRO xnoise_par, id, par
+
+	if  n_elements(par) ne 0  then begin
+	   nexp = par.nexp
+	   el_per_adu = par.el_per_adu
+	   ron = par.ron
+	   dark = par.dark
+	   therm = par.therm
+	   sky = par.sky
+	   avg = par.avg
+	   eval = par.eval
+	   phnoise = par.phnoise
+	endif else begin
+	   nexp = 1
+	   el_per_adu = 1.
+	   ron = 0.
+	   dark = 0.
+	   therm = 0.
+	   sky = 0.
+	   avg = 0
+	   eval = 1
+	   phnoise = 0
+	   par = {nexp: nexp, el_per_adu: el_per_adu, ron: ron, dark: dark, $
+			  therm: therm, sky: sky, avg: avg, eval: eval, phnoise: phnoise}
+	endelse
+	init = {nexp: strcompress(string(nexp), /REMOVE_ALL), $
+			el_per_adu: strcompress(string(el_per_adu), /REMOVE_ALL), $
+			ron: strcompress(string(ron), /REMOVE_ALL), $
+			dark: strcompress(string(dark), /REMOVE_ALL), $
+			therm: strcompress(string(therm), /REMOVE_ALL), $
+			sky: strcompress(string(sky), /REMOVE_ALL), $
+			avg: avg, eval: eval, phnoise: phnoise}
+	widget_control, id, SET_VALUE = init
+	return
+end
+
+; XNOISE: XNoise widget definition module.
+
+PRO xnoise, image, noise_std, WNUM = wnum, STDEV = stdev, $
+			PATH = path, DEFAULT_PAR = par, G_NOISE_PAR = g_noise_par, $
+			PLOT_PAR = plot_par, GROUP = group, UVALUE = uvalue
+
+	on_error, 2
+	; Create group leader if necessary
+	if  n_elements(group) eq 0  then $
+	   group_id = widget_base()  else  group_id = group
+	; Create modal base
+	if  n_elements(uvalue) eq 0  then  uvalue = 0B
+	base = widget_base(TITLE = 'XNoise', /MODAL, UVALUE = uvalue, $
+					   GROUP_LEADER = group_id)
+	; Define form
+	desc = [ $
+	'0, LABEL,Gaussian noise:,LEFT', $
+	'1, BASE,,COLUMN,FRAME', $
+	'0, BUTTON,no|yes,EXCLUSIVE,LABEL_LEFT=Evaluate from data:,TAG=eval,ROW', $
+	'0, FLOAT,,LABEL_LEFT=Read-out-noise (electrons),TAG=ron,WIDTH=8', $
+	'0, FLOAT,,LABEL_LEFT=Dark current (electrons),TAG=dark,WIDTH=8', $
+	'0, FLOAT,,LABEL_LEFT=Thermal background (electrons),TAG=therm,WIDTH=8', $
+	'2, FLOAT,,LABEL_LEFT=Sky (electrons),TAG=sky,WIDTH=8', $
+	'0, LABEL,Photon noise:,LEFT', $
+	'1, BASE,,COLUMN,FRAME', $
+	'2, BUTTON,no|yes,EXCLUSIVE,,LABEL_LEFT=Consider photon noise,TAG=phnoise,ROW', $
+	'0, LABEL,General parameters:,LEFT', $
+	'1, BASE,,COLUMN,FRAME', $
+	'0, INTEGER,,LABEL_LEFT=Number of exposures,TAG=nexp,WIDTH=8', $
+	'0, BUTTON,mean|sum,EXCLUSIVE,,LABEL_LEFT=Exposures combined by:,TAG=avg,ROW', $
+	'2, FLOAT,,LABEL_LEFT=Electrons/ADU,TAG=el_per_adu,WIDTH=8', $
+	'1, BASE,,ROW', $
+	'0, BUTTON,Compute,NO_RELEASE,TAG=compute', $
+	'2, BUTTON,Save,NO_RELEASE,TAG=save', $
+	'1, BASE,,ROW', $
+	'0, BUTTON,Help,NO_RELEASE,TAG=help', $
+	'2, BUTTON,Exit,QUIT,NO_RELEASE,TAG=exit']
+	form = cw_form(base, desc, IDS = ids, /COLUMN)
+	xnoise_par, form, par
+	for  id = 3, 6  do $
+	   widget_control, ids[id], SENSITIVE = (par.eval eq 0) and 1B
+	for  id = 12, 14  do $
+	   widget_control, ids[id], SENSITIVE = (par.eval eq 0 or par.phnoise eq 1) and 1B
+	; Define pointer to auxiliary/output data
+	data = ptr_new(xnoise_def(par, g_noise_par, plot_par, ids, image, wnum, path), /NO_COPY)
+	widget_control, form, SET_UVALUE = data
+	; Realize, register, etc.
+	widget_control, base, /REALIZE
+	xmanager, 'xnoise', base, EVENT_HANDLER = 'xnoise_event'
+	; De-reference output data
+	xnoise_del, data, par, g_noise_par, plot_par, image, wnum, stdev, noise_std, path
+	; Destroy group leader if necessary
+	if  n_elements(group) eq 0  then $
+	   widget_control, group_id, /DESTROY
+	return
+end
diff --git a/xnoise_help.txt b/xnoise_help.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5813d451b4712c8c7f1ccb7f857bd47df366912e
--- /dev/null
+++ b/xnoise_help.txt
@@ -0,0 +1,112 @@
+  XNoise help page
+
+
+
+  GENERAL DESCRIPTION
+
+  The XNoise widget computes the noise standard deviation for
+  each pixel of a given image.
+  The input image is assumed to be the sum or the mean of a
+  set of equally exposed frames. The output is a noise array.
+  The overall variance of the noise is the sum of two terms:
+  - Gaussian noise, due to the following sources:
+    1) read-out
+    2) dark current
+    3) thermal background
+    4) sky
+  - Photon noise, associated to the 'astronomical' signal.
+  Noise source 1) follows a gaussian distribution of 0 mean.
+  Noise sources 2), 3) and 4) strictly follow a Poisson
+  distribution, but since they may be often considered roughly
+  constant over the frame, the Poisson distribution can be
+  approximated by a gaussian one, spatially uniform across the
+  frame itself. While noise source 1) introduces no bias in the
+  recorded signal, sources 2), 3) and 4) have nonzero mean.
+  In general the mean dark current level, the overall thermal
+  background and the mean sky are subtracted in the pre-
+  processing phase, so their contribution to the noise cannot
+  be estimated from the residual signal: this is the reason
+  why the corresponding noise levels should be supplied by
+  the user.
+  Optionally the gaussian noise can be estimated automatically
+  by means of a secondary widget, named XNoise_StDev. The
+  result is generally over-estimated and represents the overall
+  effect of noise sources 1)-4) combined with the (photon) noise
+  associated to the diffuse emission originated by nebulosities,
+  bright stars haloes and diffuse light from faint unresolved
+  sources.
+  The photon noise on the 'astronomical' signal is considered
+  proportional to the square root of the recorded signal in each
+  pixel.
+  The XNoise widget can be used in either of the following two
+  'meaningful' modes:
+  - compute the overall noise per pixel, considering both the
+    contribution of sources 1)-4) and of photon noise;
+  - estimate the gaussian noise only by means of XNoise_StDev:
+    this is the suggested mode for very crowded fields when no
+    knowledge on sources 1)-4) is available.
+    
+ 
+ 
+  PARAMETERS
+
+  'Evaluate from data':
+      Select 'yes' to estimate the gaussian noise standard
+      deviation by means of XNoise_StDev.
+      The retrieved value is generally over-estimated, especially
+      in very crowded fields.
+
+  'Read-out-noise':
+      Read-out-noise for a single exposure.
+
+  'Dark current':
+      Dark current level for a single exposure. If the Poisson
+      noise is considered and the dark current has not been
+      subtracted (a rather unlikely situation!), this field should
+      be set to 0, because the dark current noise is accounted
+      for as Poisson noise.
+
+  'Thermal background':
+      Instrumental background for a single eexposure. If the
+      Poisson noise is considered and the thermal background
+      has not been removed, this field should be set to 0,
+      because the thermal noise is accounted for as Poisson noise.
+
+  'Sky':
+      Mean sky level for a single eexposure. If the Poisson noise
+      is considered and the sky has not been removed, this field
+      should be set to 0: the associated noise is accounted for
+      as Poisson noise.
+
+  'Consider photon noise':
+      Select 'yes' to consider the effects of both gaussian and
+      photon noise.
+
+  'Number of exposures':
+      Number of equally-exposed frames which have been combined
+      to form the input image.
+
+  'Exposures combined by':
+      Select 'mean' or 'sum' to specify how the individual exposures
+      have been combined. This will affect noise propagation from
+      each single frame to the final image.
+
+  'Electrons/ADU':
+      Number of electrons per ADU.
+
+
+
+  CONTROLS/BUTTONS
+
+  'Compute':
+      Press this button to compute the noise array using the current
+      set of parameters.
+
+  'Save':
+      Save to a FITS file the noise array.
+
+  'Help':
+      Display this help page.
+
+  'Exit':
+      Quit XNoise.
\ No newline at end of file
diff --git a/xnoise_stdev.pro b/xnoise_stdev.pro
new file mode 100644
index 0000000000000000000000000000000000000000..55de5b26ddd16b9ce930dfac9c6730848e3184ce
--- /dev/null
+++ b/xnoise_stdev.pro
@@ -0,0 +1,254 @@
+; $Id: xnoise_stdev, v 1.1 Apr 2000 e.d. $
+;
+;+
+; NAME:
+;	XNOISE_STDEV
+;
+; PURPOSE:
+;	Widget interface for the GAUSSIAN_NOISE_STD procedure.
+;	Compute the standard deviation of the gaussian noise in an image.
+;
+; CATEGORY:
+;	Widgets. Signal processing.
+;
+; CALLING SEQUENCE:
+;	XNOISE_STDEV, Image, Stdev
+;
+; INPUTS:
+;	Image: 2D data array
+;
+; KEYWORD PARAMETERS:
+;	WNUM: Window number of an existing window to plot the data histogram
+;		and the gaussian fit. It is used only if the 'Plot' button is
+;		pressed.
+;
+;	PATH:	Initial path for file browsing to save the histogram plot.
+;
+;	DEFAULT_PAR:	Structure of default parameters for the widget's form.
+;
+;	PLOT_PAR:	Structure of default parameters to plot histogram.
+;
+;	GROUP: XNoise_StDev group leader.
+;
+;	UVALUE: XNoise_StDev user value.
+;
+; OUTPUTS:
+;	Stdev:	Scalar value of noise standard deviation.
+;
+; OPTIONAL OUTPUTS:
+;	WNUM:	Set this keyword to a named variable to get the number of
+;		the new graphic window created by XPlot to plot the histogram if
+;		no window is defined on input.
+;
+;	PATH:	Set this keyword to a named variables to get the path of
+;		the file selected by the user to save the histogram plot.
+;
+;	DEFAULT_PAR:	Set this keyword to a named variables to get the
+;		structure of parameters set by the widget's user.
+;
+;	PLOT_PAR:	Set this keyword to a named variables to get the
+;		structure of parameters used to plot the histogram (see XPlot
+;		for details).
+;
+; SIDE EFFECTS:
+;	1) Initiates the XMANAGER if it is not already running.
+;	2) Call WSET to activate the graphic window identified by Wnum.
+;	3) Create a new graphic window if not defined on input.
+;	4) Any image displayed on the window Wnum is overwritten.
+;
+; RESTRICTIONS:
+;	The Help menu opens the file
+;	'/starfinder/xnoise_stdev_help.txt'.
+;
+; PROCEDURE:
+;	Create and register the widget as a modal widget.
+;	Then let the user define and or/modify the noise estimation options and
+;	apply them to the input image. As a new estimate is obtained applying
+;	the current options a dialog message appears reporting the value of the
+;	estimated noise standard deviation.
+;	The histogram and its fit may be plotted.
+;
+; MODIFICATION HISTORY:
+;	Written by: Emiliano Diolaiti, September 1999
+;	Updates:
+;	1) Enhanced error handling in event-handler
+;	   (Emiliano Diolaiti, April 2000).
+;-
+
+; XNOISE_STDEV_EVENT: XNoise_StDev event handler.
+
+PRO xnoise_stdev_event, event
+
+	catch, error
+	if  error ne 0  then begin
+	   msg = dialog_message(/ERROR, !err_string)
+	   widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	   return
+	endif
+	widget_control, event.id, GET_UVALUE = data, /NO_COPY
+	event_type = strlowcase(event.tag)
+	case  event_type  of
+	   'process': begin
+	      widget_control, /HOURGLASS
+	      widget_control, event.id, GET_VALUE = form
+	      patch = form.patch
+	      frac = form.frac > 0  &  if  frac ne 0  then  frac = 1/frac
+	      n_std = form.n_std
+	      hminsize = form.hmin
+	      hmaxsize = form.hmax
+	      nterms = 3 + form.nterms
+	      (*(*data).par).patch = form.patch
+	      (*(*data).par).frac = form.frac
+	      (*(*data).par).n_std = form.n_std
+	      (*(*data).par).hmin = form.hmin
+	      (*(*data).par).hmax = form.hmax
+	      (*(*data).par).nterms = form.nterms
+	      gauss_noise_std, *(*data).image, PATCH = patch, POINT_FRAC = frac, $
+	         N_STD = n_std, HIST_MINSIZE = hminsize, HIST_MAXSIZE = hmaxsize, $
+	         NTERMS = nterms, mode, stdev, h, v, vm, hfit, COEFF = c
+	      if  stdev ge 0  then begin
+	         *(*data).stdev = stdev
+	         *(*data).h = h  &  *(*data).hfit = hfit  &  *(*data).v = v
+	         *(*data).b = 0
+	         if  nterms gt 3  then  *(*data).b = replicate(c[3], n_elements(v))
+	         if  nterms gt 4  then  *(*data).b = *(*data).b + c[4] * v
+	         if  nterms gt 5  then  *(*data).b = *(*data).b + c[5] * v^2
+	         msg = dialog_message(/INFO, ['Mode = ', strcompress(string(mode)), '', $
+	         					   'Standard deviation = ', strcompress(string(stdev))])
+	      endif else $
+	         msg = dialog_message(/INFO, ['Computation failed.', $
+	         					   'Try with a different fitting model.'])
+	      end
+	   'plot': begin
+	      if  n_elements(*(*data).h) ne 0  then begin
+	         if  n_elements(*(*data).b) gt 1  then  b = *(*data).b
+	         xplot, *(*data).h, *(*data).v, OVERPLOT1 = *(*data).hfit, $
+	         		OVERPLOT2 = b, WNUM = *(*data).wnum, PATH = *(*data).path, $
+	         		DEFAULT_PAR = *(*data).plot_par, GROUP = event.top
+	      endif
+	      end
+	   'help': $
+	      xdispfile, file_name('starfinder', 'xnoise_stdev_help.txt'), $
+	      		 TITLE = 'XNoise_StDev help', /MODAL
+	   'exit': begin
+	      widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	      widget_control, event.top, /DESTROY
+	      end
+	   else:
+	endcase
+	if  event_type ne 'exit'  then $
+	   widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	return
+end
+
+; XNOISE_STDEV_DEF: define XNoise_StDev data structure.
+
+FUNCTION xnoise_stdev_def, par, plot_par, image, wnum, path
+
+	return, {par: ptr_new(par, /NO_COPY), $
+			 plot_par: ptr_new(plot_par, /NO_COPY), $
+			 image: ptr_new(image, /NO_COPY), $
+			 wnum: ptr_new(wnum, /NO_COPY), $
+			 path: ptr_new(path, /NO_COPY), $
+			 stdev: ptr_new(/ALLOCATE), $
+			 h: ptr_new(/ALLOCATE), hfit: ptr_new(/ALLOCATE), $
+			 v: ptr_new(/ALLOCATE), b: ptr_new(/ALLOCATE)}
+end
+
+; XNOISE_STDEV_DEL: de-reference XNoise_StDev data structure.
+
+PRO xnoise_stdev_del, data, par, plot_par, image, wnum, stdev, path
+
+	if  n_elements(*(*data).par) ne 0  then  par = *(*data).par
+	if  n_elements(*(*data).plot_par) ne 0  then  plot_par = *(*data).plot_par
+	if  n_elements(*(*data).image) ne 0  then  image = *(*data).image
+	if  n_elements(*(*data).wnum) ne 0  then  wnum = *(*data).wnum
+	if  n_elements(*(*data).stdev) ne 0  then  stdev = *(*data).stdev
+	if  n_elements(*(*data).path) ne 0  then  path = *(*data).path
+	ptr_free, (*data).par, (*data).plot_par, (*data).image, (*data).wnum, $
+			  (*data).stdev, (*data).path, (*data).h, (*data).hfit, (*data).v, (*data).b
+	ptr_free, data
+	return
+end
+
+; XNOISE_STDEV_PAR: define default parameters.
+
+PRO xnoise_stdev_par, id, par
+
+	if  n_elements(par) ne 0  then begin
+	   patch = par.patch
+	   frac = par.frac
+	   n_std = par.n_std
+	   hmin = par.hmin
+	   hmax = par.hmax
+	   nterms = par.nterms
+	endif else begin
+	   patch = 3
+	   frac = 1.
+	   n_std = 3
+	   hmin = 5
+	   hmax = 5
+	   nterms = 0
+	   par = {patch: patch, frac: frac, n_std: n_std, $
+			  hmin: hmin, hmax: hmax, nterms: nterms}
+	endelse
+	init = {patch: strcompress(string(patch), /REMOVE_ALL), $
+			frac: strcompress(string(frac), /REMOVE_ALL), $
+			n_std: strcompress(string(n_std), /REMOVE_ALL), $
+			hmin: strcompress(string(hmin), /REMOVE_ALL), $
+			hmax: strcompress(string(hmax), /REMOVE_ALL), $
+			nterms: nterms}
+	widget_control, id, SET_VALUE = init
+	return
+end
+
+; XNOISE_STDEV: XNoise_StDev widget definition module.
+
+PRO xnoise_stdev, image, stdev, WNUM = wnum, PATH = path, $
+				  DEFAULT_PAR = par, PLOT_PAR = plot_par, $
+				  GROUP = group, UVALUE = uvalue
+
+	on_error, 2
+	; Create group leader if necessary
+	if  n_elements(group) eq 0  then $
+	   group_id = widget_base()  else  group_id = group
+	; Create modal base
+	if  n_elements(uvalue) eq 0  then  uvalue = 0B
+	base = widget_base(TITLE = 'XNoise_StDev', /MODAL, UVALUE = uvalue, $
+					   GROUP_LEADER = group_id)
+	; Define form
+	desc = [ $
+	'0, LABEL,Pre-processing:,LEFT', $
+	'1, BASE,,COLUMN,FRAME', $
+	'0, INTEGER,,LABEL_LEFT=Patch size for median subtraction,TAG=patch', $
+	'0, FLOAT,,LABEL_LEFT=Fraction of data point to use,TAG=frac', $
+	'2, FLOAT,,LABEL_LEFT=Threshold to reject out-liers (St. Dev. units),TAG=n_std', $
+	'0, LABEL,Histogram computation:,LEFT', $
+	'1, BASE,,COLUMN,FRAME', $
+	'0, FLOAT,,LABEL_LEFT=Minimum number of bins in one HWHM,TAG=hmin', $
+	'2, FLOAT,,LABEL_LEFT=Size of histogram (FWHM units),TAG=hmax', $
+	'0, LABEL,Histogram fitting:,LEFT', $
+	'1, BASE,,COLUMN,FRAME', $
+	'2, BUTTON,gaussian|gaussian + costant|gaussian + linear|gaussian + quadratic,' + $
+	   'EXCLUSIVE,TAG=nterms,COLUMN', $
+	'1, BASE,,ROW', $
+	'0, BUTTON,Processing...,NO_RELEASE,TAG=process', $
+	'2, BUTTON,Plot histogram,NO_RELEASE,TAG=plot', $
+	'1, BASE,,ROW', $
+	'0, BUTTON,Help,NO_RELEASE,TAG=help', $
+	'2, BUTTON,Exit,QUIT,NO_RELEASE,TAG=exit']
+	form = cw_form(base, desc, /COLUMN)
+	xnoise_stdev_par, form, par
+	; Define pointer to auxiliary/output data
+	data = ptr_new(xnoise_stdev_def(par, plot_par, image, wnum, path), /NO_COPY)
+	widget_control, form, SET_UVALUE = data
+	; Realize, register, etc.
+	widget_control, base, /REALIZE
+	xmanager, 'xnoise_stdev', base, EVENT_HANDLER = 'xnoise_stdev_event'
+	; De-reference output data
+	xnoise_stdev_del, data, par, plot_par, image, wnum, stdev, path
+	; Destroy group leader if necessary
+	if  n_elements(group) eq 0  then $
+	   widget_control, group_id, /DESTROY
+	return
+end
diff --git a/xnoise_stdev_help.txt b/xnoise_stdev_help.txt
new file mode 100644
index 0000000000000000000000000000000000000000..bcadb628b2406678e5190d8ef45e7eead14b7575
--- /dev/null
+++ b/xnoise_stdev_help.txt
@@ -0,0 +1,70 @@
+  XNoise_StDev help page
+
+
+
+  GENERAL DESCRIPTION
+
+  The XNoise_StDev widget computes an estimate of the
+  gaussian noise standard deviation in a given image; the
+  estimator is the standard deviation of the best fit gaussian
+  to the data histogram. Before computing the histogram, the
+  input image is median-subtracted, in order to remove the
+  signal, leaving only pure noise.
+    
+ 
+ 
+  PARAMETERS
+
+  'Patch size for median subtraction':
+      Integer size of box for median smoothing of the image.
+      The median is subtracted from the image, in order to
+      remove the signal from each pixel.
+
+  'Fraction of data points to use':
+      To speed up the computation, a value < 1 may be
+      selected. In this case a sub-set of pixels is extracted
+      from the input data.
+
+  'Threshold to reject out-liers':
+      Before computing the histogram, the so-called out-liers
+      (pixels whose value is very different from the median or
+      the mean of the data) are rejected.
+      In practice the median of the data and the standard
+      deviation from the median are computed: the out-liers are
+      identified as those pixels whose absolute distance from
+      the median is larger than a multiple of the standard
+      deviation.
+
+  'Minimum number of bins in one HWHM':
+      The histogram bin is optimized in order to have a minimum
+      number of elements in the histogram width. This will
+      improve the accuracy of the fitting.
+
+  'Size of histogram':
+      Specify the size of the 'useful' part of the histogram
+      around the mode, which will be used for fitting.
+
+  'gaussian' or 'gaussian + constant', etc.:
+      Select suitable model for histogram fitting.
+
+
+
+  CONTROLS/BUTTONS
+
+  'Processing...':
+      Compute and fit the histogram using the currently defined
+      parameters. At the end of the computation, a message
+      appears reporting the estimated standard deviation and
+      the histogram mode, which should be as close as possible
+      to 0.
+
+  'Plot histogram':
+      Call the XPlot widget to plot the histogram and the best
+      fit model. If any of the 'gaussian + background term'
+      models is used, the background itself is shown in the plot.
+
+  'Help':
+      Display this help page.
+
+  'Exit':
+      Quit XNoise_StDev.
\ No newline at end of file
diff --git a/xplot.pro b/xplot.pro
new file mode 100644
index 0000000000000000000000000000000000000000..0f88d288c7a88a829fdc1de26e14cfb8f44cc0da
--- /dev/null
+++ b/xplot.pro
@@ -0,0 +1,309 @@
+; $Id: xplot, v 1.1 Apr 2000 e.d. $
+;
+;+
+; NAME:
+;	XPLOT
+;
+; PURPOSE:
+;	Widget interface to execute simple plots.
+;
+; CATEGORY:
+;	Widgets. Graphics.
+;
+; CALLING SEQUENCE:
+;	XPLOT, Y, X
+;
+; INPUTS:
+;	Y:	1D vector of ordinates to plot.
+;
+; OPTIONAL INPUTS:
+;	X:	1D vector of abscissae. The default is
+;		X = [0, 1, ..., N - 1], where N is the number of elements in Y.
+;
+; KEYWORD PARAMETERS:
+;	OVERPLOT1:	1D vector of additional values to plot over Y.
+;
+;	OVERPLOT2:	1D vector of additional values to plot over Y.
+;
+;	WNUM:	Window number of an existing window.
+;
+;	PATH:	Initial path for file browsing to save plot.
+;
+;	DEFAULT_PAR:	Structure of default parameters for the widget's form.
+;
+;	GROUP: XPlot group leader.
+;
+;	UVALUE: XPlot user value.
+;
+; OUTPUTS:
+;	No particular output, except the plot which may be saved on a file.
+;
+; OPTIONAL OUTPUTS:
+;	WNUM:	Set this keyword to a named variable to get the window number
+;		of the new created window, if not existing on input.
+;
+;	DEFAULT_PAR:	Set this keyword to a named variable to get the
+;		structure of parameters defined by the widget's user.
+;
+;	PATH:	Set this keyword to a named variable to get the path of the
+;		file selected by the user to save the plot.
+;
+; SIDE EFFECTS:
+;	1) Initiates the XMANAGER if it is not already running.
+;	2) Call WSET to activate the graphic window identified by Wnum.
+;	3) Create a new graphic window if not defined on input.
+;	4) Any previous display on the window Wnum is overwritten.
+;
+; RESTRICTIONS:
+;	1) The Help menu opens the file
+;	'/starfinder/xplot_help.txt'.
+;	2) The plot may be saved only as a GIF file.
+;
+; PROCEDURE:
+;	Create and register the widget as a modal widget. Then let the user
+;	define and or/modify the plotting options and apply them.
+;
+; MODIFICATION HISTORY:
+;	Written by: Emiliano Diolaiti, September 1999.
+;	Updates:
+;	1) Changed output from PS to GIF (Emiliano Diolaiti, Apr 2000).
+;	2) Enhanced error handling in event-handler
+;	   (Emiliano Diolaiti, April 2000).
+;-
+
+; XPLOT_LP: determine line and point style.
+
+PRO xplot_lp, type, line, psym
+
+	case  type  of
+	   0: line = 0
+	   1: line = 2
+	   2: line = 1
+	   3: psym = 10
+	   4: psym = 3
+	   5: psym = 1
+	endcase
+	return
+end
+
+; XPLOT_DO: plot data for XPlot.
+
+PRO xplot_do, x, y, y1, y2, psym1, line1, psym2, line2, $
+			  xmin, xmax, ymin, ymax, title, xtitle, ytitle, $
+			  chsize, symsize
+
+	on_error, 2
+	font = !P.Font  &  !P.Font = -1
+	plot, x, y, PSYM = psym1, LINE = line1, $
+	      XRANGE = [xmin, xmax], YRANGE = [ymin, ymax], $
+	      TITLE = title, XTITLE = xtitle, YTITLE = ytitle, $
+	      CHARSIZE = chsize, SYMSIZE = symsize
+	if  n_elements(y1) gt 1  then  oplot, x, y1, PSYM = psym2, LINE = line2
+	if  n_elements(y2) gt 1  then  oplot, x, y2, PSYM = psym2, LINE = line2
+	!P.Font = font
+	return
+end
+
+; XPLOT_EVENT: XPlot event handler.
+
+PRO xplot_event, event
+
+	catch, error
+	if  error ne 0  then begin
+	   msg = dialog_message(/ERROR, !err_string)
+	   widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	   return
+	endif
+	widget_control, event.id, GET_UVALUE = data, /NO_COPY
+	event_type = strlowcase(event.tag)
+	case  event_type  of
+	   'process': begin
+	      widget_control, /HOURGLASS
+	      widget_control, event.id, GET_VALUE = form
+	      xmin = form.xmin  &  xmax = form.xmax
+	      ymin = form.ymin  &  ymax = form.ymax
+	      title = form.title  &  xtitle = form.xtitle  &  ytitle = form.ytitle
+	      chsize = form.chsize > 0  &  symsize = form.symsize > 0
+	      type1 = form.type1  &  type2 = form.type2
+	      xplot_lp, type1, line1, psym1
+	      if  n_elements(*(*data).y1) ne 0 or n_elements(*(*data).y2) ne 0  then $
+	         xplot_lp, type2, line2, psym2
+	      *(*data).par = {xmin: xmin, xmax: xmax, ymin: ymin, ymax: ymax, $
+	   					  chsize: chsize, symsize: symsize, title: title, $
+	   					  xtitle: xtitle, ytitle: ytitle, type1: type1, type2: type2}
+	      if  n_elements(*(*data).wnum) eq 0  then begin
+	         window, /FREE  &  *(*data).wnum = !D.window
+	      endif else  wset, *(*data).wnum
+	      xplot_do, *(*data).x, *(*data).y, *(*data).y1, *(*data).y2, $
+	      			psym1, line1, psym2, line2, xmin, xmax, ymin, ymax, $
+	      			title, xtitle, ytitle, chsize, symsize
+	      end
+	   'save': begin
+	      if  n_elements(*(*data).wnum) ne 0 and n_elements(*(*data).par) ne 0  then begin
+	         file = dialog_pickfile(/WRITE, FILTER = '*.gif', $
+	         						PATH = *(*data).path, GET_PATH = path)
+	         if  file ne ''  then begin
+	            widget_control, /HOURGLASS
+	            if  strpos(file, '.gif') lt 0  then  file = file + '.gif'
+	            *(*data).path = path
+	            write_gif, file, bytscl(255 - tvrd())
+	         endif
+	      endif
+	      end
+	   'help': $
+	      xdispfile, file_name('starfinder', 'xplot_help.txt'), $
+	                 TITLE = 'XPlot help', /MODAL
+	   'exit': begin
+	      widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	      widget_control, event.top, /DESTROY
+	      end
+	   else:
+	endcase
+	if  event_type ne 'exit'  then $
+	   widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	return
+end
+
+; XPLOT_DEF: define XPlot data structure.
+
+FUNCTION xplot_def, par, x, y, y1, y2, wnum, path
+
+	return, {par: ptr_new(par, /NO_COPY), $
+			 x: ptr_new(x, /NO_COPY), y: ptr_new(y, /NO_COPY), $
+			 y1: ptr_new(y1, /NO_COPY), y2: ptr_new(y2, /NO_COPY), $
+			 wnum: ptr_new(wnum, /NO_COPY), path: ptr_new(path, /NO_COPY)}
+end
+
+; XPLOT_DEL: de-reference XPlot data structure.
+
+PRO xplot_del, data, par, x, y, y1, y2, wnum, path
+
+	if  n_elements(*(*data).par) ne 0  then  par = *(*data).par
+	if  n_elements(*(*data).x) ne 0  then  x = *(*data).x
+	if  n_elements(*(*data).y) ne 0  then  y = *(*data).y
+	if  n_elements(*(*data).y1) ne 0  then  y1 = *(*data).y1
+	if  n_elements(*(*data).y2) ne 0  then  y2 = *(*data).y2
+	if  n_elements(*(*data).wnum) ne 0  then  wnum = *(*data).wnum
+	if  n_elements(*(*data).path) ne 0  then  path = *(*data).path
+	ptr_free, (*data).par, (*data).x, (*data).y, (*data).y1, (*data).y2, $
+			  (*data).wnum, (*data).path
+	ptr_free, data
+	return
+end
+
+; XPLOT_PAR: define default parameters.
+
+PRO xplot_par, id, par, y, x
+
+	if  n_elements(par) ne 0  then begin
+	   xmin = par.xmin
+	   xmax = par.xmax
+	   ymin = par.ymin
+	   ymax = par.ymax
+	   chsize = par.chsize
+	   symsize = par.symsize
+	   title = par.title
+	   xtitle = par.xtitle
+	   ytitle = par.ytitle
+	   type1 = par.type1
+	   type2 = par.type2
+	endif else begin
+	   xmin = min(x)
+	   xmax = max(x)
+	   ymin = min(y)
+	   ymax = max(y)
+	   chsize = 1.
+	   symsize = 1.
+	   title = ''
+	   xtitle = ''
+	   ytitle = ''
+	   type1 = 0
+	   type2 = 1
+	   par = {xmin: xmin, xmax: xmax, ymin: ymin, ymax: ymax, $
+	   		  chsize: chsize, symsize: symsize, title: title, $
+	   		  xtitle: xtitle, ytitle: ytitle, type1: type1, type2: type2}
+	endelse
+	init = {xmin: strcompress(string(xmin), /REMOVE_ALL), $
+			xmax: strcompress(string(xmax), /REMOVE_ALL), $
+			ymin: strcompress(string(ymin), /REMOVE_ALL), $
+			ymax: strcompress(string(ymax), /REMOVE_ALL), $
+			type1: type1, type2: type2, $
+			chsize: strcompress(string(chsize), /REMOVE_ALL), $
+			symsize: strcompress(string(symsize), /REMOVE_ALL), $
+			title: title, xtitle: xtitle, ytitle: ytitle}
+	widget_control, id, SET_VALUE = init
+	return
+end
+
+; XPLOT: XPlot widget definition module.
+
+PRO xplot, y, x, OVERPLOT1 = y1, OVERPLOT2 = y2, WNUM = wnum, $
+		   PATH = path, DEFAULT_PAR = par, GROUP = group, UVALUE = uvalue
+
+	on_error, 2
+	if  n_elements(y) eq 0  then begin
+	   msg = dialog_message(/ERROR, 'XPlot: missing data.')
+	   return
+	endif
+	if  n_elements(x) eq 0  then  x = findgen(n_elements(y))
+	; Create group leader if necessary
+	if  n_elements(group) eq 0  then $
+	   group_id = widget_base()  else  group_id = group
+	; Create modal base
+	if  n_elements(uvalue) eq 0  then  uvalue = 0B
+	base = widget_base(TITLE = 'XPlot', /MODAL, UVALUE = uvalue, $
+					   GROUP_LEADER = group_id)
+	; Define form
+	desc = [ $
+	'0, LABEL,Range:,LEFT', $
+	'1, BASE,,COLUMN,FRAME', $
+	'1, BASE,,ROW', $
+	'0, FLOAT,,LABEL_LEFT=X lower,WIDTH=12,TAG=xmin', $
+	'2, FLOAT,,LABEL_LEFT=X upper,WIDTH=12,TAG=xmax', $
+	'1, BASE,,ROW', $
+	'0, FLOAT,,LABEL_LEFT=Y lower,WIDTH=12,TAG=ymin', $
+	'2, FLOAT,,LABEL_LEFT=Y upper,WIDTH=12,TAG=ymax', $
+	'2, BASE,,', $
+	'0, LABEL,Labels:,LEFT', $
+	'1, BASE,,COLUMN,FRAME', $
+	'0, TEXT,,LABEL_LEFT=Main title,WIDTH=12,TAG=title', $
+	'0, TEXT,,LABEL_LEFT=X-title,WIDTH=12,TAG=xtitle', $
+	'2, TEXT,,LABEL_LEFT=Y-title,WIDTH=12,TAG=ytitle', $
+	'0, LABEL,Type:,LEFT', $
+	'1, BASE,,ROW,FRAME', $
+	'1, BASE,,COLUMN', $
+	'0, LABEL,Main plot:,LEFT', $
+	'2, BUTTON,Continuous line|Dashed line|Dotted line|Steps|Dot|Plus sign,' + $
+	   'EXCLUSIVE,SET_VALUE=0,COLUMN,NO_RELEASE,TAG=type1', $
+	'1, BASE,,COLUMN', $
+	'0, LABEL,Overplot:,LEFT', $
+	'2, BUTTON,Continuous line|Dashed line|Dotted line|Steps|Dot|Plus sign,' + $
+	   'EXCLUSIVE,SET_VALUE=2,COLUMN,NO_RELEASE,TAG=type2', $
+	'2, BASE,,', $
+	'0, LABEL,Style:,LEFT', $
+	'1, BASE,,COLUMN,FRAME', $
+	'0, FLOAT,,LABEL_LEFT=Character size,WIDTH=8,TAG=chsize', $
+	'2, FLOAT,,LABEL_LEFT=Symbol size,WIDTH=8,TAG=symsize', $
+	'1, BASE,,ROW', $
+	'2, BUTTON,Plot,NO_RELEASE,TAG=process', $
+	'1, BASE,,ROW', $
+	'0, BUTTON,Save,NO_RELEASE,TAG=save', $
+	'0, BUTTON,Help,NO_RELEASE,TAG=help', $
+	'2, BUTTON,Exit,QUIT,NO_RELEASE,TAG=exit']
+	form = cw_form(base, desc, IDS = ids, /COLUMN)
+	xplot_par, form, par, y, x
+	widget_control, ids[21], $
+	   SENSITIVE = (n_elements(y1) ne 0 or n_elements(y2) ne 0) and 1B
+	; Define pointer to auxiliary/output data
+	data = ptr_new(xplot_def(par, x, y, y1, y2, wnum, path), /NO_COPY)
+	widget_control, form, SET_UVALUE = data
+	; Realize, register, etc.
+	widget_control, base, /REALIZE
+	xmanager, 'xplot', base, EVENT_HANDLER = 'xplot_event'
+	; De-reference output data
+	xplot_del, data, par, x, y, y1, y2, wnum, path
+	; Destroy group leader if necessary
+	if  n_elements(group) eq 0  then $
+	   widget_control, group_id, /DESTROY
+	return
+end
diff --git a/xplot_help.txt b/xplot_help.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c4c7b9edc07179705acf18f72933121f04aabd6b
--- /dev/null
+++ b/xplot_help.txt
@@ -0,0 +1,60 @@
+  XPlot help page
+
+
+
+  GENERAL DESCRIPTION
+
+  The XPlot widget plots a vector Y (vertical axis) vs. a vector
+  X (horizontal axis). It can optionally overplot up to two vectors
+  Y1 and Y2.
+    
+ 
+ 
+  PARAMETERS
+
+  'X lower', 'X upper':
+      Lower and upper values for horizontal axis. Notice that
+      X_upper can be smaller than X_upper. This is useful to
+      reverse the X-axis scale.
+
+  'Y lower', 'Y upper':
+      Lower and upper values for vertical axis. Notice that
+      Y_upper can be smaller than Y_upper. This is useful to
+      reverse the Y-axis scale.
+
+  'Main title':
+      Title of plot.
+
+  'X-title':
+      Label for X-axis.
+
+  'Y-title':
+      Label for Y-axis.
+
+  'Type of Main plot':
+      Select draw style (line style or points).
+
+  'Type of Overplot':
+      Select draw style for overplot(s).
+
+  'Character size':
+      Character size of title and labels.
+
+  'Symbol size':
+      Size of symbol, when draw style is 'Plus sign' (+).
+
+
+
+  CONTROLS/BUTTONS
+
+  'Plot':
+      Execute plot using currently defined options.
+
+  'Save':
+      Save plot as PostScript file.
+
+  'Help':
+      Display this help page.
+
+  'Exit':
+      Quit XPlot.
\ No newline at end of file
diff --git a/xpsf_extract.pro b/xpsf_extract.pro
new file mode 100644
index 0000000000000000000000000000000000000000..8a924902bcfce63a42afb1658be1b64598f15931
--- /dev/null
+++ b/xpsf_extract.pro
@@ -0,0 +1,562 @@
+; $Id: xpsf_extract, v 1.7 Apr 2012 e.d. $
+;
+;+
+; NAME:
+;   XPSF_EXTRACT
+;
+; PURPOSE:
+;   Widget interface for the PSF_EXTRACT procedure.
+;   Given a stellar field image, extract an estimate of the PSF
+;   by combination of a set of stars selected by the user.
+;
+; CATEGORY:
+;   Widgets. Signal processing.
+;
+; CALLING SEQUENCE:
+;   XPSF_EXTRACT, Image, Rep, Psf, Psf_fwhm, X, Y, Background, Back_Box
+;
+; INPUTS:
+;   Image:    Stellar field
+;
+;   Rep:    binary flag; 0 means that this is the first call to XPsf_Extract.
+;     When the flag is different from 0, the user is not prompted to select
+;     the secondary sources around the candidate PSF stars.
+;
+; KEYWORD PARAMETERS:
+;   DISPLAYIMAGE:  Structure of current image display options;
+;     the structure must be defined as in DEFAULT_DISPLAY_OPT.
+;
+;   DISPLAYPSF:   Structure of current PSF display options;
+;     the structure must be defined as in DEFAULT_DISPLAY_OPT.
+;
+;   PATH: Initial path for file browsing when saving reference stars.
+;     If the argument of the keyword is a named variable, its value
+;     is overwritten.
+;
+;   DEFAULT_PAR:  Structure of default parameters for the widget's form.
+;
+;   GROUP: XPsf_Extract group leader.
+;
+;   UVALUE: XPsf_Extract user value.
+;
+; OUTPUTS:
+;   Image:    Same as input Image if no saturated stars are present.
+;     Otherwise it is the input Image with corrected saturated stars.
+;
+;   Psf:  PSF estimate. The size must be specified by the user filling
+;     the interactive form
+;
+;   Psf_fwhm: FWHM of output PSF
+;
+;   X, Y: Coordinates of 'PSF stars'
+;
+;   Background:   2D array, with the same size as Image, containing an estimate
+;     of the background emission
+;
+;   Back_Box: Size of box used for estimation of the Background array (see also
+;       the file IMAGE_BACKGROUND.PRO)
+;
+; OPTIONAL OUTPUTS:
+;   IMADISPLAYOPT:     Set this keyword to a named variable to get
+;     the structure of image display options, as defined and/or
+;     modified by XPSF_EXTRACT.
+;
+;   PSFDISPLAYOPT:     Set this keyword to a named variable to get
+;     the structure of PSF display options, as defined and/or
+;     modified by XPSF_EXTRACT.
+;
+;   DEFAULT_PAR:  Set this keyword to a named variable to get the
+;     structure of parameters set by the widget's user.
+;
+; SIDE EFFECTS:
+;   Initiates the XMANAGER if it is not already running.
+;
+; RESTRICTIONS:
+;   The Help menu opens the file
+;   '/starfinder/xpsf_extract_help.txt'.
+;
+; PROCEDURE:
+;   Create and register the widget as a modal widget.
+;   Then let the user define and or/modify the PSF extraction options and apply
+;   them to the input image. As a PSF estimate is obtained applying the current
+;   options, it is displayed on the graphic window. Then the user may exit or
+;   repeat the extraction procedure with different parameters.
+;
+; MODIFICATION HISTORY:
+;   Written by: Emiliano Diolaiti, September 1999
+;   Updates:
+;   1) Enhanced error handling in event-handler
+;      (Emiliano Diolaiti, April 2000).
+;   2) Removed call to obsolete routine APPEND_ELEMENTS
+;      (Emiliano Diolaiti, June 2001).
+;   3) Modified widget parameters
+;      (Emiliano Diolaiti, September 2001).
+;   4) Renamed keywords IMAGE_DISPLAY_OPT and PSF_DISPLAY_OPT
+;      (Emiliano Diolaiti, September 2001).
+;   5) Added parameter Back_Box (E. D., August 2004).
+;   6) Skip 'secondary stars selection' step (E. D., August 2004).
+;   7) Restored 'secondary stars selection' step (E. D., January 2006).
+;   8) Added binary flag Rep (see INPUTS) (E. D., February 2006).
+;   9) Three options for average type: mean, min and median (E. D., July 2006).
+;   10) Size of fitting box to remove secondary sources disabled after first 
+;       call to XPSF_EXTRACT (E. D., April 2012).
+;   11) Added 'Sources Selection' option in the GUI. A list of PSF stars can be upload 
+;       from a file (L. S., May 2021)    
+;-
+
+; XPSF_EXTRACT_GET_PRINCIPAL: auxiliary routine to select 'PSF stars'.
+
+PRO xpsf_extract_get_principal, image, wnum, display_opt, upper_lev, psf_file, $;-----------
+                                 x_in, y_in, x, y, same_stars
+
+    on_error, 2
+    same_stars = 0B
+   
+    if  n_elements(x_in) ne 0 and n_elements(y_in) ne 0 then begin
+       if psf_file eq 1 then begin ;-----------------------------------------
+       msg = dialog_message('Do you want to use the same stars as before?', /QUESTION)
+         if  strlowcase(msg) eq 'yes'  then begin
+            x = x_in  &  y = y_in  &  same_stars = 1B  &  return
+         endif
+;----------------------------------------- 
+       endif else begin
+            x = x_in  &  y = y_in  &  return 
+       endelse
+;-----------------------------------------
+    endif
+    ; Select stars
+    display_image, image, wnum, OPTIONS = display_opt
+    id = dialog_message(['Select the stars to form the PSF.', '', $
+                 'Use the left button of your mouse; ' + $
+              'push the right button to exit.'], /INFO)
+    if  n_elements(upper_lev) ne 0  then  upper = upper_lev
+    click_on_max, image, /MARK, /SILENT, UPPER = upper, $
+                  SYMSIZE = 3, /DARK, x_click, y_click
+    nstars = n_elements(x_click)
+    if  nstars eq 0  then  return
+    ; Is there at least one unsaturated star?
+    if  n_elements(upper_lev) ne 0  then begin
+       w = where(image[x_click, y_click] lt upper_lev, count)
+       if  count eq 0  then begin
+          id = dialog_message(/ERROR, 'Please select at least one unsaturated star.')
+          return
+       endif
+    endif
+    ; Sort them in order of decreasing intensity
+    x = x_click  &  y = y_click
+    if  nstars ne 0  then begin
+       sorted = reverse(sort(image[x, y]))  &  x = x[sorted]  &  y = y[sorted]
+    endif
+    return
+end
+
+; XPSF_EXTRACT_CONFIRM: auxiliary routine to select secondary sources.
+
+PRO xpsf_extract_confirm, image, wnum, display_opt, x_in, y_in, $
+                           same_stars, psfsize, x_out, y_out
+
+    on_error, 2
+    if  n_elements(x_in) eq 0 or n_elements(y_in) eq 0  then  return
+    if  same_stars  then begin
+       x_out = x_in  &  y_out = y_in  &  return
+    endif
+    sub_arrays, image, x_in, y_in, psfsize, stack
+    nstars = n_elements(x_in)
+    for  n = 0L, nstars - 1  do begin
+       xn = -1  &  yn = -1
+       opt = default_display_opt(stack[*,*,n])
+       opt.reverse = display_opt.reverse
+       opt.stretch = display_opt.stretch
+       opt.color_table = display_opt.color_table
+       display_image, stack[*,*,n], wnum, OPTIONS = opt
+       msg = dialog_message('Confirm this star?', /QUESTION)
+       if  strlowcase(msg) eq 'no'  then begin
+          x_in[n] = -1  &  y_in[n] = -1
+       endif
+    endfor
+    w = where(x_in ge 0 and y_in ge 0, n_confirm)
+    if  n_confirm ne 0  then begin
+       x_out = x_in[w]  &  y_out = y_in[w]
+    endif
+    display_image, image, wnum, OPTIONS = display_opt
+    return
+end
+
+; XPSF_EXTRACT_GET_SECONDARY: auxiliary routine to select secondary sources.
+
+PRO xpsf_extract_get_secondary, image, wnum, display_opt, x, y, $
+                                 same_stars, psfsize, x2_in, y2_in, x2, y2
+
+    on_error, 2
+    if  n_elements(x) eq 0 or n_elements(y) eq 0  then  return
+    msg = dialog_message(['Do you want to select and subtract the ', $
+               'secondary sources around the selected stars?'], /QUESTION)
+    if  strlowcase(msg) eq 'no'  then  return
+    if  same_stars and n_elements(x2_in) ne 0 and n_elements(y2_in) ne 0  then begin
+       msg = dialog_message('Select the same secondary sources as before?', /QUESTION)
+       if  strlowcase(msg) eq 'yes'  then begin
+          x2 = x2_in  &  y2 = y2_in  &  return
+       endif
+    endif
+   sub_arrays, image, x, y, psfsize, stack
+   nstars = n_elements(x)
+   for  n = 0L, nstars - 1  do begin
+      xn = -1  &  yn = -1
+      opt = default_display_opt(stack[*,*,n])
+      opt.reverse = display_opt.reverse
+      opt.stretch = display_opt.stretch
+      opt.color_table = display_opt.color_table
+      display_image, stack[*,*,n], wnum, OPTIONS = opt
+      msg = dialog_message(['Select the main secondary sources around ' +  $
+                'the displayed star.', '', 'Use the left '  +  $
+                'button of your mouse; push the right button ' + $
+                'to exit.'], /INFO)
+       click_on_max, stack[*,*,n], /MARK, /SILENT, $
+                     BOXSIZE = 3, SYMSIZE = 3, xn, yn
+       if  xn[0] ne -1 and yn[0] ne -1  then begin
+          xn = xn + x[n] - psfsize/2  &  yn = yn + y[n] - psfsize/2
+          if  n_elements(x2) eq 0  then begin
+             x2 = xn  &  y2 = yn
+          endif else begin
+             x2 = [x2, xn]
+             y2 = [y2, yn]
+          endelse
+       endif
+   endfor
+    ; Sort secondary stars in order of decreasing intensity
+   if  n_elements(x2) ne 0  then begin
+       sorted = reverse(sort(image[x2, y2]))
+       x2 = x2[sorted]  &  y2 = y2[sorted]
+    endif
+    ; Restore previous display
+    display_image, image, wnum, OPTIONS = display_opt
+    return
+end
+
+; XPSF_EXTRACT_EVENT: XPsf_Extract event handler.
+
+PRO xpsf_extract_event, event
+
+    catch, error
+    if  error ne 0  then begin
+       msg = dialog_message(/ERROR, !err_string)
+       widget_control, event.id, SET_UVALUE = data, /NO_COPY
+       return
+    endif
+    widget_control, event.id, GET_UVALUE = data, /NO_COPY
+    event_type = strlowcase(event.tag)
+    case  event_type  of
+       'upper_lev': begin
+          widget_control, event.id, GET_VALUE = form
+          image_max = max(*(*data).image)
+          for  id = 11, 13  do $
+             widget_control, (*data).ids[id], $
+             SENSITIVE = form.upper_lev le image_max and 1B
+          end
+       'process': begin
+          widget_control, event.id, GET_VALUE = form
+          if  form.psf_size ne 0  then begin
+             ; Define input parameters of PSF_EXTRACT
+             psf_size = form.psf_size
+             back_box = form.back_box
+             n_fwhm_fit = form.n_fwhm_fit
+             norm_rad = form.norm_rad
+             avg = form.avg
+;-----------------------------------------             
+             psf_file = form.psf_file
+;-----------------------------------------             
+             satur = form.upper_lev le max(*(*data).image)
+             if  satur  then  upper_lev = form.upper_lev
+             n_fwhm_match = form.n_fwhm_match
+             n_width = form.n_width
+             mag_fac = form.mag_fac
+             ; Save parameters
+             (*data).par.psf_size = psf_size
+             (*data).par.back_box = back_box
+             (*data).back_box = back_box
+             (*data).par.n_fwhm_fit = n_fwhm_fit
+             (*data).par.norm_rad = norm_rad
+             (*data).par.avg = avg
+;-----------------------------------------             
+             (*data).par.psf_file = psf_file
+;-----------------------------------------             
+             (*data).par.upper_lev = form.upper_lev
+             (*data).par.n_fwhm_match = n_fwhm_match
+             (*data).par.n_width = n_width
+             (*data).par.mag_fac = mag_fac
+;-----------------------------------------
+              if psf_file eq 0 then begin
+                 file = dialog_pickfile(/READ, PATH = *(*data).path, GET_PATH = path)
+                 xyf = read_float_data(file, 2)
+                 x_input = transpose(xyf[0,*])
+                 y_input = transpose(xyf[1,*])
+                  *(*data).x = x_input  &  *(*data).y = y_input
+              endif
+;-----------------------------------------
+             ; Select 'PSF stars'
+             xpsf_extract_get_principal, *(*data).image, (*data).wnum, *(*data).ima_disp, $
+                upper_lev, psf_file, *(*data).x, *(*data).y, x_0, y_0, same_stars
+             xpsf_extract_confirm, *(*data).image, (*data).wnum, *(*data).ima_disp, $
+                x_0, y_0, same_stars, psf_size, x, y
+             if (*data).rep eq 0 then $
+             xpsf_extract_get_secondary, *(*data).image, (*data).wnum, *(*data).ima_disp, $
+                x, y, same_stars, psf_size, *(*data).x2, *(*data).y2, x2_0, y2_0
+             ; Estimate PSF
+             if  n_elements(x_0) ne 0 and n_elements(y_0) ne 0  then begin
+                x = x_0  &  y = y_0
+                *(*data).x = x  &  *(*data).y = y
+                if  n_elements(x2_0) ne 0 and n_elements(y2_0) ne 0  then begin
+                   compare_lists, x, y, x2_0, y2_0, MAX_DISTANCE = sqrt(2) * 1.5, $
+                                  x_1, y_1, x2_1, y2_1, SUB2 = s2
+                   if  s2[0] ge 0  then begin
+                      x2 = x2_0[s2]  &  y2 = y2_0[s2]
+                      *(*data).x2 = x2  &  *(*data).y2 = y2
+                   endif
+                endif
+                avgtype = 2 - avg
+                widget_control, /HOURGLASS
+                psf_extract, *(*data).x, *(*data).y, x2, y2, *(*data).image, $
+                   psf_size, *(*data).psf, psf_fwhm, *(*data).background, $
+                   N_FWHM_BACK = back_box, N_FWHM_FIT = n_fwhm_fit, $
+                   INTERP_TYPE = 'I', UPPER_LEVEL = upper_lev, $
+                   N_FWHM_MATCH = n_fwhm_match, N_WIDTH = n_width, $
+                   MAG_FAC = mag_fac, AVGTYPE = avgtype, $
+                   RAD_NORM = norm_rad, _EXTRA = *(*data).extra
+               ; Save outputs
+               if  n_elements(psf_fwhm) ne 0  then begin
+                  *(*data).psf_fwhm = psf_fwhm
+                   msg = dialog_message(/INFO, 'Done.')
+               endif
+             endif
+          endif else $
+             msg = dialog_message(/ERROR, 'Please select a PSF size.')
+          end
+       'disp_ima': begin
+          widget_control, /HOURGLASS
+          display_image, *(*data).image, (*data).wnum, OPTIONS = *(*data).ima_disp
+          (*data).last_disp = (*data).image
+          (*data).last_disp_opt = (*data).ima_disp
+          end
+       'disp_psf': if  n_elements(*(*data).psf) ne 0  then begin
+          widget_control, /HOURGLASS
+          display_image, *(*data).psf, (*data).wnum, OPTIONS = *(*data).psf_disp
+          (*data).last_disp = (*data).psf
+          (*data).last_disp_opt = (*data).psf_disp
+          endif
+       'disp_opt': if  n_elements(*(*data).last_disp) ne 0  then $
+          *(*data).last_disp_opt = xdisplayopt(*(*data).last_disp, (*data).wnum, $
+                  OPTIONS = *(*data).last_disp_opt, GROUP = event.top)
+       'help': $
+          xdispfile, file_name('starfinder', 'xpsf_extract_help.txt'), $
+                TITLE = 'XPsf_Extract help', /MODAL
+       'exit': begin
+          if  n_elements(*(*data).x) ne 0  then begin
+             msg = dialog_message(/QUESTION, 'Save PSF stars?')
+             if  strlowcase(msg) eq 'yes'  then begin
+                file = dialog_pickfile(/WRITE, FILTER = '*.txt', $
+                                PATH = *(*data).path, GET_PATH = path)
+                if  file ne ''  then begin
+                   widget_control, /HOURGLASS
+                   if  strpos(file, '.txt') lt 0  then  file = file + '.txt'
+                   *(*data).path = path
+                   out = [transpose(*(*data).x), transpose(*(*data).y)]
+                   openw, lun, file, /GET_LUN
+                   printf, lun, out  &  free_lun, lun
+                endif
+             endif
+          endif
+          widget_control, event.id, SET_UVALUE = data, /NO_COPY
+          widget_control, event.top, /DESTROY
+          end
+       else:
+    endcase
+    if  event_type ne 'exit'  then $
+       widget_control, event.id, SET_UVALUE = data, /NO_COPY
+    return
+end
+
+; XPSF_EXTRACT_DEF: define data structure.
+
+FUNCTION xpsf_extract_def, ids, par, image, psf, psf_fwhm, x, y, background, back_box, $
+                           rep, wnum, ima_disp, psf_disp, path, extra
+
+    return, { ids: ids, par: par, $
+           image: ptr_new(image, /NO_COPY), $
+           psf: ptr_new(psf, /NO_COPY), psf_fwhm: ptr_new(psf_fwhm, /NO_COPY), $
+           x: ptr_new(x, /NO_COPY), y: ptr_new(y, /NO_COPY), $
+           x2: ptr_new(/ALLOCATE), y2: ptr_new(/ALLOCATE), $
+           background: ptr_new(background, /NO_COPY), back_box: back_box, $
+           rep: rep, $
+           wnum: wnum, $
+           ima_disp: ptr_new(ima_disp, /NO_COPY), $
+           psf_disp: ptr_new(psf_disp, /NO_COPY), $
+           last_disp: ptr_new(/ALLOCATE), last_disp_opt: ptr_new(/ALLOCATE), $
+           path: ptr_new(path, /NO_COPY), $
+           extra: ptr_new(extra, /NO_COPY) }
+end
+
+; XPSF_EXTRACT_DEL: de-reference and de-allocate heap variables.
+
+PRO xpsf_extract_del, data, par, image, psf, psf_fwhm, x, y, background, back_box, $
+                      ima_disp, psf_disp, path, extra
+
+    par = (*data).par
+    image = *(*data).image
+    if  n_elements(*(*data).psf) ne 0  then  psf = *(*data).psf
+    if  n_elements(*(*data).psf_fwhm) ne 0  then  psf_fwhm = *(*data).psf_fwhm
+    if  n_elements(*(*data).x) ne 0 and n_elements(*(*data).y) ne 0  then begin
+       x = *(*data).x  &  y = *(*data).y
+    endif
+    if  n_elements(*(*data).background) ne 0  then  background = *(*data).background
+    back_box = (*data).back_box
+    if  n_elements(*(*data).ima_disp) ne 0  then  ima_disp = *(*data).ima_disp
+    if  n_elements(*(*data).psf_disp) ne 0  then  psf_disp = *(*data).psf_disp
+    if  n_elements(*(*data).path) ne 0  then  path = *(*data).path
+    if  n_elements(*(*data).extra) ne 0  then  extra = *(*data).extra
+    ptr_free, (*data).image, (*data).psf, (*data).psf_fwhm, $
+              (*data).x, (*data).y, (*data).x2, (*data).y2, $
+              (*data).background, (*data).ima_disp, (*data).psf_disp, $
+              (*data).last_disp, (*data).last_disp_opt, (*data).path, (*data).extra
+    ptr_free, data
+    heap_gc
+    return
+end
+
+; XPSF_EXTRACT_PAR: define default parameters.
+
+PRO xpsf_extract_par, id, par, image_max, back_box
+
+    if  n_elements(par) ne 0  then begin
+       psf_size = par.psf_size
+       if n_elements(back_box) eq 0 then back_box = par.back_box
+       n_fwhm_fit = par.n_fwhm_fit
+       norm_rad = par.norm_rad
+       avg = par.avg
+;-----------------------------------------       
+       psf_file = 1
+;-----------------------------------------       
+       upper_lev = par.upper_lev
+       n_fwhm_match = par.n_fwhm_match
+       n_width = par.n_width
+       mag_fac = par.mag_fac
+    endif else begin
+       psf_size = 0
+       if n_elements(back_box) eq 0 then back_box = 9
+       n_fwhm_fit = 2
+       norm_rad = 1.
+       avg = 0
+;-----------------------------------------       
+       psf_file = 1
+;-----------------------------------------       
+       upper_lev = 1e6
+       while  upper_lev le image_max  do  upper_lev = 10 * upper_lev
+       n_fwhm_match = 1
+       n_width = 3
+       mag_fac = 2
+    endelse
+    par = {psf_size: psf_size, back_box: back_box, n_fwhm_fit: n_fwhm_fit, $
+           norm_rad: norm_rad, avg: avg, psf_file: psf_file, upper_lev: upper_lev, $;------------------
+           n_fwhm_match: n_fwhm_match, n_width: n_width, mag_fac: mag_fac}
+    init = {psf_size: strcompress(string(psf_size), /REMOVE_ALL), $
+            back_box: strcompress(string(back_box), /REMOVE_ALL), $
+            n_fwhm_fit: strcompress(string(n_fwhm_fit), /REMOVE_ALL), $
+            norm_rad: strcompress(string(norm_rad), /REMOVE_ALL), $
+            avg: avg, psf_file: psf_file,$ ;-----------------------------------------
+            upper_lev: strcompress(string(upper_lev), /REMOVE_ALL), $
+            n_fwhm_match: strcompress(string(n_fwhm_match), /REMOVE_ALL), $
+            n_width: strcompress(string(n_width), /REMOVE_ALL), $
+            mag_fac: strcompress(string(mag_fac), /REMOVE_ALL)}
+    widget_control, id, SET_VALUE = init
+    return
+end
+
+; XPSF_EXTRACT: XPsf_Extract widget definition module.
+
+PRO xpsf_extract, image, rep, psf, psf_fwhm, x, y, background, back_box, _EXTRA = extra, $
+                  DISPLAYIMAGE = ima_disp, DISPLAYPSF = psf_disp, $
+                  PATH = path, DEFAULT_PAR = par, GROUP = group, UVALUE = uvalue
+
+    catch, error
+    if  error ne 0  then begin
+       xpsf_extract_del, data, par, image, psf, psf_fwhm, x, y, background, back_box, $
+                      ima_disp, psf_disp, path, extra
+       if  n_elements(group) eq 0  then  widget_control, group_id, /DESTROY
+       return
+    endif
+    ; Create group leader if necessary
+    if  n_elements(group) eq 0  then $
+       group_id = widget_base()  else  group_id = group
+    ; Create modal base
+    if  n_elements(uvalue) eq 0  then  uvalue = 0B
+    base = widget_base(TITLE = 'XPsf_Extract', GROUP_LEADER = group_id, $
+                 /MODAL, UVALUE = uvalue, COLUMN = 2)
+    left_base = widget_base(base, /GRID_LAYOUT)
+    right_base = widget_base(base, /GRID_LAYOUT)
+    ; Define draw window (in the right part of base)
+    s = round(0.7 * min(get_screen_size()))
+    draw = widget_draw(right_base, SCR_XSIZE = s, SCR_YSIZE = s, $
+                 /ALIGN_CENTER, RETAIN = 2)
+    ; Define form with PSF extraction parameters
+    desc = [ $
+    '0, LABEL,Boxes:,LEFT', $
+    '1, BASE,,FRAME,COLUMN', $
+    '0, INTEGER,,LABEL_LEFT=Size of output PSF,TAG=psf_size', $
+    '0, FLOAT,,LABEL_LEFT=Box size for background estimation (FWHM units),' + $
+       'TAG=back_box', $
+    '2, FLOAT,,LABEL_LEFT=Fitting box size (FWHM units),TAG=n_fwhm_fit', $
+    '0, LABEL,Point Sources Combination:,LEFT', $
+    '1, BASE,,FRAME,COLUMN', $
+    '0, FLOAT,,LABEL_LEFT=Normalization radius (FWHM units),TAG=norm_rad', $
+    '2, BUTTON,median|minimum|mean,EXCLUSIVE, ' + $
+       'LABEL_LEFT=Average type:,NO_RELEASE,ROW,TAG=avg', $
+;-----------------------------------------------
+    '0, LABEL,Sources Selection:,LEFT', $
+    '1, BASE,,FRAME,COLUMN', $
+    '2, BUTTON,yes|no,EXCLUSIVE, ' + $
+       'LABEL_LEFT=Load PSF stars coordinates from file:,NO_RELEASE,ROW,TAG=psf_file', $  
+;-------------------------------------
+    '0, LABEL,Saturated stars:,LEFT', $
+    '1, BASE,,FRAME,COLUMN', $
+    '0, FLOAT,,LABEL_LEFT=Saturation threshold,WIDTH=12,TAG=upper_lev', $
+    '0, FLOAT,,LABEL_LEFT=Search box to optimize correlation (FWHM units),' + $
+       'TAG=n_fwhm_match', $
+    '0, FLOAT,,LABEL_LEFT=Repair box (saturated core units),TAG=n_width', $
+    '2, INTEGER,,LABEL_LEFT=Sub-pixel positioning accuracy,TAG=mag_fac', $
+    '1, BASE,,ROW', $
+    '2, BUTTON,Processing...,NO_RELEASE,TAG=process', $
+    '1, BASE,,COLUMN', $
+    '0, BUTTON,Display Image,NO_RELEASE,TAG=disp_ima', $
+    '0, BUTTON,Display PSF,NO_RELEASE,TAG=disp_psf', $
+    '2, BUTTON,Display Options,NO_RELEASE,TAG=disp_opt', $
+    '1, BASE,,ROW', $
+    '0, BUTTON,Help,NO_RELEASE,TAG=help', $
+    '2, BUTTON,Exit,QUIT,NO_RELEASE,TAG=exit']
+    form = cw_form(left_base, desc, /COLUMN, IDS = ids)
+    image_max = max(image)
+    xpsf_extract_par, form, par, image_max, back_box
+    widget_control, ids[3], SENSITIVE = n_elements(background) eq 0 and 1B
+    widget_control, ids[4], SENSITIVE = rep eq 0 and 1B
+    for  id = 12, 14  do $
+       widget_control, ids[id], SENSITIVE = par.upper_lev le image_max and 1B
+    ; Realize widget
+    widget_control, base, /REALIZE
+    ; Display image and define display options
+    widget_control, draw, GET_VALUE = wnum
+    display_image, image, wnum, OPTIONS = ima_disp
+    ; Define pointer to auxiliary/output data
+    data = xpsf_extract_def(ids, par, image, psf, psf_fwhm, x, y, background, back_box, $
+                            rep, wnum, ima_disp, psf_disp, path, extra)
+    data = ptr_new(data, /NO_COPY)
+    (*data).last_disp = (*data).image
+    (*data).last_disp_opt = (*data).ima_disp
+    widget_control, form, SET_UVALUE = data
+    ; Register
+    xmanager, 'xpsf_extract', base, EVENT_HANDLER = 'xpsf_extract_event'
+    ; De-reference output data and de-allocate heap variables
+    xpsf_extract_del, data, par, image, psf, psf_fwhm, x, y, background, back_box, $
+                   ima_disp, psf_disp, path, extra
+    ; Destroy group leader if necessary
+    if  n_elements(group) eq 0  then $
+       widget_control, group_id, /DESTROY
+    return
+end
diff --git a/xpsf_extract_help.txt b/xpsf_extract_help.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2154bbb1b1d7d6fd1f8fc1f9a1a858c1acab7fe6
--- /dev/null
+++ b/xpsf_extract_help.txt
@@ -0,0 +1,146 @@
+  XPsf_Extract help page
+
+
+
+  GENERAL DESCRIPTION
+
+  The XPsf_Extract widget extracts a PSF estimate from a
+  stellar field image, as a superposition of a set of stars.
+  The user is prompted to select the candidate sources by
+  clicking with the mouse: each click is allowed to range
+  in a 5x5 box centered on the maximum of the object. After
+  selection, a blow-up of each source is shown, to allow
+  rejection of undesired candidates. Stars too close to the 
+  image edge (e.g. closer than half the size of the output 
+  PSF) should be avoided.
+  The PSF stars are cleaned from the contaminating sources. 
+  This task is accomplished in two ways. During the first 
+  PSF estimation on a given image, the user may optionally 
+  select the secondary sources around the candidate PSF stars, 
+  by clicking with the mouse; when the PSF extraction procedure 
+  is called after having already analyzed the image, the known
+  contaminating sources around the PSF stars are automatically 
+  subtracted, using the information collected so far by the 
+  program. Then the PSF stars are background-subtracted, 
+  centered with sub-pixel accuracy, normalized, stacked and 
+  finally combined by a pixel-by-pixel average with median, 
+  minimum or mean operation. Centering involves interpolation, 
+  which is reliable only on well-sampled data.
+  If present, saturated stars might be included as PSF
+  stars, because they provide useful information on the PSF
+  halo. To ensure correct normalization, the core of these
+  stars is approximately repaired, by replacing it with a scaled
+  replica of the PSF: accurate positioning is achieved by
+  correlation maximization, whereas the scaling factor is
+  determined by fitting the wings of the saturated source.
+  Nevertheless the repaired region is masked when forming
+  the PSF. Saturated stars, if not repaired, would be rejected
+  by the detection algorithm, compromising the analysis of
+  fainter sources around.
+  The XPsf_Extract widget returns the estimated PSF and, as
+  a by-product, the input image with repaired saturated stars.
+  Notice that saturated stars, if present, are repaired only
+  if selected for PSF extraction.
+ 
+
+ 
+  PARAMETERS
+
+  'Size of output PSF':
+      Set the size (in pixels units) of the output PSF array.
+
+  'Box size for background estimation':
+      The background is estimated by interpolating an array of
+      local measurements, relative to a set of image sub-regions
+      arranged in a regular grid. This parameter specifies the
+      size (in units of PSF FWHM) of each sub-region.
+      This parameter is only available in the first iteration 
+      of the PSF extraction for a given image: in later iterations, 
+      the procedure adopts the background estimate provided by 
+      the last call to XStarFinder_Run.
+
+  'Fitting box size (FWHM units)':
+      Size of box to fit the secondary sources to subtract.
+      This parameter is only available in the first iteration 
+      of the PSF extraction for a given image: in the following 
+      iterations, secondary sources around the PSF stars are 
+      automatically subtracted on the basis of the previous 
+      astrometric and photometric analysis.
+
+  'Normalization radius':
+      The PSF stars are normalized in a way that the integrated 
+      flux within a circular region centered on the stellar peak is 
+      unit. This parameter specifies the radius of this normalization
+      region. Of course, the final PSF estimate is again normalized 
+      to a total flux of 1.
+ 
+  'Average type':
+      Select the method to combine the PSF stars into a single image. 
+
+  'Source selection':
+      It is possible to load an input list of stars. The list must be in an  
+      ASCII file with two columns: X position, Y position.
+      The positions are in pixels. There is no need to re-load the list 
+      for a new iteration. 
+
+  'Saturation threshold':
+      Estimate of the saturation level in the input image. This
+      field is set by default to a very high value (larger than
+      the image maximum), indicating no saturation. A saturation
+      threshold smaller than the image maximum indicates the
+      presence of saturated stars. If one or more selected
+      stars have their maximum above this level, they are
+      considered saturated and repair is attempted.
+      If the brightest star in the image was saturated and
+      has been repaired, it is recommended to display the image
+      again and change the display options (see 'Display Image'
+      and 'Display Options' buttons below): the upper intensity
+      level of the display should be increased.
+
+  'Search box to optimize correlation':
+      Accurate positioning of the PSF onto the core of
+      saturated stars is performed by correlation maximization.
+      The 'search box' specifies the region inside which the
+      PSF is positioned to maximize the correlation. The center
+      of the 'search box' is represented by the pixel clicked
+      on by the user when selecting the star. Notice that, when
+      clicking on a saturated star, no tolerance is fixed on
+      the position of the click and no search for the nearest
+      maximum is performed: the presumed center of the
+      saturated star coincides with the click itself.
+
+  'Repair box':
+      Size of the region to use when fitting the wings of a
+      saturated star, in order to determine the proper scaling
+      factor. This box size is expressed in units of the
+      saturated core diameter.
+
+  'Sub-pixel positioning accuracy':
+      When saturated stars are only slightly corrupted, it is
+      possible to achieve sub-pixel accuracy in positioning the
+      PSF onto the saturated core. This parameter indicates the
+      number of sub-pixel offsets for correlation maximization.
+
+
+
+  CONTROLS/BUTTONS
+
+  'Processing...':
+      Extract a PSF estimate applying the currently defined options.
+
+  'Display Image':
+      Display the image array.
+
+  'Display PSF':
+      Display the PSF array.
+
+  'Display Options':
+      Call the widget application XDisplay_Opt to modify the display
+      options of the currently displayed array (either Image or PSF).
+
+  'Help':
+      Display this help page.
+
+  'Exit':
+      Quit XPsf_Extract. Before quitting, the user is prompted to
+      create an ASCII file with the positions of the PSF stars.
\ No newline at end of file
diff --git a/xpsf_smooth.pro b/xpsf_smooth.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1ba3d80a5fe3fc0285f722bc6c8d695477959a36
--- /dev/null
+++ b/xpsf_smooth.pro
@@ -0,0 +1,186 @@
+; $Id: xpsf_smooth, v 1.1 Apr 2000 e.d. $
+;
+;+
+; NAME:
+;	XPSF_SMOOTH
+;
+; PURPOSE:
+;	Widget interface for the HALO_SMOOTH function.
+;	Apply a variable box size median filter to the halo of a PSF image.
+;
+; CATEGORY:
+;	Widgets. Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = XPSF_SMOOTH(Psf, Wnum, Display_opt)
+;
+; INPUTS:
+;	Psf: 2D data array, containing the image of the point source to smooth
+;
+; OPTIONAL INPUTS:
+;	Wnum: Window number of an existing window
+;
+;	Display_opt:	Structure of current display options;
+;		the structure must be defined as in DEFAULT_DISPLAY_OPT
+;
+; KEYWORD PARAMETERS:
+;	DEFAULT_PAR:	Structure of default parameters for the widget's form.
+;
+;	GROUP: XPsf_smooth group leader.
+;
+;	UVALUE: XPsf_smooth user value.
+;
+; OUTPUTS:
+;	Result:	Halo-smoothed Psf
+;
+; OPTIONAL OUTPUTS:
+;	Wnum: window number of new window, if undefined on input
+;
+;	Display_opt:	Display options, as defined and/or modified by
+;		X_Psf_smooth
+;
+;	DEFAULT_PAR:	Set this keyword to a named variable to get the
+;		structure of parameters set by the widget's user.
+;
+; SIDE EFFECTS:
+;	1) Initiates the XMANAGER if it is not already running.
+;	2) Call DISPLAY_IMAGE to activate the graphic window identified by Wnum.
+;	3) Create a new graphic window if not defined on input (see DISPLAY_IMAGE
+;	and XDISPLAYOPT for details).
+;	4) Any image displayed on the window Wnum is overwritten first by the
+;	input image to smooth and then by the result of the processing performed
+;	by XPsf_Smooth.
+;
+; RESTRICTIONS:
+;	The Help menu opens the file
+;	'/starfinder/xpsf_smooth_help.txt'.
+;
+; PROCEDURE:
+;	Create and register the widget as a modal widget.
+;	Then let the user define and or/modify the smoothing options and apply
+;	them to the input image. As a new processed image is obtained applying
+;	the current options, it is displayed on the graphic window.
+;
+; MODIFICATION HISTORY:
+;	Written by: Emiliano Diolaiti, September 1999
+;	Updates:
+;	1) Enhanced error handling in event-handler
+;	   (Emiliano Diolaiti, April 2000).
+;-
+
+; XPSF_SMOOTH_EVENT: XPsf_Smooth event handler.
+
+PRO xpsf_smooth_event, event
+
+	catch, error
+	if  error ne 0  then begin
+	   msg = dialog_message(/ERROR, !err_string)
+	   widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	   return
+	endif
+	widget_control, event.id, GET_UVALUE = data, /NO_COPY
+	event_type = strlowcase(event.tag)
+	case  event_type  of
+	   'process': begin
+	      widget_control, /HOURGLASS
+	      widget_control, event.id, GET_VALUE = form
+	      (*data).par.rad = form.rad
+	      (*data).par.rw = form.rw
+	      (*data).par.rp = form.rp
+	      (*data).par.aw = form.aw
+	      (*data).par.ap = form.ap
+	      (*data).par.pad = form.pad
+	      r = form.rad  &  rw = form.rw  &  rp = form.rp
+	      aw = form.aw * !pi / 180.  &  ap = form.ap
+	      pad = (form.pad eq 1) and 1B
+	      (*data).psf_out = halo_smooth((*data).psf_in, r, PAD_0 = pad, $
+					        R_WIDTH = rw, A_WIDTH = aw, R_EXP = rp, A_EXP = ap)
+	      display_image, (*data).psf_out, (*data).wnum, OPT = (*data).display_opt
+	      end
+	   'display': (*data).display_opt = $
+	      xdisplayopt((*data).psf_out, (*data).wnum, /NODISPLAY, $
+	      			  OPTIONS = (*data).display_opt, GROUP = event.top)
+	   'help': $
+	      xdispfile, file_name('starfinder', 'xpsf_smooth_help.txt'), $
+	      		 TITLE = 'XPsf_Smooth help', /MODAL
+	   'exit': begin
+	      widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	      widget_control, event.top, /DESTROY
+	      end
+	   else:
+	endcase
+	if  event_type ne 'exit'  then $
+	   widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	return
+end
+
+; XPSF_SMOOTH_PAR: define default parameters.
+
+PRO xpsf_smooth_par, id, minsiz, par
+
+	if  n_elements(par) ne 0  then begin
+	   rad = par.rad  &  rw = par.rw  &  rp = par.rp
+	   aw = par.aw  &  ap = par.ap  &  pad = par.pad
+	endif else begin
+	   rad = round(minsiz/4.)  &  rw = round(rad/2.)  &  rp = 2
+	   aw = 22.5  &  ap = 3  &  pad = 0
+	   par = {rad: rad, rw: rw, rp: rp, aw: aw, ap: ap, pad: pad}
+	endelse
+	init = {rad: strcompress(string(rad), /REMOVE_ALL), $
+			rw: strcompress(string(rw), /REMOVE_ALL), $
+			rp: strcompress(string(rp), /REMOVE_ALL), $
+			aw: strcompress(string(aw), /REMOVE_ALL), $
+			ap: strcompress(string(ap), /REMOVE_ALL), $
+			pad: pad}
+	widget_control, id, SET_VALUE = init
+	return
+end
+
+; XPSF_SMOOTH: XPsf_Smooth widget definition module.
+
+FUNCTION xpsf_smooth, psf, wnum, display_opt, DEFAULT_PAR = par, $
+					  GROUP = group, UVALUE = uvalue
+
+	on_error, 2
+	; Display image and define display options
+	display_image, psf, wnum, OPTIONS = display_opt
+	; Create group leader if necessary
+	if  n_elements(group) eq 0  then $
+	   group_id = widget_base()  else  group_id = group
+	; Create modal base
+	if  n_elements(uvalue) eq 0  then  uvalue = 0B
+	base = widget_base(TITLE = 'XPsf_Smooth', /MODAL, UVALUE = uvalue, $
+					   GROUP_LEADER = group_id)
+	; Define form
+	desc = [ $
+	'0, INTEGER,,LABEL_LEFT=Inner radius,TAG=rad', $
+	'0, INTEGER,,LABEL_LEFT=Radial width of smoothing box,TAG=rw', $
+	'0, INTEGER,,LABEL_LEFT=Radial power,TAG=rp', $
+	'0, FLOAT,,LABEL_LEFT=Angular width of smoothing box (deg.),TAG=aw', $
+	'0, INTEGER,,LABEL_LEFT=Angular power,TAG =ap', $
+	'0, BUTTON,No|Yes,EXCLUSIVE,LABEL_LEFT=Pad,NO_RELEASE,ROW,TAG=pad', $
+	'1, BASE,,ROW', $
+	'0, BUTTON,Processing...,NO_RELEASE,TAG=process', $
+	'2, BUTTON,Display Options,NO_RELEASE,TAG=display', $
+	'1, BASE,,ROW', $
+	'0, BUTTON,Help,NO_RELEASE,TAG=help', $
+	'2, BUTTON,Exit,QUIT,NO_RELEASE,TAG=exit']
+	form = cw_form(base, desc, /COLUMN)
+	xpsf_smooth_par, form, min(size52(psf, /DIM)), par
+	; Define pointer to auxiliary/output data
+	data = {par: par, psf_in: psf, wnum: wnum, $
+			display_opt: display_opt, psf_out: psf}
+	data = ptr_new(data, /NO_COPY)
+	widget_control, form, SET_UVALUE = data
+	; Realize, register, etc.
+	widget_control, base, /REALIZE
+	xmanager, 'xpsf_smooth', base, EVENT_HANDLER = 'xpsf_smooth_event'
+	; De-reference output data
+	par = (*data).par  &  psf_out = (*data).psf_out
+	display_opt = (*data).display_opt
+	ptr_free, data
+	; Destroy group leader if necessary
+	if  n_elements(group) eq 0  then $
+	   widget_control, group_id, /DESTROY
+	return, psf_out
+end
diff --git a/xpsf_smooth_help.txt b/xpsf_smooth_help.txt
new file mode 100644
index 0000000000000000000000000000000000000000..cbe147c76c7e3fee1b55c435c3ec11affa22e00b
--- /dev/null
+++ b/xpsf_smooth_help.txt
@@ -0,0 +1,58 @@
+  XPsf_Smooth help page
+
+
+  GENERAL DESCRIPTION
+
+  The XPsf_Smooth widget applies a variable box size median
+  smoothing technique to the halo of a PSF image. The smoothing
+  is performed only on the pixels lying outside a pre-fixed
+  distance from the image maximum. The size of the smoothing
+  box increases outwards as a power-law function of the radial
+  distance from the center.
+    
+ 
+ 
+  PARAMETERS
+
+  'Inner radius':
+      Minimum distance from the PSF maximum for median smoothing.
+
+  'Radial width of smoothing box':
+      Radial width of smoothing box at a distance 2 * (Inner radius)
+      from the center. Expressed in pixels.
+
+  'Radial power':
+      Exponent of power law expressing the radial width of the box
+      as a function of the distance from the center.
+
+  'Angular width of smoothing box':
+      Radial width of smoothing box at a distance 2 * (Inner radius)
+      from the center. Expressed in degrees.
+
+  'Angular power':
+      Exponent of power law expressing the angular width of the box
+      as a function of the distance from the center.
+
+  'Pad':
+      Set 'yes' to pad the array with a frame of 0s before smoothing.
+      It may be useful to prevent edge effects. Not always necessary.
+
+
+
+  CONTROLS/BUTTONS
+
+  'Processing...':
+      Apply the currently defined options to the input image.
+      Whenever the 'Processing...' button is pressed, the previous
+      result is overwritten by the input image and the processing
+      is performed with the current options. The result of the
+      last processing is returned on output.
+
+  'Display Options':
+      Modify the display options of the displayed image.
+
+  'Help':
+      Display this help page.
+
+  'Exit':
+      Quit XPsf_Smooth.
\ No newline at end of file
diff --git a/xreplace_pix.pro b/xreplace_pix.pro
new file mode 100644
index 0000000000000000000000000000000000000000..81aa061367477b677977ab201cd89ddda5bd0868
--- /dev/null
+++ b/xreplace_pix.pro
@@ -0,0 +1,205 @@
+; $Id: xreplace_pix, v 1.1 Apr 2000 e.d. $
+;
+;+
+; NAME:
+;	XREPLACE_PIX
+;
+; PURPOSE:
+;	Widget interface for the REPLACE_PIX function.
+;	Replace given pixels in a 2D array with the median of a suitable
+;	neighborhood. The pixels to replace are excluded from the computation
+;	of the local median.
+;
+; CATEGORY:
+;	Widgets. Signal processing.
+;
+; CALLING SEQUENCE:
+;	Result = XREPLACE_PIX(Array, X_pix, Y_pix)
+;
+; INPUTS:
+;	Array: 2D data array, containing pixels to replace
+;
+; OPTIONAL INPUTS:
+;	X_pix, Y_pix:	Coordinates of pixels to replace
+;
+; KEYWORD PARAMETERS:
+;	PATH:	Initial path for file browsing when reading bad pixels mask.
+;		If the argument of the keyword is a named variable, its value
+;		is overwritten.
+;
+;	WNUM:	Number of existing graphic window.
+;
+;	DISPLAY_OPT:	Display options for Array.
+;
+;	GROUP: Xreplace_Pix group leader.
+;
+;	UVALUE: Xreplace_Pix user value.
+;
+; OUTPUTS:
+;	Result:	Array with replaced pixels
+;
+; OPTIONAL OUTPUTS:
+;	X_pix, Y_pix:	Coordinates of pixels to replace
+;
+;	WNUM: window number of new window, if undefined on input.
+;
+;	DISPLAY_OPT:	Display options, as defined and/or modified by
+;		Xreplace_Pix.
+;
+; SIDE EFFECTS:
+;	1) Initiates the XMANAGER if it is not already running.
+;	2) Call DISPLAY_IMAGE to activate the graphic window identified by Wnum.
+;	3) Create a new graphic window if not defined on input (see DISPLAY_IMAGE
+;	and XDISPLAYOPT for details).
+;	4) Any image displayed on the window Wnum is overwritten first by the
+;	input array and then by the result of the processing.
+;
+; RESTRICTIONS:
+;	1) The pixels to replace must be marked by 0s in a binary mask which
+;	is read from a FITS file by Xreplace_Pix.
+;	2) The Help menu opens the file
+;	'/starfinder/xreplace_pix_help.txt'.
+;
+; PROCEDURE:
+;	Create and register the widget as a modal widget.
+;	Then let the user define and or/modify the smoothing options and apply
+;	them to the input array. As a new processed array is obtained, it is
+;	displayed on the graphic window.
+;
+; MODIFICATION HISTORY:
+;	Written by: Emiliano Diolaiti, September 1999
+;	Updates:
+;	1) Enhanced error handling in event-handler
+;	   (Emiliano Diolaiti, April 2000).
+;-
+
+; XREPLACE_PIX_EVENT: XReplace_Pix event handler.
+
+PRO xreplace_pix_event, event
+
+	catch, error
+	if  error ne 0  then begin
+	   msg = dialog_message(/ERROR, !err_string)
+	   widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	   return
+	endif
+	widget_control, event.id, GET_UVALUE = data, /NO_COPY
+	event_type = strlowcase(event.tag)
+	case  event_type  of
+	   'replace': begin
+	      if  n_elements(*(*data).x_pix) ne 0  then begin
+	         form = cw_form(['0,INTEGER,3,LABEL_LEFT=Enter box size to compute median,TAG=box', $
+	         				 '2, BUTTON,OK,QUIT,NO_RELEASE'], TITLE = 'Box size to compute median')
+	         box = form.box > 3
+	         widget_control, /HOURGLASS
+	         *(*data).array_out = replace_pix(*(*data).array_in, $
+	         					  *(*data).x_pix, *(*data).y_pix, BOXSIZE = box)
+	         display_image, *(*data).array_out, *(*data).wnum, OPT = *(*data).display_opt
+	      endif else $
+	         msg = dialog_message(/ERROR, 'Please read bad pixels mask.')
+	      end
+	   'load': begin
+	      file = dialog_pickfile(/READ, FILTER = '*.fits', $
+	      						 PATH = *(*data).path, GET_PATH = path)
+	      if  file ne ''  then begin
+	         widget_control, /HOURGLASS
+	         *(*data).path = path
+	         fits_read, file, mask
+	         w = where(mask eq 0, count)
+	         if  count ne 0  then $
+	            subs_to_coord, w, (size52(mask, /DIM))[0], *(*data).x_pix, *(*data).y_pix
+	      endif
+	      end
+	   'display': *(*data).display_opt = $
+	      xdisplayopt(*(*data).array_out, *(*data).wnum, /NODISPLAY, $
+	      			  OPTIONS = *(*data).display_opt, GROUP = event.top)
+	   'help': $
+	      xdispfile, file_name('starfinder', 'xreplace_pix_help.txt'), $
+	      		 TITLE = 'XReplace_Pix help', /MODAL
+	   'exit': begin
+	      widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	      widget_control, event.top, /DESTROY
+	      end
+	   else:
+	endcase
+	if  event_type ne 'exit'  then $
+	   widget_control, event.id, SET_UVALUE = data, /NO_COPY
+	return
+end
+
+; XREPLACE_PIX_DEF: define data structure.
+
+FUNCTION xreplace_pix_def, array, x_pix, y_pix, path, wnum, display_opt
+
+	return, {array_in: ptr_new(array), path: ptr_new(path, /NO_COPY), $
+			 wnum: ptr_new(wnum, /NO_COPY), $
+			 display_opt: ptr_new(display_opt, /NO_COPY), $
+			 array_out: ptr_new(array), $
+			 x_pix: ptr_new(x_pix, /NO_COPY), y_pix: ptr_new(y_pix, /NO_COPY)}
+end
+
+; XREPLACE_PIX_DEL: de-reference output data.
+
+PRO xreplace_pix_del, data, path, wnum, display_opt, array_out, x_pix, y_pix
+
+	if  n_elements(*(*data).path) ne 0  then  path = *(*data).path
+	if  n_elements(*(*data).wnum) ne 0  then  wnum = *(*data).wnum
+	if  n_elements(*(*data).display_opt) ne 0  then  display_opt = *(*data).display_opt
+	if  n_elements(*(*data).array_out) ne 0  then  array_out = *(*data).array_out
+	if  n_elements(*(*data).x_pix) ne 0  then begin
+	   x_pix = *(*data).x_pix  &  y_pix = *(*data).y_pix
+	endif
+	ptr_free, (*data).array_in, (*data).path, (*data).wnum, (*data).display_opt, $
+			  (*data).array_out, (*data).x_pix, (*data).y_pix
+	ptr_free, data
+	return
+end
+
+; XREPLACE_PIX: XReplace_Pix widget definition module.
+
+FUNCTION xreplace_pix, array, x_pix, y_pix, PATH = path, $
+					   WNUM = wnum, DISPLAY_OPT = display_opt, $
+					   GROUP = group, UVALUE = uvalue
+
+	on_error, 2
+	if  n_elements(array) eq 0  then begin
+	   mgs = dialog_message(/ERROR, 'Missing data array.')
+	   return, array
+	endif
+	; Display image and define display options
+	display_image, array, wnum, OPTIONS = display_opt
+	; Create group leader if necessary
+	if  n_elements(group) eq 0  then $
+	   group_id = widget_base()  else  group_id = group
+	; Create modal base
+	if  n_elements(uvalue) eq 0  then  uvalue = 0B
+	base = widget_base(TITLE = 'XReplace_Pix', /MODAL, UVALUE = uvalue, $
+					   GROUP_LEADER = group_id)
+	; Define form
+	desc = [ $
+	'1, BASE,,ROW', $
+	'1, BASE,,COLUMN', $
+	'0, BUTTON,Read bad pixels,NO_RELEASE,TAG=load', $
+	'2, BUTTON,Replace,NO_RELEASE,TAG=replace', $
+	'1, BASE,,COLUMN', $
+	'2, BUTTON,Display Options,NO_RELEASE,TAG=display', $
+	'2, BASE,,', $
+	'1, BASE,,ROW', $
+	'1, BASE,,ROW', $
+	'0, BUTTON,Help,NO_RELEASE,TAG=help', $
+	'2, BUTTON,Exit,QUIT,NO_RELEASE,TAG=exit', $
+	'2, BASE,,']
+	form = cw_form(base, desc, /COLUMN)
+	; Define pointer to auxiliary/output data
+	data = ptr_new(xreplace_pix_def(array, x_pix, y_pix, path, wnum, display_opt), /NO_COPY)
+	widget_control, form, SET_UVALUE = data
+	; Realize, register, etc.
+	widget_control, base, /REALIZE
+	xmanager, 'xreplace_pix', base, EVENT_HANDLER = 'xreplace_pix_event'
+	; De-reference output data
+	xreplace_pix_del, data, path, wnum, display_opt, array_out, x_pix, y_pix
+	; Destroy group leader if necessary
+	if  n_elements(group) eq 0  then $
+	   widget_control, group_id, /DESTROY
+	return, array_out
+end
diff --git a/xreplace_pix_help.txt b/xreplace_pix_help.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0e0c1a0bf15ed957c8b48390105385ef0f307288
--- /dev/null
+++ b/xreplace_pix_help.txt
@@ -0,0 +1,29 @@
+  XReplace_Pix help page
+
+
+  GENERAL DESCRIPTION
+
+  The XReplace_Pix widget replaces bad values in a given image
+  with the median of the good data in a suitable neighborhood of
+  each bad pixel.
+    
+ 
+
+  CONTROLS/BUTTONS
+
+  'Read bad pixels':
+      Enter name of FITS file containing a binary mask of bad
+      pixels, marked by 0s. The bad pixels array must have the
+      same size as the input image.
+
+  'Display Options':
+      Modify the display options of the currently displayed image.
+
+  'Replace':
+      Replace bad pixels.
+
+  'Help':
+      Display this help page.
+
+  'Exit':
+      Quit XHelp.
\ No newline at end of file
diff --git a/xstarfinder.pro b/xstarfinder.pro
new file mode 100644
index 0000000000000000000000000000000000000000..1dc352c502ecc88724c0446abc401bb824e4d72b
--- /dev/null
+++ b/xstarfinder.pro
@@ -0,0 +1,914 @@
+; $Id: xstarfinder.pro, v 1.8 Apr 2012 e.d. $
+;
+;+
+; NAME:
+;   XSTARFINDER
+;
+; PURPOSE:
+;   Package for stellar fields analysis.
+;
+; CATEGORY:
+;   Widgets.
+;
+; CALLING SEQUENCE:
+;   XSTARFINDER
+;
+; KEYWORD PARAMETERS:
+;   GROUP:    Group leader, i.e. identifier of the calling widget program
+;
+;   BLOCK:    Set this keyword to a nonzero value to have the IDL command
+;     line blocked when this application is registered
+;
+;   UVALUE:   User value to be assigned to XStarFinder
+;
+; SIDE EFFECTS:
+;   Initiates the XMANAGER if it is not already running.
+;
+; PROCEDURE:
+;   Create and register the widget and then exit. The additional data
+;   required by the program are stored as a structure of pointers in the
+;   user value of a child of the top level base.
+;
+; MODIFICATION HISTORY:
+;   Written by: Emiliano Diolaiti, August-September 1999.
+;   Updates:
+;   1) Enhanced error handling in event-handler
+;      (Emiliano Diolaiti, April 2000).
+;   2) Modified 'Repeat PSF extraction' task
+;      (Emiliano Diolaiti, September 2001).
+;   3) 'Repeat PSF extraction' task replaced by a call to the
+;      PSF extraction procedure, to allow a more flexible tuning
+;      of the parameters (Emiliano Diolaiti, January 2002).
+;   4) Fixed problem with parameter 'Box for Background estimation'
+;      (E. D., August 2004).
+;   5) When a new image is loaded, all the existing data are erased, while
+;      all the configuration parameters are preserved (E. D., August 2004).
+;   6) The PSF is automatically normalized whenever it is loaded, extracted or
+;      processed (E. D., August 2004).
+;   7) Added task to display detected sources in 'Image' menu (E. D., August 2006).
+;   8) Output text file with parameters of detected sources is now on 7 columns 
+;      (E. D., March 2012).
+;   9) Added task to display residual image (image - synthetic field) 
+;      (E. D., April 2012).
+;-
+
+
+
+;;; EVENT PROCEDURES
+
+; LOAD_IMAGE_EV: load FITS format image data from input file and display it.
+
+PRO load_image_ev, data_p, path_p, HDR = hdr_p, $
+                   DISPLAY = display, drawid, display_par_p, $
+                   LOADED = loaded, FILE = file_p
+
+    on_error, 2
+    file = dialog_pickfile(/READ, FILTER = '*.fits', $
+                           PATH = *path_p, GET_PATH = path)
+    loaded = file ne ''
+    if  not loaded  then  return
+    widget_control, /HOURGLASS
+    fits_read, file, data, hdr
+    if n_elements(path) ne 0 then *path_p = path
+    if n_elements(data) ne 0 then *data_p = data
+    if ptr_valid(file_p) then *file_p = file
+    if ptr_valid(hdr_p) then *hdr_p = hdr
+    if keyword_set(display) then begin
+;      *display_par_p = default_display_opt(data)
+       display_image_ev, drawid, path_p, display_par_p, data_p
+    endif
+    return
+end
+
+; DISPLAY_IMAGE_EV: display image data using current options.
+
+PRO display_image_ev, drawid, path_p, display_par_p, data_p, $
+                      HDR = hdr_p, FILE = file_p
+
+    on_error, 2
+    no_data = not ptr_valid(data_p)
+    if  no_data  then  data_p = ptr_new(/ALLOCATE)
+    if  n_elements(*data_p) eq 0  then begin
+       if  not ptr_valid(hdr_p)  then  hdr_p = ptr_new(/ALLOCATE)
+       load_image_ev, data_p, path_p, HDR = hdr_p, FILE = file_p
+    endif
+    if  size52(*data_p, /N_DIM) ne 2  then  return
+    widget_control, /HOURGLASS
+    if  n_elements(*display_par_p) eq 0  then $
+       *display_par_p = default_display_opt(*data_p)
+    display_image, *data_p, drawid, OPTIONS = *display_par_p
+    return
+end
+
+; DISPLAY_OPTIONS_EV: modify display options by means of XDisplayOpt.
+
+PRO display_options_ev, drawid, last_data_p, display_par_p, group_leader
+
+    on_error, 2
+    if  n_elements(*last_data_p) eq 0  then begin
+       msg = dialog_message('Please select data', /ERROR)
+       return
+    endif
+    widget_control, /HOURGLASS
+    if  size52(*last_data_p, /TYPE) eq 7  then $
+       fits_read, *last_data_p, data  else  data = *last_data_p
+    *display_par_p = xdisplayopt(data, drawid, /NODISPLAY, $
+               OPTIONS = *display_par_p, GROUP = group_leader)
+    return
+end
+
+; SAVE_IMAGE_EV: save image data in FITS-format output file.
+
+PRO save_image_ev, data_p, path_p, HDR = hdr_p
+
+    on_error, 2
+    if  n_elements(*data_p) eq 0  then  return
+    file = dialog_pickfile(/WRITE, FILTER = '*.fits',  $
+                    PATH = *path_p, GET_PATH = path)
+    if  file eq ''  then  return
+    widget_control, /HOURGLASS
+    if  strpos(file, '.fits') lt 0  then  file = file + '.fits'
+    *path_p = path
+    if  ptr_valid(hdr_p)  then $
+       if  n_elements(*hdr_p) ne 0  then  header = *hdr_p
+    writefits, file, *data_p, header
+    return
+end
+
+; NOISE_STD_EV: compute st. dev. of gaussian noise in the image.
+
+PRO noise_std_ev, data, group_leader
+
+    on_error, 2
+    if  n_elements(*data.image.image) eq 0  then begin
+       msg = dialog_message('Please select data', /ERROR)
+       return
+    endif
+    xnoise, *data.image.image, *data.image.noise_std, WNUM = *data.draw, $
+         PATH = *data.path, DEFAULT_PAR = *data.image.noise_par, $
+         G_NOISE_PAR = *data.image.g_noise_par, PLOT_PAR = $
+         *data.image.plot_par, GROUP = group_leader
+    return
+end
+
+; REPLACE_BAD_EV: replace bad pixels in the input image.
+
+PRO replace_badpix_ev, data, group_leader
+
+    on_error, 2
+    if  n_elements(*data.image.image) eq 0  then begin
+       msg = dialog_message('Please select data', /ERROR)
+       return
+    endif
+    *data.image.image = xreplace_pix(*data.image.image, $
+                 *data.image.x_badpix, *data.image.y_badpix, $
+                 PATH = *data.path, WNUM = *data.draw, $
+                 DISPLAY_OPT = *data.image.image_display_par, $
+                 GROUP = group_leader)
+    return
+end
+
+; PSF_EXTRACT_EV: extract PSF from image.
+
+PRO psf_extract_ev, data, group_leader
+
+    on_error, 2
+    if  n_elements(*data.image.image) eq 0  then begin
+       msg = dialog_message('Please select data', /ERROR)
+       return
+    endif
+    rep = n_elements(*data.image.x_stars) ne 0 and $
+          n_elements(*data.image.y_stars) ne 0 and $
+          n_elements(*data.image.f_stars) ne 0 and $
+          n_elements(*data.image.stars) ne 0 and $
+          n_elements(*data.psf.psf) ne 0
+    xpsf_extract, *data.image.image, rep, *data.psf.psf, *data.psf.psf_fwhm, $
+                  *data.psf.x_psf, *data.psf.y_psf, *data.image.background, *data.image.backbox, $
+                  STARS = *data.image.stars, PSF = *data.psf.psf, $
+                  X_STARS = *data.image.x_stars, Y_STARS = *data.image.y_stars, $
+                  FLUXES = *data.image.f_stars, $
+                  DEFAULT_PAR = *data.psf.extract_par, $
+                  DISPLAYIMAGE = *data.image.image_display_par, $
+                  DISPLAYPSF = *data.psf.psf_display_par, $
+                  PATH = *data.path, GROUP = group_leader
+    if n_elements(*data.psf.psf) ne 0 then $
+       for rep = 1, 2 do *data.psf.psf = *data.psf.psf / total(*data.psf.psf)
+;   xpsf_extract, *data.image.image, *data.psf.psf, *data.psf.psf_fwhm, $
+;                 *data.psf.x_psf, *data.psf.y_psf, *data.image.background, $
+;                 DEFAULT_PAR = *data.psf.extract_par, $
+;                 DISPLAYIMAGE = *data.image.image_display_par, $
+;                 DISPLAYPSF = *data.psf.psf_display_par, $
+;                 PATH = *data.path, GROUP = group_leader
+;   if  n_elements(*data.psf.psf_fwhm) ne 0  then begin
+;      if  n_elements(*data.psf.extract_par) ne 0  then $
+;         n_fwhm = (*data.psf.extract_par).n_fwhm_back  else  n_fwhm = 9
+;      *data.image.backbox = round(n_fwhm * *data.psf.psf_fwhm)
+;   endif
+    return
+end
+
+; PSF_REPEAT_EV: repeat extraction procedure after 1st analysis.
+
+;PRO psf_repeat_ev, data
+
+;    on_error, 2
+;    if  n_elements(*data.image.image) eq 0  then begin
+;       msg = dialog_message('Load image first', /ERROR)
+;       return
+;    endif
+;    if  n_elements(*data.image.stars) eq 0  then begin
+;       msg = dialog_message('Analyze the image before', /ERROR)
+;       return
+;    endif
+;    if  n_elements(*data.psf.extract_par) * $
+;       n_elements(*data.psf.x_psf) eq 0  then begin
+;       msg = dialog_message('Run PSF extraction procedure first', /ERROR)
+;       return
+;    endif
+;    widget_control, /HOURGLASS
+;    xpsf_extract, *data.image.image, *data.psf.psf, *data.psf.psf_fwhm, $
+;                  *data.psf.x_psf, *data.psf.y_psf, *data.image.background, *data.image.backbox, $
+;                  STARS = *data.image.stars, PSF = *data.psf.psf, $
+;                  X_STARS = *data.image.x_stars, Y_STARS = *data.image.y_stars, $
+;                  FLUXES = *data.image.f_stars, $
+;                  DEFAULT_PAR = *data.psf.extract_par, $
+;                  DISPLAYIMAGE = *data.image.image_display_par, $
+;                  DISPLAYPSF = *data.psf.psf_display_par, $
+;                  PATH = *data.path, GROUP = group_leader
+;    if n_elements(*data.psf.psf) ne 0 then $
+;       for rep = 1, 2 do *data.psf.psf = *data.psf.psf / total(*data.psf.psf)
+;    return
+;end
+
+; PSF_SUPPORT_EV: PSF support event.
+
+PRO psf_support_ev, data, group_leader
+
+    on_error, 2
+    if  n_elements(*data.psf.psf) eq 0  then begin
+       msg = dialog_message('Please define PSF', /ERROR)
+       return
+    endif
+    *data.psf.psf = ximage_support(*data.psf.psf, *data.draw, $
+                       *data.psf.psf_display_par, $
+                       DEFAULT_PAR = *data.psf.support_par, $
+                       GROUP = group_leader)
+    for rep = 1, 2 do *data.psf.psf = *data.psf.psf / total(*data.psf.psf)
+    return
+end
+
+; PSF_SMOOTH_EV: PSF halo smooth event.
+
+PRO psf_smooth_ev, data, group_leader
+
+    on_error, 2
+    if  n_elements(*data.psf.psf) eq 0  then begin
+       msg = dialog_message('Please define PSF', /ERROR)
+       return
+    endif
+    *data.psf.psf = xpsf_smooth(*data.psf.psf, *data.draw, $
+                    *data.psf.psf_display_par, $
+                    DEFAULT_PAR = *data.psf.smooth_par, $
+                    GROUP = group_leader)
+    for rep = 1, 2 do *data.psf.psf = *data.psf.psf / total(*data.psf.psf)
+    return
+end
+
+; NORMALIZE_PSF_EV: PSF normalization event.
+
+PRO normalize_psf_ev, data
+
+    on_error, 2
+    if  n_elements(*data.psf.psf) eq 0  then begin
+       msg = dialog_message('Please define PSF', /ERROR)
+       return
+    endif
+    widget_control, /HOURGLASS
+    for  rep = 1, 2  do  *data.psf.psf = *data.psf.psf / total(*data.psf.psf)
+    return
+end
+
+; SELECT_REF_EV: select and save positions of reference stars in a given image.
+
+PRO select_ref_ev, data
+
+    on_error, 2
+    if  n_elements(*data.image.image) eq 0  then begin
+       msg = dialog_message('Please select data', /ERROR)
+       return
+    endif
+    display_image, *data.image.image, *data.draw, $
+             OPTIONS = *data.image.image_display_par
+    msg = dialog_message(['Select the reference stars.', '', $
+                    'Use the left button of your mouse; ' + $
+                    'push the right button to exit.'], /INFO)
+    if  n_elements(*data.psf.psf_fwhm) ne 0  then $
+       click_box = round(*data.psf.psf_fwhm)  else  click_box = 3
+    click_on_max, *data.image.image, /MARK, /SILENT, x, y, $
+            BOXSIZE = click_box, SYMSIZE = click_box
+    if  n_elements(x) eq 0 or n_elements(y) eq 0  then  return
+    file = dialog_pickfile(/WRITE, FILTER = '*.txt', PATH = *data.path, $
+          GET_PATH = path, TITLE = 'Select file to save reference stars')
+    if  file ne '' then begin
+       widget_control, /HOURGLASS
+       if  strpos(file, '.txt') lt 0  then  file = file + '.txt'
+       *data.path = path
+       out = [transpose(x),transpose(y)]
+       openw, lun, file, /GET_LUN
+       printf, lun, out  &  free_lun, lun
+    endif
+    return
+end
+
+; ASTROM_PHOTOM_EV: astrometry and photometry event.
+
+PRO astrom_photom_event, data, group_leader
+
+    on_error, 2
+    if  n_elements(*data.image.image) eq 0  then begin
+       msg = dialog_message('Load Image', /ERROR)
+       return
+    endif
+    if  n_elements(*data.psf.psf) eq 0  then begin
+       msg = dialog_message('Load or estimate PSF', /ERROR)
+       return
+    endif
+    if  n_elements(*data.psf.psf_fwhm) eq 0  then $
+       *data.psf.psf_fwhm = fwhm(*data.psf.psf, /CUBIC, MAG = 3)
+    if  n_elements(*data.image.backbox) eq 0  then $
+       *data.image.backbox = 9
+    xstarfinder_run, *data.image.image, *data.psf.psf, *data.psf.psf_fwhm, $
+         *data.image.background, *data.image.backbox, $
+         NOISE_STD = *data.image.noise_std, $
+         X_BAD = *data.image.x_badpix, Y_BAD = *data.image.y_badpix, $
+         STARS = *data.image.stars, $
+         *data.image.x_stars, *data.image.y_stars, *data.image.f_stars, $
+         *data.image.sx_stars, *data.image.sy_stars, *data.image.sf_stars, $
+         *data.image.c_stars, DEFAULT_PAR = *data.image.run_par, $
+         GROUP = group_leader, PATH = *data.path;, LOADFILE = *data.loadfile
+    if  n_elements(*data.image.f_stars) ne 0  then begin
+       *data.image.syn_field = *data.image.stars
+       if  n_elements(*data.image.background) ne 0  then $
+          *data.image.syn_field = *data.image.syn_field + *data.image.background
+       *data.image.res = *data.image.image - *data.image.syn_field
+    endif
+    return
+end
+
+; DISPLAY_STARS_EV: display detected sources on graphic window.
+
+PRO display_stars_ev, data
+
+    if  n_elements(*data.image.f_stars) eq 0  then begin
+       msg = dialog_message('Please run Astrometry and Photometry task before.', /ERROR)
+       return
+    endif
+    erase
+    display_image, *data.last_display, *data.draw, OPTIONS = *data.last_display_par
+    crosses, *data.image.image, /EX, *data.image.x_stars, *data.image.y_stars
+    return
+end
+
+
+; SAVE_LIST_EV: save list of detected stars.
+
+PRO save_list_ev, data
+
+    if  n_elements(*data.image.f_stars) eq 0  then begin
+       msg = dialog_message('Please run Astrometry and Photometry task before.', /ERROR)
+       return
+    endif
+    file = dialog_pickfile(/WRITE, FILTER = '*.txt', PATH = *data.path, $
+          GET_PATH = path, TITLE = 'Select file to save list of stars')
+    if  file ne '' then begin
+       widget_control, /HOURGLASS
+       if  strpos(file, '.txt') lt 0  then  file = file + '.txt'
+       *data.path = path
+       out = [transpose(*data.image.x_stars), $
+              transpose(*data.image.y_stars), $
+              transpose(*data.image.f_stars), $
+              transpose(*data.image.sx_stars), $
+              transpose(*data.image.sy_stars), $
+              transpose(*data.image.sf_stars), $
+              transpose(*data.image.c_stars)]
+       openw, lun, file, /GET_LUN, WIDTH = 200
+       printf,lun, '# x    y    f    x_err    y_err     f_err   corr  '
+       printf, lun, out  &  free_lun, lun
+    endif
+    return
+end
+
+
+; INIT_DATA: initialize pointers to image or PSF data.
+
+PRO init_data, data, field
+
+    on_error, 2
+    widget_control, /HOURGLASS
+    case  field  of
+       'image': begin
+          ptr_free, $
+             data.image.background, $
+             data.image.back_hdr, data.image.noise_std, $
+             data.image.x_badpix, data.image.y_badpix, $
+             data.image.x_stars, data.image.y_stars, data.image.f_stars, $
+             data.image.sx_stars, data.image.sy_stars, data.image.sf_stars, $
+             data.image.c_stars, data.image.stars, data.image.syn_field, $
+             data.psf.psf, data.psf.psf_hdr, data.psf.psf_fwhm, data.psf.x_psf, data.psf.y_psf
+          data.image.background = ptr_new(/ALLOCATE)
+          data.image.back_hdr = ptr_new(/ALLOCATE)
+          data.image.noise_std = ptr_new(/ALLOCATE)
+          data.image.x_badpix = ptr_new(/ALLOCATE)
+          data.image.y_badpix = ptr_new(/ALLOCATE)
+          data.image.x_stars = ptr_new(/ALLOCATE)
+          data.image.y_stars = ptr_new(/ALLOCATE)
+          data.image.f_stars = ptr_new(/ALLOCATE)
+          data.image.sx_stars = ptr_new(/ALLOCATE)
+          data.image.sy_stars = ptr_new(/ALLOCATE)
+          data.image.sf_stars = ptr_new(/ALLOCATE)
+          data.image.c_stars = ptr_new(/ALLOCATE)
+          data.image.stars = ptr_new(/ALLOCATE)
+          data.image.syn_field = ptr_new(/ALLOCATE)
+          data.image.res = ptr_new(/ALLOCATE)
+          data.psf.psf = ptr_new(/ALLOCATE)
+          data.psf.psf_hdr = ptr_new(/ALLOCATE)
+          data.psf.psf_fwhm = ptr_new(/ALLOCATE)
+          data.psf.x_psf = ptr_new(/ALLOCATE)
+          data.psf.y_psf = ptr_new(/ALLOCATE)
+          end
+       'psf': begin
+          ptr_free, data.psf.psf_fwhm, data.psf.x_psf, data.psf.y_psf
+          data.psf.psf_fwhm = ptr_new(/ALLOCATE)
+          data.psf.x_psf = ptr_new(/ALLOCATE)
+          data.psf.y_psf = ptr_new(/ALLOCATE)
+          end
+       endcase
+    return
+end
+
+; CHECK_PTR: check undefined heap variables in data structure.
+
+PRO check_ptr, data, action
+
+    on_error, 2
+    widget_control, /HOURGLASS
+    case  action  of
+       'in': begin
+          if  not ptr_valid(data.draw)  then  data.draw = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.path)  then  data.path = ptr_new(/ALLOCATE)
+;          if  not ptr_valid(data.loadfile)  then  data.loadfile = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.file)  then  data.file = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.last_display)  then  data.last_display = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.last_display_par)  then  data.last_display_par = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.other_display_par)  then  data.other_display_par = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.image)  then  data.image.image = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.image_display_par)  then  data.image.image_display_par = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.image_hdr)  then  data.image.image_hdr = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.background)  then  data.image.background = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.back_display_par)  then  data.image.back_display_par = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.back_hdr)  then  data.image.back_hdr = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.backbox)  then  data.image.backbox = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.noise_par)  then  data.image.noise_par = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.g_noise_par)  then  data.image.g_noise_par = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.plot_par)  then  data.image.plot_par = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.noise_std)  then  data.image.noise_std = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.x_badpix)  then  data.image.x_badpix = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.y_badpix)  then  data.image.y_badpix = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.run_par)  then  data.image.run_par = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.x_stars)  then  data.image.x_stars = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.y_stars)  then  data.image.y_stars = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.f_stars)  then  data.image.f_stars = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.sx_stars)  then  data.image.sx_stars = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.sy_stars)  then  data.image.sy_stars = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.sf_stars)  then  data.image.sf_stars = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.c_stars)  then  data.image.c_stars = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.stars)  then  data.image.stars = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.stars_display_par)  then  data.image.stars_display_par = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.syn_field)  then  data.image.syn_field = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.syn_display_par)  then  data.image.syn_display_par = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.res)  then  data.image.res = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.image.res_display_par)  then  data.image.res_display_par = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.psf.psf)  then  data.psf.psf = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.psf.extract_par)  then  data.psf.extract_par = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.psf.support_par)  then  data.psf.support_par = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.psf.smooth_par)  then  data.psf.smooth_par = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.psf.psf_display_par)  then  data.psf.psf_display_par = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.psf.psf_hdr)  then  data.psf.psf_hdr = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.psf.psf_fwhm)  then  data.psf.psf_fwhm = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.psf.x_psf)  then  data.psf.x_psf = ptr_new(/ALLOCATE)
+          if  not ptr_valid(data.psf.y_psf)  then  data.psf.y_psf = ptr_new(/ALLOCATE)
+          end
+       'out': begin
+          if  n_elements(*data.draw) eq 0  then  data.draw = ptr_new()
+          if  n_elements(*data.path) eq 0  then  data.path = ptr_new()
+;          if  n_elements(*data.loadfile) eq 0  then  data.loadfile = ptr_new()
+          if  n_elements(*data.file) eq 0  then  data.file = ptr_new()
+          if  n_elements(*data.last_display) eq 0  then  data.last_display = ptr_new()
+          if  n_elements(*data.last_display_par) eq 0  then  data.last_display_par = ptr_new()
+          if  n_elements(*data.other_display_par) eq 0  then  data.other_display_par = ptr_new()
+          if  n_elements(*data.image.image) eq 0  then  data.image.image = ptr_new()
+          if  n_elements(*data.image.image_display_par) eq 0  then  data.image.image_display_par = ptr_new()
+          if  n_elements(*data.image.image_hdr) eq 0  then  data.image.image_hdr = ptr_new()
+          if  n_elements(*data.image.background) eq 0  then  data.image.background = ptr_new()
+          if  n_elements(*data.image.back_display_par) eq 0  then  data.image.back_display_par = ptr_new()
+          if  n_elements(*data.image.back_hdr) eq 0  then  data.image.back_hdr = ptr_new()
+          if  n_elements(*data.image.backbox) eq 0  then  data.image.backbox = ptr_new()
+          if  n_elements(*data.image.noise_par) eq 0  then  data.image.noise_par = ptr_new()
+          if  n_elements(*data.image.g_noise_par) eq 0  then  data.image.g_noise_par = ptr_new()
+          if  n_elements(*data.image.plot_par) eq 0  then  data.image.plot_par = ptr_new()
+          if  n_elements(*data.image.noise_std) eq 0  then  data.image.noise_std = ptr_new()
+          if  n_elements(*data.image.x_badpix) eq 0  then  data.image.x_badpix = ptr_new()
+          if  n_elements(*data.image.y_badpix) eq 0  then  data.image.y_badpix = ptr_new()
+          if  n_elements(*data.image.run_par) eq 0  then  data.image.run_par = ptr_new()
+          if  n_elements(*data.image.x_stars) eq 0  then  data.image.x_stars = ptr_new()
+          if  n_elements(*data.image.y_stars) eq 0  then  data.image.y_stars = ptr_new()
+          if  n_elements(*data.image.f_stars) eq 0  then  data.image.f_stars = ptr_new()
+          if  n_elements(*data.image.sx_stars) eq 0  then  data.image.sx_stars = ptr_new()
+          if  n_elements(*data.image.sy_stars) eq 0  then  data.image.sy_stars = ptr_new()
+          if  n_elements(*data.image.sf_stars) eq 0  then  data.image.sf_stars = ptr_new()
+          if  n_elements(*data.image.c_stars) eq 0  then  data.image.c_stars = ptr_new()
+          if  n_elements(*data.image.stars) eq 0  then  data.image.stars = ptr_new()
+          if  n_elements(*data.image.stars_display_par) eq 0  then  data.image.stars_display_par = ptr_new()
+          if  n_elements(*data.image.syn_field) eq 0  then  data.image.syn_field = ptr_new()
+          if  n_elements(*data.image.syn_display_par) eq 0  then  data.image.syn_display_par = ptr_new()
+          if  n_elements(*data.image.res) eq 0  then  data.image.res = ptr_new()
+          if  n_elements(*data.image.res_display_par) eq 0  then  data.image.res_display_par = ptr_new()
+          if  n_elements(*data.psf.psf) eq 0  then  data.psf.psf = ptr_new()
+          if  n_elements(*data.psf.extract_par) eq 0  then  data.psf.extract_par = ptr_new()
+          if  n_elements(*data.psf.support_par) eq 0  then  data.psf.support_par = ptr_new()
+          if  n_elements(*data.psf.smooth_par) eq 0  then  data.psf.smooth_par = ptr_new()
+          if  n_elements(*data.psf.psf_display_par) eq 0  then  data.psf.psf_display_par = ptr_new()
+          if  n_elements(*data.psf.psf_hdr) eq 0  then  data.psf.psf_hdr = ptr_new()
+          if  n_elements(*data.psf.psf_fwhm) eq 0  then  data.psf.psf_fwhm = ptr_new()
+          if  n_elements(*data.psf.x_psf) eq 0  then  data.psf.x_psf = ptr_new()
+          if  n_elements(*data.psf.y_psf) eq 0  then  data.psf.y_psf = ptr_new()
+          end
+       endcase
+    return
+end
+
+; SESSION_EV: save or restore XStarFinder session.
+
+PRO session_ev, data, action
+
+    on_error, 2
+    case  action  of
+       'save': begin
+          file = dialog_pickfile(/WRITE, FILTER = '*.sav', $
+                          PATH = *data.path, GET_PATH = path)
+          if  file ne '' then begin
+             widget_control, /HOURGLASS
+             if  strpos(file, '.sav') lt 0  then  file = file + '.sav'
+             *data.path = path
+             check_ptr, data, 'out'
+             save, FILENAME = file, data
+             check_ptr, data, 'in'
+          endif
+          end
+       'restore': begin
+          file = dialog_pickfile(/READ, FILTER = '*.sav', $
+                          PATH = *data.path, GET_PATH = path)
+          if  file ne '' then begin
+             widget_control, /HOURGLASS
+             restore, file
+             check_ptr, data, 'in'
+             *data.path = path
+          endif
+          end
+    endcase
+    return
+end
+
+; XSTARFINDER_HELP_EV: display help file.
+
+PRO xstarfinder_help_ev, name, group
+
+    on_error, 2
+    file = '_help.txt'  &  title = ' help'
+    case strlowcase(name) of
+       'xstarfinder': begin
+          file = 'xstarfinder' + file
+          title = 'XStarFinder' + title
+          end
+       'image': begin
+          file = 'image' + file
+          title = 'Image' + title
+          end
+       'psf': begin
+          file = 'psf' + file
+          title = 'PSF' + title
+          end
+       'display': begin
+          file = 'display' + file
+          title = 'Display' + title
+          end
+    endcase
+    xdispfile, file_name('starfinder', file), TITLE = title, GROUP = group
+    return
+end
+
+; XSTARFINDER_EVENT: XStarFinder event handler.
+
+PRO xstarfinder_event, event
+
+    catch, error
+    if  error ne 0  then begin
+       msg = dialog_message(/ERROR, !err_string)
+       child = widget_info(event.top, /CHILD)
+       widget_control, child, SET_UVALUE = data, /NO_COPY
+       return
+    endif
+    child = widget_info(event.top, /CHILD)
+    widget_control, child, GET_UVALUE = data, /NO_COPY
+    quit_confirm = 0B
+
+    case event.value of
+
+       'Image.Load....Image': begin
+          load_image_ev, data.image.image, data.path, $
+                     HDR = data.image.image_hdr, /DISPLAY, $
+                     *data.draw, data.image.image_display_par, $
+                     LOADED = loaded
+          if  loaded  then begin
+             init_data, data, 'image'
+             data.last_display = data.image.image
+             data.last_display_par = data.image.image_display_par
+          endif
+          end
+       'Image.Load....Background': begin
+          load_image_ev, data.image.background, data.path, $
+                     HDR = data.image.back_hdr, /DISPLAY, $
+                     *data.draw, data.image.back_display_par
+          data.last_display = data.image.background
+          data.last_display_par = data.image.back_display_par
+          end
+       'Image.Noise.Load': load_image_ev, data.image.noise_std, data.path
+       'Image.Noise.Compute': noise_std_ev, data, event.top
+       'Image.Bad Pixels': replace_badpix_ev, data, event.top
+       'Image.Reference sources': select_ref_ev, data
+       'Image.Help': xstarfinder_help_ev, 'image', event.top
+       'Image.Save.Image': $
+          save_image_ev, data.image.image, data.path, $
+                      HDR = data.image.image_hdr
+       'Image.Save.Background': $
+          save_image_ev, data.image.background, data.path, $
+                     HDR = data.image.back_hdr
+       'Image.Save.Detected stars': $
+          save_image_ev, data.image.stars, data.path
+       'Image.Save.Synthetic field': $
+          save_image_ev, data.image.syn_field, data.path
+       'Image.Save.Residual image': $
+          save_image_ev, data.image.res, data.path
+       'Image.Save.List of stars': save_list_ev, data
+
+       'PSF.Load...': begin
+          load_image_ev, data.psf.psf, data.path, $
+                     HDR = data.psf.psf_hdr, /DISPLAY, $
+                     *data.draw, data.psf.psf_display_par, $
+                     LOADED = loaded
+          if  loaded  then begin
+             init_data, data, 'psf'
+             data.last_display = data.psf.psf
+             data.last_display_par = data.psf.psf_display_par
+             for rep = 1, 2 do *data.psf.psf = *data.psf.psf / total(*data.psf.psf)
+          endif
+          end
+       'PSF.Extract from image': psf_extract_ev, data, event.top
+       'PSF.Post process.Support': psf_support_ev, data, event.top
+       'PSF.Post process.Halo smoothing': psf_smooth_ev, data, event.top
+;      'PSF.Normalize': normalize_psf_ev, data
+       'PSF.Help': xstarfinder_help_ev, 'psf', event.top
+       'PSF.Save': $
+           save_image_ev, data.psf.psf, data.path, HDR = data.psf.psf_hdr
+
+       'Astrometry and Photometry': astrom_photom_event, data, event.top
+
+       'Display detected sources': display_stars_ev, data
+
+       'Compare Lists': $
+          xcompare_lists, *data.draw, PATH = *data.path, GROUP = event.top
+
+       'Display.Select data.Image': begin
+          display_image_ev, *data.draw, data.path, $
+                     data.image.image_display_par, $
+                     data.image.image, HDR = data.image.image_hdr
+          data.last_display = data.image.image
+          data.last_display_par = data.image.image_display_par
+          end
+       'Display.Select data.PSF': begin
+          display_image_ev, *data.draw, data.path, $
+                     data.psf.psf_display_par, $
+                     data.psf.psf, HDR = data.psf.psf_hdr
+          data.last_display = data.psf.psf
+          data.last_display_par = data.psf.psf_display_par
+          end
+       'Display.Select data.Background': begin
+          display_image_ev, *data.draw, data.path, $
+                     data.image.back_display_par, $
+                     data.image.background, HDR = data.image.back_hdr
+          data.last_display = data.image.background
+          data.last_display_par = data.image.back_display_par
+          end
+       'Display.Select data.Detected stars': begin
+          display_image_ev, *data.draw, data.path, $
+                     data.image.stars_display_par, $
+                     data.image.stars
+          data.last_display = data.image.stars
+          data.last_display_par = data.image.stars_display_par
+          end
+       'Display.Select data.Synthetic field': begin
+          display_image_ev, *data.draw, data.path, $
+                     data.image.syn_display_par, $
+                     data.image.syn_field
+          data.last_display = data.image.syn_field
+          data.last_display_par = data.image.syn_display_par
+          end
+       'Display.Select data.Residual image': begin
+          display_image_ev, *data.draw, data.path, $
+                     data.image.res_display_par, $
+                     data.image.res
+          data.last_display = data.image.res
+          data.last_display_par = data.image.res_display_par
+          end
+       'Display.Select data.Other...': begin
+          ptr_free, data.other_display_par
+          data.other_display_par = ptr_new(/ALLOCATE)
+          display_image_ev, *data.draw, data.path, $
+                            data.other_display_par, FILE = data.file
+          data.last_display = data.file
+          data.last_display_par = data.other_display_par
+          end
+       'Display.Options': $
+          display_options_ev, *data.draw, data.last_display, $
+                    data.last_display_par, event.top
+       'Display.Help': xstarfinder_help_ev, 'display', event.top
+
+       'Session.Save': session_ev, data, 'save'
+       'Session.Restore': session_ev, data, 'restore'
+
+       'Help': xstarfinder_help_ev, 'xstarfinder', event.top
+
+       'Quit': begin
+          msg = dialog_message(/QUESTION, 'Really quit XStarFinder?')
+          quit_confirm = strlowcase(msg) eq 'yes'
+          if  quit_confirm  then begin
+             xstarfinder_del, data     ; de-allocates heap variables
+             widget_control, event.top, /DESTROY
+          endif
+          end
+
+       else:
+
+    endcase
+    if  event.value ne 'Quit' or $
+       event.value eq 'Quit' and not quit_confirm  then $
+       widget_control, child, SET_UVALUE = data, /NO_COPY
+    return
+end
+
+
+
+;;; WIDGET DEFINITION PROCEDURES/FUNCTIONS
+
+; XSTARFINDER_PROCESSING_MENU: define menu 1.
+
+FUNCTION xstarfinder_processing_menu
+
+    return, ['1\Image', $
+          '1\Load...', '0\Image', '2\Background', $
+          '1\Noise', '0\Compute', '2\Load', $
+          '0\Bad Pixels', $
+          '0\Reference sources', $
+          '1\Save', '0\Image', '0\Background', '0\Detected stars', $
+             '0\Synthetic field', '0\Residual image', '2\List of stars', $
+          '2\Help', $   ; end of Image sub-menu
+          '1\PSF', $
+          '0\Load...', '0\Extract from image', $
+          '1\Post process', '0\Support', '2\Halo smoothing', $
+;       '0\Save', '2\Help',    $   ; end of PSF sub-menu
+          '0\Normalize', '0\Save', '2\Help',  $   ; end of PSF sub-menu
+          '0\Astrometry and Photometry', $   ; Astrometry - Photometry button
+          '0\Display detected sources', $   ; Display detected sources button
+          '0\Compare Lists']   ; Compare Lists button
+end
+
+; XSTARFINDER_UTILITIES_MENU: define menu 2.
+
+FUNCTION xstarfinder_utilities_menu
+
+    return, ['1\Display', $
+          '1\Select data', '0\Image', '0\PSF', '0\Background', $
+          '0\Detected stars', '0\Synthetic field', '0\Residual image', '2\Other...', $
+          '0\Options', '2\Help', $
+          '1\Session', '0\Save', '2\Restore', '0\Help', '0\Quit']
+end
+
+; XSTARFINDER_DEF: define structure of pointers to the data
+; required by the program.
+
+FUNCTION xstarfinder_def
+
+    return, $
+    { image: $     ; image data
+       {image: ptr_new(/ALLOCATE), $
+        image_display_par: ptr_new(/ALLOCATE), $
+        image_hdr: ptr_new(/ALLOCATE), $
+        background: ptr_new(/ALLOCATE), $
+        back_display_par: ptr_new(/ALLOCATE), $
+        back_hdr: ptr_new(/ALLOCATE), $
+        backbox: ptr_new(/ALLOCATE), $
+        noise_par: ptr_new(/ALLOCATE), $
+        g_noise_par: ptr_new(/ALLOCATE), $
+        plot_par: ptr_new(/ALLOCATE), $
+        noise_std: ptr_new(/ALLOCATE), $
+        x_badpix: ptr_new(/ALLOCATE), y_badpix: ptr_new(/ALLOCATE), $
+        run_par: ptr_new(/ALLOCATE), $
+        x_stars: ptr_new(/ALLOCATE), $
+        y_stars: ptr_new(/ALLOCATE), $
+        f_stars: ptr_new(/ALLOCATE), $
+        sx_stars: ptr_new(/ALLOCATE), $
+        sy_stars: ptr_new(/ALLOCATE), $
+        sf_stars: ptr_new(/ALLOCATE), $
+        c_stars: ptr_new(/ALLOCATE), $
+        stars: ptr_new(/ALLOCATE), stars_display_par: ptr_new(/ALLOCATE), $
+        syn_field: ptr_new(/ALLOCATE), syn_display_par: ptr_new(/ALLOCATE), $
+        res: ptr_new(/ALLOCATE), res_display_par: ptr_new(/ALLOCATE)}, $
+      psf: $     ; PSF data
+       {psf: ptr_new(/ALLOCATE), $
+        extract_par: ptr_new(/ALLOCATE), $
+        support_par: ptr_new(/ALLOCATE), $
+        smooth_par: ptr_new(/ALLOCATE), $
+        psf_display_par: ptr_new(/ALLOCATE), $
+        psf_hdr: ptr_new(/ALLOCATE), $
+        psf_fwhm: ptr_new(/ALLOCATE), $
+        x_psf: ptr_new(/ALLOCATE), y_psf: ptr_new(/ALLOCATE)}, $
+      draw: ptr_new(/ALLOCATE),           $
+      path: ptr_new(/ALLOCATE),           $
+;      loadfile: ptr_new(/ALLOCATE),       $
+      file: ptr_new(/ALLOCATE),           $
+      last_display: ptr_new(/ALLOCATE),   $
+      other_display_par: ptr_new(/ALLOCATE), $
+      last_display_par: ptr_new(/ALLOCATE) }
+end
+
+; XSTARFINDER_DEL: delete heap variables.
+
+PRO xstarfinder_del, data
+
+    on_error, 2
+    ; de-allocate memory pointed by data structure fields
+    ptr_free, data.image.image, data.image.image_display_par, $
+         data.image.image_hdr, data.image.background, $
+         data.image.back_display_par, data.image.back_hdr, $
+         data.image.backbox, data.image.noise_par, $
+         data.image.g_noise_par, data.image.plot_par, $
+         data.image.noise_std, data.image.x_badpix, data.image.y_badpix, $
+         data.image.run_par, data.image.x_stars, data.image.y_stars, $
+         data.image.f_stars, data.image.sx_stars, data.image.sy_stars, $
+         data.image.sf_stars, data.image.c_stars, data.image.stars, $
+         data.image.stars_display_par, data.image.syn_field, $
+         data.image.syn_display_par, $
+         data.image.res_display_par, $
+         data.psf.psf, data.psf.extract_par, data.psf.support_par, $
+         data.psf.smooth_par, data.psf.psf_display_par, $
+         data.psf.psf_hdr, data.psf.psf_fwhm, $
+         data.psf.x_psf, data.psf.y_psf, $
+         data.draw, data.path, data.file, data.last_display, $
+;         data.draw, data.path, data.loadfile, data.file, data.last_display, $
+         data.other_display_par, data.last_display_par
+    ; de-allocate any inaccessible heap variables
+    heap_gc
+    return
+end
+
+; XSTARFINDER: XStarFinder widget definition module.
+
+PRO xstarfinder, GROUP = group, BLOCK = block, UVALUE = uvalue
+
+    on_error, 2
+    ; define top level base, partitioned into two parts: left and right
+    if  n_elements(uvalue) eq 0  then  uvalue = 0B
+    s = round(1.0 * min(get_screen_size()))
+    base = widget_base(TITLE = 'XStarFinder', COLUMN = 2, UVALUE  = uvalue)
+    left_base = widget_base(base, ROW = 2)
+    right_base = widget_base(base)
+    ; define commands (in left part of base)
+    menu = xstarfinder_processing_menu()
+    processing = cw_pdmenu(left_base, menu, /COLUMN, /RETURN_FULL_NAME)
+    menu = xstarfinder_utilities_menu()
+    util = cw_pdmenu(left_base, menu, /COLUMN, /RETURN_FULL_NAME)
+    ; define draw window (in right part of base)
+    draw = widget_draw(right_base, SCR_XSIZE = s, SCR_YSIZE = s, $
+                 /ALIGN_CENTER, RETAIN = 2)
+    ; realize widgets
+    widget_control, base, /REALIZE
+    widget_control, draw, GET_VALUE = wnum
+    ; allocate memory for global data and store it in user value
+    ; of the left base
+    data = xstarfinder_def()  &  *data.draw = wnum
+    widget_control, left_base, SET_UVALUE = data, /NO_COPY
+    ; register with XManager
+    xmanager, 'xstarfinder', base, EVENT_HANDLER = 'xstarfinder_event', $
+           GROUP_LEADER = group, NO_BLOCK = not keyword_set(block) and 1B
+    return
+end
diff --git a/xstarfinder_help.txt b/xstarfinder_help.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9481f4fac0d358fe78a102d7c6700d5674d3f342
--- /dev/null
+++ b/xstarfinder_help.txt
@@ -0,0 +1,199 @@
+  XSTARFINDER - v1.8
+
+
+
+  1) GENERAL DESCRIPTION.
+
+  XStarFinder is a general purpose astrometry and photometry
+  toolkit for crowded stellar fields analysis.
+  It has been designed for well-sampled high and low Strehl
+  images. The current version considers the PSF constant over
+  the field of view; a method to handle anisoplanatic effects
+  in wide-field Adaptive Optics observations is under
+  development.
+
+
+
+  2) MAIN MENU DESCRIPTION.
+
+  The controls in the main menu are:
+
+  'Image' pull-down menu:
+      Load image from FITS file, display it and perform basic
+      operations (compute standard deviation of gaussian noise,
+      repair bad pixels, select reference sources by mouse click).
+      Save by-products of the analysis (e.g. image after repair
+      of saturated stars, synthetic field, background estimate,
+      etc.).
+
+  'PSF' pull-down menu:
+      Load PSF from FITS file or extract it directly from the
+      image. The PSF extraction task allows the user to repair
+      the saturated stars in the input image.
+      The 'PSF' pull-down menu includes tasks for basic post-
+      processing of the extracted PSF (e.g. support masking,
+      halo smoothing, normalization) and allows one to save
+      the retrieved estimate of the PSF.
+
+  'Astrometry and Photometry' button:
+      Detect stars in the input image, performing astrometry and
+      photometry. The PSF, either load from a file or extracted
+      from the image, is used as a rigid template which may be
+      shifted and scaled to match other objects in the field.
+      The list of detected stars can be saved to an ASCII file.
+
+  'Display detected sources' button:
+      After running the 'Astrometry and Photometry' task, this 
+      command displays the detected sources with a '+' symbol, 
+      superimposed on the last displayed image. 
+
+  'Compare Lists' button:
+      Compare two data sets representing the results obtained
+      on different images of the same field (e.g. in different
+      filters) and create a simple color-magnitude diagram.
+      The data sets are supposed to be reciprocally translated
+      and rotated. The plotted diagram can be saved as
+      PostScript file.
+
+  'Display' pull-down menu:
+      Define display options (intensity range, stretch, chopping
+      threshold, color table) for the currently displayed image.
+
+  'Session' pull-down menu:
+      Save current session or restore a previously saved one.
+
+  'Help' button:
+      Display this help file. Notice that every secondary widget
+      application is provided with its own help page.
+
+  'Quit' button:
+      Exit XStarFinder.
+
+
+
+  3) NOTES ON VARIABLES.
+
+  XStarFinder is a compound application. The main widget which
+  appears on the screen (called XStarFinder) is nothing more than
+  an interface allowing the user to call different widget-based
+  applications, in order to perform various operations on the
+  stellar field image.
+  The main widget defines a memory area to store some 'global'
+  variables, namely
+  - image: the stellar field
+  - PSF: array containing an image of the Point Spread Function
+  - noise: array, with the same size as the image, containing the
+       noise standard deviation for each image pixel
+  - background: array, with the same size as the image, with an
+       estimate of the background emission. Available after PSF
+       extraction or stellar field analysis
+  - detected stars: synthetic image, containing one replica of the
+       PSF for each detected star in the field. Available after
+       stars detection
+  - synthetic field: sum of background array and detected stars
+  - residual image: difference of image and synthetic field
+  - list of detected stars: positions, fluxes, formal errors and
+       correlation coefficients. Available after stars detection
+  - other data and parameters.
+  The global variables are maintained and modified in the course
+  of the current session. As one of these variables is processed
+  by some application, its previous value is overwritten: if the
+  user wishes to keep track of the values assumed by the variable
+  in the course of the session, he/she should save the variable
+  itself or the entire session whenever necessary.
+  All the global data are basically divided into two groups:
+  those associated to the image (image, background, noise array,
+  stellar field model, list of detected stars, ...) and those
+  associated to the PSF (PSF array, coordinates of stars selected
+  by the user to form the PSF, ...). Whenever the user loads a new
+  image or a new PSF, all the associated data are erased, to avoid
+  'mixing' different data. The only exception is represented by
+  the default parameters of the secondary widgets applications
+  (see below): in this case the user selected parameters are saved.
+  Every secondary widget application has a set of default
+  parameters, which can be modified interactively by the user.
+  The user-defined values become the new default values of the
+  widget's set of parameters until the user quits XStarFinder
+  without saving the current session. This feature may help the
+  user to analyze two images of the same field. Of course, if the
+  observations were taken at different wavelengths, all the
+  'structural' parameters (e.g. those related to the PSF FWHM,
+  as the box size for PSF extraction) must be scaled properly.
+  Nevertheless, saving the user-defined values of the widgets'
+  parameters might be tricky in some situations, for instance
+  when two images of different targets and/or in different
+  observing conditions are analyzed in sequence. In these cases
+  it is recommended to close the current XStarFinder session
+  and open a new one, in order to restore the default values of
+  the parameters.
+
+ 
+
+  4) NOTES ON INPUT/OUTPUT.
+
+  XStarFinder can load/save images from/to FITS files. Every
+  output FITS file has the same header as the corresponding input
+  file. A minimal default header is written when the saved item
+  has no corresponding input (e.g. the PSF when it is extracted
+  from the stellar field).
+  It is strongly recommended to avoid overwriting existing FITS
+  files, to avoid losing important header information.
+
+ 
+
+  5) MODIFICATIONS.
+  
+  * Main menu
+    The button 'Display detected sources' allows to display the 
+    detected stars after running the 'Astrometry and Photometry' task. 
+    Each detected source is marked by a '+' sign. 
+
+  * PSF extraction
+    The task "Repeat PSF extraction" has been removed. Now, in order 
+    to repeat the PSF estimation, the normal task "Extract from image" 
+    has to be used instead. This allows greater flexibility in the 
+    selection of the parameters. 
+    The possibility to select by mouse-click the contaminating sources 
+    around the candidate stars for PSF estimation, previously removed, 
+    has been restored. However this option is only available in the 
+    first PSF extraction. Once the image has been analyzed and the 
+    stellar sources have been detected by the program, if the user 
+    wants to obtain a new PSF estimate she/he is not prompted to select 
+    the contaminating sources around the PSF stars: these secondary 
+    sources are automatically subtracted, based upon the information 
+    available from the previous image analysis.
+    Three strategies are now available to combine pixel-by-pixel the 
+    stars selected for the PSF estimation: median, minimum and mean.
+
+  * Astrometry/Photometry
+    The "Deblend" option, previously removed, has been restored.
+    The minimum acceptable distance between any two acceptable stars 
+    (this parameter was coded in the STARFINDER.PRO module) has now 
+    been added as a parameter in the GUI. The default is 1, i.e. 1 PSF 
+    FWHM is the default minimum acceptable distance between two sources. 
+    Two options concerning the background have been added in the GUI: 
+    the possibility to keep the background map (used in the detection 
+    and correlation analysis of the sources) fixed and the option to 
+    avoid fitting the local background below a given source with a 
+    tilted plane (in this case, the local background is extracted from 
+    the global background map and kept fixed in the fitting). 
+    Finally, it is possible to load a known list of sources and avoid
+    the detection phase. The loaded sources are just fitted. If the fit 
+    of a given source fails, the source is rejected.
+
+  * Background
+    The background is estimated by default by interpolating a set 
+    of local background measurements carried out on a grid of 
+    sub-regions in the image. This method is applied by 
+    XStarFinder_Run on the image cleaned from the sources known so 
+    far.
+    An alternative background estimation method is available in 
+    XStarFinder_Run: it consists of a median filtering of the image. 
+    This method, when applied on the image cleaned from the known 
+    stars, may be useful to estimate the background contribution 
+    when this is very irregular. If applied in the very first pass 
+    of XStarFinder_Run, this method may overestimate the background 
+    below bright sources.
+    The background estimate calculated by XStarFinder_Run is also 
+    passed to XPsf_Extract, when this task is called to refine the PSF 
+    estimate.
\ No newline at end of file
diff --git a/xstarfinder_run.pro b/xstarfinder_run.pro
new file mode 100644
index 0000000000000000000000000000000000000000..e8d83cbf0f4d89ebe175994f71cc46856b9c95dd
--- /dev/null
+++ b/xstarfinder_run.pro
@@ -0,0 +1,467 @@
+; $Id: xstarfinder_run, v 1.6 Apr 2012 e.d. $
+;
+;+
+; NAME:
+;   XSTARFINDER_RUN
+;
+; PURPOSE:
+;   Widget interface for the STARFINDER procedure.
+;   Detect stars in a stellar field and determine astrometry and photometry.
+;
+; CATEGORY:
+;   Widgets. Signal processing.
+;
+; CALLING SEQUENCE:
+;   XSTARFINDER_RUN, Image, Psf, Psf_fwhm, Background, X, Y, F, Sx, Sy, Sf, C
+;
+; INPUTS:
+;   Image:    Stellar field
+;
+;   Psf:  2D array, containing the Point Spread Function.
+;
+;   Psf_fwhm: PSF FWHM.
+;
+;   Background:   2D array, containing an initial guess of the image background
+;
+;   Back_Box: Box size to compute the background.
+;
+; KEYWORD PARAMETERS:
+;   X_BAD, Y_BAD: Coordinates of bad pixels.
+;
+;   PATH: Initial path for file browsing when saving the results.
+;     If the argument of the keyword is a named variable, its value
+;     is overwritten.
+;
+;   DEFAULT_PAR:  Structure of default parameters for the widget's form.
+;
+;   GROUP: XPsf_Extract group leader.
+;
+;   UVALUE: XPsf_Extract user value.
+;
+; OUTPUTS:
+;   Background:   2D array, containing the updated image background
+;
+;   X, Y: Positions of detected stars. Origin is at (0, 0).
+;
+;   F:    Stellar fluxes, referred to the normalization of the input Psf.
+;
+;   Sx, Sy, Sf:   Formal errors on astrometry and photometry. Available
+;     only if the necessary information on the image noise are supplied.
+;
+;   C:    Correlation coefficient of each detected star. The objects detected
+;     and analyzed as 'blends' have the correlation coefficient set to
+;     -1 by default.
+;
+; OPTIONAL OUTPUTS:
+;   NOISE_STD:    2D array, containing an estimate of the noise standard
+;     deviation for each pixel in the input image. If undefined on input,
+;     it can be read from file.
+;
+;   STARS:    Image model released by StarFinder, given by a superposition
+;     of shifted scaled PSFs, one for eaach detected star.
+;
+;   DEFAULT_PAR:  Set this keyword to a named variable to get the
+;     structure of parameters set by the widget's user.
+;
+; SIDE EFFECTS:
+;   Initiates the XMANAGER if it is not already running.
+;
+; RESTRICTIONS:
+;   The Help menu opens the file
+;   '/starfinder/xstarfinder_run_help.txt'.
+;
+; PROCEDURE:
+;   Create and register the widget as a modal widget.
+;   Then let the user define and or/modify the analysis options and apply
+;   them to the input image. The results may be saved on a text a file.
+;
+; MODIFICATION HISTORY:
+;   Written by: Emiliano Diolaiti, September 1999
+;   Updates:
+;   1) Enhanced error handling in event-handler
+;      (Emiliano Diolaiti, April 2000).
+;   2) BACKGROUND and BACK_BOX are now parameters (E. D., August 2004).
+;   3) Removed DEBLEND options (E. D., August 2004).
+;   4) Added following options in the GUI:
+;      * Upgrade background map
+;      * Fit local background with tilted plane
+;      * Set minimum source distance (E. D., July 2006).
+;   5) Added 'Load list' command, to load an input list of sources to
+;      be fitted, without any search (E. D., August 2006).
+;   6) Modified some keyword settings in call to STARFINDER (E.D., March 2012).
+;      Modified settings are: 
+;      a) Background estimation --> removed /SKY_MEDIAN, set CUBIC = -0.5
+;   7) Output text file with parameters of detected sources is now on 7 columns 
+;      (E.D., March 2012).
+;   8) Restored DEBLEND options. Two modes available: "Deblend detected sources" 
+;      and "Deblend rejected sources" (E. D., April 2012).
+;   9) Added 'Fit only fluxes' command, available when list of sources is loaded 
+;     (E. D., April 2012).
+;   10) Slightly changed widget design (E. D., April 2012).
+;   11) Added option to estimate background by median filtering. Default is 
+;      local estimate + interpolation (E. D., April 2012).
+;-
+
+; XSTARFINDER_RUN_EVENT: XStarFinder_Run event handler.
+
+PRO xstarfinder_run_event, event
+
+    catch, error
+    if  error ne 0  then begin
+       msg = dialog_message(/ERROR, !err_string)
+       child = widget_info(event.top, /CHILD)
+       widget_control, child, SET_UVALUE = data, /NO_COPY
+       close, /ALL
+       return
+    endif
+    ; Get user value
+    child = widget_info(event.top, /CHILD)
+    widget_control, child, GET_UVALUE = data, /NO_COPY
+    ; Event case
+    event_id = event.id  &  id = (*data).id
+    case event_id of
+       id.noise: begin
+          widget_control, id.noise, GET_VALUE = noise
+;          (*data).par.noise = noise
+          widget_control, id.rel_thresh, GET_VALUE = rel_thresh
+          rel_thresh = (rel_thresh eq 1 and noise eq 1) and 1B
+;          (*data).par.rel_thresh = rel_thresh
+          widget_control, id.rel_thresh, SET_VALUE = rel_thresh, $
+                      SENSITIVE = (noise eq 1) and 1B
+          end
+       id.bkg: begin
+          widget_control, id.bkg, GET_VALUE = bkg
+;          (*data).par.bkg = bkg
+          widget_control, id.bbox, SENSITIVE = bkg and 1B
+          widget_control, id.bmeth, SENSITIVE = bkg and 1B
+          end
+       id.load: begin
+          file = dialog_pickfile(/READ, PATH = *(*data).path, GET_PATH = path)
+          if file ne '' then begin
+             *(*data).loadfile = file
+             *(*data).path = path
+             widget_control, id.fluxopt, SENSITIVE = 1B
+             widget_control, id.cthresh, SENSITIVE = 0B
+             widget_control, id.csub, SENSITIVE = 0B
+             widget_control, id.bkg, SENSITIVE = 0B
+             widget_control, id.bbox, SENSITIVE = 0B
+             widget_control, id.bmeth, SENSITIVE = 0B
+             widget_control, id.deblend, SENSITIVE = 0B
+             widget_control, id.deblost, SENSITIVE = 0B
+          endif
+          end
+       id.proc: begin
+          ; Read out form and store parameters
+          widget_control, id.dthresh, GET_VALUE = threshold
+          str_threshold = threshold.tag0
+          (*data).par.dthresh = str_threshold
+          threshold = float(str_sep(strcompress(str_threshold, /REMOVE_ALL), ','))
+          widget_control, id.rel_thresh, GET_VALUE = rel_thresh
+          (*data).par.rel_thresh = rel_thresh
+          rel_thresh = (rel_thresh eq 1) and 1B
+          widget_control, id.cthresh, GET_VALUE = min_correlation
+          min_correlation = min_correlation.tag0
+          (*data).par.cthresh = min_correlation
+          widget_control, id.csub, GET_VALUE = correl_mag
+          correl_mag = correl_mag.tag0 > 1
+          (*data).par.csub = correl_mag
+          widget_control, id.noise, GET_VALUE = noise
+          (*data).par.noise = noise
+          if  noise eq 1  then  noise_std = *(*data).noise_std
+          widget_control, id.bkg, GET_VALUE = bkg
+          (*data).par.bkg = bkg
+          widget_control, id.bbox, GET_VALUE = bbox
+          bbox = bbox.tag0
+          (*data).par.bbox = bbox
+          (*data).back_box = bbox
+          if bkg and 1B then back_box = round(bbox * (*data).psf_fwhm)
+          widget_control, id.bmeth, GET_VALUE = bmeth
+          (*data).par.bmeth = bmeth
+          sky_median = (bmeth eq 1) and 1B
+          widget_control, id.slant, GET_VALUE = slant
+          (*data).par.slant = slant
+          no_slant = (not slant) and 1B
+          widget_control, id.mindist, GET_VALUE = mindist
+          mindist = mindist.tag0
+          (*data).par.mindist = mindist
+          widget_control, id.deblend, GET_VALUE = deblend
+          (*data).par.deblend = deblend
+          deblend = (deblend eq 1) and 1B
+          widget_control, id.deblost, GET_VALUE = deblost
+          (*data).par.deblost = deblost
+          deblost = (deblost eq 1) and 1B
+          widget_control, id.niter, GET_VALUE = niter
+          niter = niter.tag0
+          (*data).par.niter = niter
+          widget_control, id.fluxopt, GET_VALUE = fluxopt
+          (*data).par.fluxopt = fluxopt
+          fluxopt = (fluxopt eq 1) and (n_elements(*(*data).loadfile) ne 0) and 1B
+          if n_elements(*(*data).loadfile) ne 0 then begin
+             xyf = read_float_data(*(*data).loadfile, 3)
+             x_input = transpose(xyf[0,*])
+             y_input = transpose(xyf[1,*])
+             f_input = transpose(xyf[2,*])
+          endif
+          ; Call STARFINDER and store results
+          if  str_threshold eq ''  then $
+             msg = dialog_message(/ERROR, ['Enter one or more detection thresholds', $
+                           'separated by commas.']) $
+          else begin
+             widget_control, /HOURGLASS
+;             minif = round((*data).psf_fwhm / 2)
+             starfinder, *(*data).image, *(*data).psf, $
+                   X_BAD = *(*data).x_bad, Y_BAD = *(*data).y_bad, $
+;                   BACKGROUND = *(*data).background, BACK_BOX = back_box, /SKY_MEDIAN, $
+;                   BACKGROUND = *(*data).background, BACK_BOX = back_box, CUBIC = -0.5, $;/SKY_MEDIAN, $
+                   BACKGROUND = *(*data).background, BACK_BOX = back_box, $
+                   CUBIC = -0.5, SKY_MEDIAN = sky_median, $
+                   threshold, REL_THRESHOLD = rel_thresh, /PRE_SMOOTH, $
+                   NOISE_STD = *(*data).noise_std, min_correlation, $
+                   CORREL_MAG = correl_mag, INTERP_TYPE = 'I', $
+                   NO_SLANT = no_slant, MIN_DISTANCE = mindist, $
+                   DEBLEND = deblend, DEBLOST = deblost, $
+                   N_ITER = niter, /SILENT, $
+                   X_INPUT = x_input, Y_INPUT = y_input, F_INPUT = f_input, $
+                   FLUXOPT = fluxopt, $
+                   x, y, f, sx, sy, sf, c, STARS = *(*data).stars
+             nstars = n_elements(f)
+             msg = dialog_message(/INFO, strcompress(string(nstars)) + ' detected stars.')
+             if  nstars ne 0  then begin
+                *(*data).x = [x]  &  *(*data).sx = [sx]
+                *(*data).y = [y]  &  *(*data).sy = [sy]
+                *(*data).f = [f]  &  *(*data).sf = [sf]
+                *(*data).c = [c]
+             endif
+          endelse
+          end
+       id.sav: begin
+          if  n_elements(*(*data).f) ne 0  then begin
+             file = dialog_pickfile(/WRITE, FILTER = '*.txt', $
+                    PATH = *(*data).path, GET_PATH = path)
+             if  file ne ''  then begin
+                widget_control, /HOURGLASS
+                out = [transpose(*(*data).x), $
+                      transpose(*(*data).y), $
+                      transpose(*(*data).f), $
+                      transpose(*(*data).sx), $
+                      transpose(*(*data).sy), $
+                      transpose(*(*data).sf), $
+                      transpose(*(*data).c)]
+                if  strpos(file, '.txt') lt 0  then  file = file + '.txt'
+                *(*data).path = path
+                openw, lun, file, /GET_LUN, WIDTH = 200
+                printf,lun, '# x    y    f    x_err    y_err     f_err   corr  '
+                printf, lun, out  &  free_lun, lun
+             endif
+          endif
+          end
+       id.hlp: $
+          xdispfile, file_name('starfinder', 'xstarfinder_run_help.txt'), $
+                TITLE = 'XStarFinder_Run help', /MODAL
+       id.ex: begin
+          widget_control, child, SET_UVALUE = data, /NO_COPY
+          widget_control, event.top, /DESTROY
+          end
+       else:
+    endcase
+    if  event_id ne id.ex  then $
+       widget_control, child, SET_UVALUE = data, /NO_COPY
+    return
+end
+
+; XSTARFINDER_RUN_DEF: define data structure.
+
+FUNCTION xstarfinder_run_def, id, par, image, psf, background, back_box, noise_std, $
+                              x_bad, y_bad, psf_fwhm, path, loadfile
+
+    data = {id: id, par: par, path: ptr_new(path), loadfile: ptr_new(loadfile), $
+         image: ptr_new(image, /NO_COPY), $
+         psf: ptr_new(psf, /NO_COPY), psf_fwhm: psf_fwhm, $
+         background: ptr_new(background, /NO_COPY), back_box: back_box, $
+         noise_std: ptr_new(noise_std, /NO_COPY), $
+         stars: ptr_new(/ALLOCATE), $
+         x_bad: ptr_new(x_bad, /NO_COPY), y_bad: ptr_new(y_bad, /NO_COPY), $
+         x: ptr_new(/ALLOCATE), sx: ptr_new(/ALLOCATE), $
+         y: ptr_new(/ALLOCATE), sy: ptr_new(/ALLOCATE), $
+         f: ptr_new(/ALLOCATE), sf: ptr_new(/ALLOCATE), c: ptr_new(/ALLOCATE)}
+    return, data
+end
+
+; XSTARFINDER_RUN_DEL: de-reference and de-allocate heap variables.
+
+PRO xstarfinder_run_del, data, image, psf, background, back_box, noise_std, x_bad, y_bad, $
+                  stars, x, y, f, sx, sy, sf, c, path, loadfile, par
+
+    if  not ptr_valid(data)  then begin
+       heap_gc  &  return
+    endif
+    if  n_elements(*(*data).image) ne 0  then $
+       image = *(*data).image
+    if  n_elements(*(*data).psf) ne 0  then $
+       psf = *(*data).psf
+    if  n_elements(*(*data).background) ne 0  then $
+       background = *(*data).background
+    back_box = (*data).back_box
+    if  n_elements(*(*data).noise_std) ne 0  then $
+       noise_std = *(*data).noise_std
+    if  n_elements(*(*data).x_bad) ne 0  then begin
+       x_bad = *(*data).x_bad  &  y_bad = *(*data).y_bad
+    endif
+    if  n_elements(*(*data).stars) ne 0  then $
+       stars = *(*data).stars
+    if  n_elements(*(*data).f) ne 0  then begin
+       x = *(*data).x  &  sx = *(*data).sx
+       y = *(*data).y  &  sy = *(*data).sy
+       f = *(*data).f  &  sf = *(*data).sf
+       c = *(*data).c
+    endif
+    if  n_elements(*(*data).path) ne 0  then  path = *(*data).path
+    if  n_elements(*(*data).loadfile) ne 0  then  loadfile = *(*data).loadfile
+    par = (*data).par
+    ptr_free, (*data).image, (*data).psf, (*data).background, $
+           (*data).noise_std, (*data).x_bad, (*data).y_bad, $
+           (*data).stars, (*data).x, (*data).y, (*data).f, $
+           (*data).sx, (*data).sy, (*data).sf, (*data).c, $
+           (*data).path, (*data).loadfile
+    ptr_free, data
+    return
+end
+
+; XSTARFINDER_RUN_PAR: define default parameters.
+
+PRO xstarfinder_run_par, id, noise_def, back_box, par
+
+    if  n_elements(par) ne 0  then begin
+       dthresh = par.dthresh
+       cthresh = par.cthresh
+       csub = par.csub
+       noise = (par.noise eq 1 and noise_def) and 1B
+       rel_thresh = (par.rel_thresh eq 1 and noise) and 1B
+       bkg = par.bkg
+       bbox = back_box
+       bmeth = par.bmeth
+       slant = par.slant
+       mindist = par.mindist
+       deblend = par.deblend
+       deblost = par.deblost
+       niter = par.niter
+       fluxopt = par.fluxopt
+    endif else begin
+       if  noise_def  then  dthresh = '3., 3.'  else  dthresh = '0., 0.'
+       rel_thresh = noise_def
+       cthresh = 0.7
+       csub = 2
+       noise = noise_def
+       bkg = 1B
+       bbox = back_box
+       bmeth = 0
+       slant = 1B
+       mindist = 1.0
+       deblend = 0
+       deblost = 0
+       niter = 2
+       fluxopt = 0
+       par = {dthresh: dthresh, rel_thresh: rel_thresh, $
+                cthresh: cthresh, csub: csub, noise: noise, $
+                bkg: bkg, bbox: bbox, bmeth: bmeth, slant: slant, mindist: mindist, $
+                niter: niter, deblend: deblend, deblost: deblost, fluxopt: fluxopt}
+;                bkg: bkg, bbox: bbox, slant: slant, mindist: mindist, niter: niter}
+;                bbox: bbox, deblend: deblend, niter: niter}
+    endelse
+    widget_control, id.dthresh, SET_VALUE = {tag0: strcompress(string(dthresh), /REMOVE_ALL)}
+    widget_control, id.rel_thresh, SET_VALUE = rel_thresh, SENSITIVE = noise and 1B
+    widget_control, id.cthresh, SET_VALUE = {tag0: strcompress(string(cthresh), /REMOVE_ALL)}
+    widget_control, id.csub, SET_VALUE = {tag0: strcompress(string(csub), /REMOVE_ALL)}
+    widget_control, id.noise, SET_VALUE = noise, SENSITIVE = noise_def
+    widget_control, id.bkg, SET_VALUE = bkg
+    widget_control, id.bbox, SET_VALUE = {tag0: strcompress(string(bbox), /REMOVE_ALL)}, SENSITIVE = bkg and 1B
+    widget_control, id.bmeth, SET_VALUE = bmeth, SENSITIVE = bkg and 1B
+    widget_control, id.slant, SET_VALUE = slant
+    widget_control, id.mindist, SET_VALUE = {tag0: strcompress(string(mindist), /REMOVE_ALL)}
+    widget_control, id.deblend, SET_VALUE = deblend
+    widget_control, id.deblost, SET_VALUE = deblost
+    widget_control, id.niter, SET_VALUE = {tag0: strcompress(string(niter), /REMOVE_ALL)}
+    widget_control, id.fluxopt, SET_VALUE = fluxopt, SENSITIVE = 0B
+    return
+end
+
+; XSTARFINDER_RUN: XStarFinder_Run widget definition module.
+
+PRO xstarfinder_run, image, psf, psf_fwhm, background, back_box, $
+               X_BAD = x_bad, Y_BAD = y_bad, NOISE_STD = noise_std, $
+               STARS = stars, x, y, f, sx, sy, sf, c, DEFAULT_PAR = par, $
+               PATH = path, GROUP = group, UVALUE = uvalue
+;               PATH = path, LOADFILE = loadfile, GROUP = group, UVALUE = uvalue
+
+    catch, error
+    if  error ne 0  then begin
+       xstarfinder_run_del, data, image, psf, background, back_box, noise_std, x_bad, y_bad, $
+                     stars, x, y, f, sx, sy, sf, c, path, loadfile, par
+       if  n_elements(group) eq 0  then $
+          widget_control, group_id, /DESTROY
+       return
+    endif
+    ; Create group leader if necessary
+    if  n_elements(group) eq 0  then $
+       group_id = widget_base()  else  group_id = group
+    ; Create modal base
+    if  n_elements(uvalue) eq 0  then  uvalue = 0B
+    base = widget_base(TITLE = 'XStarFinder_Run', /MODAL, UVALUE = uvalue, $
+                 GROUP_LEADER = group_id, /COLUMN)
+    ; Define child, to store data structure
+    child = widget_base(base)
+    ; Define Search parameters
+    lab_s = widget_label(base, VALUE = 'Search:', /ALIGN_LEFT)
+    s_base = widget_base(base, /FRAME, /COLUMN)
+    dthresh = cw_form(s_base, '0,TEXT,,WIDTH=16,LABEL_LEFT=Detection threshold(s)')
+    rel_thresh = cw_bgroup(s_base, 'Relative threshold', /NONEXCLUSIVE, /ROW)
+    ; Define Correlation parameters
+    lab_c = widget_label(base, VALUE = 'Correlation:', /ALIGN_LEFT)
+    c_base = widget_base(base, /FRAME, /COLUMN)
+    cthresh = cw_form(c_base, '0,FLOAT,,WIDTH=8,LABEL_LEFT=Correlation threshold')
+    csub = cw_form(c_base, '0,INTEGER,,WIDTH=8,LABEL_LEFT=No. of sub-pixel offsets')
+    ; Define Noise and Background parameters
+    lab_o = widget_label(base, VALUE = 'Noise and background:', /ALIGN_LEFT)
+    o_base = widget_base(base, /FRAME, /COLUMN)
+    noise = cw_bgroup(o_base, 'Use noise estimate', /NONEXCLUSIVE)
+    bkg = cw_bgroup(o_base, 'Upgrade background', /NONEXCLUSIVE)
+    bbox = cw_form(o_base, '0,INTEGER,,WIDTH=8,LABEL_LEFT=Box size for background estimation (FWHM units)')
+    bmeth = cw_bgroup(o_base, 'Estimate background by median filtering', /NONEXCLUSIVE)
+    lab_f = widget_label(base, VALUE = 'Fitting and deblending:', /ALIGN_LEFT)
+    f_base = widget_base(base, /FRAME, /COLUMN)
+    slant = cw_bgroup(f_base, 'Fit background below sources', /NONEXCLUSIVE)
+    mindist = cw_form(f_base, '0,FLOAT,,WIDTH=8,LABEL_LEFT=Minimum distance of close sources (FWHM units)')
+    deblend = cw_bgroup(f_base, 'Deblend detected sources', /NONEXCLUSIVE)
+    deblost = cw_bgroup(f_base, 'Deblend rejected sources', /NONEXCLUSIVE)
+    niter = cw_form(f_base, '0,INTEGER,,WIDTH=8,LABEL_LEFT=Final re-fitting iterations')
+    fluxopt = cw_bgroup(f_base, 'Fit only fluxes', /NONEXCLUSIVE)
+    u_base1 = widget_base(base, /ROW)
+    load = widget_button(u_base1, VALUE = 'Load list')
+    proc = widget_button(u_base1, VALUE = 'Processing')
+    sav = widget_button(u_base1, VALUE = 'Save results')
+    u_base2 = widget_base(base, /ROW)
+    hlp = widget_button(u_base2, VALUE = 'Help')
+    ex = widget_button(u_base2, VALUE = 'Exit')
+    ; Define pointer to auxiliary/output data
+    id = {dthresh: dthresh, rel_thresh: rel_thresh, $
+         cthresh: cthresh, csub: csub, noise: noise, $
+         bkg: bkg, bbox: bbox, bmeth: bmeth, slant: slant, mindist: mindist, niter: niter, $
+         deblend: deblend, deblost: deblost, fluxopt: fluxopt, $
+;        bbox: bbox, deblend: deblend, niter: niter, $
+         load: load, proc: proc, sav: sav, hlp: hlp, ex: ex}
+    xstarfinder_run_par, id, n_elements(noise_std) ne 0 and 1B, back_box, par
+    data = xstarfinder_run_def(id, par, image, psf, background, back_box, noise_std, $
+                               x_bad, y_bad, psf_fwhm, path, loadfile)
+    data = ptr_new(data, /NO_COPY)
+    widget_control, child, SET_UVALUE = data
+    ; Realize, register, etc.
+    widget_control, base, /REALIZE
+    xmanager, 'xstarfinder_run', base, EVENT_HANDLER = 'xstarfinder_run_event'
+    ; De-reference output data and de-allocate heap variables
+    xstarfinder_run_del, data, image, psf, background, back_box, noise_std, x_bad, y_bad, $
+                         stars, x, y, f, sx, sy, sf, c, path, loadfile, par
+    ; Destroy group leader if necessary
+    if  n_elements(group) eq 0  then $
+       widget_control, group_id, /DESTROY
+    return
+end
diff --git a/xstarfinder_run_help.txt b/xstarfinder_run_help.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4795eeff81ff81d9c9a4c219c2195fd84140fa3f
--- /dev/null
+++ b/xstarfinder_run_help.txt
@@ -0,0 +1,227 @@
+  XStarFinder_Run help page
+
+
+
+  GENERAL DESCRIPTION
+
+  Given a stellar field and an estimate of the Point Spread
+  Function (PSF), the XStarFinder_Run application detects the
+  stellar sources and estimate their position and flux. The image
+  may be contaminated by a smooth background emission.
+
+  The basic analysis procedure consists of 3 phases:
+   1) detection of candidate stars above a given threshold in the
+      background-removed image
+   2) check and analysis of detected objects, sorted by
+      decreasing intensity
+   3) re-fitting
+  The analysis of each object (step 2) includes the following
+  steps:
+  - object re-identification, after subtraction of already known
+    stars, to reject spurious detections associated to PSF features
+    of brighter sources
+  - correlation check, to measure the similarity of the object
+    with the PSF
+  - local fitting, to determine position and flux; fitting takes
+    into account the contribution of other stars; the contribution 
+    of the local background may be taken into account by fitting a 
+    tilted plane or as a fixed contribution, taken from the current 
+    background map
+  - upgrading of a 'stellar field model', which contains a
+    copy of the PSF for each detected star; it is basically
+    used to take into account the contribution of bright sources
+    when analyzing fainter and fainter ones.
+
+  The procedure above (phases 1-3) may be iterated: a new list of 
+  objects is formed by searching in the image after subtraction of 
+  the previously detected stars. Then the analysis proceeds on the
+  original frame. This iteration is very useful to detect close
+  binaries and resolve crowded groups, down to separations
+  comparable to the PSF FWHM.
+
+  At the end of the last iteration an optional de-blending 
+  strategy may be applied to look for very close sources. This 
+  strategy skips the correlation check.
+  Two deblending modes are available: deblending of detected sources 
+  (looking for close companions around previously detected sources) and 
+  deblending of rejected sources (trying to resolve previously lost 
+  objects into groups of close companions).
+
+  At the end of the analysis, all the detected sources are re-fitted 
+  a given number of times to improve astrometry and photometry.
+
+  If the approximate positions and fluxes are known, it is possible 
+  to load a list of sources, skipping the detection and analysis 
+  steps 1)+2) described above. In this case, only step 3) is performed 
+  and the input sources are just fitted a pre-fixed number of times. The 
+  outcome of the fitting process of each source undergoes the same 
+  validation checks carried out in a normal fitting process (i.e. flux 
+  above threshold, distance between two close sources above minimum 
+  distance). If the fit of a given source fails, the source is 
+  removed from the list.
+
+
+ 
+  PARAMETERS
+
+  'Detection threshold(s)':
+      Enter one or more detection thresholds separated by
+      commas.
+      The number of thresholds specifies also the number of
+      iterations of the basic analysis procedure (see steps 1,
+      2, 3 in the GENERAL DESCRIPTION).
+      A detection threshold represents the minimum central
+      intensity of an acceptable star, after removing the local
+      background contribution.
+      An effective choice is to select two detection levels,
+      both equal to (3 * Sigma), where Sigma is an estimate of
+      the noise standard deviation.
+      A threshold of 0 should always be avoided.
+
+  'Relative threshold':
+      If this option is set, the detection threshold is considered
+      as a relative threshold, in units of the noise standard
+      deviation. This button is active only if the noise is
+      defined on input, i.e. if the noise computation procedure
+      has been run before using this application.
+
+  'Correlation threshold':
+      Scalar value, representing the minimum correlation to accept
+      an object.
+
+  'No. of sub-pixel offsets':
+      The correlation of the object with the PSF is affected by the
+      relative off-centering between the two patterns; this parameter
+      specifies the number of sub-pixel offsets to maximize the
+      correlation.
+
+  'Use noise estimate':
+      Set this option to use the input noise array (or the noise 
+      estimated on the data) to perform a weighted PSF fitting on 
+      the presumed objects. When this option is applied, an estimate 
+      of the formal errors on astrometry and photometry will be 
+      computed.
+
+  'Upgrade background':
+      Set this option to upgrade the background estimate (see next 
+      parameter for details). If this option is disabled, the 
+      background map is kept fixed, equal to the input value.
+
+  'Box size for background estimation':
+      An accurate background estimate is necessary for accurate
+      objects detection and for a more reliable computation of
+      the correlation coefficient of each object with the PSF.
+      By default the background is estimated on the current residual 
+      image (input image - stars detected so far) by interpolating an 
+      array of local measurements, carried out on a set of image 
+      sub-regions arranged in a regular grid. This parameter 
+      specifies the size (in units of PSF FWHM) of each sub-region.
+      This parameter is set by default to the same value that has
+      been used in the PSF extraction procedure (XPsf_Extract).
+
+  'Estimate background by median filtering'
+      Set this option to estimate the background by median filtering 
+      of the current residual image, instead of using the default 
+      method explained above. The filtering is carried out on the 
+      same box size defined above. 
+      Estimating the background by median filtering may be useful 
+      when the background contribution is very irregular. This 
+      method should be applied after a first run of the program: 
+      at the very first run, this method may overestimate the 
+      background below bright sources.
+      Typically this method for background estimation is slower 
+      than the default method.
+
+  'Fit background below sources':
+      Set this option to take into account the local background 
+      by means of a tilted plane, which is optimized together with 
+      the parameters of the source(s) being fit. If this option is 
+      not set, the local background estimate is derived from the 
+      background map described above (see previous parameter for 
+      details) and kept fixed in the fitting process.  
+
+  'Minimum distance of close sources':
+      Very close sources are fit together. A check is performed 
+      on the outcome of the fit: if the sources are closer than 
+      this distance (in units of PSF FHWM), then the fit is 
+      considered unacceptable and the last detected source in the 
+      group is rejected as a false detection. Usually a minimum 
+      distance equal to the PSF FWHM is a safe limit. A smaller 
+      threshold should be used only when the PSF estimate is very 
+      accurate and in good signal-to-noise conditions.
+      It is recommended to set this parameter to 0 (or to a small 
+      value) when an input list of sources is loaded for fitting.
+
+  'Deblend detected sources'
+      Set this option to look for close companions around 
+      previously detected sources that have not been found by 
+      iterating the basic procedure (steps 1, 2, 3) described above. 
+      Candidate sources above the detection threshold are just fit 
+      (no correlation check is carried out).
+
+  'Deblend rejected sources'
+      Set this option to try to resolve previously lost objects 
+      into blends of close companions. In some cases, in fact, a 
+      blend of e.g. two close sources may not pass the correlation 
+      check and may be simply lost. Candidate sources above the 
+      detection threshold are just fit (no correlation check is 
+      carried out).
+
+  'Final re-fitting iterations':
+      At the end of each iteration (see GENERAL DESCRIPTION),
+      all the currently known stars are re-fitted once.
+      At the end of the whole analysis, the re-fitting may be
+      further iterated to improve the astrometry and photometry.
+      This parameter is to set the number of final re-fitting
+      iterations. The default is 2.
+      If an input list of sources is loaded, this parameters defines 
+      the number of fitting iterations of these sources. In this case 
+      more than 2 iterations are usually required (e.g. 4-5).
+
+  'Fit only fluxes':
+      Set this option to fit only the fluxes of the candidate stars 
+      when an input list of sources is loaded. NOTE: this option 
+      is active only when an input list is loaded.
+
+
+
+  CONTROLS/BUTTONS
+
+  'Load list':
+      Load an input list of stars. The list must be in an ASCII file 
+      with three columns: X position, Y position, Flux.
+      The positions are in pixels, the flux is referred to the PSF. 
+      When a list is loaded, the program will not perform a new 
+      detection: the loaded sources will be just fit a number of time 
+      given by the parameter 'Final re-fitting iterations'. 
+      NOTE 1: the file name is kept in memory until the XStarFinder_Run 
+      task is closed. Every time the 'Processing' button is pressed to 
+      run the task, the input list is loaded again from the file.
+      NOTE 2: when an input list is loaded, some parameters of the GUI 
+      are disabled: these parameters are not used when an input list 
+      is loaded for fitting.
+
+  'Processing':
+      Analyze stellar field, applying the currently defined options.
+
+  'Save results':
+      Save list of stars on ASCII file. The output list is organized
+      as a 7 columns table, with the following format:
+
+      X  Y  Flux  Sigma_X  Sigma_Y  Sigma_Flux  Correlation
+
+      where
+      - X, Y  are the coordinates of a star in pixels
+      - Flux  is the total flux
+      - Sigma_X, Sigma_Y, Sigma_F  are the formal error estimates
+             on X, Y, Flux respectively
+      - Correlation  is the correlation coefficient of the star;
+             notice that the correlation coefficient of a star
+             found by de-blending (if applied) is set to -1
+                   
+
+  'Help':
+      Display this help page.
+
+  'Exit':
+      Quit XStarFinder_Run.
\ No newline at end of file