function rsamobj = loadbobfile(infile, snum, enum)
    % LOADBOBFILE Load an RSAM binary file
    % Usage:
    %   self = loadbobfile(infile, snum, enum)
    % Example:
    rsamobj = rsam();
    if nargin<3
        help rsam/loadbobfile
        warning('Not enough input parameters')
        return
    end
    f = struct;
    f.file = infile;
    f.found = false;
    f.snum = snum;
    f.enum = enum;

    if exist(infile,'file')
        f.found = true;
    end

    [dirname,basename] = fileparts(infile);
    if length(basename)==8
        rsamobj.sta = basename(1:4);
    end

    rsamobj.files = f;
    rsamobj = load(rsamobj);
    rsamobj.snum = snum;
    rsamobj.enum = enum;
end


function name = getComputerName()
% GETCOMPUTERNAME returns the name of the computer (hostname)
% name = getComputerName()
%
% WARN: output string is converted to lower case
%
%
% See also SYSTEM, GETENV, ISPC, ISUNIX
%
% m j m a r i n j (AT) y a h o o (DOT) e s
% (c) MJMJ/2007
% MOD: MJMJ/2013

[ret, name] = system('hostname');

if ret ~= 0,
   if ispc
      name = getenv('COMPUTERNAME');
   else
      name = getenv('HOSTNAME');
   end
end
% name = strtrim(lower(name));


function res = fiducials(this, newfiducials)
% Method for getting/setting the fiducials field
% FORMAT res = fiducials(this, fiducials)
% _______________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% Vladimir Litvak
% $Id: fiducials.m 3589 2009-11-20 17:17:41Z guillaume $

switch nargin
    case 1
         res = this.fiducials;
    case 2
         this.fiducials = newfiducials;
         res = this;
end


function bgui(state)

    report_this_filefun(mfilename('fullpath'));

    if nargin == 0  % Build the GUI
        % Create the Figure Window
        figure_w_normalized_uicontrolunits('Units','normal','Position',[.25 .25 .5 .5], ...
            'Name','BGUI Example','NumberTitle','off', ...
            'Color','w');
        % Set the default units for uicontrols to 'normal'.
        % This makes it easier to place the uicontrols, and
        % the increase/decrease in size if the figure is
        % resized.
        set(gcf,'DefaultUicontrolUnits','normal')
        % Add a static text uicontrol
        st = uicontrol('Style','text','String','Enter Command:', ...
            'Position',[.1 .8 .8 .1], ...
            'BackgroundColor','w','ForegroundColor','k', ...
            'HorizontalAlignment','left');
        % Add the edit uicontrol
        h = uicontrol('Style','edit','Position',[.1 .6 .8 .2], ...
            'min',0,'max',2)
        % Add the push button
        i = uicontrol('Style','push','Position',[.1 .2 .8 .3], ...
            'String','Evaluate Edit Block', ...
            'Callback','bgui(''evaluate'')');
        % Store the handle to the edit block in the figures
        % UserData propert.  This is done to avoid the use of
        % global variable.  See the UserData section in the
        % Building a Graphical User Interface Guide for more
        % information.
        set(gcf,'UserData',h)

    elseif strcmp(state,'evaluate') % Push button selected
        % Get the handle to the edit uicontrol
        h = get(gcf,'UserData');
        % Extract the command
        com = get(h,'String');
        % Evaluate the string using eval(try,catch)
        eval(com,'error(''Invalid MATLAB Command'')')

    end


function se_hdr = GE_readHeaderSeries(fid, byte_align)
%
% se_hdr = read_series_header(fid, byte_align)
%
% Loads the series header from a file with filed id fid
% and returns it as a structure.
% if byte_align = 1 then 32-bit alignment (SGI, LX2 format)
% if byte_align = 0 then 16-bit alignment (Sun, 5.X format)
%
%
% Souheil J. Inati
% Dartmouth College
% May 2000
% souheil.inati@dartmouth.edu
%

% define the structure and read in the data
% to overcome the byte alignment problems
% break up the assignment into pieces using the setfield function
se_hdr = struct('se_suid', fread(fid,4,'uchar'));                       %Suite ID for this Series%
se_hdr = setfield(se_hdr, 'se_uniq', fread(fid,1,'int16'));            %The Make-Unique Flag%
se_hdr = setfield(se_hdr, 'se_diskid', fread(fid,1,'uchar'));          %Disk ID for this Series%
fseek(fid,1,0); % 16-bit alignment
se_hdr = setfield(se_hdr, 'se_exno', fread(fid,1,'uint16'));            %Exam Number%
se_hdr = setfield(se_hdr, 'se_no ', fread(fid,1,'int16'));              %Series Number%
se_hdr = setfield(se_hdr, 'se_datetime', fread(fid,1,'int32'));        %Allocation Series Data/Time stamp%
se_hdr = setfield(se_hdr, 'se_actual_dt', fread(fid,1,'int32'));       %Actual Series Data/Time stamp%
se_hdr = setfield(se_hdr, 'se_desc', fread(fid,30,'uchar'));       %Series Description%
se_hdr = setfield(se_hdr, 'pr_sysid', fread(fid,9,'uchar'));       %Primary Receiver Suite and Host%
se_hdr = setfield(se_hdr, 'pansysid', fread(fid,9,'uchar'));       %Archiver Suite and Host%
se_hdr = setfield(se_hdr, 'se_typ ', fread(fid,1,'int16'));             %Series Type%
se_hdr = setfield(se_hdr, 'se_source ', fread(fid,1,'int16'));          %Series from which prescribed%
se_hdr = setfield(se_hdr, 'se_plane ', fread(fid,1,'int16'));           %Most-like Plane (for L/S)%
se_hdr = setfield(se_hdr, 'scan_type ', fread(fid,1,'int16'));          %Scout or Axial (for CT)%
se_hdr = setfield(se_hdr, 'position', fread(fid,1,'int32'));           %Patient Position%
se_hdr = setfield(se_hdr, 'entry', fread(fid,1,'int32'));              %Patient Entry%
se_hdr = setfield(se_hdr, 'anref', fread(fid,3,'uchar'));          %Anatomical reference%
fseek(fid,1,0); % 16-bit alignment
se_hdr = setfield(se_hdr, 'lmhor', fread(fid,1,'float32'));              %Horizontal Landmark%
se_hdr = setfield(se_hdr, 'prtcl', fread(fid,25,'uchar'));         %Scan Protocol Name%
fseek(fid,1,0); % 16-bit alignment
se_hdr = setfield(se_hdr, 'se_contrast ', fread(fid,1,'int16'));        %Non-zero if > 0 image used contrast(L/S)%
se_hdr = setfield(se_hdr, 'start_ras', fread(fid,1,'uchar'));          %RAS letter for first scan location (L/S)%
fseek(fid,1,0); % 16-bit alignment
if byte_align; fseek(fid,2,0); end % 32-bit alignment
se_hdr = setfield(se_hdr, 'start_loc', fread(fid,1,'float32'));          %First scan location (L/S)%
se_hdr = setfield(se_hdr, 'end_ras', fread(fid,1,'uchar'));            %RAS letter for last scan location (L/S)%
fseek(fid,1,0); % 16-bit alignment
if byte_align; fseek(fid,2,0); end % 32-bit alignment
se_hdr = setfield(se_hdr, 'end_loc', fread(fid,1,'float32'));            %Last scan location (L/S)%
se_hdr = setfield(se_hdr, 'se_pseq ', fread(fid,1,'int16'));            %Last Pulse Sequence Used (L/S)%
se_hdr = setfield(se_hdr, 'se_sortorder ', fread(fid,1,'int16'));       %Image Sort Order (L/S)%
se_hdr = setfield(se_hdr, 'se_lndmrkcnt', fread(fid,1,'int32'));       %Landmark Counter%
se_hdr = setfield(se_hdr, 'se_nacq ', fread(fid,1,'int16'));            %Number of Acquisitions%
se_hdr = setfield(se_hdr, 'xbasest ', fread(fid,1,'int16'));            %Starting number for baselines%
se_hdr = setfield(se_hdr, 'xbaseend', fread(fid,1,'int16'));            %Ending number for baselines%
se_hdr = setfield(se_hdr, 'xenhst', fread(fid,1,'int16'));             %Starting number for enhanced scans%
se_hdr = setfield(se_hdr, 'xenhend', fread(fid,1,'int16'));            %Ending number for enhanced scans%
if byte_align; fseek(fid,2,0); end % 32-bit alignment
se_hdr = setfield(se_hdr, 'se_lastmod', fread(fid,1,'int32'));         %Date/Time of Last Change%
se_hdr = setfield(se_hdr, 'se_alloc_key', fread(fid,13,'uchar'));  %Process that allocated this record%
fseek(fid,1,0); % 16-bit alignment
if byte_align; fseek(fid,2,0); end % 32-bit alignment
se_hdr = setfield(se_hdr, 'se_delta_cnt', fread(fid,1,'int32'));       %Indicates number of updates to header%
se_hdr = setfield(se_hdr, 'se_verscre', fread(fid,2,'uchar'));     %Genesis Version - Created%
se_hdr = setfield(se_hdr, 'se_verscur', fread(fid,2,'uchar'));     %Genesis Version - Now%
se_hdr = setfield(se_hdr, 'se_pds_a', fread(fid,1,'float32'));           %PixelData size - as stored%
se_hdr = setfield(se_hdr, 'se_pds_c', fread(fid,1,'float32'));           %PixelData size - Compressed%
se_hdr = setfield(se_hdr, 'se_pds_u', fread(fid,1,'float32'));           %PixelData size - UnCompressed%
se_hdr = setfield(se_hdr, 'se_checksum', fread(fid,1,'uint32'));        %Series Record checksum%
se_hdr = setfield(se_hdr, 'se_complete', fread(fid,1,'int32'));        %Series Complete Flag%
se_hdr = setfield(se_hdr, 'se_numarch', fread(fid,1,'int32'));         %Number of Images Archived%
se_hdr = setfield(se_hdr, 'se_imagect', fread(fid,1,'int32'));         %Last Image Number Used%
se_hdr = setfield(se_hdr, 'se_numimages', fread(fid,1,'int32'));       %Number of Images Existing%
se_hdr = setfield(se_hdr, 'se_images', struct('length', fread(fid,1,'uint32'), ...
                                               'data', fread(fid,1,'uint32'))); %Image Keys for this Series%
se_hdr = setfield(se_hdr, 'se_numunimg', fread(fid,1,'int32'));        %Number of Unstored Images%
se_hdr = setfield(se_hdr, 'se_unimages', struct('length', fread(fid,1,'uint32'), ...
                                               'data', fread(fid,1,'uint32'))); %Unstored Image Keys for this Series%
se_hdr = setfield(se_hdr, 'se_toarchcnt', fread(fid,1,'int32'));       %Number of Unarchived Images%
se_hdr = setfield(se_hdr, 'se_toarchive', struct('length', fread(fid,1,'uint32'), ...
                                               'data', fread(fid,1,'uint32'))); %Unarchived Image Keys for this Series%
se_hdr = setfield(se_hdr, 'echo1_alpha', fread(fid,1,'float32'));        %Echo 1 Alpha Value%
se_hdr = setfield(se_hdr, 'echo1_beta', fread(fid,1,'float32'));         %Echo 1 Beta Value%
se_hdr = setfield(se_hdr, 'echo1_window', fread(fid,1,'uint16'));       %Echo 1 Window Value%
se_hdr = setfield(se_hdr, 'echo1_level', fread(fid,1,'int16'));        %Echo 1 Level Value%
se_hdr = setfield(se_hdr, 'echo2_alpha', fread(fid,1,'float32'));        %Echo 2 Alpha Value%
se_hdr = setfield(se_hdr, 'echo2_beta', fread(fid,1,'float32'));         %Echo 2 Beta Value%
se_hdr = setfield(se_hdr, 'echo2_window', fread(fid,1,'uint16'));       %Echo 2 Window Value%
se_hdr = setfield(se_hdr, 'echo2_level', fread(fid,1,'int16'));        %Echo 2 Level Value%
se_hdr = setfield(se_hdr, 'echo3_alpha', fread(fid,1,'float32'));        %Echo 3 Alpha Value%
se_hdr = setfield(se_hdr, 'echo3_beta', fread(fid,1,'float32'));         %Echo 3 Beta Value%
se_hdr = setfield(se_hdr, 'echo3_window', fread(fid,1,'uint16'));       %Echo 3 Window Value%
se_hdr = setfield(se_hdr, 'echo3_level', fread(fid,1,'int16'));        %Echo 3 Level Value%
se_hdr = setfield(se_hdr, 'echo4_alpha', fread(fid,1,'float32'));        %Echo 4 Alpha Value%
se_hdr = setfield(se_hdr, 'echo4_beta', fread(fid,1,'float32'));         %Echo 4 Beta Value%
se_hdr = setfield(se_hdr, 'echo4_window', fread(fid,1,'uint16'));       %Echo 4 Window Value%
se_hdr = setfield(se_hdr, 'echo4_level', fread(fid,1,'int16'));        %Echo 4 Level Value%
se_hdr = setfield(se_hdr, 'echo5_alpha', fread(fid,1,'float32'));        %Echo 5 Alpha Value%
se_hdr = setfield(se_hdr, 'echo5_beta', fread(fid,1,'float32'));         %Echo 5 Beta Value%
se_hdr = setfield(se_hdr, 'echo5_window', fread(fid,1,'uint16'));       %Echo 5 Window Value%
se_hdr = setfield(se_hdr, 'echo5_level', fread(fid,1,'int16'));        %Echo 5 Level Value%
se_hdr = setfield(se_hdr, 'echo6_alpha', fread(fid,1,'float32'));        %Echo 6 Alpha Value%
se_hdr = setfield(se_hdr, 'echo6_beta', fread(fid,1,'float32'));         %Echo 6 Beta Value%
se_hdr = setfield(se_hdr, 'echo6_window', fread(fid,1,'uint16'));       %Echo 6 Window Value%
se_hdr = setfield(se_hdr, 'echo6_level', fread(fid,1,'int16'));        %Echo 6 Level Value%
se_hdr = setfield(se_hdr, 'echo7_alpha', fread(fid,1,'float32'));        %Echo 7 Alpha Value%
se_hdr = setfield(se_hdr, 'echo7_beta', fread(fid,1,'float32'));         %Echo 7 Beta Value%
se_hdr = setfield(se_hdr, 'echo7_window', fread(fid,1,'uint16'));       %Echo 7 Window Value%
se_hdr = setfield(se_hdr, 'echo7_level', fread(fid,1,'int16'));        %Echo 7 Level Value%
se_hdr = setfield(se_hdr, 'echo8_alpha', fread(fid,1,'float32'));        %Echo 8 Alpha Value%
se_hdr = setfield(se_hdr, 'echo8_beta', fread(fid,1,'float32'));         %Echo 8 Beta Value%
se_hdr = setfield(se_hdr, 'echo8_window', fread(fid,1,'uint16'));       %Echo 8 Window Value%
se_hdr = setfield(se_hdr, 'echo8_level', fread(fid,1,'int16'));        %Echo 8 Level Value%
se_hdr = setfield(se_hdr, 'series_uid', fread(fid,32,'uchar'));    %Series Entity Unique ID%
se_hdr = setfield(se_hdr, 'landmark_uid', fread(fid,32,'uchar'));  %Landmark Unique ID%
se_hdr = setfield(se_hdr, 'equipmnt_uid', fread(fid,32,'uchar'));  %Equipment Unique ID%
se_hdr = setfield(se_hdr, 'se_padding', fread(fid,588,'uchar'));   %Spare Space%

return


function w = addhistory(w, whathappened,varargin)
   %ADDHISTORY function in charge of adding history to a waveform
   %   waveform = addhistory(waveform, whathappened);
   %   waveform = addhistory(waveform, formatString, [variables...])
   %
   %   Mostly, addhistory is internal to the waveform methods, and will be
   %   updated automatically when you change the waveform.  Things like
   %   filtering, taking a hilbert envelope, or detrending will automatically
   %   drop notes into the waveform's HISTORY field.
   %
   %   The second way of using addhistory follows the syntax of sprintf
   %
   %   Input Arguments
   %       WAVEFORM: a waveform object   N-DIMENSIONAL
   %       WHATHAPPENED: absolutely anything.  Really.
   %
   %   AddHistory appends not only what happened, but also keeps track of WHEN
   %   it happened.
   %
   %   Control of whether or not history is added automatically lies within
   %   the waveform constructor (in a global variable called WAVEFORM_HISTORY)
   %
   %   example
   %       w = waveform; %create a blank waveform
   %       w = addhistory(w,'the following procedures done by DoIt.m');
   %       N = 1; M = 'Today'
   %       w = addhistory(w,'this is sample #%d date:%s',N,M);
   %       % output: "this is sample #1 date:Today"
   %
   %
   % See also WAVEFORM/ADDFIELD, WAVEFORM/GET, WAVEFORM/HISTORY, SPRINTF

   % AUTHOR: Celso Reyes, Geophysical Institute, Univ. of Alaska Fairbanks
   % $Date$
   % $Revision$

   global WAVEFORM_HISTORY
   if nargin > 2,
      whathappened = sprintf(whathappened, varargin{:});
   end
   if WAVEFORM_HISTORY
      modtime = now;
      for N = 1 : numel(w);
         %History is stored in a cell, the format of which is [WHAT, WHEN]
         if isempty(w(N).history)
            w(N).history = {whathappened, modtime};
         else
            w(N).history = [w(N).history; {whathappened, modtime}];
         end
      end
   end
end


function data = CreateEditData(fieldCells, session)
%
%  data = CreateEditData(fieldCells, session)
%
% Compare the field names in the session structure with
% those specified by fieldCells. If they match, add
% field name, label, contents, edit flat, and length to the
% output data struct array.
%
% See GetReconEdit.m for more information.
%
% DBR, 4/99

sessionFields = fieldnames(session);
iMatch = 0;

for iField=1:size(fieldCells, 1)
  field = fieldCells{iField, 1};

  if strmatch(field, sessionFields, 'exact')
    iMatch = iMatch + 1;
    data(iMatch).field = field;
    label = fieldCells{iField, 2};
    data(iMatch).label = label;
    fieldName = fieldCells{iField, 1};
    content = num2str(session.(fieldName));
    data(iMatch).content = content;
    data(iMatch).edit = fieldCells{iField, 3};
    data(iMatch).width = length(label) + length(content);
  end

end

return;


function printfunctionstack(symbol)
% PRINTFUNCTIONSTACK print the list of functions in the stack
%
%    PRINTFUNCTIONSTACK prints a full list of the nested function calls on the stack, so it tells you where in your code you are.
%
%    EXAMPLE:
%	function myfunc1()
%		debug.printfunctionstack('>')
%		myfunc2()
%		debug.printfunctionstack('<')
%	end
%	function myfunc2()
%		debug.printfunctionstack('>')
%		myfunc3()
%		debug.printfunctionstack('<')
%	end
%	function myfunc3()
%		debug.printfunctionstack('>')
%		disp('hello world')
%		debug.printfunctionstack('<')
%	end
%
%	debug.set_debug(1)
%	myfunc1()
%
%	would result in:
%	>myfunc1
%	>myfunc1>myfunc2
%	>myfunc1>myfunc2>myfunc3
%	hello world
%	<myfunc1<myfunc2<myfunc3
%	<myfunc1<myfunc2
%	<myfunc1
%
%    See also debug.set_debug, debug.get_debug, debug.print_debug, setpref.

% AUTHOR: Glenn Thompson, UAF-GI
% $Date: $
% $Revision: -1 $

st = dbstack;
outstr='';
if numel(st)>1
        for c=numel(st):-1:2
                outstr = sprintf('%s%s%s',outstr, symbol,st(c).name);
        end
end
debug.print_debug(1, '%s at %s',outstr,datestr(now));


function toolboxUpdateHeader
% Update the headers of all the files.
%
% USAGE
%  toolboxUpdateHeader
%
% INPUTS
%
% OUTPUTS
%
% EXAMPLE
%
% See also
%
% Piotr's Computer Vision Matlab Toolbox      Version 3.40
% Copyright 2014 Piotr Dollar.  [pdollar-at-gmail.com]
% Licensed under the Simplified BSD License [see external/bsd.txt]

header={
  'Piotr''s Computer Vision Matlab Toolbox      Version 3.40'; ...
  'Copyright 2014 Piotr Dollar.  [pdollar-at-gmail.com]'; ...
  'Licensed under the Simplified BSD License [see external/bsd.txt]'};

root=fileparts(fileparts(mfilename('fullpath')));
ds=dir(root); ds=ds([ds.isdir]); ds={ds.name};
ds=ds(3:end); ds=setdiff(ds,{'.git','doc'});
subds = { '/', '/private/' };
exts = {'m','c','cpp','h','hpp'};
omit = {'Contents.m','fibheap.h','fibheap.cpp'};

for i=1:length(ds)
  for j=1:length(subds)
    for k=1:length(exts)
      d=[root '/' ds{i} subds{j}];
      if(k==1), comment='%'; else comment='*'; end
      fs=dir([d '*.' exts{k}]); fs={fs.name}; fs=setdiff(fs,omit);
      n=length(fs); for f=1:n, fs{f}=[d fs{f}]; end
      for f=1:n, toolboxUpdateHeader1(fs{f},header,comment); end
    end
  end
end

end

function toolboxUpdateHeader1( fName, header, comment )

% set appropriate comment symbol in header
m=length(header); for i=1:m, header{i}=[comment ' ' header{i}]; end

% read in file and find header
disp(fName); lines=readFile(fName);
loc = find(not(cellfun('isempty',strfind(lines,header{1}(1:40)))));
if(isempty(loc)), error('NO HEADER: %s\n',fName); end; loc=loc(1);

% check that header is properly formed, return if up to date
for i=1:m; assert(isequal(lines{loc+i-1}(1:10),header{i}(1:10))); end
if(~any(strfind(lines{loc},'NEW'))); return; end

% update copyright year and overwrite rest of header
lines{loc+1}(13:16)=header{2}(13:16);
for i=[1 3:m]; lines{loc+i-1}=header{i}; end
writeFile( fName, lines );

end

function lines = readFile( fName )
fid = fopen( fName, 'rt' ); assert(fid~=-1);
lines=cell(10000,1); n=0;
while( 1 )
  n=n+1; lines{n}=fgetl(fid);
  if( ~ischar(lines{n}) ), break; end
end
fclose(fid); n=n-1; lines=lines(1:n);
end

function writeFile( fName, lines )
fid = fopen( fName, 'w' );
for i=1:length(lines); fprintf( fid, '%s\n', lines{i} ); end
fclose(fid);
end


function [OutputError,flir_vid] = PIVlab_capture_flir_synced_capture(flir_vid,nr_of_images,do_realtime,ROI_live,frame_nr_display)

hgui=getappdata(0,'hgui');
image_handle_flir=getappdata(hgui,'image_handle_flir');
OutputError=0;

flir_frames_to_capture = nr_of_images*2;

%% capture data

while flir_vid.FramesAcquired < (flir_frames_to_capture) &&  getappdata(hgui,'cancel_capture') ~=1
	ima = image_handle_flir.CData;
	set(frame_nr_display,'String',['Image nr.: ' int2str(round(flir_vid.FramesAcquired/2))]);
	drawnow limitrate
	%% sharpness indicator
	sharpness_enabled = getappdata(hgui,'sharpness_enabled');
	if sharpness_enabled == 1 % sharpness indicator
		textx=1240;
		texty=950;
		[~,~] = PIVlab_capture_sharpness_indicator (ima,textx,texty);
	else
		delete(findobj('tag','sharpness_display_text'));
	end
	crosshair_enabled = getappdata(hgui,'crosshair_enabled');
	if crosshair_enabled == 1 %cross-hair
		%% cross-hair
		locations=[0.15 0.5 0.85];
		half_thickness=1;
		brightness_incr=101;
		ima_ed=ima;
		old_max=max(ima(:));
		for loca=locations
			%vertical
			ima_ed(:,round(size(ima,2)*loca)-half_thickness:round(size(ima,2)*loca)+half_thickness)=ima_ed(:,round(size(ima,2)*loca)-half_thickness:round(size(ima,2)*loca)+half_thickness)+brightness_incr;
			%horizontal
			ima_ed(round(size(ima,1)*loca)-half_thickness:round(size(ima,1)*loca)+half_thickness,:)=ima_ed(round(size(ima,1)*loca)-half_thickness:round(size(ima,1)*loca)+half_thickness,:)+brightness_incr;
		end
		ima_ed(ima_ed>old_max)=old_max;
		set(image_handle_flir,'CData',ima_ed);
	end
	%% HISTOGRAM
	if getappdata(hgui,'hist_enabled')==1
		if isvalid(image_handle_flir)
			hist_fig=findobj('tag','hist_fig');
			if isempty(hist_fig)
				hist_fig=figure('numbertitle','off','MenuBar','none','DockControls','off','Name','Live histogram','Toolbar','none','tag','hist_fig','CloseRequestFcn', @HistWindow_CloseRequestFcn);
			end
			if ~exist ('old_hist_y_limits','var')
				old_hist_y_limits =[0 35000];
			else
				if isvalid(hist_obj)
					old_hist_y_limits=get(hist_obj.Parent,'YLim');
				end
			end
			hist_obj=histogram(ima(1:2:end,1:2:end),'Parent',hist_fig,'binlimits',[0 255]);
		end
		%lowpass hist y limits for better visibility
		if ~exist ('new_hist_y_limits','var')
			new_hist_y_limits =[0 35000];
		end
		new_hist_y_limits=get(hist_obj.Parent,'YLim');
		set(hist_obj.Parent,'YLim',(new_hist_y_limits*0.5 + old_hist_y_limits*0.5))
	else
		hist_fig=findobj('tag','hist_fig');
		if ~isempty(hist_fig)
			close(hist_fig)
		end
	end
	drawnow limitrate;
	%% Autofocus
	%% Lens control
	%to be implemented...
end

stoppreview(flir_vid)
stop(flir_vid);
set(frame_nr_display,'String',['Image nr.: ' int2str(round(flir_vid.FramesAcquired/2))]);
drawnow;

function HistWindow_CloseRequestFcn(hObject,~)
hgui=getappdata(0,'hgui');
setappdata(hgui,'hist_enabled',0);
try
	delete(hObject);
catch
	delete(gcf);
end


function [tests,pass,perf]=test_mrgann(varargin)

inputs={'verbose'};
verbose=0;
for n=1:nargin
    if(~isempty(varargin{n}))
        eval([inputs{n} '=varargin{n};']);
    end
end

%Test the examples
test_string={'wqrs(''mitdb/100'');mrgann(''mitdb/100'',''atr'',''wqrs'',''testAnn'')'};

clean_up={['delete([pwd filesep ''mitdb'' filesep ''*'']);' ...
          'rmdir([pwd filesep ''mitdb''],''s'');';]};
[tests,pass,perf]=test_wrapper(test_string,clean_up,verbose);


function savexml(filename, varargin)
%SAVEXML Save workspace variables to disk in XML.
%  SAVEXML FILENAME saves all workspace variables to the XML-file
%  named FILENAME.xml. The data may be retrieved with LOADXML. if
%  FILENAME has no extension, .xml is assumed.
%
%  SAVE, by itself, creates the XML-file named 'matlab.xml'. It is
%  an error if 'matlab.xml' is not writable.
%
%  SAVE FILENAME X saves only X.
%  SAVE FILENAME X Y Z saves X, Y, and Z. The wildcard '*' can be
%  used to save only those variables that match a pattern.
%
%  SAVE ... -APPEND adds the variables to an existing file.
%
%  Use the functional form of SAVE, such as SAVE(filename','var1','var2'),
%  when the filename or variable names are stored in strings.
%
%  See also SAVE, MAT2XML, XMLTREE.

%  Copyright 2003 Guillaume Flandin.
%  $Revision: 6530 $  $Date: 2003/07/10 13:50 $

%  $Id: savexml.m 6530 2015-08-21 14:43:52Z guillaume $

if nargin == 0
    filename = 'matlab.xml';
    fprintf('\nSaving to: %s\n\n',filename);
else
    if ~ischar(filename)
        error('[SAVEXML] Argument must contain a string.');
    end
    [pathstr,name,ext] = fileparts(filename);
    if isempty(ext)
        filename = [filename '.xml'];
    end
end
if nargin <= 1, varargin = {'*'}; end

if nargout > 0
    error('[SAVEXML] Too many output arguments.');
end

if strcmpi(varargin{end},'-append')
    if length(varargin) > 1
        varargin = varargin(1:end-1);
    else
        varargin = {'*'};
    end
    if exist(filename,'file')
        % TODO % No need to parse the whole tree ? detect duplicate variables ?
        t = xmltree(filename);
    else
        error(sprintf(...
        '[SAVEXML] Unable to write file %s: file does not exist.',filename));
    end
else
    t = xmltree('<matfile/>');
end

for i=1:length(varargin)
    v = evalin('caller',['whos(''' varargin{i} ''')']);
    if isempty(v)
        error(['[SAVEXML] Variable ''' varargin{i} ''' not found.']);
    end
    for j=1:length(v)
        [t, uid] = add(t,root(t),'element',v(j).name);
        t = attributes(t,'add',uid,'type',v(j).class);
        t = attributes(t,'add',uid,'size',xml_num2str(v(j).size));
        t = xml_var2xml(t,evalin('caller',v(j).name),uid);
    end
end

save(t,filename);

%=======================================================================
function t = xml_var2xml(t,v,uid)

    switch class(v)
        case {'double','single','logical'}
            if ~issparse(v)
                t = add(t,uid,'chardata',xml_num2str(v));
            else % logical
                [i,j,s] = find(v);
                [t, uid2] = add(t,uid,'element','row');
                t = attributes(t,'add',uid2,'size',xml_num2str(size(i)));
                t = add(t,uid2,'chardata',xml_num2str(i));
                [t, uid2] = add(t,uid,'element','col');
                t = attributes(t,'add',uid2,'size',xml_num2str(size(j)));
                t = add(t,uid2,'chardata',xml_num2str(j));
                [t, uid2] = add(t,uid,'element','val');
                t = attributes(t,'add',uid2,'size',xml_num2str(size(s)));
                t = add(t,uid2,'chardata',xml_num2str(s));
            end
        case 'struct'
            names = fieldnames(v);
            for j=1:prod(size(v))
                for i=1:length(names)
                    [t, uid2] = add(t,uid,'element',names{i});
                    t = attributes(t,'add',uid2,'index',num2str(j));
                    t = attributes(t,'add',uid2,'type',...
                        class(getfield(v(j),names{i})));
                    t = attributes(t,'add',uid2,'size', ...
                        xml_num2str(size(getfield(v(j),names{i}))));
                    t = xml_var2xml(t,getfield(v(j),names{i}),uid2);
                end
            end
        case 'cell'
            for i=1:prod(size(v))
                [t, uid2] = add(t,uid,'element','cell');
                % TODO % special handling of cellstr ?
                t = attributes(t,'add',uid2,'index',num2str(i));
                t = attributes(t,'add',uid2,'type',class(v{i}));
                t = attributes(t,'add',uid2,'size',xml_num2str(size(v{i})));
                t = xml_var2xml(t,v{i},uid2);
            end
        case 'char'
            % TODO % char values should be in CData
            if size(v,1) > 1
                t = add(t,uid,'chardata',v'); % row-wise order
            else
                t = add(t,uid,'chardata',v);
            end
        case {'int8','uint8','int16','uint16','int32','uint32'}
            [t, uid] = add(t,uid,'element',class(v));
            % TODO % Handle integer formats (cannot use sprintf or num2str)
        otherwise
            if ismember('serialize',methods(class(v)))
                % TODO % is CData necessary for class output ?
                t = add(t,uid,'cdata',serialize(v));
            else
                warning(sprintf(...
                '[SAVEXML] Cannot convert from %s to XML.',class(v)));
            end
    end

%=======================================================================
function s = xml_num2str(n)
    % TODO % use format ?
    if isempty(n)
        s = '[]';
    else
        s = ['[' sprintf('%g ',n(1:end-1))];
        s = [s num2str(n(end)) ']'];
    end


%                                          [ux,ispos] = psdfactor(x,K)
% PSDFACTOR  UX'*UX Cholesky factorization
%
% **********  INTERNAL FUNCTION OF SEDUMI **********
%
% See also sedumi

function [ux,ispos] = psdfactor(x,K) %#ok
%
% This file is part of SeDuMi 1.1 by Imre Polik and Oleksandr Romanko
% Copyright (C) 2005 McMaster University, Hamilton, CANADA  (since 1.1)
%
% Copyright (C) 2001 Jos F. Sturm (up to 1.05R5)
%   Dept. Econometrics & O.R., Tilburg University, the Netherlands.
%   Supported by the Netherlands Organization for Scientific Research (NWO).
%
% Affiliation SeDuMi 1.03 and 1.04Beta (2000):
%   Dept. Quantitative Economics, Maastricht University, the Netherlands.
%
% Affiliations up to SeDuMi 1.02 (AUG1998):
%   CRL, McMaster University, Canada.
%   Supported by the Netherlands Organization for Scientific Research (NWO).
%
% 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.,  51 Franklin Street, Fifth Floor, Boston, MA
% 02110-1301, USA

disp('The SeDuMi binaries are not installed.')
disp('In Matlab, launch "install_sedumi" in the folder you put the SeDuMi files.')
disp('For more information see the file Install.txt.')
error(' ')


classdef K3Supervisor < simiam.controller.Supervisor
%% SUPERVISOR switches between controllers and handles their inputs/outputs.
%
% Properties:
%   current_controller      - Currently selected controller
%   controllers             - List of available controllers
%   goal_points             - Set of goal points
%   goal_index              - Pointer to current goal point
%   v                       - Robot velocity
%
% Methods:
%   execute - Selects and executes the current controller.

% Copyright (C) 2013, Georgia Tech Research Corporation
% see the LICENSE file included with this software

    properties
    %% PROPERTIES

        states
        eventsd

        current_state

        prev_ticks          % Previous tick count on the left and right wheels
        v
        goal

        goal_prev
        d_stop
        d_at_obs
        d_unsafe
        d_prog
        p

        direction

        v_gtg
        v_ao
        v_fw

%         is_init
    end

    methods
    %% METHODS

        function obj = K3Supervisor()
        %% SUPERVISOR Constructor
            obj = obj@simiam.controller.Supervisor();

            % initialize the controllers
            obj.controllers{1} = simiam.controller.AvoidObstacles();
            obj.controllers{2} = simiam.controller.GoToGoal();
            obj.controllers{3} = simiam.controller.GoToAngle();
            obj.controllers{4} = simiam.controller.AOandGTG();
            obj.controllers{5} = simiam.controller.Stop();
            obj.controllers{6} = simiam.controller.FollowWall();
            obj.controllers{7} = simiam.controller.SlidingMode();

            % set the initial controller
            obj.current_controller = obj.controllers{4};
            obj.current_state = 4;

            % generate the set of states
            for i = 1:length(obj.controllers)
                obj.states{i} = struct('state', obj.controllers{i}.type, ...
                                       'controller', obj.controllers{i});
            end

            % define the set of eventsd
            obj.eventsd{1} = struct('event', 'at_obstacle', ...
                                   'callback', @at_obstacle);

            obj.eventsd{2} = struct('event', 'at_goal', ...
                                   'callback', @at_goal);

            obj.eventsd{3} = struct('event', 'obstacle_cleared', ...
                                    'callback', @obstacle_cleared);

            obj.eventsd{4} = struct('event', 'unsafe', ...
                                    'callback', @unsafe);

            obj.eventsd{5} = struct('event', 'progress_made', ...
                                    'callback', @progress_made);

            obj.eventsd{6} = struct('event', 'sliding_left', ...
                                    'callback', @sliding_left);

            obj.eventsd{7} = struct('event', 'sliding_right', ...
                                    'callback', @sliding_right);

            obj.prev_ticks = struct('left', 0, 'right', 0);

            obj.v               = 0.15;

            obj.goal            = [-1;1];
            obj.goal_prev       = obj.goal;
            obj.d_stop          = 0.05;
            obj.d_at_obs        = 0.10;
            obj.d_unsafe        = 0.03;

            obj.d_prog = 10;

            obj.p = simiam.util.Plotter();
            obj.current_controller.p = obj.p;
        end

        function execute(obj, dt)
        %% EXECUTE Selects and executes the current controller.
        %   execute(obj, robot) will select a controller from the list of
        %   available controllers and execute it.
        %
        %   See also controller/execute

%             if(~obj.is_init)
%                 hold(obj.robot.parent, 'on');
%                 obj.v_gtg = plot(obj.robot.parent, [0 0], [0 0], 'b-');
%                 obj.v_ao = plot(obj.robot.parent, [0 0], [0 0], 'r-');
%                 obj.v_fw = plot(obj.robot.parent, [0 0], [0 0], 'g-');
%                 obj.is_init = true;
%             end

            inputs = obj.controllers{4}.inputs;
            inputs.x_g = obj.goal(1);
            inputs.y_g = obj.goal(2);
            inputs.v = obj.v;

%             if(~all(obj.goal==obj.goal_prev))
% %                 [x,y,theta] = obj.state_estimate.unpack();
% %                 if(norm(obj.goal-[x;y])<norm(obj.goal_prev-[x;y]))
%                     obj.set_progress_point();
% %                 end
%                 obj.goal_prev = obj.goal;
%                 obj.switch_to_state('go_to_goal');
%             end
%
            if (obj.check_event('at_goal'))
                obj.switch_to_state('stop');

%                 [x,y,theta] = obj.state_estimate.unpack();
%                 fprintf('stopped at (%0.3f,%0.3f)\n', x, y);
            else
                obj.switch_to_state('ao_and_gtg');
            end
%             elseif(obj.check_event('unsafe'))
%                 obj.switch_to_state('avoid_obstacles');
%             else
%                 if (obj.is_in_state('go_to_goal'))
%                     if(obj.check_event('at_obstacle') && obj.check_event('sliding_left'))
%                         obj.direction = 'left';
% %                         fprintf('now following to the left\n');
%                         obj.switch_to_state('follow_wall');
%                         obj.set_progress_point();
%                     elseif(obj.check_event('at_obstacle') && obj.check_event('sliding_right'))
%                         obj.direction = 'right';
% %                         fprintf('now following to the right\n');
%                         obj.switch_to_state('follow_wall');
%                         obj.set_progress_point();
%                     end
%                 elseif (obj.is_in_state('follow_wall') && strcmp(obj.direction,'left'))
%                     if(obj.check_event('progress_made') && ~obj.check_event('sliding_left'))
%                         obj.switch_to_state('go_to_goal');
%                     end
%                 elseif (obj.is_in_state('follow_wall') && strcmp(obj.direction, 'right'))
%                     if(obj.check_event('progress_made') && ~obj.check_event('sliding_right'))
%                         obj.switch_to_state('go_to_goal');
%                     end
%                 elseif (obj.is_in_state('avoid_obstacles'))
%                     if(obj.check_event('obstacle_cleared'))
% %                         if(obj.check_event('sliding_left'))
% %                             obj.direction = 'left';
% %                             obj.switch_to_state('follow_wall');
% %                         elseif(obj.check_event('sliding_right'))
% %                             obj.direction = 'right';
% %                             obj.switch_to_state('follow_wall');
% %                         else
%                             obj.switch_to_state('go_to_goal');
% %                         end
%                     end
%                 end
%
%             end

%             elseif(obj.check_event('unsafe'))
%                 obj.switch_to_state('avoid_obstacles');
%             else
%                 if (obj.is_in_state('go_to_goal'))
%                     if(obj.check_event('at_obstacle') && obj.check_event('sliding_left'))
%                         obj.direction = 'left';
% %                         fprintf('now following to the left\n');
%                         obj.switch_to_state('follow_wall');
%                         obj.set_progress_point();
%                     elseif(obj.check_event('at_obstacle') && obj.check_event('sliding_right'))
%                         obj.direction = 'right';
% %                         fprintf('now following to the right\n');
%                         obj.switch_to_state('follow_wall');
%                         obj.set_progress_point();
%                     end
%                 elseif (obj.is_in_state('follow_wall') && strcmp(obj.direction,'left'))
%                     if(obj.check_event('progress_made') && ~obj.check_event('sliding_left'))
%                         obj.switch_to_state('go_to_goal');
%                     end
%                 elseif (obj.is_in_state('follow_wall') && strcmp(obj.direction, 'right'))
%                     if(obj.check_event('progress_made') && ~obj.check_event('sliding_right'))
%                         obj.switch_to_state('go_to_goal');
%                     end
%                 elseif (obj.is_in_state('avoid_obstacles'))
%                     if(obj.check_event('obstacle_cleared'))
% %                         if(obj.check_event('sliding_left'))
% %                             obj.direction = 'left';
% %                             obj.switch_to_state('follow_wall');
% %                         elseif(obj.check_event('sliding_right'))
% %                             obj.direction = 'right';
% %                             obj.switch_to_state('follow_wall');
% %                         else
%                             obj.switch_to_state('go_to_goal');
% %                         end
%                     end
%                 end

%             end

%             inputs.direction = obj.direction;

            outputs = obj.current_controller.execute(obj.robot, obj.state_estimate, inputs, dt);

            [vel_r, vel_l] = obj.robot.dynamics.uni_to_diff(outputs.v, outputs.w);
            obj.robot.set_wheel_speeds(vel_r, vel_l);

%             fprintf('(v,w) = (%0.3f,%0.3f)\n', outputs.v, outputs.w);

            obj.update_odometry();
%             [x, y, theta] = obj.state_estimate.unpack();
%             fprintf('current_pose: (%0.3f,%0.3f,%0.3f)\n', x, y, theta);
        end

        function set_progress_point(obj)
            [x, y, theta] = obj.state_estimate.unpack();
            obj.d_prog = norm([x-obj.goal(1);y-obj.goal(2)]);
        end

        %% Events %%

        function rc = sliding_left(obj, state, robot)
            inputs = obj.controllers{7}.inputs;
            inputs.x_g = obj.goal(1);
            inputs.y_g = obj.goal(2);
            inputs.direction = 'left';

            obj.controllers{7}.execute(obj.robot, obj.state_estimate, inputs, 0);

            u_gtg = obj.controllers{7}.u_gtg;
            u_ao = obj.controllers{7}.u_ao;
            u_fw = obj.controllers{7}.u_fw;

            %% START CODE BLOCK %%
            sigma = [u_gtg u_ao]\u_fw;
            %% END CODE BLOCK %%

            rc = false;
            if sigma(1) > 0 && sigma(2) > 0
%                 fprintf('now sliding left\n');
                rc = true;
            end
        end

        function rc = sliding_right(obj, state, robot)
            inputs = obj.controllers{7}.inputs;
            inputs.x_g = obj.goal(1);
            inputs.y_g = obj.goal(2);
            inputs.direction = 'right';

            obj.controllers{7}.execute(obj.robot, obj.state_estimate, inputs, 0);

            u_gtg = obj.controllers{7}.u_gtg;
            u_ao = obj.controllers{7}.u_ao;
            u_fw = obj.controllers{7}.u_fw;

            %% START CODE BLOCK
            sigma = [u_gtg u_ao]\u_fw;
            %% END CODE BLOCK

            rc = false;
            if sigma(1) > 0 && sigma(2) > 0
%                 fprintf('now sliding right\n');
                rc = true;
            end
        end

        function rc = at_obstacle(obj, state, robot)
            ir_distances = obj.robot.get_ir_distances();
            rc = false;                                     % Assume initially that the robot is clear of obstacle

            % Loop through and test the sensors (only the front set)
            if any(ir_distances(2:7) < obj.d_at_obs)
                rc = true;
            end
        end

        function rc = unsafe(obj, state, robot)
            ir_distances = obj.robot.get_ir_distances();
            rc = false;             % Assume initially that the robot is clear of obstacle

            % Loop through and test the sensors (only the front set)
            if any(ir_distances(2:7) < obj.d_unsafe)
                    rc = true;
            end
        end

        function rc = at_goal(obj, state, robot)
            [x,y,theta] = obj.state_estimate.unpack();
            rc = false;

            % Test distance from goal
            if norm([x - obj.goal(1); y - obj.goal(2)]) < obj.d_stop
                rc = true;
            end
        end

        function rc = obstacle_cleared(obj, state, robot)
            ir_distances = obj.robot.get_ir_distances();
            rc = false;              % Assume initially that the robot is clear of obstacle

            % Loop through and test the sensors (only front set)
            if all(ir_distances(2:7) > obj.d_at_obs)
                rc = true;
            end
        end

        function rc = progress_made(obj, state, robot)

            % Check for any progress
            [x, y, theta] = obj.state_estimate.unpack();
            epsilon = 0.1;

            %% START CODE BLOCK %%
            rc = false;
            if norm([x-obj.goal(1); y-obj.goal(2)]) < (obj.d_prog - epsilon)
                rc = true;          % progress has been made
            end
            %% END CODE BLOCK %%

        end

        %% State machine support functions

        function set_current_controller(obj, ctrl)
            % save plots
            obj.current_controller = ctrl;
            obj.p.switch_2d_ref();
            obj.current_controller.p = obj.p;
        end

        function rc = is_in_state(obj, name)
            rc = strcmp(name, obj.states{obj.current_state}.state);
        end

        function switch_to_state(obj, name)

            if(~obj.is_in_state(name))
                for i=1:numel(obj.states)
                    if(strcmp(obj.states{i}.state, name))
                        obj.set_current_controller(obj.states{i}.controller);
                        obj.current_state = i;
                        fprintf('switching to state %s\n', name);
                        return;
                    end
                end
            else
%                 fprintf('already in state %s\n', name);
                return
            end

            fprintf('no state exists with name %s\n', name);
        end

        function rc = check_event(obj, name)
           for i=1:numel(obj.eventsd)
               if(strcmp(obj.eventsd{i}.event, name))
                   rc = obj.eventsd{i}.callback(obj, obj.states{obj.current_state}, obj.robot);
                   return;
               end
           end

           % return code (rc)
           fprintf('no event exists with name %s\n', name);
           rc = false;
        end

        %% Odometry

        function update_odometry(obj)
        %% UPDATE_ODOMETRY Approximates the location of the robot.
        %   obj = obj.update_odometry(robot) should be called from the
        %   execute function every iteration. The location of the robot is
        %   updated based on the difference to the previous wheel encoder
        %   ticks. This is only an approximation.
        %
        %   state_estimate is updated with the new location and the
        %   measured wheel encoder tick counts are stored in prev_ticks.

            % Get wheel encoder ticks from the robot
            right_ticks = obj.robot.encoders(1).ticks;
            left_ticks = obj.robot.encoders(2).ticks;

            % Recal the previous wheel encoder ticks
            prev_right_ticks = obj.prev_ticks.right;
            prev_left_ticks = obj.prev_ticks.left;

            % Previous estimate
            [x, y, theta] = obj.state_estimate.unpack();

            % Compute odometry here
            R = obj.robot.wheel_radius;
            L = obj.robot.wheel_base_length;
            m_per_tick = (2*pi*R)/obj.robot.encoders(1).ticks_per_rev;

            d_right = (right_ticks-prev_right_ticks)*m_per_tick;
            d_left = (left_ticks-prev_left_ticks)*m_per_tick;
            d_center = (d_right + d_left)/2;

            x_dt = d_center*cos(theta);
            y_dt = d_center*sin(theta);
            theta_dt = (d_right - d_left)/L;

            theta_new = theta + theta_dt;
            x_new = x + x_dt;
            y_new = y + y_dt;
%             fprintf('Estimated pose (x,y,theta): (%0.3g,%0.3g,%0.3g)\n', x_new, y_new, theta_new);

            % Save the wheel encoder ticks for the next estimate
            obj.prev_ticks.right = right_ticks;
            obj.prev_ticks.left = left_ticks;

            % Update your estimate of (x,y,theta)
            obj.state_estimate.set_pose([x_new, y_new, theta_new]);
        end
    end
end


function found = existDataType(dataTypeName,dataTypes,fullMatch)
%
%      found = existDataType([dataTypeName],[dataTypes],[fullMatch])
%
%   Check whether a dataType with dataTypeName exists in the mrSESSION structure.
%
%   If a full match to the dataType name is not found, then we return
%   found=0.
%
%   If a full match is found, mrSESSION.dataTypes(found) is the dataType.
%
%   If a partial match (fullMatch = 0) is requested, then existDataType() can
%   find several matches (i.e., whenever the first part of the data type name matches
%   the dataTypeName string). In this case, found returns a list of indices
%   whose names match the dataTypeName.  If no matches are found, then
%   found = 0 is returned.
%
%   Examples:
%       existDataType('Atlases',dataTypes,0) returns a list of partial matches
%        mrSESSION.dataTypes(found) all begin with the phrase 'Atlases', such as
%        'Atlases-1'.
%
% dataTypes: optional dataTypes structure. Default is to use the global dataTYPES.
%
% djh, 3/2001

global dataTYPES

if ~exist('dataTypes','var') || isempty(dataTypes),  dataTypes = dataTYPES; end
if ~exist('fullMatch','var'), fullMatch = 1; end

ndataTypes = length(dataTypes);

if fullMatch
    found = 0;
    for ii=1:ndataTypes
        if strcmp(dtGet(dataTypes(ii), 'Name'),dataTypeName);
            found = ii;
            return;
        end
    end
else
    found = zeros(1,ndataTypes);
    for ii=1:ndataTypes
        found(ii) =  strncmp(dtGet(dataTypes(ii), 'Name'),dataTypeName,length(dataTypeName));
    end
    found = find(found);
    if isempty(found), found = 0; end
end

return;


function gid = slguid()
%SLGUID Generates a GUID (Global Unique Identifier)
%
% $ Syntax $
%   - gid = slguid()
%
% $ Description $
%   - gid = slguid() generates a 128-bit GUID, which is represented by
%     a 16 x 1 UINT8 array. If it succeeds, an 1 x 16 array is returned
%     otherwise an error is reported.
%
% $ Remarks $
%   - In current implementation, it is based on win32guid_core mex
%     cpp function, thus only Win32 or compatible platform is supported.
%
% $ History $
%   - Created by Dahua Lin, on Aug 12, 2006
%

if ~strcmpi(computer(), 'PCWIN') && ~strcmpi(computer(), 'PCWIN64')
    error('sltoolbox:notsupportplatform', ...
        'Only win32 or x64 platform is supported for slguid');
end

[b, gid] = win32guid_core();

if ~b
    error('sltoolbox:rterror', ...
        'Fail to generate GUID');
end


function publish_html(filename, outputDir, stylesheet)

% publish_html - publish a file to HTML format
%
%    publish_html(filename, outputDir, stylesheet);
%
%   Copyright (c) 2008 Gabriel Peyre

if nargin<1
    filename = 'content';
end
if nargin<2
    outputDir = 'html';
end
if nargin<3
    stylesheet = [outputDir '/gpeyre.xsl'];
end

opts.outputDir = outputDir;
if not(isempty(stylesheet))
    opts.stylesheet = stylesheet;
end
file = publish(filename,opts);

web(file);


function [optarg] = ft_cfg2keyval(cfg)

% FT_CFG2KEYVAL converts between a structure and a cell-array with key-value
% pairs which can be used for optional input arguments.
%
% Use as
%   optarg = ft_cfg2keyval(cfg)
%
% See also FT_KEYVAL2CFG, FT_GETOPT

% Copyright (C) 2006-2016, Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% 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$

if ~isempty(cfg)
  optarg = [fieldnames(cfg) struct2cell(cfg)]';
  optarg = optarg(:)';
else
  optarg = {};
end


function val = get_params(pot, name)
% GET_PARAMS Accessor function for a field (dpot)
% val = get_params(pot, name)
%
% e.g., get_params(pot, 'table') or 'domain'

switch name
 case 'table', val = pot.T;
 case 'domain', val = pot.domain;
 otherwise,
  error(['invalid field name ' name]);
end


function [cfg] = ft_rejectartifact(cfg, data)

% FT_REJECTARTIFACT removes data segments containing artifacts. It returns a
% configuration structure with a modified trial definition which can be used for
% preprocessing of only the clean data.
%
% You should start by detecting the artifacts in the data using the function
% FT_ARTIFACT_xxx where xxx is the type of artifact. Subsequently FT_REJECTARTIFACT
% looks at the detected artifacts and removes them from the trial definition or from
% the data. In case you wish to replace bad parts by NaNs, you have to specify data
% as an input parameter.
%
% Use as
%   [cfg] = ft_rejectartifact(cfg)
% with the cfg as obtained from FT_DEFINETRIAL, or as
%   [data] = ft_rejectartifact(cfg, data)
% with the data as obtained from FT_PREPROCESSING
%
% The following configuration options are supported
%   cfg.artfctdef.reject          = 'none', 'partial', 'complete', 'nan', 'zero', or 'value' (default = 'complete')
%   cfg.artfctdef.minaccepttim    = when using partial rejection, minimum length
%                                   in seconds of remaining trial (default = 0.1)
%   cfg.artfctdef.crittoilim      = when using complete rejection, reject trial only when artifacts occur within
%                                   this time window (default = whole trial). This only works with in-memory data,
%                                   since trial time axes are unknown for data on disk.
%   cfg.artfctdef.feedback        = 'yes' or 'no' (default = 'no')
%   cfg.artfctdef.invert          = 'yes' or 'no' (default = 'no')
%   cfg.artfctdef.value           = scalar value to replace the data in the artifact segments (default = nan)
%   cfg.artfctdef.eog.artifact    = Nx2 matrix with artifact segments, this is added to the cfg by using FT_ARTIFACT_EOG
%   cfg.artfctdef.jump.artifact   = Nx2 matrix with artifact segments, this is added to the cfg by using FT_ARTIFACT_JUMP
%   cfg.artfctdef.muscle.artifact = Nx2 matrix with artifact segments, this is added to the cfg by using FT_ARTIFACT_MUSCLE
%   cfg.artfctdef.zvalue.artifact = Nx2 matrix with artifact segments, this is added to the cfg by using FT_ARTIFACT_ZVALUE
%   cfg.artfctdef.visual.artifact = Nx2 matrix with artifact segments, this is added to the cfg by using FT_DATABROWSER
%   cfg.artfctdef.xxx.artifact    = Nx2 matrix with artifact segments, this could be added by your own artifact detection function
%
% A trial that contains an artifact can be rejected completely or partially. In case
% of partial rejection, a minimum length of the resulting sub-trials can be specified
% using minaccepttim.
%
% Output:
%   If cfg is the only input parameter, the output is a cfg structure with an updated trl.
%   If cfg and data are both input parameters, the output is an updated raw data structure with only the clean data segments.
%
% To facilitate data-handling and distributed computing you can use
%   cfg.inputfile   =  ...
% If you specify this option the input data will be read from a *.mat
% file on disk. This mat files should contain only a single variable named 'data',
% corresponding to the input structure.
%
% See also FT_ARTIFACT_ZVALUE, FT_ARTIFACT_EOG, FT_ARTIFACT_MUSCLE, FT_ARTIFACT_JUMP,
% FT_ARTIFACT_THRESHOLD, FT_ARTIFACT_CLIP, FT_ARTIFACT_ECG, FT_DATABROWSER,
% FT_REJECTVISUAL

% Undocumented local options:
% cfg.headerfile
% cfg.reject
% cfg.trl
% cfg.trlold
% cfg.version
%
% These old configuration options are still supported
% cfg.rejectmuscle      = 'no' or 'yes'
% cfg.rejecteog         = 'no' or 'yes'
% cfg.rejectjump        = 'no' or 'yes'
% cfg.rejectfile        = string with filename
% cfg.artfctdef.writerej = filename of rejection file
% cfg.artfctdef.type    = cell-array with strings, e.g. {'eog', 'muscle' 'jump'}

% Copyright (C) 2003-2020, Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% 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$

% FIXME this function contains a lot of lines of code that pertain to backward
% compatibility support that dates back to 2004/2005. It would be good to strip
% that code and only keep the relevant parts

% these are used by the ft_preamble/ft_postamble function and scripts
ft_revision = '$Id$';
ft_nargin   = nargin;
ft_nargout  = nargout;

% do the general setup of the function
ft_defaults
ft_preamble init
ft_preamble debug
ft_preamble loadvar data
ft_preamble provenance data

% the ft_abort variable is set to true or false in ft_preamble_init
if ft_abort
  return
end

% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'dataset2files', 'yes');

% set the defaults
cfg.artfctdef              = ft_getopt(cfg, 'artfctdef');
cfg.artfctdef.type         = ft_getopt(cfg.artfctdef, 'type', {});
cfg.artfctdef.reject       = ft_getopt(cfg.artfctdef, 'reject', 'complete');
cfg.artfctdef.minaccepttim = ft_getopt(cfg.artfctdef, 'minaccepttim', 0.1);
cfg.artfctdef.crittoilim   = ft_getopt(cfg.artfctdef, 'crittoilim', []);
cfg.artfctdef.feedback     = ft_getopt(cfg.artfctdef, 'feedback', 'no');
cfg.artfctdef.invert       = ft_getopt(cfg.artfctdef, 'invert', 'no');
cfg.artfctdef.value        = ft_getopt(cfg.artfctdef, 'value', nan);

% convert from old-style to new-style configuration
if isfield(cfg,'reject')
  ft_warning('converting from old-style artifact configuration to new-style');
  cfg.artfctdef.reject = cfg.reject;
  cfg = rmfield(cfg, 'reject');
end

% convert from old-style to new-style configuration
if isfield(cfg.artfctdef,'common')
  ft_warning('converting from old-style artifact configuration to new-style');
  if isfield(cfg.artfctdef.common,'minaccepttim')
    cfg.artfctdef.minaccepttim = cfg.artfctdef.common.minaccepttim;
    cfg.artfctdef = rmfield(cfg.artfctdef, 'common');
  end
end

% ensure that it is a cell-array
if ischar(cfg.artfctdef.type)
  cfg.artfctdef.type = {cfg.artfctdef.type};
end

% support the rejectXXX cfg settings for backward compatibility
if isfield(cfg, 'rejectmuscle')
  fn = find(strcmp('muscle', cfg.artfctdef.type));
  if strcmp(cfg.rejectmuscle,'yes') && isempty(fn)
    % this overrules the other setting, add it to the type-list
    cfg.artfctdef.type = cat(1, {'muscle'}, cfg.artfctdef.type(:));
  elseif strcmp(cfg.rejectmuscle,'no') && ~isempty(fn)
    % this overrules the other setting, remove it from the type-list
    cfg.artfctdef.type(fn) = [];
  end
  cfg = rmfield(cfg, 'rejectmuscle');
end

% support the rejectXXX cfg settings for backward compatibility
if isfield(cfg, 'rejecteog')
  fn = find(strcmp('eog', cfg.artfctdef.type));
  if strcmp(cfg.rejecteog,'yes') && isempty(fn)
    % this overrules the other setting, add it to the type-list
    cfg.artfctdef.type = cat(1, {'eog'}, cfg.artfctdef.type(:));
  elseif strcmp(cfg.rejecteog,'no') && ~isempty(fn)
    % this overrules the other setting, remove it from the type-list
    cfg.artfctdef.type(fn) = [];
  end
  cfg = rmfield(cfg, 'rejecteog');
end

% support the rejectXXX cfg settings for backward compatibility
if isfield(cfg, 'rejectjump')
  fn = find(strcmp('jump', cfg.artfctdef.type));
  if strcmp(cfg.rejectjump,'yes') && isempty(fn)
    % this overrules the other setting, add it to the type-list
    cfg.artfctdef.type = cat(1, {'jump'}, cfg.artfctdef.type(:));
  elseif strcmp(cfg.rejectjump,'no') && ~isempty(fn)
    % this overrules the other setting, remove it from the type-list
    cfg.artfctdef.type(fn) = [];
  end
  cfg = rmfield(cfg, 'rejectjump');
end

% support the rejectXXX cfg settings for backward compatibility
if isfield(cfg, 'rejectfile')
  % this is slightly different to the ones above, since rejectfile is either 'no' or contains the filename
  fn = find(strcmp('file', cfg.artfctdef.type));
  if ~strcmp(cfg.rejectfile,'no') && isempty(fn)
    % this overrules the other setting, add it to the type-list
    cfg.artfctdef.type = cat(1, {'file'}, cfg.artfctdef.type(:));
  elseif strcmp(cfg.rejectfile,'no') && ~isempty(fn)
    % this overrules the other setting, remove it from the type-list
    cfg.artfctdef.type(fn) = [];
  end
end

% the data can be specified as input variable or through cfg.inputfile
hasdata = exist('data', 'var');

if hasdata
  % ensure that the data is valid for this function
  data = ft_checkdata(data, 'datatype', 'raw', 'hassampleinfo', 'yes');
end

if hasdata && isfield(data, 'sampleinfo')
  % construct the trial definition from the sampleinfo and the trialinfo
  trl = sampleinfo2trl(data);
elseif isfield(cfg, 'trl') && ischar(cfg.trl)
  % load the trial information from file
  trl = loadvar(cfg.trl, 'trl');
elseif isfield(cfg, 'trl')
  % use the trial information that was specified
  trl = cfg.trl;
else
  % there must be trials that can be scanned for artifacts and/or rejected
  ft_error('no trials were selected, cannot perform artifact detection/rejection');
end

% remember the original trial definition, this may include additional columns
trlold = trl;

% the code below expects an Nx3 matrix with begsample, endsample and offset
if istable(trl)
  trl = table2array(trl(:,1:3));
else
  trl = trl(:,1:3);
end

% ensure the crittoilim input argument is valid
if ~isempty(cfg.artfctdef.crittoilim)

  if (size(cfg.artfctdef.crittoilim,2) ~= 2 ...
      || (size(cfg.artfctdef.crittoilim,1) ~= size(trl,1) ...
      && size(cfg.artfctdef.crittoilim,1) ~= 1))
    ft_error('if specified, cfg.artfctdef.crittoilim should be a 1x2 or Nx2 vector');
  end

  % if specified as 1x2 vector, expand into Nx2
  if (size(cfg.artfctdef.crittoilim,1) == 1)
    cfg.artfctdef.crittoilim = repmat(cfg.artfctdef.crittoilim,size(trl,1),1);
  end

  checkCritToi = 1; % flag for convenience
else
  checkCritToi = 0;
end

% prevent double occurences of artifact types, ensure that the order remains the same
[fn, i] = unique(cfg.artfctdef.type);
cfg.artfctdef.type = cfg.artfctdef.type(sort(i));
% ensure that it is a row vector
cfg.artfctdef.type = cfg.artfctdef.type(:)';

% If bad parts are to be filled with NaNs, make sure data is available
if ~hasdata && any(strcmp({'nan', 'zero', 'value'}, cfg.artfctdef.reject))
  ft_error('If bad parts are to be filled with NaNs or another value, the input data has to be specified');
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% call the appropriate function for each of the artifact types
% this will produce a Nx2 matrix with the begin and end sample of artifacts
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for type=1:length(cfg.artfctdef.type)
  funhandle = ft_getuserfun(cfg.artfctdef.type{type}, 'artifact');
  ft_info('evaluating %s\n', func2str(funhandle));
  % each call to artifact_xxx adds cfg.artfctdef.xxx.artifact
  if hasdata
    cfg = feval(funhandle, cfg, data);
  else
    cfg = feval(funhandle, cfg);
  end
end

% collect the artifacts that have been detected from cfg.artfctdef.xxx.artifact
fn = fieldnames(cfg.artfctdef);
sel = false(size(fn));
artifact = {};
for i=1:length(fn)
  sel(i) = issubfield(cfg.artfctdef, fn{i}) && issubfield(cfg.artfctdef, [fn{i} '.artifact']);
  if sel(i)
    artifact{end+1} = getsubfield(cfg.artfctdef, [fn{i} '.artifact']);
    num = size(artifact{end}, 1);
    if isempty(num)
      num = 0;
    end
    ft_info('detected %3d %s artifacts\n', num, fn{i});
  end
end

% update the configuration to reflect the artifacts types that were scanned
cfg.artfctdef.type = fn(sel);

% combine all trials into a single boolean vector
trialall = trl2boolvec(trl);

% combine all artifacts into a single vector
rejectall = zeros(1, max(trl(:,2)));
for i=1:length(cfg.artfctdef.type)
  begsample = [];
  endsample = [];
  if istable(artifact{i}) && ~isempty(artifact{i})
    begsample = artifact{i}.begsample;
    endsample = artifact{i}.endsample;
  elseif ~istable(artifact{i}) && ~isempty(artifact{i})
    begsample = artifact{i}(:,1);
    endsample = artifact{i}(:,2);
  end
  for j=1:length(begsample)
    rejectall(begsample(j):endsample(j)) = i;  % the artifact type is coded here
  end
end

% ensure that both vectors are the same length
if length(trialall)>length(rejectall)
  rejectall(length(trialall)) = 0;
elseif length(trialall)<length(rejectall)
  trialall(length(rejectall)) = 0;
end

% make header, needed only for sampling frequency
if hasdata
  hdr = ft_fetch_header(data);
else
  if isfield(cfg, 'headerformat')
    hdr = ft_read_header(cfg.headerfile, 'headerformat', cfg.headerformat);
  else
    hdr = ft_read_header(cfg.headerfile);
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% give visual feedback on the trial definition and the artifacts
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if strcmp(cfg.artfctdef.feedback, 'yes')
  COLOR = 'grcmykgrcmykgrcmykgrcmyk';
  % compute the time axis that corresponds with each trial
  time = cell(size(trl,1), 1);
  timebeg = nan(size(trl,1), 1);
  timeend = nan(size(trl,1), 1);
  for i=1:size(trl,1)
    time{i} = offset2time(trl(i,3), hdr.Fs, trl(i,2)-trl(i,1)+1);
    timebeg(i) = time{i}(1);
    timeend(i) = time{i}(end);
  end

  figure
  title('linear display of the continuous data')
  xlabel('sample number');
  hold on
  x = 1:length(trialall);
  y = ones(size(trialall)) * 0.53;
  y(~trialall) = nan;
  plot(x, y, 'b');
  for i=1:length(cfg.artfctdef.type)
    x = 1:length(rejectall);
    y = ones(size(rejectall)) * (0.5 - i*0.03);
    y(~(rejectall==i)) = nan;
    plot(x, y, COLOR(i));
  end
  set(gca, 'ytick', []);
  fn = (trialall~=0) | (rejectall~=0);
  [dum2, fn] = find(fn);
  smpbeg = fn(1)   - hdr.Fs;
  smpend = fn(end) + hdr.Fs;
  axis([smpbeg smpend 0 1]);
  legend([{'defined trials'}, cfg.artfctdef.type(:)']);

  figure
  title('individual trials aligned to time-zero')
  xlabel('time (s)');
  ylabel('trial number');
  hold on
  for i=1:size(trl,1)
    x = [time{i}(1) time{i}(end)];
    y = [i i];
    plot(x, y, 'b')
    for j=1:length(cfg.artfctdef.type)
      x = time{i};
      y = rejectall(trl(i,1):trl(i,2));
      y(y~=j) = nan;
      y(y==j) = i + j*0.03;
      plot(x, y, COLOR(j));
    end
  end
  axis([min(timebeg)-0.1 max(timeend)+0.1 0.5 size(trl,1)+0.5]);
  axis ij
  legend([{'defined trials'}, cfg.artfctdef.type(:)']);
end % feedback

% convert to logical, this is required for the subsequent code
rejectall = (rejectall~=0);

% invert the artifact selection
if istrue(cfg.artfctdef.invert)
  ft_info('inverting selection of clean/artifactual data\n');
  rejectall = ~rejectall;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% write the rejection to an EEP format file
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if isfield(cfg.artfctdef, 'writerej') && ~isempty(cfg.artfctdef.writerej)
  fid = fopen(cfg.artfctdef.writerej, 'w');
  if fid<0
    ft_error('could not open rejection file for writing');
  else
    % determine the begin and end of each rejected period (in samples)
    rejectonset = find(diff([0 rejectall])== 1);
    rejectofset = find(diff([rejectall 0])==-1);
    % determine the begin and end of each rejected period (in seconds)
    rejectonset = (rejectonset-1)/hdr.Fs;
    rejectofset = (rejectofset-1)/hdr.Fs;
    for rejlop=1:length(rejectonset)
      ft_info(fid, '%f-%f\n', rejectonset(rejlop), rejectofset(rejlop));
    end
    fclose(fid);
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% remove the trials that (partially) coincide with a rejection mark
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if any(strcmp(cfg.artfctdef.reject, {'partial', 'complete', 'nan', 'zero', 'value'}))

  count_complete_reject = 0;
  count_partial_reject  = 0;
  count_nan             = 0;
  count_zero            = 0;
  count_value           = 0;
  count_outsidecrit     = 0;

  trlCompletelyRemovedInd = [];
  trlPartiallyRemovedInd  = [];

  % add a 4th column with the original trial number
  trl(:,4) = 1:size(trl,1);

  trlnew = [];
  for trial=1:size(trl,1)
    % cut out the part of the rejection-axis corresponding with this trial
    rejecttrial = rejectall(trl(trial,1):trl(trial,2));

    if all(not(rejecttrial))
      % the whole trial is good
      trlnew = [trlnew; trl(trial,:)];

    elseif all(rejecttrial) && strcmp(cfg.artfctdef.reject, 'nan')
      % the whole trial is bad, but it is requested to be replaced with NaNs
      data.trial{trial}(:,rejecttrial) = nan;
      trlnew = [trlnew; trl(trial,:)]; % Mark the trial as good as nothing will be removed
      count_nan = count_nan + 1;

    elseif all(rejecttrial) && strcmp(cfg.artfctdef.reject, 'zero')
      % the whole trial is bad, but it is requested to be replaced with zeros
      data.trial{trial}(:,rejecttrial) = 0;
      trlnew = [trlnew; trl(trial,:)]; % Mark the trial as good as nothing will be removed
      count_zero = count_zero + 1;

    elseif all(rejecttrial) && strcmp(cfg.artfctdef.reject, 'value')
      % the whole trial is bad, but it is requested to be replaced with a specific value
      data.trial{trial}(:,rejecttrial) = cfg.artfctdef.value;
      trlnew = [trlnew; trl(trial,:)]; % Mark the trial as good as nothing will be removed
      count_value = count_value + 1;

    elseif all(rejecttrial)
      % the whole trial is bad
      count_complete_reject = count_complete_reject + 1;
      trlCompletelyRemovedInd = [trlCompletelyRemovedInd trial];

    elseif any(rejecttrial) && strcmp(cfg.artfctdef.reject, 'complete')
      % some part of the trial is bad, check if within crittoilim?
      if (checkCritToi)
        critInd = (data.time{trial} >= cfg.artfctdef.crittoilim(trial,1) & data.time{trial} <= cfg.artfctdef.crittoilim(trial,2));
        if (any(critInd & rejecttrial))
          count_complete_reject = count_complete_reject + 1;
          trlCompletelyRemovedInd = [trlCompletelyRemovedInd trial];
          continue;
        else
          trlnew = [trlnew; trl(trial,:)];
          count_outsidecrit = count_outsidecrit + 1;
        end
      else % no crittoilim checking required
        count_complete_reject = count_complete_reject + 1;
        trlCompletelyRemovedInd = [trlCompletelyRemovedInd trial];
        continue;
      end

    elseif any(rejecttrial) && strcmp(cfg.artfctdef.reject, 'partial')
      % some part of the trial is bad, reject only the bad part
      partial = [];
      rejecttrial = [0 not(rejecttrial) 0];
      % the first column is the begin sample, the second the end sample and the third is the offset
      partial(:,1) = find(diff(rejecttrial(:))== 1) + trl(trial,1) - 1;
      partial(:,2) = find(diff(rejecttrial(:))==-1) + trl(trial,1) - 2;
      partial(:,3) = find(diff(rejecttrial(:))== 1) - 1 + trl(trial,3);
      % some people use additional columns in the trl matrix to store trigger values and/or reaction times
      % these should remain linked to the original trial, i.e. they should be copied for each new fragment
      for i=4:size(trl,2)
        partial(:,i) = trl(trial,i);
      end
      minacceptnumsmp = round(cfg.artfctdef.minaccepttim .* hdr.Fs);
      partial((partial(:,2)-partial(:,1))<minacceptnumsmp,:) = [];
      trlnew = [trlnew; partial];
      count_partial_reject = count_partial_reject + 1;
      trlPartiallyRemovedInd = [trlPartiallyRemovedInd trial];

    elseif any(rejecttrial) && strcmp(cfg.artfctdef.reject, 'nan')
      % Some part of the trial is bad, replace bad part with NaNs
      data.trial{trial}(:,rejecttrial) = nan;
      trlnew = [trlnew; trl(trial,:)]; % Mark the trial as good as nothing will be removed
      count_nan = count_nan + 1;

    elseif any(rejecttrial) && strcmp(cfg.artfctdef.reject, 'zero')
      % Some part of the trial is bad, replace bad part with zeros
      data.trial{trial}(:,rejecttrial) = 0;
      trlnew = [trlnew; trl(trial,:)]; % Mark the trial as good as nothing will be removed
      count_zero = count_zero + 1;

    elseif any(rejecttrial) && strcmp(cfg.artfctdef.reject, 'value')
      % Some part of the trial is bad, replace bad part with specified value
      data.trial{trial}(:,rejecttrial) = cfg.artfctdef.value;
      trlnew = [trlnew; trl(trial,:)]; % Mark the trial as good as nothing will be removed
      count_value = count_value + 1;

    end
  end % for each trial

  ft_info('rejected %3d trials completely\n', count_complete_reject);
  ft_info('rejected %3d trials partially\n', count_partial_reject);
  ft_info('filled parts of %3d trials with NaNs\n', count_nan);
  ft_info('filled parts of %3d trials with zeros\n', count_zero);
  ft_info('filled parts of %3d trials with a specified value\n', count_value);
  if (checkCritToi)
    ft_info('retained %3d trials with artifacts outside critical window\n', count_outsidecrit);
  end
  ft_info('resulting %3d trials\n', size(trlnew,1));

  if strcmp(cfg.artfctdef.feedback, 'yes')
    ft_info('the following trials were completely removed: ');
    for k = trlCompletelyRemovedInd
      ft_info('%d ', k);
    end
    ft_info('\nthe following trials were partially removed: ');
    for k = trlPartiallyRemovedInd
      ft_info('%d ', k);
    end
    ft_info('\n');
  end

  begsample = trlnew(:,1);
  endsample = trlnew(:,2);
  offset    = trlnew(:,3);
  number    = trlnew(:,4); % numbers corresponding to the original trials
  if istable(trlold)
    trlnew = table(begsample, endsample, offset);
    % concatenate the additional columns from the original trial definition
    trlnew = cat(2, trlnew, trlold(number, 4:end));
  else
    % concatenate the additional columns from the original trial definition
    trlnew = [begsample endsample offset trlold(number, 4:end)];
  end

  cfg.trlold = trlold;  % return the original trial definition in the configuration
  cfg.trl    = trlnew;  % return the cleaned trial definition in the configuration

else
  cfg.trlold = trlold;  % return the original trial definition in the configuration
  cfg.trl    = trlold;  % return the original trial definition in the configuration
  ft_info('not rejecting any data, only marking the artifacts\n');
end

if isempty(cfg.trl)
  ft_error('No trials left after artifact rejection.')
else
  if hasdata
    switch (cfg.artfctdef.reject)
      case 'complete'
        % only keep the trials without any artifacts
        tmpcfg = keepfields(cfg, {'showcallinfo', 'trackcallinfo', 'trackusage', 'trackdatainfo', 'trackmeminfo', 'tracktimeinfo', 'checksize'});
        tmpcfg.trials = number(:);
        data   = ft_selectdata(tmpcfg, data);
        % restore the provenance information
        [cfg, data] = rollback_provenance(cfg, data);

      case 'partial'
        if isfield(data, 'sampleinfo')
          tmp = sortrows(data.sampleinfo, 1);
          begsample = tmp(:,1);
          endsample = tmp(:,2);
          hasoverlap = any(endsample(1:end-1)>=begsample(2:end));
        else
          hasoverlap = false;
        end

        % if the input data consists of partially overlapping trials, ft_redefinetrial->ft_fetch_data will throw an error
        % this is avoided by looking over individual trials

        if ~hasoverlap
          % apply the updated trial definition to the data
          tmpcfg      = keepfields(cfg, {'trl', 'showcallinfo', 'trackcallinfo', 'trackusage', 'trackdatainfo', 'trackmeminfo', 'tracktimeinfo', 'checksize'});
          data        = ft_redefinetrial(tmpcfg, data);
          % restore the provenance information
          [cfg, data] = rollback_provenance(cfg, data);
        else
          % loop over individual trials
          singletrial = cell(1, numel(data.trial));
          for i=1:numel(data.trial)
            singletrial{i} = removefields(data, {'time', 'trial'});
            singletrial{i}.time  = data.time(i);
            singletrial{i}.trial = data.trial(i);
            singletrial{i}.sampleinfo = data.sampleinfo(i,:);
            if isfield(singletrial{i}, 'trialinfo')
              singletrial{i}.trialinfo = singletrial{i}.trialinfo(i,:);
            end
            tmpcfg = keepfields(cfg, {'showcallinfo', 'trackcallinfo', 'trackusage', 'trackdatainfo', 'trackmeminfo', 'tracktimeinfo', 'checksize'});
            tmpcfg.showcallinfo = 'no';
            tmpcfg.trl = cfg.trl(number==i, :);
            singletrial{i} = ft_redefinetrial(tmpcfg, singletrial{i});
            [tmpcfg, singletrial{i}] = rollback_provenance(cfg, singletrial{i});
            tmpcfg.trl = cfg.trl;
            cfg        = tmpcfg; % needed to keep the original cfg.trl
          end
          data = ft_appenddata([], singletrial{:});
          % restore the provenance information
          [cfg, data] = rollback_provenance(cfg, data);
        end % hasoverlap

      case {'nan', 'zero', 'value', 'none'}
        % do not remove the parts that were filled with NaNs or zeros

      otherwise
        ft_error('unsupported cfg.artfctdef.reject');
    end % switch

  end % hasdata
end

% do the general cleanup and bookkeeping at the end of the function
ft_postamble debug
ft_postamble provenance
if hasdata
  ft_postamble previous data
  ft_postamble history  data
  ft_postamble savevar  data
  % return the data, the output variable is called cfg instead of data
  cfg = data;
end


function T_hat = run_tc(params)
  %T_hat = run_tc_full(params);
  T_hat = run_tc_blk(params);
end


function extras = write_extras(fname,extras)
% Write extra bits of information
%_______________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

%
% $Id$

[pth,nam,ext] = fileparts(fname);
switch ext
case {'.hdr','.img','.nii'}
    mname = fullfile(pth,[nam '.mat']);
case {'.HDR','.IMG','.NII'}
    mname = fullfile(pth,[nam '.MAT']);
otherwise
    mname = fullfile(pth,[nam '.mat']);
end
if isstruct(extras) && ~isempty(fieldnames(extras)),
    savefields(mname,extras);
end;

function savefields(fnam,p)
if length(p)>1, error('Can''t save fields.'); end;
fn = fieldnames(p);
for i_=1:length(fn),
    eval([fn{i_} '= p.' fn{i_} ';']);
end;
if str2num(version('-release'))>=14,
    fn = {'-V6',fn{:}};
end;
if numel(fn)>0,
    save(fnam,fn{:});
end;
return;


% read_eeglabheader() - import EEGLAB dataset files
%
% Usage:
%   >> header = read_eeglabheader(filename);
%
% Inputs:
%   filename - [string] file name
%
% Outputs:
%   header   - FILEIO toolbox type structure
%
% Author: Arnaud Delorme, SCCN, INC, UCSD, 2008-

%123456789012345678901234567890123456789012345678901234567890123456789012

% Copyright (C) 2008 Arnaud Delorme, SCCN, INC, UCSD, arno@salk.edu
%
% 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 header = read_eeglabheader(filename)

if nargin < 1
  help read_eeglabheader
  return
end

if ~isstruct(filename)
  s = whos('-file', filename);
  if any(strcmp({s.name}', 'EEG'))
    load('-mat', filename, 'EEG');
  else % EEGLAB > 2021.0 saves content of EEG as default
    EEG = load('-mat', filename);
  end
else
  EEG = filename;
end

header.Fs          =  EEG.srate;
header.nChans      =  EEG.nbchan;
header.nSamples    =  EEG.pnts;
header.nSamplesPre = -EEG.xmin*EEG.srate;
header.nTrials     =  EEG.trials;
try
  header.label     = { EEG.chanlocs.labels }';
catch
  ft_warning('creating default channel names');
  for i=1:header.nChans
    header.label{i} = sprintf('chan%03d', i);
  end
end
ind = 1;
for i = 1:length( EEG.chanlocs )
  if isfield(EEG.chanlocs(i), 'X') && ~isempty(EEG.chanlocs(i).X)
    header.elec.label{ind, 1} = EEG.chanlocs(i).labels;
    % this channel has a position
    header.elec.elecpos(ind,1) = EEG.chanlocs(i).X;
    header.elec.elecpos(ind,2) = EEG.chanlocs(i).Y;
    header.elec.elecpos(ind,3) = EEG.chanlocs(i).Z;
    ind = ind+1;
  end
end

if ind>1 && isfield(EEG, 'chaninfo') && isfield(EEG.chaninfo, 'nosedir') && ~isempty(EEG.chaninfo.nosedir)
  switch EEG.chaninfo.nosedir
    case '+X'
      header.elec.coordsys = 'ctf';
    case '-X'
      header.elec.coordsys = 'pls';
    case '+Y'
      header.elec.coordsys = 'ras';
    case '-Y'
      header.elec.coordsys = 'lpi';
    otherwise
  end
end

% remove data
% -----------
%if isfield(EEG, 'datfile')
%    if ~isempty(EEG.datfile)
%        EEG.data = EEG.datfile;
%    end
%else
%    EEG.data = 'in set file';
%end;
EEG.icaact = [];

header.orig = EEG;


function set_visible(hia,v)
for c=1:length(v)
    v1=v(c);
    set(hia(v1),'visible','on');
end


classdef FontColorable < handle
    % Mixin for component with Font color (but no other editable font properties)

    % Copyright 2020-2021 The MathWorks Inc.

    %% Properties
    properties (AbortSet)

        % Font color
        FontColor (1,3) double {wt.validators.mustBeBetweenZeroAndOne} = [0 0 0]

    end %properties

    %% Internal properties
    properties (AbortSet, Transient, NonCopyable, ...
            Access = {?wt.abstract.BaseWidget, ?wt.test.BaseWidgetTest} )

        % List of graphics controls to apply to
        FontColorableComponents (:,1) matlab.graphics.Graphics

    end %properties

    %% Accessors
    methods

        function set.FontColor(obj,value)
            obj.FontColor = value;
            obj.updateFontColorableComponents()
        end

        function set.FontColorableComponents(obj,value)
            obj.FontColorableComponents = value;
            obj.updateFontColorableComponents()
        end

    end %methods

    %% Methods
    methods (Access = protected)

        function updateFontColorableComponents(obj)

                hasFontColorProp = isprop(obj.FontColorableComponents,"FontColor");

                wt.utility.fastSet(obj.FontColorableComponents(hasFontColorProp),...
                    "FontColor",obj.FontColor);

                hasForegroundColorProp = ~hasFontColorProp & ...
                    isprop(obj.FontColorableComponents,"ForegroundColor");

                wt.utility.fastSet(obj.FontColorableComponents(hasForegroundColorProp),...
                    "ForegroundColor",obj.FontColor);

        end %function

    end %methods

end %classdef


function ids = database_ids( database, gt_set )
    switch database,
      case 'nyud4oObj',
        ids = getImageSet(gt_set);
      otherwise,
        index_file = fullfile(mcg_root_dir,'datasets',database, 'gt_sets',[gt_set '.txt']);
        fileID = fopen(index_file);
        ids = textscan(fileID, '%s');
        ids = ids{1};
        fclose(fileID);
    end
end