function check3Color(img)
%
%
%        check3Color(img)
%
%
%        Input:
%           -img: an image to be tested if it is a three color channels
%           image
%
%     Copyright (C) 2011  Francesco Banterle
%
%     This program is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
%     This program is distributed in the hope that it will be useful,
%     but WITHOUT ANY WARRANTY; without even the implied warranty of
%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%     GNU General Public License for more details.
%
%     You should have received a copy of the GNU General Public License
%     along with this program.  If not, see <http://www.gnu.org/licenses/>.
%

%is a three color channels image?
if(size(img, 3) ~= 3)
    error('The image has to be a three color channels image.');
end

end


function test_nint_test01 ( )

%*****************************************************************************80
%
%% TEST01 just prints out the title information.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 March 2007
%
%  Author:
%
%    John Burkardt
%
  clear

  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST01\n' );
  fprintf ( 1, '  GET_PROBLEM_NUM returns the number of problems.\n' );
  fprintf ( 1, '  P00_NAME(#) returns the name for problem #.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  We use these two routines to print a directory\n' );
  fprintf ( 1, '  of all the problems.\n' );

  problem_num = get_problem_num ( );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  The number of problems available is %d\n', problem_num );
  fprintf ( 1, '\n' );

  for problem = 1 : problem_num

    name = p00_name ( problem );
    fprintf ( 1, '  %8d  "%s";\n', problem, name );

  end

  return
end


function rgb = skin_dark

% This returns a predefined color as [red green blue] values
%   red               = [255   0   0]/255;
%   green             = [  0 192   0]/255;
%   blue              = [  0   0 255]/255;
%   magenta           = [255 255   0]/255;
%   cyan              = [  0 255 255]/255;
%   yellow            = [255 255   0]/255;
%   white             = [255 255 255]/255;
%   black             = [  0   0   0]/255;
%
%   skull             = [140  85  85]/255
%   cortex            = [255 213 119]/255;
%   cortex_light      = [199 194 169]/255;
%   cortex_dark       = [100  97  85]/255;
%   skin              = [249 223 192]/255;
%   skin_light        = [249 223 192]/255;
%   skin_medium_light = [225 194 158]/255;
%   skin_medium       = [188 142 106]/255;
%   skin_medium_dark  = [155 102	65]/255;
%   skin_dark         = [ 91  71  61]/255;
%
% The different skin-based colors follow the Fitzpatrick scale with type I and II
% combined, and return RGB values that approximate those used by Apple in the emoji
% skin tones. See also https://emojipedia.org/emoji-modifier-sequence/
%
% If no specific skin tone is specified, this function returns a light skin color.
% This corresponds with that of one of the developers who approximated his own skin
% color more than 15 years ago upon the first implementation of this function.

% returns a predefined color as [red green blue] values
rgb = [ 91	 71	 61]/255;


function[j]=mat2vect(i)
j = [];
j =[i(1,:).';i(2,:).';i(3,:).';i(4,:).';i(5,:).';i(6,:).';i(7,:).'; ...
    i(8,:).';i(9,:).';i(10,:).';i(11,:).';i(12,:).';i(13,:).' ...
    ;i(14,:).';i(15,:).';i(16,:).';i(17,:).';i(18,:).' ...
    ;i(19,:).';i(20,:).';i(21,:).';i(22,:).';i(23,:).';i(24,:).';i(25,:).'...
    ;i(26,:).';i(27,:).';i(28,:).';i(29,:).';i(30,:).';i(31,:).';i(32,:).'...
    ;i(33,:).';i(34,:).';i(35,:).'];
end


function [grayscale_sequence] = sequence_grayscale(sequence)
% sequence_grayscale Returns grayscale sequence
%
% This sequence converter returns a grayscale version of an input sequence.
%
% Cache notice: The results of this function are cached in the workspace cache directory.
%
% Input:
% - sequence (structure): A valid sequence structure.
%
% Output:
% - grayscale_sequence (structure): A sequence descriptor of a converted sequence.

cache_directory = fullfile(get_global_variable('directory'), 'cache', 'grayscale', sequence.name);

mkpath(cache_directory);

cache_groundtruth = fullfile(cache_directory, 'groundtruth.txt');

sequence_groundtruth = fullfile(sequence.directory, 'groundtruth.txt');

if file_newer_than(cache_groundtruth, sequence_groundtruth)
    grayscale_sequence = sequence_create(cache_directory, 'name', sequence.name);
    grayscale_sequence.tags.names = sequence.tags.names;
    grayscale_sequence.tags.data = sequence.tags.data;
    grayscale_sequence.properties = sequence.properties;
    return;
end;

print_debug('Generating cached grayscale sequence ''%s''...', sequence.name);

for i = 1:sequence.length

    color_image = imread(sequence_get_image(sequence, i));

    gray_image = repmat(rgb2gray(color_image), [1 1 3]);

    imwrite(gray_image, fullfile(cache_directory, sprintf('%08d.jpg', i)));

end;

write_trajectory(cache_groundtruth, sequence.groundtruth);

grayscale_sequence = sequence_create(cache_directory, 'name', sequence.name);

grayscale_sequence.tags.names = sequence.tags.names;
grayscale_sequence.tags.data = sequence.tags.data;


function value = p22_i4vec ( action, name, dim_num, value )

%*****************************************************************************80
%
%% P22_I4VEC sets or gets I4VEC parameters for problem 22.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    19 March 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string ACTION, the action.
%    'D' sets the object to a default value.
%    'G' means the current value of the object should be returned.
%    'S' means the input values of the object and its dimension should
%    be stored.
%
%    Input, string NAME, the name of the parameter.
%    'E' is the exponent vector.
%
%    Input, integer DIM_NUM, the dimension of the object.
%
%    Input/output, integer VALUE(DIM_NUM), the value of the object.
%
  persistent e
  persistent dim_num_save

  if ( size ( dim_num_save ) == 0 )
    dim_num_save = 0;
  end

  if ( dim_num_save ~= dim_num )
    dim_num_save = 0;
    e = [];
  end

  if ( dim_num_save == 0 )
    dim_num_save = dim_num;
  end

  if ( action == 'D' | action == 'd' )

    if ( name == 'E' | name == 'e' | name == '*' )
      e(1:dim_num) = 2;
    end

  elseif ( action == 'G' | action == 'g' )

    if ( name == 'E' | name == 'e' )
      value(1:dim_num) = e(1:dim_num);
    else
      fprintf ( 1, '\n' );
      fprintf ( 1, 'P22_I4VEC - Fatal error!\n' );
      fprintf ( 1, '  Unrecognized name = "%s".\n', name );
      error ( 'P22_I4VEC - Fatal error!' );
    end

  elseif ( action == 'S' | action == 's' )

    if ( name == 'E' | name == 'e' )
      e(1:dim_num) = value(1:dim_num);
    else
      fprintf ( 1, '\n' );
      fprintf ( 1, 'P22_I4VEC - Fatal error!\n' );
      fprintf ( 1, '  Unrecognized name = "%s".\n', name );
      error ( 'P22_I4VEC - Fatal error!' );
    end

  else

    fprintf ( 1, '\n' );
    fprintf ( 1, 'P22_I4VEC - Fatal error!\n' );
    fprintf ( 1, '  Unrecognized action = "%s".\n', action );
    error ( 'P22_I4VEC - Fatal error!' );

  end

  return
end


% ------------------------------------------------------------------------
%          Crop, Rotate, Adjust Contrast, and Downsample Histology
% ------------------------------------------------------------------------

%%  SET FILE AND PARAMETERS

% * remember to run one cell at a time, instead of the whole script at once *

% directory of histology images
image_folder = 'C:\Drive\Histology\cfos';

% directory to save the processed images -- can be the same as the above image_folder
% results will be put inside a new folder called 'processed' inside of this image_folder
save_folder = 'C:\Drive\Histology\cfos';

% name of images, in order anterior to posterior or vice versa
% once these are downsampled they will be named ['original name' '_processed.tif']
image_file_names = dir([image_folder filesep '*.tif']); % get the contents of the image_folder
image_file_names = natsortfiles({image_file_names.name});
% image_file_names = {'slide no 2_RGB.tif','slide no 3_RGB.tif','slide no 4_RGB.tif'}; % alternatively, list each image in order

% if the images are individual slices (as opposed to images of multiple
% slices, which must be cropped using the cell CROP AND SAVE SLICES)
image_files_are_individual_slices = true;

% use images that are already at reference atlas resolution (here, 10um/pixel)
use_already_downsampled_image = true;

% pixel size parameters: microns_per_pixel of large images in the image
% folder (if use_already_downsampled_images is set to false);
% microns_per_pixel_after_downsampling should typically be set to 10 to match the atlas
microns_per_pixel = 3.233;
microns_per_pixel_after_downsampling = 10;

% ----------------------
% additional parameters
% ----------------------

% if the images are cropped (image_file_are_individual_slices = false),
% name to save cropped slices as; e.g. the third cropped slice from the 2nd
% image containing many slices will be saved as: save_folder/processed/save_file_name02_003.tif
save_file_name = 'SS096_';

% increase gain if for some reason the images are not bright enough
gain = 1;

% plane to view ('coronal', 'sagittal', 'transverse')
plane = 'coronal';

% size in pixels of reference atlas brain. For coronal slice, this is 800 x 1140
if strcmp(plane,'coronal')
    atlas_reference_size = [800 1140];
elseif strcmp(plane,'sagittal')
    atlas_reference_size = [800 1320];
elseif strcmp(plane,'transverse')
    atlas_reference_size = [1140 1320];
end

% finds or creates a folder location for processed images --
% a folder within save_folder called processed
folder_processed_images = fullfile(save_folder, 'processed');
if ~exist(folder_processed_images)
    mkdir(folder_processed_images)
end

%% LOAD AND PROCESS SLICE PLATE IMAGES

% close all figures
close all

% if the images need to be downsampled to 10um pixels (use_already_downsampled_image = false),
% this will downsample and allow you to adjust contrast of each channel of each image from image_file_names
%
% if the images are already downsampled (use_already_downsampled_image = true), this will allow
% you to adjust the contrast of each channel
%
% Open Histology Viewer figure
try; figure(histology_figure);
catch; histology_figure = figure('Name','Histology Viewer'); end
warning('off', 'images:initSize:adjustingMag'); warning('off', 'MATLAB:colon:nonIntegerIndex');

% Function to downsample and adjust histology image
HistologyBrowser(histology_figure, save_folder, image_folder, image_file_names, folder_processed_images, image_files_are_individual_slices, ...
            use_already_downsampled_image, microns_per_pixel, microns_per_pixel_after_downsampling, gain)

%% CROP AND SAVE SLICES -- run once the above is done, if image_file_are_individual_slices = false

% close all figures
close all

% run this function if the images from image_file_names have several
% slices, per image (e.g. an image of an entire histology slide)
%
% this function allows you to crop all the slices you would like to
% process im each image, by drawing rectangles around them in the figure.
% these will be further processed in the next cell
if ~image_files_are_individual_slices
    histology_figure = figure('Name','Histology Viewer');
    HistologyCropper(histology_figure, save_folder, image_file_names, atlas_reference_size, save_file_name, use_already_downsampled_image)
else
    disp('individually cropped slices already available')
end

%% GO THROUGH TO FLIP HORIZONTAL SLICE ORIENTATION, ROTATE, SHARPEN, and CHANGE ORDER

% close all figures
close all

% this takes images from folder_processed_images ([save_folder/processed]),
% and allows you to rotate, flip, sharpen, crop, and switch their order, so they
% are in anterior->posterior or posterior->anterior order, and aesthetically pleasing
%
% it also pads images smaller than the reference_size and requests that you
% crop images larger than this size
%
% note -- presssing left or right arrow saves the modified image, so be
% sure to do this even after modifying the last slice in the folder
slice_figure = figure('Name','Slice Viewer');
SliceFlipper(slice_figure, folder_processed_images, atlas_reference_size)


function caffe_set_input(net, input)
%
% This file is part of the code that implements the following ICCV2015 accepted paper:
% title: "Object detection via a multi-region & semantic segmentation-aware CNN model"
% authors: Spyros Gidaris, Nikos Komodakis
% institution: Universite Paris Est, Ecole des Ponts ParisTech
% Technical report: http://arxiv.org/abs/1505.01749
% code: https://github.com/gidariss/mrcnn-object-detection
%
% AUTORIGHTS
% --------------------------------------------------------
% Copyright (c) 2015 Spyros Gidaris
%
% "Object detection via a multi-region & semantic segmentation-aware CNN model"
% Technical report: http://arxiv.org/abs/1505.01749
% Licensed under The MIT License [see LICENSE for details]
% ---------------------------------------------------------

input_blob_names = net.inputs;
input_size  = caffe_get_blobs_size(net, input_blob_names);
assert(numel(input_size) == numel(input));

caffe_set_blobs_data(net, input, input_blob_names);
end


function [out,pos] = max( in, plonk, dim )
%MAX for nested cells
%
% (c) Thomas Kuestner
% ---------------------------------------------------------------------

% return scalar value
[out, ~] = flattenCellMatrix(in.data);
if(nargin == 1)
    out = max(cellfun(@(x) max(x(:)), out));
else
    [out, pos] = cellfun(@(x) max(x,[],dim), out, 'UniformOutput', false);
end

end


function [x,rank,info] = gelsd(a,b_in,rcond)
%GELSD   Computing eigen information.
%   [X,INFO] = GELSD(A,B,RCOND)
%
%	No input parameter are optional. If you want an easy to use interface,
%	see GELS.

    x = [];
	rank = [] ;
	info = [];

	if (nargin~=3),
		disp('Wrong number of input parameters.');
		return;
	end;

	    %Do all the boring checking
	if (~isnumeric(a)),
		disp('The matrix is not composed of numeric values.');
		return;
	elseif (isinteger(a)),
		a=double(a);
	end;

	m=int32(size(a,1));
	n=int32(size(a,2));
	nrhs=int32(size(b_in,2));
	lda=int32(m);
	ldb=int32(max(m,n));

	if (isDouble(b_in)),
		b=zeros(double(ldb),double(nrhs));
		b(1:size(b_in,1) , 1:size(b_in,2)) = b_in;
	else
		b=single(zeros(double(ldb),double(nrhs)));
		b(1:size(b_in,1) , 1:size(b_in,2)) = b_in;
	end;
	rank=int32(0);

	if (isComplex(a) || isComplex(b)),
		if (isDouble(a) || isDouble(b))

			if (~isComplex(b)),
				b=complex(b);
			end;
			if (~isComplex(a)),
				a=complex(a);
			end;
			if (~isDouble(b)),
				b=double(b);
			end;
			if (~isDouble(a)),
				a=double(a);
			end;
			s=zeros(double(min(m,n)),1);
			work=complex(zeros(1));
			rwork=zeros(1);
			iwork=int32(zeros(1));
			lwork=int32(-1);
			info=int32(-1);
			[ m, n, nrhs, a, lda, x, ldb, s, rcond, rank, work, lwork, rwork, iwork, info]=lapack_zgelsd(m, n, nrhs, a, lda, b, ldb, s, rcond, rank, work, lwork, rwork, iwork, info);
			lwork=int32(work(1));
			work=complex(zeros(double(lwork),1));
			lrwork=int32(rwork(1));
			smlsiz=25;
			nlvl = max( 0, int32( log2( double(min( m,n ))/double(smlsiz+1) ) ) + 1 );
			lrwork = 10*min(m,n) + 2*min(m,n)*smlsiz + 8*min(m,n)*nlvl + 3*smlsiz*nrhs + (smlsiz+1)*(smlsiz+1);

			liwork = max(1, 3*min(m,n)*nlvl + 11*min(m,n));
			rwork=zeros(double(lrwork),1);
			iwork=int32(zeros(double(liwork),1));
			[ m, n, nrhs, a, lda, x, ldb, s, rcond, rank, work, lwork, rwork, iwork, info]=lapack_zgelsd(m, n, nrhs, a, lda, b, ldb, s, rcond, rank, work, lwork, rwork, iwork, info);

		else %complex single
			if (~isComplex(b)),
				b=complex(b);
			end;
			if (~isComplex(a)),
				a=complex(a);
			end;
			s=single(zeros(double(min(m,n)),1));

			work=single(complex(zeros(1,1)));
			work(1)=sqrt(-1)+1;
			lwork=int32(single(-1));
			rwork=single(zeros(1));
			iwork=int32(zeros(1));
			info=int32(single(-1));
			[ m, n, nrhs, a, lda, x, ldb, s, rcond, rank, work, lwork, rwork, iwork, info]=lapack_cgelsd(m, n, nrhs, a, lda, b, ldb, s, rcond, rank, work, lwork, rwork, iwork, info);
			lwork=int32(work(1));
			work=single(complex(zeros(double(lwork),1)));
			lrwork=int32(rwork(1));
			smlsiz=25;
			nlvl = max( 0, int32( log2( double(min( m,n ))/double(smlsiz+1) ) ) + 1 );
			lrwork = 10*min(m,n) + 2*min(m,n)*smlsiz + 8*min(m,n)*nlvl + 3*smlsiz*nrhs + (smlsiz+1)*(smlsiz+1);

			liwork = max(1, 3*min(m,n)*nlvl + 11*min(m,n));
			rwork=single(zeros(double(lrwork),1));
			iwork=int32(zeros(double(liwork),1));
			[ m, n, nrhs, a, lda, x, ldb, s, rcond, rank, work, lwork, rwork, iwork, info]=lapack_cgelsd(m, n, nrhs, a, lda, b, ldb, s, rcond, rank, work, lwork, rwork, iwork, info);

		end;
	else %real double
		if (isDouble(a) || isDouble(b)),
			smlsiz=int32(32);
			nlvl = max( 0, int32( log2( double(min( m,n ))/double((double(smlsiz)+1)) )  + 1) );
			lwork= int32(11*double(max(m,n)) + 2*double(max(m,n))*double(smlsiz) + 8*double(max(m,n))*double(nlvl) + double(max(m,n))*double(nrhs));
			liwork=int32(3 * double(min(m,n)) * double(nlvl) + 11 * double(min(m,n)));
			iwork=int32(zeros(double(liwork),1));
			if (~isDouble(b)),
				b=double(b);
			end;
			if (~isDouble(a)),
				a=double(a);
			end;
			s=zeros(double(min(m,n)),1);
			info=int32(-1);
			iwork=int32(zeros(double(liwork),1));
			work=zeros(double(lwork),1);
			[ m, n, nrhs, a, lda, x, ldb, s, rcond, rank, work, lwork, iwork, info]=lapack_dgelsd(m, n, nrhs, a, lda, b, ldb, s, rcond, rank, work, lwork, iwork, info);
		else %real single
			smlsiz=int32(25);
			nlvl = max( 0, int32( log2( double(min( m,n ))/double((smlsiz+1)) ) ) + 1 );
			liwork=int32(3 * min(m,n) * nlvl + 11 * min(m,n));
			lwork= int32(11*max(m,n) + 2*max(m,n)*smlsiz + 8*max(m,n)*nlvl + max(m,n)*nrhs);
			iwork=int32(zeros(double(liwork),1));
			work=single(zeros(double(lwork),1));
			s=single(zeros(double(min(m,n)),1));

			info=int32(-1);
			[ m, n, nrhs, a, lda, x, ldb, s, rcond, rank, work, lwork, iwork, info]=lapack_sgelsd(m, n, nrhs, a, lda, b, ldb, s, rcond, rank, work, lwork, iwork, info);
		end;
	end;

	x=x(1:double(n),1:double(nrhs));


function [imgRgb, overlayImg, overlayMaskImg, anatImg] = mrAnatOverlayMontage(overlayImg, xform, anatImg, anatXform, cmap, overlayClipRng, acpcSlices, fname, plane, alpha, labelFlag, upsamp, numAcross, clusterThresh, autoCropBorder)
% imgRgb = mrAnatOverlayMontage(overlayImg, xform, anatImg, anatXform, cmap, overlayClipRng, acpcSlices, [fname], [plane=3], [alpha=1], [labelFlag=true], [upsamp=0], [numAcross=[]], [clusterThresh=0], [autoCropBorder=0])
%
% Quick hack for displaying nice overlay montages.
% plane: presents sagittal (1) coronal (2) or axial (3) slices. default is
% axials.   STILL A PROBLEM WITH THE SLICE SELECTION!!!
%
% HISTORY:
% 2006.08.07 RFD: wrote it.
% 2006.08.10 MBS: added plane flag

if(~exist('cmap','var')) cmap = []; end
if(~exist('fname','var')) fname = ''; end
if(~exist('plane','var')||isempty(plane)) plane = 3; end
if(~exist('alpha','var')||isempty(alpha)) alpha = 1; end
if(~exist('labelFlag','var')||isempty(labelFlag)) labelFlag = true; end
if(size(overlayImg,4)~=3&&size(overlayImg,4)~=1)
    error('overlay must be XxYxZ or XxYxZx3!');
end
if(~exist('upsamp','var')||isempty(upsamp)) upsamp = 0; end
if(~exist('numAcross','var')) numAcross = []; end
overlayInterp = [0 0 0 0 0 0];
if(~exist('clusterThresh','var')||isempty(clusterThresh)) clusterThresh = 0; end
clusterConnectivity = 18;

% Set to Inf for no autocropping
if ~exist('autoCropBorder', 'var') || isempty(autoCropBorder)
autoCropBorder = 0;
end

[t,r,s,k] = affineDecompose(xform);
if(size(anatXform,1)==1 || size(anatXform,2)==1)
    % assume it's not a full xform but just mmPerVox. To convert it to a
    % full xform, we have to assume that it is the same as the overlay
    % xform except for maybe a scale difference.
    anatMmPerVox = anatXform(:)';
    anatXform = xform*diag([anatXform./s 1]);
else
    [at,ar,anatMmPerVox,ak] = affineDecompose(anatXform);
end

if(isfinite(autoCropBorder))
    tmp = sum(anatImg,3);
    x = find(sum(tmp,1)); x = [x(1) x(end)];
    y = find(sum(tmp,2)); y = [y(1) y(end)];
    tmp = squeeze(sum(anatImg,1));
    z = find(sum(tmp,1)); z = [z(1) z(end)];
    clear tmp;
    pad = [-autoCropBorder autoCropBorder];
    x = x+pad; y = y+pad; z = z+pad;
    anatImg = anatImg(y(1):y(2),x(1):x(2),z(1):z(2));
    anatXform = inv(inv(anatXform)*[1 0 0 -y(1); 0 1 0 -x(1); 0 0 1 -z(1); 0 0 0 1]);
end

anatSz = size(anatImg);
if(alpha>0)
    overlaySz = size(overlayImg);
    if(size(overlayImg,4)>1)
        overlayMaskImg = repmat(double(mean(overlayImg,4)>overlayClipRng(1)),[1 1 1 size(overlayImg,4)]);
    else
        overlayMaskImg = double(overlayImg>overlayClipRng(1));
    end
    if(clusterThresh>0)
        overlayMaskImg = double(bwareaopen(overlayMaskImg,clusterThresh,clusterConnectivity));
    end
    if(~all(xform(:)==anatXform(:)) || ~all(anatSz(1:3)==overlaySz(1:3)))
        %bb = dtiGet(0,'defaultBoundingBox');
        bb = anatXform*[1,1,1,1;[anatSz,1]]';
        bb = bb(1:3,:)';
        disp('Resampling overlay image to match background image resolution...');
        overlayImg = mrAnatResliceSpm(overlayImg, inv(xform), bb, anatMmPerVox, overlayInterp, false);
        overlayMaskImg = mrAnatResliceSpm(overlayMaskImg, inv(xform), bb, anatMmPerVox, overlayInterp, false);
    end
    overlayImg(overlayImg>overlayClipRng(2)) = overlayClipRng(2);
    overlayImg = (overlayImg-overlayClipRng(1))./(overlayClipRng(2)-overlayClipRng(1));
else
    overlayImg = [];
end
slXform = inv(anatXform);
if plane==3
    % axials, reorient so that the eyes point up
    perm = [2 1 3 4];
    flip = 1;
    for(ii=1:length(acpcSlices)) slLabel{ii} = sprintf('Z = %d',acpcSlices(ii)); end
    slImg = slXform*[zeros(length(acpcSlices),2) acpcSlices' ones(length(acpcSlices),1)]';
    slImg = round(slImg(3,:));
elseif plane==1
    % sagittals, looking left
    perm = [3 2 1 4];
    flip = [2,1];
    for(ii=1:length(acpcSlices)) slLabel{ii} = sprintf('X = %d',acpcSlices(ii)); end
    slImg = slXform*[acpcSlices' zeros(length(acpcSlices),2) ones(length(acpcSlices),1)]';
    slImg = round(slImg(1,:));
elseif plane==2
    % coronals
    perm = [3 1 2 4];
    flip = 1;
    for(ii=1:length(acpcSlices)) slLabel{ii} = sprintf('Y = %d',acpcSlices(ii)); end
    slImg = slXform*[zeros(length(acpcSlices),1) acpcSlices' zeros(length(acpcSlices),1) ones(length(acpcSlices),1)]';
    slImg = round(slImg(2,:));
end
anatImg = flipdim(permute(anatImg,perm),flip(1));
if(numel(flip)>1), anatImg = flipdim(anatImg,flip(2)); end
if(~isempty(overlayImg))
    overlayImg = flipdim(permute(overlayImg,perm),flip(1));
    overlayMaskImg = flipdim(permute(overlayMaskImg,perm),flip(1));
    if(numel(flip)>1)
        overlayImg = flipdim(overlayImg,flip(2));
        overlayMaskImg = flipdim(overlayMaskImg,flip(2));
    end
end

if(~labelFlag) slLabel = ''; end

[imgRgb,junk,numColsRows] = makeMontage3(anatImg, slImg, anatMmPerVox(1), upsamp, [], numAcross, 0);
if(~isempty(overlayImg))
    overlayMask = makeMontage3(overlayMaskImg, slImg, anatMmPerVox(1), upsamp, [], numAcross, 0);
    overlayMask = overlayMask>=0.5;
    overlay = makeMontage3(overlayImg, slImg, anatMmPerVox(1), upsamp, [], numAcross, 0);
    if(size(overlayImg,4)==3)
        if(alpha>1)
            % alpha>1 applies a gamma to the transparency map
            g = 1/alpha;
            alpha = 1;
            lum = repmat(mean(overlay,3).^g,[1,1,3]);
            imgRgb(overlayMask) = (1-lum(overlayMask).*alpha).*imgRgb(overlayMask) + lum(overlayMask).*alpha.*overlay(overlayMask);
        else
            imgRgb(overlayMask) = (1-alpha).*imgRgb(overlayMask) + alpha.*overlay(overlayMask);
        end
    else
        if(isempty(cmap)), cmap = autumn(256); end
        overlay = mean(overlay,3);
        %n = isnan(overlay);
        %overlay(n) = 0;
        %if(size(overlay,3)>1)
        %    n = sum(n,3); n(n==0) = NaN;
        %    overlay = sum(overlay,3)./sum(n,3);
        %    overlay(isnan(n)) = 0;
        %end
        inds = round(overlay*255+1);
        inds(isnan(inds)) = 1;
        overlay = reshape(cmap(inds,:),[size(overlay) 3]);
        overlay(~overlayMask|isnan(overlay)) = 0;
        imgRgb(overlayMask) = (1-alpha).*imgRgb(overlayMask) + alpha.*overlay(overlayMask);
    end
end
figure;
if(exist('imshow.m','file'))
  iptsetpref('ImshowBorder','tight')
  imshow(imgRgb);
else
  image(imgRgb); axis equal; axis off;
  set(gca,'Position',[0,0,1,1]);
end
set(gcf,'userData',imgRgb);
disp('im=get(gcf,''userData''); % get the raw image data');
mrUtilLabelMontage(slLabel, numColsRows, gcf, gca);

if(~isempty(fname)) mrUtilPrintFigure(fname); end
if(~isempty(overlayImg))
    legendLabels = explode(',',sprintf('%0.0f,',linspace(overlayClipRng(1),overlayClipRng(2),5)));
    legendLabels = legendLabels(1:end-1);
    legendLabels{end} = ['>=' num2str(overlayClipRng(2),'%0.3g')];
    if(~isempty(cmap))
        %if(~isempty(fname)) mrUtilMakeColorbar(cmap, legendLabels, '', [fname '_legend']);
        %else  mrUtilMakeColorbar(cmap, legendLabels, ''); end
    end
end

% be kind to those who forget a semicolon:
if(nargout<1) clear imgRgb; end
return;


function save_txt(key,outfilename)
% Saves the Key to a text file.
% Inputs:
%   key: An object of type Key.
%   outfilename: The name for the output text file.

assert(nargin==2)
assert(isa(key,'Key'))
assert(isa(outfilename,'char'))
assert(key.validate())

outfile = fopen(outfilename,'w');

[x,y] = ind2sub(size(key.tar),find(key.tar));
numentries = length(x);
for ii=1:numentries
    modelname = key.modelset{x(ii)};
    segname = key.segset{y(ii)};
    fprintf(outfile,'%s %s target\n',modelname,segname);
end

[x,y] = ind2sub(size(key.non),find(key.non));
numentries = length(x);
for ii=1:numentries
    modelname = key.modelset{x(ii)};
    segname = key.segset{y(ii)};
    fprintf(outfile,'%s %s nontarget\n',modelname,segname);
end

fclose(outfile);


%Device Device enumeration for the brick
%
% Notes::
% - Collection of enumeration constants used for the brick

classdef Device < uint8
    enumeration
         % motor definitions (found in c_output.c => NOS DATA8)
         MotorA (1)
         MotorB (2)
         MotorC (4)
         MotorD (8)
         % braking (found in c_output.c)
         Coast (0)
         Brake (1)
         % sensor ports (found in c_output.c)
         Port1 (0)
         Port2 (1)
         Port3 (2)
         Port4 (3)
         % LED patterns (found in bytecodes.h)
         LedBlack (0)
         LedGreen (1)
         LedRed   (2)
         LedOrange (3)
         LedGreenFlash (4)
         LedRedFlash (5)
         LedOrangeFlash (6)
         LedGreenPulse (7)
         LedRedPulse (8)
         LedOrangePulse (9)
         % colors (found in bytecodes.h)
         NoColor (0)
         BlackColor (1)
         BlueColor (2)
         GreenColor (3)
         YellowColor (4)
         RedColor (5)
         WhiteColor (6)
         BrownColor (7)
         % ultrasonic sensor definitions (found in types.html)
         Ultrasonic (30)
         USDistCM (0)
         USDistIN (1)
         USListen (2)
         % gyro sensor definitions (found in types.html)
         Gyro (32)
         GyroAng (0)
         GyroRate (1)
         % touch sensor definitions (found in types.html)
         Touch (16)
         Pushed (0)
         Bumps (1)
         % color sensor definitions (found in types.html)
         Color (29)
         ColReflect (0)
         ColAmbient (1)
         ColColor (2)
    end
end


% Test for @chebfun/comet3.m

function pass = test_comet3(pref)

if ( nargin < 1 )
    pref = chebfunpref();
end

% Real scalar functions.
fsr1 = chebfun(@sin, [-1 0 1], pref);
fsr2 = chebfun(@cos, [-1 0.5 1], pref);
fsr3 = chebfun(@exp, [-1 -0.5 1], pref);

% Real array-valued functions.
far1 = chebfun(@(x) [sin(x) cos(x) exp(x)], [-1 0 1], pref);

% Real quasimatrices.
fqr1 = cheb2quasi(far1);

% Obviously, we can't check if the plots are correct without human
% intervention, so all these tests are meant to do is make sure that we don't
% crash.

hfig = figure('Visible', 'off');

% Check COMET and COMET3.
pass(1) = doesNotCrash(@() comet3(fsr1, fsr2, fsr3));
pass(2) = doesNotCrash(@() comet3(far1));
pass(3) = doesNotCrash(@() comet3(fqr1));

close(hfig);

end

function pass = doesNotCrash(fn)

try
    fn();
    pass = true;
catch ME;
    pass = false;
end

end


function [ringWedgeScans ringWedgeFields] = readRingWedgeScans(dlgTitle);
%
%   [ringWedgeScans ringWedgeFields]  = readRingWedgeScans(dlgTitle);
%
% Author: Wandell, Brewer
% Purpose:
%    Utility to read ring and wedge scan numbers
%    ringWedgeScans(1) is the scan num of the ring
%    ringWedgeScans(2) is the scan num of the wege
%
% ras, 04/2009: updated with slots for the data field (co, amp, ph, map)
% for each scan as well. (Important for pRF data.)
if notDefined('dlgTitle'), dlgTitle='Read ring and wedge scan numbers'; end

dlg(1).fieldName = 'ringScan';
dlg(end).style = 'number';
dlg(end).value = 1;
dlg(end).string = 'Eccentricity (ring) data scan?';

dlg(end+1).fieldName = 'ringField';
dlg(end).style = 'popup';
dlg(end).list = {'co' 'amp' 'ph' 'map'};
dlg(end).value = 'map';
dlg(end).string = 'Polar Angle (wedge) data field?';

dlg(end+1).fieldName = 'wedgeScan';
dlg(end).style = 'number';
dlg(end).value = 1;
dlg(end).string = 'Eccentricity (ring) data scan?';

dlg(end+1).fieldName = 'wedgeField';
dlg(end).style = 'popup';
dlg(end).list = {'co' 'amp' 'ph' 'map'};
dlg(end).value = 'ph';
dlg(end).string = 'Polar Angle (wedge) data field?';

[resp ok] = generalDialog(dlg, dlgTitle);

if ~ok, error('User Aborted.');		end

ringWedgeScans = [resp.ringScan resp.wedgeScan];
ringWedgeFields = {resp.ringField resp.wedgeField};

return;


function tfi_hackOffSkull(normImg,fslStripImg,stripImg);
%
% tfi_hackOffSkull(normImg,fslStripImg,stripImg);
%
% Problem: there are 2 attempts to produce a skull-stripped
% image in the tfi path (one produced by fsl bet, and one
% produced by SkullStrip.tcl), and neither of them
% reliably do all the things needed.
%
% Solution: combine info from the two. This loads
% both the existing volumes, sets the norm img
% to zero wherever the fsl stripped img is zero,
% and saves the result as stripImg.
%
% This is a very crude hack designed to test the
% remaining code until Jonas updates SkullStrip.
%
%
% ras 02/05.
[img1 mmpervox1] = loadAnalyze(normImg);
[img2 mmpervox2] = loadAnalyze(fslStripImg);
if ~isequal(mmpervox1,mmpervox2)
    error('Volumes not equal size.')
end

img1(img2==0) = 0;
saveAnalyze(img1,stripImg(1:end-4),mmpervox1);

return


%%*****************************************************************
%% sqlp: main solver
%%*****************************************************************
%% SDPT3: version 4.0
%% Copyright (c) 1997 by
%% Kim-Chuan Toh, Michael J. Todd, Reha H. Tutuncu
%% Last Modified: 16 Sep 2004
%%*****************************************************************

  function [obj,X,y,Z,info,runhist] = sqlpmain(blk,At,C,b,par,parbarrier,X0,y0,Z0);

   global spdensity smallblkdim  printlevel msg
   global solve_ok  use_LU  exist_analytic_term numpertdiagschur
   global schurfun  schurfun_par
%%
   matlabversion = par.matlabversion;
   vers          = par.vers;
   predcorr      = par.predcorr;
   gam           = par.gam;
   expon         = par.expon;
   gaptol        = par.gaptol;
   inftol        = par.inftol;
   steptol       = par.steptol;
   maxit         = par.maxit;
   printlevel    = par.printlevel;
   stoplevel     = par.stoplevel;
   scale_data    = par.scale_data;
   spdensity     = par.spdensity;
   rmdepconstr   = par.rmdepconstr;
   smallblkdim   = par.smallblkdim;
   schurfun      = par.schurfun;
   schurfun_par  = par.schurfun_par;
   ublksize      = par.ublksize;
%%
   tstart = clock;
   X = X0; y = y0; Z = Z0;
   for p = 1:size(blk,1)
      if strcmp(blk{p,1},'u'); Z{p} = zeros(blk{p,2},1); end
   end
%%
%%-----------------------------------------
%% convert unrestricted blk to linear blk.
%%-----------------------------------------
%%
   convertlen = 0;
   [blk,At,C,X,Z,u2lblk,ublkidx] = sqlpu2lblk(blk,At,C,X,Z,par,convertlen);
   for p = 1:size(blk,1)
      pblk = blk(p,:);
      if (u2lblk(p) == 1)
         n = 2*blk{p,2};
         blk{p,1} = 'l';  blk{p,2} = n;
         parbarrier{p} = zeros(1,n);
         At{p} = [At{p}; -At{p}];
         tau = max(1,norm(C{p}));
         C{p} = [C{p}; -C{p}];
         msg = 'convert ublk to lblk';
         if (printlevel); fprintf(' *** %s',msg); end
         b2 = 1 + abs(b');
         normCtmp = 1+norm(C{p});
         normAtmp = 1+sqrt(sum(At{p}.*At{p}));
         if (n > 1000)
            const = sqrt(n);
         else
	    const = n;
         end
         if (par.startpoint == 1)
            X{p} = const* max([1,b2./normAtmp]) *ones(n,1);
            Z{p} = const* max([1,normAtmp/sqrt(n),normCtmp/sqrt(n)]) *ones(n,1);
            X{p} = X{p}.*(1+1e-10*randmat(n,1,0,'u'));
            Z{p} = Z{p}.*(1+1e-10*randmat(n,1,0,'u'));
	 else
            const = max(abs(X{p})) + 100;
            X{p} = [X{p}+const; const*ones(n/2,1)];
            %%old: const = 100; Z{p} = [const*ones(n/2,1); const*ones(n/2,1)];
            Z{p} = [abs(Z0{p}); abs(Z0{p})] + 1e-4;
         end
      end
   end
%%-----------------------------------------
%% check whether {A1,...,Am} is
%% linearly independent.
%%-----------------------------------------
%%
   m0 = length(b);
   [At,b,y,indeprows,par.depconstr,feasible,par.AAt] = ...
    checkdepconstr(blk,At,b,y,rmdepconstr);
   if (~feasible)
      obj = []; X = cell(size(blk,1),1); y = []; Z = cell(size(blk,1),1);
      runhist = [];
      msg = 'SQLP is not feasible';
      if (printlevel); fprintf('\n %s \n',msg); end
      return;
   end
   par.normAAt = norm(par.AAt,'fro');
%%
%%-----------------------------------------
%% scale SQLP data. Note: must be done only
%% after checkdepconstr
%%-----------------------------------------
%%
   normA2 = 1+ops(At,'norm');
   normb2 = 1+norm(b);
   normC2 = 1+ops(C,'norm');
   normX0 = 1+ops(X0,'norm');
   normZ0 = 1+ops(Z0,'norm');
   if (scale_data)
      [At,C,b,normA,normC,normb,X,y,Z] = scaling(blk,At,C,b,X,y,Z);
   else
      normA = 1; normC = 1; normb = 1;
   end
%%
%%-----------------------------------------
%% find the combined list of non-zero
%% elements of Aj, j = 1:k, for each k.
%% IMPORTANT NOTE: Ak, C are permuted.
%%-----------------------------------------
%%
   par.numcolAt = length(b);
   [At,C,X,Z,par.permA,par.permZ] = sortA(blk,At,C,b,X,Z);
   [par.isspA,par.nzlistA,par.nzlistAsum,par.isspAy,par.nzlistAy] = nzlist(blk,At,par);
%%
%%-----------------------------------------
%% create an artifical non-negative block
%% for a purely log-barrier problem
%%-----------------------------------------
%%
   numblkold = size(blk,1);
   nn = 0;
   for p = 1:size(blk,1);
      pblk = blk(p,:);
      idx = find(parbarrier{p}==0);
      if ~isempty(idx);
         if strcmp(pblk{1},'l')
            nn = nn + length(idx);
         elseif strcmp(pblk{1},'q')
            nn = nn + sum(pblk{2}(idx));
         elseif strcmp(pblk{1},'s')
            nn = nn + sum(pblk{2}(idx));
         end
      end
   end
   if (nn==0)
      analytic_prob = 1;
      numblk = size(blk,1)+1;
      blk{numblk,1} = 'l'; blk{numblk,2} = 1;
      At{numblk,1} = sparse(1,length(b));
      C{numblk,1} = 1;
      X{numblk,1} = 1e3;
      Z{numblk,1} = 1e3;
      parbarrier{numblk,1} = 0;
      u2lblk(numblk,1) = 0;
      nn = nn + 1;
   else
      analytic_prob = 0;
   end
%%
   exist_analytic_term = 0;
   for p = 1:size(blk,1);
      idx = find(parbarrier{p} > 0);
      if ~isempty(idx);
         exist_analytic_term = 1;
      end
   end
%%-----------------------------------------
%% initialization
%%-----------------------------------------
%%
   EE = ops(blk,'identity');
   normE2 = ops(EE,'norm'); Zpertold = 1;
   for p = 1:size(blk,1)
      normCC(p) = 1+ops(C(p),'norm');
      normEE(p) = 1+ops(EE(p),'norm');
   end
   [Xchol,indef(1)] = blkcholfun(blk,X);
   [Zchol,indef(2)] = blkcholfun(blk,Z);
   if any(indef)
      msg = 'stop: X or Z not positive definite';
      if (printlevel); fprintf('\n  %s\n',msg); end
      info.termcode = -3;
      info.msg1 = msg;
      obj = []; X = cell(size(blk,1),1); y = []; Z = cell(size(blk,1),1);
      runhist = [];
      return;
   end
   AX = AXfun(blk,At,par.permA,X);
   rp = b-AX;
   ZpATy = ops(Z,'+',Atyfun(blk,At,par.permA,par.isspAy,y));
   ZpATynorm = ops(ZpATy,'norm');
   Rd = ops(C,'-',ZpATy);
   objadd0 = 0;
   if (scale_data)
      for p = 1:size(blk,1)
         pblk = blk(p,:);
         objadd0 = objadd0 + sum(parbarrier{p}.*pblk{2})*log(normA{p});
      end
   end
   objadd = blkbarrier(blk,X,Z,Xchol,Zchol,parbarrier) + objadd0;
   obj = (normb*normC)*[blktrace(blk,C,X), b'*y] + objadd;
   gap = (normb*normC)*blktrace(blk,X,Z) - diff(objadd);
   relgap = gap/(1+sum(abs(obj)));
   prim_infeas = norm(rp)/normb2;
   dual_infeas = ops(Rd,'norm')/normC2;
   infeas = max(prim_infeas,dual_infeas);
   if (scale_data)
      infeas_org(1) = prim_infeas*normb;
      infeas_org(2) = dual_infeas*normC;
   else
      infeas_org = [0,0];
   end
   trXZ = blktrace(blk,X,Z,parbarrier);
   if (nn > 0); mu  = trXZ/nn; else; mu = gap/ops(X,'getM'); end
   normX = ops(X,'norm');
%%
   termcode = 0; restart = 0;
   pstep = 1; dstep = 1; pred_convg_rate = 1; corr_convg_rate = 1;
   prim_infeas_min  = prim_infeas;
   dual_infeas_min  = dual_infeas;
   prim_infeas_best = prim_infeas;
   dual_infeas_best = dual_infeas;
   infeas_best = infeas;
   relgap_best = relgap;
   homRd = inf; homrp = inf; dy = zeros(length(b),1);
   msg = []; msg2 = []; msg3 = [];
   runhist.pobj    = obj(1);
   runhist.dobj    = obj(2);
   runhist.gap     = gap;
   runhist.relgap  = relgap;
   runhist.pinfeas = prim_infeas;
   runhist.dinfeas = dual_infeas;
   runhist.infeas  = infeas;
   runhist.pstep   = 0;
   runhist.dstep   = 0;
   runhist.step    = 0;
   runhist.normX   = normX;
   runhist.cputime = etime(clock,tstart);
   ttime.preproc   = runhist.cputime;
   ttime.pred = 0; ttime.pred_pstep = 0; ttime.pred_dstep = 0;
   ttime.corr = 0; ttime.corr_pstep = 0; ttime.corr_dstep = 0;
   ttime.pchol = 0; ttime.dchol = 0; ttime.misc = 0;
%%
%%-----------------------------------------
%% display parameters and initial info
%%-----------------------------------------
%%
   if (printlevel >= 2)
      fprintf('\n********************************************');
      fprintf('***********************\n');
      fprintf('   SDPT3: Infeasible path-following algorithms');
      fprintf('\n********************************************');
      fprintf('***********************\n');
      [hh,mm,ss] = mytime(ttime.preproc);
      if (printlevel>=3)
         fprintf(' version  predcorr  gam  expon  scale_data\n');
         if (vers == 1); fprintf('   HKM '); elseif (vers == 2); fprintf('    NT '); end
         fprintf('     %1.0f      %4.3f',predcorr,gam);
         fprintf('   %1.0f        %1.0f    %1.0f\n',expon,scale_data);
         fprintf('\nit pstep dstep pinfeas dinfeas  gap')
         fprintf('      prim-obj      dual-obj    cputime\n');
         fprintf('------------------------------------------------');
         fprintf('-------------------\n');
         fprintf('%2.0f|%4.3f|%4.3f|%2.1e|%2.1e|',0,0,0,prim_infeas,dual_infeas);
         fprintf('%2.1e|%- 7.6e %- 7.6e| %s:%s:%s|',gap,obj(1),obj(2),hh,mm,ss);
      end
   end
%%
%%---------------------------------------------------------------
%% start main loop
%%---------------------------------------------------------------
%%
   param.termcode    = termcode;
   param.iter        = 0;
   param.obj         = obj;
   param.relgap      = relgap;
   param.prim_infeas = prim_infeas;   param.dual_infeas = dual_infeas;
   param.homRd       = homRd;         param.homrp       = homrp;
   param.AX          = AX;            param.ZpATynorm   = ZpATynorm;
   param.normA       = normA;
   param.normb       = normb;         param.normC       = normC;
   param.normX0      = normX0;        param.normZ0      = normZ0;
   param.m0          = m0;            param.indeprows   = indeprows;
   param.prim_infeas_bad = 0;
   param.dual_infeas_bad = 0;
   param.prim_infeas_min = prim_infeas;
   param.dual_infeas_min = dual_infeas;
   param.gaptol      = gaptol;
   param.inftol      = inftol;
   param.maxit       = maxit;
   param.scale_data  = scale_data;
   param.printlevel  = printlevel;
   param.ublksize    = ublksize;
   Xbest = X; ybest = y; Zbest = Z;
%%
   for iter = 1:maxit;
      tstart  = clock;
      timeold = tstart;
      update_iter = 0; breakyes = 0;
      pred_slow = 0; corr_slow = 0; step_short = 0;
      par.parbarrier = parbarrier;
      par.iter    = iter;
      par.obj     = obj;
      par.relgap  = relgap;
      par.pinfeas = prim_infeas;
      par.dinfeas = dual_infeas;
      par.rp      = rp;
      par.y       = y;
      par.dy      = dy;
      par.normX   = normX;
      par.ZpATynorm = ZpATynorm;
      %%if (printlevel > 2); fprintf(' %2.1e',par.normX); end
      if (iter == 1 | restart); Cpert = min(1,normC2/ops(EE,'norm')); end
      if (runhist.dinfeas(1) > 1e-3) & (~exist_analytic_term) ...
         & (relgap > 1e-4)
         if (par.normX > 5e3 & iter < 20)
            Cpert = Cpert*0.5;
         elseif (par.normX > 5e2 & iter < 20);
            Cpert = Cpert*0.3;
         else;
            Cpert = Cpert*0.1;
         end
         Rd = ops(Rd,'+',EE,Cpert);
         %%if (printlevel > 2); fprintf('|%2.1e',Cpert); end
      end
%%---------------------------------------------------------------
%% predictor step.
%%---------------------------------------------------------------
%%
      if (predcorr)
         sigma = 0;
      else
         sigma = 1-0.9*min(pstep,dstep);
         if (iter == 1); sigma = 0.5; end;
      end
      sigmu = cell(size(blk,1),1);
      for p = 1:size(blk,1)
         sigmu{p} = max(sigma*mu, parbarrier{p}');
      end
      invXchol = cell(size(blk,1),1);
      invZchol = ops(Zchol,'inv');
      if (vers == 1);
         [par,dX,dy,dZ,coeff,L,hRd] = ...
          HKMpred(blk,At,par,rp,Rd,sigmu,X,Z,invZchol);
      elseif (vers == 2);
         [par,dX,dy,dZ,coeff,L,hRd] = ...
          NTpred(blk,At,par,rp,Rd,sigmu,X,Z,Zchol,invZchol);
      end
      if (solve_ok <= 0)
         msg = 'stop: difficulty in computing predictor directions';
         if (printlevel); fprintf('\n  %s',msg); end
         runhist.pinfeas(iter+1) = runhist.pinfeas(iter);
         runhist.dinfeas(iter+1) = runhist.dinfeas(iter);
         runhist.relgap(iter+1)  = runhist.relgap(iter);
         runhist.cputime(iter+1) = etime(clock,tstart);
         termcode = -4;
         break; %% do not ues breakyes = 1
      end
      timenew = clock;
      ttime.pred = ttime.pred + etime(timenew,timeold); timeold = timenew;
%%
%%-----------------------------------------
%% step-lengths for predictor step
%%-----------------------------------------
%%
      if (gam == 0)
         gamused = 0.9 + 0.09*min(pstep,dstep);
      else
         gamused = gam;
      end
      [Xstep,invXchol] = steplength(blk,X,dX,Xchol,invXchol);
      pstep = min(1,gamused*full(Xstep));
      timenew = clock;
      ttime.pred_pstep = ttime.pred_pstep + etime(timenew,timeold); timeold = timenew;
      Zstep = steplength(blk,Z,dZ,Zchol,invZchol);
      dstep = min(1,gamused*full(Zstep));
      trXZnew = trXZ + pstep*blktrace(blk,dX,Z,parbarrier) ...
                 + dstep*blktrace(blk,X,dZ,parbarrier) ...
                 + pstep*dstep*blktrace(blk,dX,dZ,parbarrier);
      if (nn > 0); mupred  = trXZnew/nn; else; mupred = 1e-16; end
      mupredhist(iter) = mupred;
      timenew = clock;
      ttime.pred_dstep = ttime.pred_dstep + etime(timenew,timeold); timeold = timenew;
%%
%%-----------------------------------------
%%  stopping criteria for predictor step.
%%-----------------------------------------
%%
      if (min(pstep,dstep) < steptol) & (stoplevel) & (iter > 10)
         msg = 'stop: steps in predictor too short';
         if (printlevel)
            fprintf('\n  %s',msg);
            fprintf(': pstep = %3.2e,  dstep = %3.2e\n',pstep,dstep);
         end
         runhist.cputime(iter+1) = etime(clock,tstart);
         termcode = -2;
         breakyes = 1;
      end
      if (~predcorr)
         if (iter >= 2)
            idx = [max(2,iter-2) : iter];
            pred_slow = all(mupredhist(idx)./mupredhist(idx-1) > 0.4);
            idx = [max(2,iter-5) : iter];
            pred_convg_rate = mean(mupredhist(idx)./mupredhist(idx-1));
            pred_slow = pred_slow + (mupred/mu > 5*pred_convg_rate);
         end
         if (max(mu,infeas) < 1e-6) & (pred_slow) & (stoplevel)
            msg = 'stop: lack of progress in predictor';
            if (printlevel)
               fprintf('\n  %s',msg);
               fprintf(': mupred/mu = %3.2f, pred_convg_rate = %3.2f.',...
               mupred/mu,pred_convg_rate);
            end
            runhist.cputime(iter+1) = etime(clock,tstart);
            termcode = -2;
            breakyes = 1;
         else
            update_iter = 1;
         end
      end
%%---------------------------------------------------------------
%% corrector step.
%%---------------------------------------------------------------
%%
      if (predcorr) & (~breakyes)
         step_pred = min(pstep,dstep);
         if (mu > 1e-6)
            if (step_pred < 1/sqrt(3));
               expon_used = 1;
            else
               expon_used = max(expon,3*step_pred^2);
            end
         else
            expon_used = max(1,min(expon,3*step_pred^2));
         end
         if (nn==0)
             sigma = 0.2;
         elseif (mupred < 0)
             sigma = 0.8;
         else
            sigma = min(1, (mupred/mu)^expon_used);
         end
         sigmu = cell(size(blk,1),1);
         for p = 1:size(blk,1)
            sigmu{p} = max(sigma*mu, parbarrier{p}');
         end
         if (vers == 1)
            [dX,dy,dZ] = HKMcorr(blk,At,par,rp,Rd,sigmu,hRd,...
             dX,dZ,coeff,L,X,Z);
         elseif (vers == 2)
            [dX,dy,dZ] = NTcorr(blk,At,par,rp,Rd,sigmu,hRd,...
             dX,dZ,coeff,L,X,Z);
         end
         if (solve_ok <= 0)
            msg = 'stop: difficulty in computing corrector directions';
            if (printlevel); fprintf('\n  %s',msg); end
            runhist.pinfeas(iter+1) = runhist.pinfeas(iter);
            runhist.dinfeas(iter+1) = runhist.dinfeas(iter);
            runhist.relgap(iter+1)  = runhist.relgap(iter);
            runhist.cputime(iter+1) = etime(clock,tstart);
            termcode = -4;
            break; %% do not ues breakyes = 1
         end
         timenew = clock;
         ttime.corr = ttime.corr + etime(timenew,timeold); timeold = timenew;
%%
%%-----------------------------------
%% step-lengths for corrector step
%%-----------------------------------
%%
         if (gam == 0)
            gamused = 0.9 + 0.09*min(pstep,dstep);
         else
            gamused = gam;
         end
         Xstep = steplength(blk,X,dX,Xchol,invXchol);
         pstep = min(1,gamused*full(Xstep));
         timenew = clock;
         ttime.corr_pstep = ttime.corr_pstep+etime(timenew,timeold); timeold = timenew;
         Zstep = steplength(blk,Z,dZ,Zchol,invZchol);
         dstep = min(1,gamused*full(Zstep));
         trXZnew = trXZ + pstep*blktrace(blk,dX,Z,parbarrier) ...
                    + dstep*blktrace(blk,X,dZ,parbarrier)...
                    + pstep*dstep*blktrace(blk,dX,dZ,parbarrier);
         if (nn > 0); mucorr  = trXZnew/nn; else; mucorr = 1e-16; end
         timenew = clock;
         ttime.corr_dstep = ttime.corr_dstep+etime(timenew,timeold); timeold = timenew;
%%
%%-----------------------------------------
%%  stopping criteria for corrector step
%%-----------------------------------------
         if (iter >= 2)
            idx = [max(2,iter-2) : iter];
            corr_slow = all(runhist.gap(idx)./runhist.gap(idx-1) > 0.8);
            idx = [max(2,iter-5) : iter];
            corr_convg_rate = mean(runhist.gap(idx)./runhist.gap(idx-1));
            corr_slow = corr_slow + (mucorr/mu > max(min(1,5*corr_convg_rate),0.8));
         end
	 if (max(relgap,infeas) < 1e-6) & (iter > 20) ...
            & (corr_slow > 1) & (stoplevel)
            msg = 'stop: lack of progress in corrector';
   	    if (printlevel)
               fprintf('\n  %s',msg);
               fprintf(': mucorr/mu = %3.2f, corr_convg_rate = %3.2f',...
               mucorr/mu,corr_convg_rate);
            end
            runhist.cputime(iter+1) = etime(clock,tstart);
            termcode = -2;
            breakyes = 1;
         else
            update_iter = 1;
         end
      end
%%---------------------------------------------------------------
%% udpate iterate
%%---------------------------------------------------------------
      indef = [1,1];
      if (update_iter)
         for t = 1:5
            [Xchol,indef(1)] = blkcholfun(blk,ops(X,'+',dX,pstep));
            timenew = clock;
            ttime.pchol = ttime.pchol + etime(timenew,timeold); timeold = timenew;
            if (indef(1)); pstep = 0.8*pstep; else; break; end
         end
	 if (t > 1); pstep = gamused*pstep; end
	 for t = 1:5
            [Zchol,indef(2)] = blkcholfun(blk,ops(Z,'+',dZ,dstep));
            timenew = clock;
            ttime.dchol = ttime.dchol + etime(timenew,timeold); timeold = timenew;
            if (indef(2)); dstep = 0.8*dstep; else; break; end
         end
	 if (t > 1); dstep = gamused*dstep; end
         %%-------------------------------------------
         AXtmp = AX + pstep*AXfun(blk,At,par.permA,dX);
         prim_infeasnew = norm(b-AXtmp)/normb2;
         if (relgap < 5*infeas); alpha = 1e2; else; alpha = 1e3; end
         if any(indef)
            if indef(1); msg = 'stop: X not positive definite'; end
            if indef(2); msg = 'stop: Z not positive definite'; end
            if (printlevel); fprintf('\n  %s',msg); end
            termcode = -3;
            breakyes = 1;
         elseif (prim_infeasnew > max([1e-8,relgap,20*prim_infeas]) & iter > 10) ...
            | (prim_infeasnew > max([1e-7,1e3*prim_infeas,0.1*relgap]) & relgap < 1e-2) ...
            | (prim_infeasnew > alpha*max([1e-9,param.prim_infeas_min]) ...
               & (prim_infeasnew > max([3*prim_infeas,0.1*relgap])) ...
               & (iter > 25) & (dual_infeas < 1e-6) & (relgap < 0.1)) ...
            | ((prim_infeasnew > 1e3*prim_infeas & prim_infeasnew > 1e-12) ...
               & (max(relgap,dual_infeas) < 1e-8))
            if (stoplevel)
               msg = 'stop: primal infeas has deteriorated too much';
               if (printlevel); fprintf('\n  %s, %2.1e',msg,prim_infeasnew); end
               termcode = -7;
               breakyes = 1;
            end
         elseif (trXZnew > 1.05*runhist.gap(iter)) & (~exist_analytic_term) ...
	    & ((infeas < 1e-5) & (relgap < 1e-4) & (iter > 20) ...
	       | (max(infeas,relgap) < 1e-7) & (iter > 10))
            if (stoplevel)
               msg = 'stop: progress in duality gap has deteriorated';
               if (printlevel); fprintf('\n  %s, %2.1e',msg,trXZnew); end
               termcode = -8;
               breakyes = 1;
            end
         else
            X = ops(X,'+',dX,pstep);
            y = y + dstep*dy;
            Z = ops(Z,'+',dZ,dstep);
         end
      end
%%---------------------------------------------------------------
%% adjust linear blk arising from unrestricted blk
%%---------------------------------------------------------------
      if (~breakyes)
         for p = 1:size(blk,1)
            if (u2lblk(p) == 1)
               len = blk{p,2}/2;
               xtmp = min(X{p}([1:len]),X{p}(len+[1:len]));
               alpha = 0.8;
               X{p}([1:len])     = X{p}([1:len]) - alpha*xtmp;
               X{p}(len+[1:len]) = X{p}(len+[1:len]) - alpha*xtmp;
               if (mu < 1e-4) %% old: (mu < 1e-7)
                  Z{p} = 0.5*mu./max(1,X{p}); %% good to keep this step
               else
                  ztmp = min(1,max(Z{p}([1:len]),Z{p}(len+[1:len])));
                  if (dual_infeas > 1e-4 & dstep < 0.2)
                     beta = 0.3;
                  else
                     beta = 0.0;
                  end
                  %% important to set beta = 0 at later stage.
                  Z{p}([1:len])     = Z{p}([1:len]) + beta*ztmp;
                  Z{p}(len+[1:len]) = Z{p}(len+[1:len]) + beta*ztmp;
               end
            end
         end
      end
%%--------------------------------------------------
%% perturb Z: do this step before checking for break
%%--------------------------------------------------
      if (~breakyes) & (~exist_analytic_term)
         trXZtmp = blktrace(blk,X,Z);
         trXE  = blktrace(blk,X,EE);
         Zpert = max(1e-12,0.2*min(relgap,prim_infeas)).*normC2./normE2;
         Zpert = min(Zpert,0.1*trXZtmp./trXE);
         Zpert = min([1,Zpert,1.5*Zpertold]);
         if (infeas < 0.1)
            Z = ops(Z,'+',EE,Zpert);
            [Zchol,indef(2)] = blkcholfun(blk,Z);
            if any(indef(2))
               msg = 'stop: Z not positive definite';
               if (printlevel); fprintf('\n  %s',msg); end
               termcode = -3;
               breakyes = 1;
            end
            %%if (printlevel > 2); fprintf(' %2.1e',Zpert); end
         end
         Zpertold = Zpert;
      end
%%---------------------------------------------------------------
%% compute rp, Rd, infeasibities, etc
%%---------------------------------------------------------------
%%
      AX  = AXfun(blk,At,par.permA,X);
      rp  = b-AX;
      ZpATy = ops(Z,'+',Atyfun(blk,At,par.permA,par.isspAy,y));
      ZpATynorm = ops(ZpATy,'norm');
      Rd  = ops(C,'-',ZpATy);
      objadd = blkbarrier(blk,X,Z,Xchol,Zchol,parbarrier) + objadd0;
      obj = (normb*normC)*[blktrace(blk,C,X), b'*y] + objadd;
      gap = (normb*normC)*blktrace(blk,X,Z) - diff(objadd);
      relgap = gap/(1+sum(abs(obj)));
      prim_infeas = norm(rp)/normb2;
      dual_infeas = ops(Rd,'norm')/normC2;
      infeas = max(prim_infeas,dual_infeas);
      if (scale_data)
         infeas_org(1) = prim_infeas*normb;
         infeas_org(2) = dual_infeas*normC;
      end
      homRd = inf; homrp = inf;
      if (ops(parbarrier,'norm') == 0)
         if (obj(2) > 0); homRd = ZpATynorm/(obj(2)); end
         if (obj(1) < 0); homrp = norm(AX)/(-obj(1))/(normC); end
      end
      trXZ = blktrace(blk,X,Z,parbarrier);
      if (nn > 0); mu = trXZ/nn; else; mu = gap/ops(X,'getM'); end
      normX = ops(X,'norm');
%%
      runhist.pobj(iter+1)  = obj(1);
      runhist.dobj(iter+1)  = obj(2);
      runhist.gap(iter+1)   = gap;
      runhist.relgap(iter+1)  = relgap;
      runhist.pinfeas(iter+1) = prim_infeas;
      runhist.dinfeas(iter+1) = dual_infeas;
      runhist.infeas(iter+1)  = infeas;
      runhist.pstep(iter+1)   = pstep;
      runhist.dstep(iter+1)   = dstep;
      runhist.step(iter+1)    = min(pstep,dstep);
      runhist.normX(iter+1)   = normX;
      runhist.cputime(iter+1) = etime(clock,tstart);
      timenew = clock;
      ttime.misc = ttime.misc + etime(timenew,timeold); timeold = timenew;
      [hh,mm,ss] = mytime(sum(runhist.cputime));
      if (printlevel>=3)
         fprintf('\n%2.0f|%4.3f|%4.3f',iter,pstep,dstep);
         fprintf('|%2.1e|%2.1e|%2.1e|',prim_infeas,dual_infeas,gap);
         fprintf('%- 7.6e %- 7.6e| %s:%s:%s|',obj(1),obj(2),hh,mm,ss);
      end
%%--------------------------------------------------
%% check convergence
%%--------------------------------------------------
      param.use_LU      = use_LU;
      param.stoplevel   = stoplevel;
      param.termcode    = termcode;
      param.iter        = iter;
      param.obj         = obj;
      param.gap         = gap;
      param.relgap      = relgap;
      param.prim_infeas = prim_infeas;
      param.dual_infeas = dual_infeas;
      param.mu        = mu;
      param.homRd     = homRd;
      param.homrp     = homrp;
      param.AX        = AX;
      param.ZpATynorm = ZpATynorm;
      param.normX     = ops(X,'norm');
      param.normZ     = ops(Z,'norm');
      param.numpertdiagschur = numpertdiagschur;
      if (~breakyes)
         [param,breakyes,restart,msg2] = sqlpcheckconvg(param,runhist);
      end
      if (restart)
         [X,y,Z] = infeaspt(blk,At,C,b,2,1e5);
         rp  = b-AXfun(blk,At,par.permA,X);
         ZpATy = ops(Z,'+',Atyfun(blk,At,par.permA,par.isspAy,y));
         Rd  = ops(C,'-',ZpATy);
         trXZ = blktrace(blk,X,Z,parbarrier);
         mu   = trXZ/nn;
         gap  =  (normb*normC)*blktrace(blk,X,Z) - diff(objadd);
         prim_infeas = norm(rp)/normb2;
         dual_infeas = ops(Rd,'norm')/normC2;
         infeas = max(prim_infeas,dual_infeas);
         [Xchol,indef(1)] = blkcholfun(blk,X);
         [Zchol,indef(2)] = blkcholfun(blk,Z);
         stoplevel = 3;
      end
%%--------------------------------------------------
%% check for break
%%--------------------------------------------------
      if ((prim_infeas < 1.5*prim_infeas_best) ...
         | (max(relgap,infeas) < 0.8*max(relgap_best,infeas_best))) ...
         & (max(relgap,dual_infeas) < 0.8*max(relgap_best,dual_infeas_best))
         Xbest = X; ybest = y; Zbest = Z;
         prim_infeas_best = prim_infeas;
         dual_infeas_best = dual_infeas;
         relgap_best = relgap; infeas_best = infeas;
         update_best(iter+1) = 1;
         %%fprintf('#')
      else
         update_best(iter+1) = 0;
      end
      if (max(relgap_best,infeas_best) < 1e-4 ...
          & norm(update_best(max(1,iter-1):iter+1)) == 0)
         msg = 'lack of progress in infeas';
         if (printlevel); fprintf('\n  %s',msg); end
         termcode = -9;
         breakyes = 1;
      end
      if (breakyes); break; end
   end
%%---------------------------------------------------------------
%% end of main loop
%%---------------------------------------------------------------
%%
   use_bestiter = 1;
   if (use_bestiter) & (param.termcode <= 0)
      X = Xbest; y = ybest; Z = Zbest;
      Xchol = blkcholfun(blk,X);
      Zchol = blkcholfun(blk,Z);
      AX = AXfun(blk,At,par.permA,X);
      rp = b-AX;
      ZpATy = ops(Z,'+',Atyfun(blk,At,par.permA,par.isspAy,y));
      Rd = ops(C,'-',ZpATy);
      objadd = blkbarrier(blk,X,Z,Xchol,Zchol,parbarrier) + objadd0;
      obj = (normb*normC)*[blktrace(blk,C,X), b'*y] + objadd;
      gap = (normb*normC)*blktrace(blk,X,Z) - diff(objadd);
      relgap = gap/(1+sum(abs(obj)));
      prim_infeas = norm(rp)/normb2;
      dual_infeas = ops(Rd,'norm')/normC2;
      infeas = max(prim_infeas,dual_infeas);
      runhist.pobj(iter+1)  = obj(1);
      runhist.dobj(iter+1)  = obj(2);
      runhist.gap(iter+1)   = gap;
      runhist.relgap(iter+1)  = relgap;
      runhist.pinfeas(iter+1) = prim_infeas;
      runhist.dinfeas(iter+1) = dual_infeas;
      runhist.infeas(iter+1)  = infeas;
   end
%%---------------------------------------------------------------
%% unscale and produce infeasibility certificates if appropriate
%%---------------------------------------------------------------
   if (iter >= 1)
      [X,y,Z,termcode,resid,reldist,msg3] = ...
      sqlpmisc(blk,At,C,b,X,y,Z,par.permZ,param);
   end
%%---------------------------------------------------------------
%% recover unrestricted blk from linear blk
%%---------------------------------------------------------------
%%
   for p = 1:size(blk,1)
      if (u2lblk(p) == 1)
         n = blk{p,2}/2;
         X{p} = X{p}(1:n)-X{p}(n+[1:n]);
         Z{p} = Z{p}(1:n);
      end
   end
   for p = 1:size(ublkidx,1)
      if ~isempty(ublkidx{p,2})
         n0 = ublkidx{p,1}; idxB = setdiff([1:n0]',ublkidx{p,2});
         tmp = zeros(n0,1); tmp(idxB) = X{p}; X{p} = tmp;
         tmp = zeros(n0,1); tmp(idxB) = Z{p}; Z{p} = tmp;
      end
   end
   if (analytic_prob)
      X = X(1:numblkold); Z = Z(1:numblkold);
   end
%%---------------------------------------------------------------
%% print summary
%%---------------------------------------------------------------
%%
   maxC = 1+ops(ops(C,'abs'),'max');
   maxb = 1+max(abs(b));
   if (scale_data)
      dimacs = [infeas_org(1)*normb2/maxb; 0; infeas_org(2)*normC2/maxC; 0];
   else
      dimacs = [prim_infeas*normb2/maxb; 0; dual_infeas*normC2/maxC; 0];
   end
   dimacs = [dimacs; [-diff(obj); gap]/(1+sum(abs(obj)))];
   info.dimacs   = dimacs;
   info.termcode = termcode;
   info.iter     = iter;
   info.obj      = obj;
   info.gap      = gap;
   info.relgap   = relgap;
   info.pinfeas  = prim_infeas;
   info.dinfeas  = dual_infeas;
   info.cputime  = sum(runhist.cputime);
   info.time     = ttime;
   info.resid    = resid;
   info.reldist  = reldist;
   info.normX    = ops(X,'norm');
   info.normy    = norm(y);
   info.normZ    = ops(Z,'norm');
   info.normb    = normb2; info.maxb = maxb;
   info.normC    = normC2; info.maxC = maxC;
   info.normA    = normA2;
   info.msg1     = msg;
   info.msg2     = msg2;
   info.msg3     = msg3;
   sqlpsummary(info,ttime,infeas_org,printlevel);
%%*****************************************************************************


% pop_erpparams() - Set plotting and statistics parameters for cluster ERP
%                   plotting
% Usage:
%   >> STUDY = pop_erpparams(STUDY, 'key', 'val');
%
% Inputs:
%   STUDY        - EEGLAB STUDY set
%
% Input:
%   'topotime'   - [real] Plot ERP scalp maps at one specific latency (ms).
%                   A latency range [min max] may also be defined (the
%                   ERP is then averaged over the interval) {default: []}
%   'filter'     - [real] low pass filter the ERP curves at a given
%                  frequency threshold. Default is no filtering.
%   'timerange'  - [min max] ERP plotting latency range in ms.
%                  {default: the whole epoch}
%   'ylim'       - [min max] ERP limits in microvolts {default: from data}
%   'plotgroups' - ['together'|'apart'] 'together' -> plot subject groups
%                  on the same axis in different colors, else ('apart')
%                  on different axes. {default: 'apart'}
%   'plotconditions' - ['together'|'apart'] 'together' -> plot conditions
%                  on the same axis in different colors, else ('apart')
%                  on different axes. Note: Keywords 'plotgroups' and
%                  'plotconditions' may not both be set to 'together'.
%                  {default: 'together'}
%   'averagechan' - ['on'|'off'] average data channels when several are
%                  selected.
%
% See also: std_erpplot()
%
% Authors: Arnaud Delorme, CERCO, CNRS, 2006-

% Copyright (C) Arnaud Delorme, 2006
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

function [ STUDY, com ] = pop_erpparams(STUDY, varargin);

STUDY = default_params(STUDY);
TMPSTUDY = STUDY;
com = '';
if isempty(varargin)

    enablecond         = fastif(length(STUDY.design(STUDY.currentdesign).variable(1).value)>1, 'on', 'off');
    enablegroup        = fastif(length(STUDY.design(STUDY.currentdesign).variable(2).value)>1, 'on', 'off');
    detachplots        = fastif(strcmpi(STUDY.etc.erpparams.detachplots,'on'), 1, 0);
    plotconditions     = fastif(strcmpi(STUDY.etc.erpparams.plotconditions, 'together'), 1, 0);
    plotgroups         = fastif(strcmpi(STUDY.etc.erpparams.plotgroups,'together'), 1, 0);
    radio_averagechan  = fastif(strcmpi(STUDY.etc.erpparams.averagechan,'on'), 1, 0);
    radio_scalptopo    = fastif(isempty(STUDY.etc.erpparams.topotime), 0, 1);
    if radio_scalptopo, radio_averagechan = 0; end;
    if radio_scalptopo+radio_averagechan == 0, radio_scalparray = 1; else radio_scalparray = 0; end;

    cb_radio = [ 'set(findobj(gcbf, ''userdata'', ''radio''), ''value'', 0);' ...
                 'set(gcbo, ''value'', 1);' ...
                 'set(findobj(gcbf, ''tag'', ''topotime''), ''string'', '''');' ];
    cb_edit  = [ 'set(findobj(gcbf, ''userdata'', ''radio''), ''value'', 0);' ...
                 'set(findobj(gcbf, ''tag'', ''scalptopotext''), ''value'', 1);' ];
    uilist = { ...
           {'style' 'text'       'string' 'ERP plotting options' 'fontweight' 'bold' 'fontsize', 12} ...
        {} {'style' 'text'       'string' 'Time limits (ms) [low high]' } ...
           {'style' 'edit'       'string' num2str(STUDY.etc.erpparams.timerange) 'tag' 'timerange' } ...
        {} {'style' 'text'       'string' 'Plot limits [low high]'} ...
           {'style' 'edit'       'string' num2str(STUDY.etc.erpparams.ylim) 'tag' 'ylim' } ...
        {} {'style' 'text'       'string' 'Lowpass plotted data [Hz]' } ...
           {'style' 'edit'       'string' num2str(STUDY.etc.erpparams.filter) 'tag' 'filter' } ...
        {} ...
           {'style' 'text'       'string' 'ERP plotting format' 'fontweight' 'bold' 'fontsize', 12} ...
        {} {'style' 'checkbox'   'string' 'Plot first variable on the same panel' 'value' plotconditions 'enable' enablecond  'tag' 'plotconditions' } ...
        {} {'style' 'checkbox'   'string' 'Plot second variable on the same panel' 'value' plotgroups 'enable' enablegroup 'tag' 'plotgroups' } ...
        {} {'style' 'checkbox'   'string' 'Detach plots' 'value' detachplots 'enable' 'on' 'tag' 'detachtag' } ...
        {} ...
           {'style' 'text'       'string' 'Multiple channels selection' 'fontweight' 'bold' 'tag', 'spec' 'fontsize', 12} ...
        {} {'style' 'radio'      'string' 'Plot channels in scalp array'    'value' radio_scalparray 'tag' 'scalparray'       'userdata' 'radio' 'callback' cb_radio} { } ...
        {} {'style' 'radio'      'string'  'Plot topography at time (ms)' 'value' radio_scalptopo  'tag' 'scalptopotext' 'userdata' 'radio' 'callback' cb_radio} ...
           {'style' 'edit'       'string' num2str(STUDY.etc.erpparams.topotime) 'tag' 'topotime' 'callback' cb_edit } ...
        {} {'style' 'radio'      'string' 'Average selected channels' 'value' radio_averagechan 'tag' 'averagechan' 'userdata' 'radio' 'callback' cb_radio} { } };
    cbline = [0.07 1.1];
    otherline = [ 0.07 0.6 .3];
    chanline  = [ 0.07 0.8 0.3];
    geometry = { 1 otherline otherline otherline 1 1 cbline cbline cbline 1 1 chanline chanline chanline };
    geomvert = [1.2 1 1 1 0.5 1.2 1 1 1 0.5 1.2 1 1 1 ];

    % component plotting
    % ------------------
    if isnan(STUDY.etc.erpparams.topotime)
        geometry(end-4:end) = [];
        geomvert(end-4:end) = [];
        uilist(end-10:end) = [];
    end;

    [out_param userdat tmp res] = inputgui( 'geometry' , geometry, 'uilist', uilist, 'geomvert', geomvert, ...
                                            'title', 'ERP plotting options -- pop_erpparams()');
    if isempty(res), return; end;

    % decode inputs
    % -------------
    %if res.plotgroups & res.plotconditions, warndlg2('Both conditions and group cannot be plotted on the same panel'); return; end;
    if res.plotgroups, res.plotgroups = 'together'; else res.plotgroups = 'apart'; end;
    if res.plotconditions , res.plotconditions  = 'together'; else res.plotconditions  = 'apart'; end;
    if res.detachtag, res.detachtag = 'on'; else res.detachtag = 'off'; end;
    if ~isfield(res, 'topotime'), res.topotime = STUDY.etc.erpparams.topotime;
    else res.topotime  = str2num( res.topotime );
    end;
    res.timerange = str2num( res.timerange );
    res.ylim      = str2num( res.ylim );
    res.filter    = str2num( res.filter );
    if ~isfield(res, 'averagechan'), res.averagechan = STUDY.etc.erpparams.averagechan;
    elseif res.averagechan, res.averagechan = 'on'; else res.averagechan = 'off';
    end;

    % build command call
    % ------------------
    options = {};
    if ~strcmpi( char(res.filter), char(STUDY.etc.erpparams.filter)), options = { options{:} 'filter' res.filter }; end;
    if ~strcmpi( res.plotgroups, STUDY.etc.erpparams.plotgroups), options = { options{:} 'plotgroups' res.plotgroups }; end;
    if ~strcmpi( res.plotconditions , STUDY.etc.erpparams.plotconditions ), options = { options{:} 'plotconditions'  res.plotconditions  }; end;
    if ~strcmpi( res.detachtag, STUDY.etc.erpparams.detachplots), options = { options{:} 'detachplots' res.detachtag}; end;
    if ~isequal(res.ylim       , STUDY.etc.erpparams.ylim),      options = { options{:} 'ylim' res.ylim       }; end;
    if ~isequal(res.timerange  , STUDY.etc.erpparams.timerange)  , options = { options{:} 'timerange' res.timerange }; end;
    if ~isequal(res.averagechan, STUDY.etc.erpparams.averagechan), options = { options{:} 'averagechan' res.averagechan }; end;
    if (all(isnan(res.topotime)) & all(~isnan(STUDY.etc.erpparams.topotime))) | ...
            (all(~isnan(res.topotime)) & all(isnan(STUDY.etc.erpparams.topotime))) | ...
                (all(~isnan(res.topotime)) & ~isequal(res.topotime, STUDY.etc.erpparams.topotime))
        options = { options{:} 'topotime' res.topotime };
    end;
    if ~isempty(options)
        STUDY = pop_erpparams(STUDY, options{:});
        com = sprintf('STUDY = pop_erpparams(STUDY, %s);', vararg2str( options ));
    end;
else
    if strcmpi(varargin{1}, 'default')
        STUDY = default_params(STUDY);
    else
        for index = 1:2:length(varargin)
            if ~isempty(strmatch(varargin{index}, fieldnames(STUDY.etc.erpparams), 'exact'))
                STUDY.etc.erpparams = setfield(STUDY.etc.erpparams, varargin{index}, varargin{index+1});
            end;
        end;
    end;
end;

% scan clusters and channels to remove erpdata info if timerange has changed
% ----------------------------------------------------------
if ~isequal(STUDY.etc.erpparams.timerange, TMPSTUDY.etc.erpparams.timerange)
    rmfields = { 'erpdata' 'erptimes' };
    for iField = 1:length(rmfields)
        if isfield(STUDY.cluster, rmfields{iField})
            STUDY.cluster = rmfield(STUDY.cluster, rmfields{iField});
        end;
        if isfield(STUDY.changrp, rmfields{iField})
            STUDY.changrp = rmfield(STUDY.changrp, rmfields{iField});
        end;
    end;
end;

function STUDY = default_params(STUDY)
    if ~isfield(STUDY.etc, 'erpparams'), STUDY.etc.erpparams = []; end;
    if ~isfield(STUDY.etc.erpparams, 'topotime'),         STUDY.etc.erpparams.topotime = []; end;
    if ~isfield(STUDY.etc.erpparams, 'filter'),           STUDY.etc.erpparams.filter = []; end;
    if ~isfield(STUDY.etc.erpparams, 'timerange'),        STUDY.etc.erpparams.timerange = []; end;
    if ~isfield(STUDY.etc.erpparams, 'ylim'     ),        STUDY.etc.erpparams.ylim      = []; end;
    if ~isfield(STUDY.etc.erpparams, 'plotgroups') ,      STUDY.etc.erpparams.plotgroups = 'apart'; end;
    if ~isfield(STUDY.etc.erpparams, 'plotconditions') ,  STUDY.etc.erpparams.plotconditions  = 'apart'; end;
    if ~isfield(STUDY.etc.erpparams, 'averagechan') ,     STUDY.etc.erpparams.averagechan  = 'off'; end;
    if ~isfield(STUDY.etc.erpparams, 'detachplots') ,     STUDY.etc.erpparams.detachplots  = 'on'; end;


%kglinexyz 'Create Polylines from ASCII XYZ Data'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros glinexyz.pane file
%
% Parameters:
% InputFile: i 'Input ASCII Data ', required: 'input ASCII data containing polyline points'
% String: name 'Name ', default: 'line': 'object name'
% OutputFile: o 'Output Geometry Object', required: 'output geometry object'
%
% Example: o = kglinexyz(i, {'i','';'name','line';'o',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% glinexyz - Create Polylines from ASCII XYZ Data
%
%  DESCRIPTION
% .I glinexyz
% will read in an ASCII file of coordinate information and produce a
% series of connected polyline primitives.
%
% The ASCII input should contain blocks of information, where each block
% consists of a number indicating how many vertices will be contained in
% the polyline and then a series of XYZ points, with one for each
% vertex.  The format of the input ASCII file is illustrated below :
%
%
%       number of vertices in first connected polyline
%       X value   Y value   Z value
%       X value   Y value   Z value
%       X value   Y value   Z value
% 	 .         .         .
% 	 .         .         .
% 	 .         .         .
%       X value   Y value   Z value
%       number of vertices in second connected polyline
%       X value   Y value   Z value
% 	 .         .         .
% 	 .         .         .
% 	 .         .         .
%
%
%
% A single connected polyline primitive will be created for each
% successive block of information.  The resulting geometry will not
% contain any color data.  To create colored polyline segments, please
% see "glinecolor."
%
%
%
%  EXAMPLES
%
%  "SEE ALSO"
% glinecolor
%
%  RESTRICTIONS
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1996,1997 , The Regents of the University of California.  All rights reserved.
%

function varargout = kglinexyz(varargin)
if nargin ==0
  Inputs={};arglist={'',''};
elseif nargin ==1
  Inputs=varargin{1};arglist={'',''};
elseif nargin ==2
  Inputs=varargin{1}; arglist=varargin{2};
else error('Usage: [out1,..] = kglinexyz(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i', '__input';'name', 'line';'o', '__output'};
maxval={0,0,0};
minval={0,0,0};
istoggle=[0,1,0];
was_set=istoggle * 0;
paramtype={'InputFile','String','OutputFile'};
% identify the input arrays and assign them to the arguments as stated by the user
if ~iscell(Inputs)
Inputs = {Inputs};
end
NumReqOutputs=1; nextinput=1; nextoutput=1;
  for ii=1:size(arglist,1)
  wasmatched=0;
  for jj=1:size(narglist,1)
   if strcmp(arglist{ii,1},narglist{jj,1})  % a given argument was matched to the possible arguments
     wasmatched = 1;
     was_set(jj) = 1;
     if strcmp(narglist{jj,2}, '__input')
      if (nextinput > length(Inputs))
        error(['Input ' narglist{jj,1} ' has no corresponding input!']);
      end
      narglist{jj,2} = 'OK_in';
      nextinput = nextinput + 1;
     elseif strcmp(narglist{jj,2}, '__output')
      if (nextoutput > nargout)
        error(['Output nr. ' narglist{jj,1} ' is not present in the assignment list of outputs !']);
      end
      if (isempty(arglist{ii,2}))
        narglist{jj,2} = 'OK_out';
      else
        narglist{jj,2} = arglist{ii,2};
      end

      nextoutput = nextoutput + 1;
      if (minval{jj} == 0)
         NumReqOutputs = NumReqOutputs - 1;
      end
     elseif isstr(arglist{ii,2})
      narglist{jj,2} = arglist{ii,2};
     else
        if strcmp(paramtype{jj}, 'Integer') & (round(arglist{ii,2}) ~= arglist{ii,2})
            error(['Argument ' arglist{ii,1} ' is of integer type but non-integer number ' arglist{ii,2} ' was supplied']);
        end
        if (minval{jj} ~= 0 | maxval{jj} ~= 0)
          if (minval{jj} == 1 & maxval{jj} == 1 & arglist{ii,2} < 0)
            error(['Argument ' arglist{ii,1} ' must be bigger or equal to zero!']);
          elseif (minval{jj} == -1 & maxval{jj} == -1 & arglist{ii,2} > 0)
            error(['Argument ' arglist{ii,1} ' must be smaller or equal to zero!']);
          elseif (minval{jj} == 2 & maxval{jj} == 2 & arglist{ii,2} <= 0)
            error(['Argument ' arglist{ii,1} ' must be bigger than zero!']);
          elseif (minval{jj} == -2 & maxval{jj} == -2 & arglist{ii,2} >= 0)
            error(['Argument ' arglist{ii,1} ' must be smaller than zero!']);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} < minval{jj})
            error(['Argument ' arglist{ii,1} ' must be bigger than ' num2str(minval{jj})]);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} > maxval{jj})
            error(['Argument ' arglist{ii,1} ' must be smaller than ' num2str(maxval{jj})]);
          end
        end
     end
     if ~strcmp(narglist{jj,2},'OK_out') &  ~strcmp(narglist{jj,2},'OK_in')
       narglist{jj,2} = arglist{ii,2};
     end
   end
   end
   if (wasmatched == 0 & ~strcmp(arglist{ii,1},''))
        error(['Argument ' arglist{ii,1} ' is not a valid argument for this function']);
   end
end
% match the remaining inputs/outputs to the unused arguments and test for missing required inputs
 for jj=1:size(narglist,1)
     if  strcmp(paramtype{jj}, 'Toggle')
        if (narglist{jj,2} ==0)
          narglist{jj,1} = '';
        end;
        narglist{jj,2} = '';
     end;
     if  ~strcmp(narglist{jj,2},'__input') && ~strcmp(narglist{jj,2},'__output') && istoggle(jj) && ~ was_set(jj)
          narglist{jj,1} = '';
          narglist{jj,2} = '';
     end;
     if strcmp(narglist{jj,2}, '__input')
      if (minval{jj} == 0)  % meaning this input is required
        if (nextinput > size(Inputs))
           error(['Required input ' narglist{jj,1} ' has no corresponding input in the list!']);
        else
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        end
      else  % this is an optional input
        if (nextinput <= length(Inputs))
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end;
     else
     if strcmp(narglist{jj,2}, '__output')
      if (minval{jj} == 0) % this is a required output
        if (nextoutput > nargout & nargout > 1)
           error(['Required output ' narglist{jj,1} ' is not stated in the assignment list!']);
        else
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
          NumReqOutputs = NumReqOutputs-1;
        end
      else % this is an optional output
        if (nargout - nextoutput >= NumReqOutputs)
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end
     end
  end
end
if nargout
   varargout = cell(1,nargout);
else
  varargout = cell(1,1);
end
global KhorosRoot
if exist('KhorosRoot') && ~isempty(KhorosRoot)
w=['"' KhorosRoot];
else
if ispc
  w='"C:\Program Files\dip\khorosBin\';
else
[s,w] = system('which cantata');
w=['"' w(1:end-8)];
end
end
[varargout{:}]=callKhoros([w 'glinexyz"  '],Inputs,narglist);


function [ncs] = read_neuralynx_ncs(filename, begrecord, endrecord)

% READ_NEURALYNX_NCS reads a single continuous channel file
%
% Use as
%   [ncs] = read_neuralynx_ncs(filename)
%   [ncs] = read_neuralynx_ncs(filename, begrecord, endrecord)

% Copyright (C) 2005-2007, Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.ru.nl/neuroimaging/fieldtrip
% for the documentation and details.
%
%    FieldTrip is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    FieldTrip is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id: read_neuralynx_ncs.m 2885 2011-02-16 09:41:58Z roboos $

if nargin<2
  begrecord = 1;
end
if nargin<3
  endrecord = inf;
end

% the file starts with a 16*1024 bytes header in ascii, followed by a number of records
hdr = neuralynx_getheader(filename);
fid = fopen(filename, 'rb', 'ieee-le');

% determine the length of the file
fseek(fid, 0, 'eof');
headersize = 16384;
recordsize = 1044;
NRecords   = floor((ftell(fid) - headersize)/recordsize);

if NRecords>0
  if (ispc), fclose(fid); end
  % read the timestamp from the first and last record
  hdr.FirstTimeStamp = neuralynx_timestamp(filename, 1);
  hdr.LastTimeStamp  = neuralynx_timestamp(filename, inf);
  if (ispc), fid = fopen(filename, 'rb', 'ieee-le'); end
else
  hdr.FirstTimeStamp = nan;
  hdr.LastTimeStamp  = nan;
end

if begrecord==0 && endrecord==0
  % only read the header
elseif begrecord<1
  error('cannot read before the first record');
elseif begrecord>NRecords
  error('cannot read beyond the last record')
elseif endrecord>NRecords
  endrecord = NRecords;
end

if begrecord>=1 && endrecord>=begrecord
  % rewind to the first record to be read
  status = fseek(fid, headersize + (begrecord-1)*recordsize, 'bof');
  if status~=0
    error('cannot jump to the requested record');
  end

  numrecord    = (endrecord-begrecord+1);
  TimeStamp    = zeros(1,numrecord,'uint64');
  ChanNumber   = zeros(1,numrecord);
  SampFreq     = zeros(1,numrecord);
  NumValidSamp = zeros(1,numrecord);
  Samp         = zeros(512,numrecord);  % this allows easy reshaping into a 1xNsamples vector

  for k=1:numrecord
    % read a single continuous data record
    TimeStamp(k)    = fread(fid,   1, 'uint64=>uint64');
    ChanNumber(k)   = fread(fid,   1, 'int32');
    SampFreq(k)     = fread(fid,   1, 'int32');
    NumValidSamp(k) = fread(fid,   1, 'int32');
    Samp(:,k)       = fread(fid, 512, 'int16');
    % mark the invalid samples
    Samp((NumValidSamp+1):end,k) = nan;
  end

  % store the record data in the output structure
  ncs.TimeStamp    = TimeStamp;
  ncs.ChanNumber   = ChanNumber;
  ncs.SampFreq     = SampFreq;
  ncs.NumValidSamp = NumValidSamp;
  % apply the scaling factor from ADBitVolts and convert to uV
  ncs.dat          = Samp * hdr.ADBitVolts * 1e6;

end
fclose(fid);

% store the header info in the output structure
ncs.NRecords = NRecords;
ncs.hdr      = hdr;


function C = cs_permute (A,p,q)                                             %#ok
%CS_PERMUTE permute a sparse matrix.
%   C = cs_permute(A,p,q) computes C = A(p,q)
%
%   Example:
%       Prob = UFget ('HB/arc130') ; A = Prob.A ; [m n] = size (A) ;
%       p = randperm (m) ; q = randperm (n) ;
%       C = cs_permute (A,p,q) ;    % C = A(p,q)
%
%   See also CS_SYMPERM, SUBSREF.

%   Copyright 2006-2007, Timothy A. Davis.
%   http://www.cise.ufl.edu/research/sparse

error ('cs_permute mexFunction not found') ;


function self = retrieve(dataformat, varargin)
%CATALOG.RETRIEVE Read seismic events from common file formats & data sources.
% retrieve can read events from many different earthquake catalog file
% formats (e.g. Seisan, Antelope) and data sources (e.g. IRIS DMC) into a
% GISMO Catalog object.
%
% Usage:
%       catalogObject = CATALOG.RETRIEVE(dataformat, 'param1', _value1_, ...
%                                                   'paramN', _valueN_)
%
% dataformat may be:
%
%   * 'iris' (for IRIS DMC, using irisFetch.m),
%   * 'antelope' (for a CSS3.0 Antelope/Datascope database)
%   * 'seisan' (for a Seisan database with a REA/YYYY/MM/ directory structure)
%   * 'zmap' (converts a Zmap data strcture to a Catalog object)
%
% The name-value parameter pairs supported are the same as those supported
% by irisFetch.Events(). Currently these are:
%
%     startTime
%     endTime
%     eventId
%     fetchLimit
%     magnitudeType
%     minimumLongitude
%     maximumLongitude
%     minimumLatitude
%     maximumLatitude
%     minimumMagnitude
%     maximumMagnitude
%     minimumDepth
%     maximumDepth
%
% And the two convenience parameters:
%
% radialcoordinates = [ centerLatitude, centerLongitude, maximumRadius ]
%
% boxcoordinates = [ minimumLatitude maximumLatitude minimumLongitude maximumLongitude ]
%
% For examples, see Catalog_cookbook. Also available at:
% https://geoscience-community-codes.github.io/GISMO/tutorials/html/Catalog_cookbook.html
%
%
% See also CATALOG, IRISFETCH, CATALOG_COOKBOOK

% Author: Glenn Thompson (glennthompson1971@gmail.com)

%% To do:
% Implement name-value parameter pairs for all methods
% Test the Antelope method still works after factoring out db_load_origins
% Test the Seisan method more
% Add in support for 'get_arrivals'

    debug.printfunctionstack('>')

    switch lower(dataformat)
        case 'iris'
            if exist('irisFetch.m','file')
                    ev = irisFetch.Events(varargin{:});
                    self = Catalog.read_catalog.iris(ev);
            else
                warning('Cannot find irisFetch.m')
            end
        case {'css3.0','antelope', 'datascope'}
            if admin.antelope_exists()
                self = Catalog.read_catalog.antelope(varargin{:});
            else
                warning('Sorry, cannot read event Catalog from Antelope database as Antelope toolbox for MATLAB not found')
                self = Catalog();
            end
        case 'seisan'
            self = Catalog.read_catalog.seisan(varargin{:});
        case 'aef'
            self = Catalog.read_catalog.aef(varargin{:});
        case 'sru'
            self = Catalog.read_catalog.sru(varargin{:});
        case 'vdap'
            self = Catalog.read_catalog.vdap(varargin{:});
        case 'zmap'
            self = Catalog.read_catalog.zmap(varargin{:});
        otherwise
            self = NaN;
            fprintf('format %s unknown\n\n',data_source);
    end
    if isempty(self)
        self=Catalog();
    end

    debug.printfunctionstack('<')
end