function trx = ReadMWTBlobFile(filename,trx,id)

% multiple files input, then call recursively
if iscell(filename),
  if nargin < 2,
    trx = [];
  end
  if nargin < 3,
    id = [];
  end
  for i1 = 1:numel(filename),
    trx = ReadMWTBlobFile(filename{i1},trx,id);
  end
  return;
end

nparams = 10;
nspinepts = 11;
contouroffset = '0';

if nargin < 2 || isempty(trx),
  trx = [];
  ids = [];
  havereadcontour = false;
  havereadspine = false;
else
  ids = [trx.id];
  havereadcontour = isfield(trx,'xcontour');
  havereadspine = isfield(trx,'xspine');
end

blobsext = '.blobs';
[~,~,ext] = fileparts(filename);
isblobs = strcmp(blobsext,ext);

fid = fopen(filename,'r');
if fid < 1,
  error('Could not open file %s for reading',filename);
end

% read in the id
if isblobs,
  while true,
    id = nan;
    isdone = false;
    while true,
      l1 = fgetl(fid);
      if ~ischar(l1),
        isdone = true;
        break;
      end
      if isempty(l1),
        continue;
      end
      if l1(1) == '%',
        id = str2double(l1(2:end));
      end
      break;
    end
    if isdone,
      break;
    end
    if isnan(id),
      warning('Could not parse id for line >%s<',l1);
      continue;
    end
    ReadMWTBlobFile1();
  end
else
  if nargin < 3 || isempty(id),
    id = 1;
  end
  ReadMWTBlobFile1();
end
%
% % set nframes
% for i1 = 1:numel(trx),
%   trx(i1).nframes = trx(i1).endframe - trx(i1).firstframe + 1;
% end

% sort by ids
[ids,order] = sort(ids);
trx = trx(order);

% check for missing data
for i1 = 1:numel(trx),
  if any(isnan(trx(i1).timestamps)),
    warning('%d frames of data not set for target %d',nnz(isnan(trx(i1).timestamps)),i1);
  end
end

fclose(fid);

  function ReadMWTBlobFile1()

    idi = find(ids == id,1);
    if ~isempty(idi),
      warning('Reading data for id %d more than once',id);
    end

    while true,
      filepos = ftell(fid);
      l = fgetl(fid);
      if ~ischar(l),
        break;
      end
      if isempty(l),
        continue;
      end
      % new id
      if isblobs && l(1) == '%',
        fseek(fid,filepos,'bof');
        break;
      end

      % parse the parameters in the data line
      [data_curr,count,errmsg,nextindex] = sscanf(l,'%f',nparams);
      if count < nparams || ~isempty(errmsg),
        warning('Could not parse data for id %d, line >%s<, error message: %s',id,l,errmsg);
        continue;
      end
      l = l(nextindex:end);

      % read in the contour, spine if it exists
      readcontour = false;
      readspine = false;
      while ~isempty(l),
        [w,count,~,nextindex] = sscanf(l,'%s',1);
        if count == 1,
          l = l(nextindex:end);
          switch w,
            case '%',
              [tmp,count,~,nextindex] = sscanf(l,'%f',nspinepts*2);
              if count == nspinepts*2,
                readspine = true;
                xspine = tmp(1:2:end-1);
                yspine = tmp(2:2:end);
              else
                warning('Error parsing spine points');
              end
              l = l(nextindex:end);
            case '%%',
              [tmp,count,~,nextindex] = sscanf(l,'%f',3);
              l = l(nextindex:end);
              if count == 3,
                xstart = tmp(1);
                ystart = tmp(2);
                ncontourpts = tmp(3);
                [a,count,~,nextindex] = sscanf(l,'%s',1);
                l = l(nextindex:end);
                if count == 1,
                  % convert to binary
                  b = dec2bin(a - contouroffset,8) == '1';
                  b = b(:,3:end)';
                  % first bit is 1 when y is changing
                  isy = b(1:2:end-1);
                  % second bit is 1 when positive change
                  ispos = b(2:2:end);
                  isy = isy(1:ncontourpts-1);
                  ispos = ispos(1:ncontourpts-1);
                  dx = double(~isy);
                  dx(~ispos) = -dx(~ispos);
                  dy = double(isy);
                  dy(~ispos) = -dy(~ispos);
                  xcontour = cumsum([xstart,dx]);
                  ycontour = cumsum([ystart,dy]);
                  readcontour = true;
                end
              end
            otherwise,
              warning('Unknown delimiter %s',w);
          end
        end
      end

      if ~readcontour && havereadcontour,
        xcontour = {};
        ycontour = {};
      end
      if ~readspine && havereadspine,
        xspine = nan(nspinepts,1);
        yspine = nan(nspinepts,1);
      end

      f = data_curr(1);
      timestamps = data_curr(2);
      x = data_curr(3);
      y = data_curr(4);
      area = data_curr(5);
      vx = data_curr(6);
      vy = data_curr(7);
      a = sqrt(vx^2+vy^2);
      theta = atan2(vy,vx);
      b = data_curr(8);
      length = data_curr(9);
      width = data_curr(10);

      if readspine,
        xspine = xspine + x;
        yspine = yspine + y;
      end

      % first time reading a contour
      if readcontour && ~havereadcontour,
        for tmpi = 1:numel(trx),
          nframescurr = trx(tmpi).endframe - trx(tmpi).firstframe + 1;
          trx(tmpi).xcontour = cell(1,nframescurr);
          trx(tmpi).ycontour = cell(1,nframescurr);
        end
      end
      % first time reading a spine
      if readspine && ~havereadspine,
        for tmpi = 1:numel(trx),
          nframescurr = trx(tmpi).endframe - trx(tmpi).firstframe + 1;
          trx(tmpi).xspine = nan(nspinepts,nframescurr);
          trx(tmpi).yspine = nan(nspinepts,nframescurr);
        end
      end

      if isempty(idi),
        idi = numel(ids) + 1;
        newtrx = struct('x',x,'y',y,'theta',theta,'a',a,'b',b,'id',id,...
          'firstframe',f,'nframes',nan,'endframe',f,'off',1-f,'timestamps',timestamps,...
          'area',area,'length',length,'width',width);
        if readcontour,
          newtrx.xcontour = {xcontour(:)};
          newtrx.ycontour = {ycontour(:)};
        elseif havereadcontour,
          newtrx.xcontour = {};
          newtrx.ycontour = {};
        end
        if readspine,
          newtrx.xspine = xspine(:);
          newtrx.yspine = yspine(:);
        elseif havereadspine,
          newtrx.xspine = nan(nspinepts,1);
          newtrx.yspine = nan(nspinepts,1);
        end

        if isempty(ids),
          trx = newtrx;
        else
          trx = structarrayset(trx,idi,newtrx);
        end
        ids(idi) = id;

      else

        % assume everything comes in order of frames, but some frames may
        % be skipped
        npad = f-trx(idi).endframe-1;
        if npad > 0,
          trx(idi).x(end+1:end+npad) = nan;
          trx(idi).y(end+1:end+npad) = nan;
          trx(idi).a(end+1:end+npad) = nan;
          trx(idi).b(end+1:end+npad) = nan;
          trx(idi).theta(end+1:end+npad) = nan;
          trx(idi).length(end+1:end+npad) = nan;
          trx(idi).width(end+1:end+npad) = nan;
          trx(idi).area(end+1:end+npad) = nan;
          trx(idi).timestamps(end+1:end+npad) = nan;

          if readcontour || havereadcontour,
            tmp = cell(1,npad);
            trx(idi).xcontour = [trx(idi).xcontour,tmp];
            trx(idi).ycontour = [trx(idi).ycontour,tmp];
          end

          if readspine || havereadspine,
            trx(idi).xspine(:,end+1:end+npad) = nan;
            trx(idi).yspine(:,end+1:end+npad) = nan;
          end
        end

        i = f - trx(idi).firstframe + 1;
        trx(idi).x(i) = x;
        trx(idi).y(i) = y;
        trx(idi).a(i) = a;
        trx(idi).b(i) = b;
        trx(idi).theta(i) = theta;
        trx(idi).length(i) = length;
        trx(idi).width(i) = width;
        trx(idi).area(i) = area;
        trx(idi).timestamps(i) = timestamps;

        if readcontour || havereadcontour,
          trx(idi).xcontour{i} = xcontour;
          trx(idi).ycontour{i} = ycontour;
        end

        if readspine || havereadspine,
          trx(idi).xspine(:,i) = xspine;
          trx(idi).yspine(:,i) = yspine;
        end
        trx(idi).endframe = max(f,trx(idi).endframe);

      end

      havereadcontour = havereadcontour || readcontour;
      havereadspine = havereadspine || readspine;

    end

    if isempty(idi),
      %fprintf('Read 0 frames for id %d\n',id);
    else
      trx(idi).nframes = trx(idi).endframe-trx(idi).firstframe+1;
      %fprintf('Read %d frames for id %d\n',trx(idi).nframes,id);
    end

    if havereadcontour,
      for tmpi = 1:numel(trx),
        nframescurr = trx(tmpi).nframes;
        nadd = nframescurr - numel(trx(tmpi).xcontour);
        if nadd > 0,
          trx(tmpi).xcontour(end+1:end+nadd) = cell(1,nadd);
          trx(tmpi).ycontour(end+1:end+nadd) = cell(1,nadd);
        end
      end
    end
    if havereadspine,
      for tmpi = 1:numel(trx),
        nframescurr = trx(tmpi).nframes;
        nadd = nframescurr - size(trx(tmpi).xspine,2);
        if nadd > 0,
          trx(tmpi).xspine(:,end+1:end+nadd) = nan;
          trx(tmpi).yspine(:,end+1:end+nadd) = nan;
        end
      end
    end

  end

end


function [version, released] = manopt_version()
% Returns the version of the Manopt package you are running, as a vector.
%
% function [version, released] = manopt_version()
%
% version(1) is the primary version number.
% released is the date this version was released, in the same format as the
% date() function in Matlab.

    version = [2, 0, 0];
    released = '06-Jul-2015';

end


function title = p06_title ( )

%*****************************************************************************80
%
%% P06_TITLE returns the title of problem P06.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 February 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, string TITLE, the title of the problem.
%
  title = 'Problem 6, Enright and Pryce #B1';

  return
end


clear
close all

% Set defaults
font_size = 11;
set(0, 'DefaultAxesFontSize',font_size)

line_width = 1;
set(0, 'DefaultLineLineWidth',line_width)

font_size = 15;
set(0, 'DefaultTextFontSize',font_size)

subplot(2,1,1)

dualtree_eg1

box off

% remove defaults
set(0, 'DefaultAxesFontSize','remove')
set(0, 'DefaultLineLineWidth','remove')
set(0, 'DefaultTextFontSize','remove')

if 1
    % paperposition
    paperpos = [2 2 7 5];    % [left, bottom, width, height]

    set(gcf, 'PaperPositionMode', 'manual');
    set(gcf, 'PaperUnits', 'inches');
    set(gcf, 'PaperPosition', paperpos);
end

print -depsc figures/dualtree_eg1_figure

% then open eps file and save as png file.


function [roiInd coords] = roiGetAllIndices(vw)
% Get the indices of all open ROIs
% [roiInd coords] = roiGetAllCoords(vw)

if notDefined('vw'), vw = getCurView; end

roistodisplay = viewGet(vw, 'ROIs to Display');
ROIs = viewGet(vw, 'ROIs');

for ii = 1:length(roistodisplay)
    thisroi = roistodisplay(ii);

    if ii == 1,  coords = ROIs(thisroi).coords;
    else         coords = [coords ROIs(thisroi).coords]; end
end

% eliminate redundant voxels
if ~exist('coords', 'var') || isempty(coords)
    roiInd = []; coords = []; return;
end
coords = intersectCols(coords, coords);

% coords2index
[roiInd coords] = roiIndices(vw, coords);

return


function [colors, allRoiVertInds, dataMask, vw, newColors] = meshDrawROIs(vw, colors, v2g, perimThickness, dataMask, prefs)
%
% Overlay ROI colors on top of the data color overlay
%
% NOTE: an ROI named 'mask' (case-insensitive) will NOT be drawn- it will
% be used to mask away data outside the mask ROI.
%
% NOTE: the following code is slow and should be optimized.
%
% HISTORY:
%  broken off by ras, sometime in 2006.
%  ras 03/07: updated ROI outline parsing to sync with the new way of
%             specifying what ROIs to show (see roiSetOptions).
%  2007.08.23 RFD: fixed broken data masking code.
%  ras, 11/07: streamlined code (broke off two subfunctions), fixed a bug
%				in which perimeters of multiple ROIs were interfering with
%				one another.
%  2009.12.30 JW: allow filling of single ROIs (with name containing
%               string 'fill'), even if other ROIs are drawn as perimeter.
%               Useful for masking out artifacts.
%

newColors = zeros(size(colors));
% If we want the ROIs to be translucent patches, then make the color of the
% ROIs a weighted sum of the ROI color and the underlay color. If we are
% not drawing the ROIs as translucent patches, then make the weight 1 such
% that we are painting the ROI voxels (presumably just the boundaries) only
% the color of the ROI, with no underlay.
if strcmpi('patches', viewGet(vw, 'roidrawmethod'))
    w = .3;
else
    w = 1;
end

% get list of ROIs to show
roiList = viewGet(vw, 'ROIsToDisplay');

% roiList can (should) not be 0
if(roiList == 0)
    roiList = [];
end

% Put any mask ROIs at the end of the list.
if ~isempty(roiList)
    ROInames = viewGet(vw, 'ROI names');
    maskRoiIndex = strcmpi('mask',ROInames(roiList));
    if any(maskRoiIndex)
        maskRoiIndex = ismember(roiList, maskRoiIndex);
        [~,inds] = sort(maskRoiIndex);
        roiList = roiList(inds);
    end
end

if notDefined('perimThickness')
    % Option to display only the ROI perimeter.
    % '1' is a good number to use here.
    % ras 01/06: inherits from the view's settings
    if checkfields(vw, 'ui', 'roiDrawMethod')
        switch lower(viewGet(vw, 'roi draw method'))
            case 'boxes', perimThickness = 0;  % filled
            case 'perimeter', perimThickness = 1; % thin outlines
            case 'filled perimeter', perimThickness = 2; % thick outlines
            case 'patches', perimThickness = 0; % filled, translucent patches
        end
    end
end

if ~exist('prefs', 'var'),
    % this takes a LONG time!
    prefs = mrmPreferences;
end

% we'll need some standard colors for mapping labels
% (e.g. 'y') to vals (e.g. [1 1 0]):
[stdColVals, stdColLabs]  = meshStandardColors;

%%%%%%Main part:
% Substitute the ROI color for appropriate nearest neighbor vertices
allRoiVertInds = [];
if ~isempty(viewGet(vw, 'ROIs'))

    %% loop across ROIs
    for iR = roiList
        roi = viewGet(vw, 'ROIs', iR);
        %% find indices of those mesh vertices belonging to this ROI:
        % Note this is a new method of getting roiVertInds. We now use a
        % viewGet. We can also use a viewSet in order to store the indices
        % so that they do not need to be calculated each time. See, e.g,
        % roiSetVertInds.m
        roiVertInds = viewGet(vw, 'roiVertInds', iR, prefs);

        %% modify mesh colors using roiVertInds
		% If this is a mask ROI, don't show the ROI, just mask the data.
		if strfind(lower(roi.name), 'mask')
			tmp = false(size(dataMask));
			tmp(roiVertInds) = true;
			dataMask = dataMask & tmp;
			clear tmp;
            % The lines below
            % roiMaskIndices = roiVertInds;
            % roiMaskIndices = adjustPerimeter(roiMaskIndices, [], vw, prefs);
            % dataMask(roiMaskIndices) = 1;
			continue
		end

		% find ROI perimeter / dilate ROI, depending on the settings
        %   if the roi name contains the string 'fill', we display the ROI
        %   as a solid color instead of a perimeter
        if strfind(lower(roi.name), 'fill'), p = []; else p = perimThickness; end
        roiVertInds = adjustPerimeter(roiVertInds, p, vw, prefs);

		% expand dataMask so that the entire ROI will be drawn
        if exist('roiMaskIndices', 'var'),
    		dataMask(intersect(roiVertInds,roiMaskIndices)) = 1;
        else
            dataMask(roiVertInds) = 1;
        end

		%% modify the colors for this ROI's vertices
        if (ischar(roi.color))
            colVal = stdColVals(:, strfind(stdColLabs, roi.color));
        else
            % Check to see if we have a 3x1 vector.
            colVal = roi.color(:);
            if (length(colVal)~=3)
                error('Bad ROI color');
            end
        end

		newColors(1:3,roiVertInds) = repmat(colVal*255, 1, length(roiVertInds));

        newColors(newColors>255) = 255;
        newColors(newColors<0) = 0;

        colors(1:3,roiVertInds) = w*newColors(1:3,roiVertInds) + (1-w)*colors(1:3,roiVertInds);
		%% store this ROI's vertices in a list of all ROI vertex locations
		allRoiVertInds = [allRoiVertInds(:); roiVertInds(:)];
    end
end

colors(colors>255) = 255;
colors(colors<0) = 0;

return


function handles = switchMode(handles, newMode)
%SWITCHMODE   Go from one mode of CHEBGUI to another.
% Calling sequence:
%   HANDLES = SWITCHMODE(HANDLES, NEWMODE)
% where
%   HANDLES:    A MATLAB handle object for the CHEBGUI figure.
%   NEWMODE:    Mode we want to switch to.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

% Do a lot of disabling/enabling and hiding/showing objects on the CHEBGUI
% figure.
if ( strcmp(newMode, 'bvp') ) % Going into BVP mode
    handles.guifile.type = 'bvp';

    set(handles.button_bvp, 'Value', 1)
    set(handles.button_ivp, 'Value', 0)
    set(handles.button_pde, 'Value', 0)
    set(handles.button_eig, 'Value', 0)

    set(handles.panel_DEs, 'Title', 'Differential equations')
    set(handles.toggle_useLatest, 'Visible', 'on')

    set(handles.panel_timedomain, 'Visible', 'off')

    set(handles.button_realplot, 'Visible', 'off')
    set(handles.button_imagplot, 'Visible', 'off')
    set(handles.popupmenu_bottomFig, 'Visible', 'on')
    set(handles.toggle_useLatest, 'Value', 0)

    if ( isempty(fieldnames(handles.latest)) )
        set(handles.toggle_useLatest, 'Enable', 'off')
    end

    % Change heading for BC/IC input field:
    set(handles.panel_BCs, 'Title', 'Boundary conditions')

    % Hide the iter_list box:
    handles = hideIterList(handles);

    % Show the initial guess panel, and ensure it has the correct title:
    set(handles.panel_initialGuess, 'Visible', 'on', 'Title', 'Initial guess');

    set(handles.panel_eigopts, 'Visible', 'Off')

    % Switch from LBC and RBC fields to BC
    handles = toggleBCinput(handles, 'off', 'on');

    % Change the list of available options.
    % Enable ODE menu options
    set(handles.menu_odedampednewton, 'Enable', 'On')
    set(handles.menu_odeplotting, 'Enable', 'On')
    % Disable IVP solver option
    set(handles.menu_ivpSolver, 'Enable', 'off');
    % Disable PDE menu options
    set(handles.menu_pdeSolver, 'Enable', 'Off')
    set(handles.menu_pdeplotting, 'Enable', 'Off')
    set(handles.menu_pdeholdplot, 'Enable', 'Off')
    set(handles.menu_pdefix, 'Enable', 'Off')
    set(handles.menu_fixN, 'Enable', 'Off')

    % Make the discretization visible
    set(handles.panel_discretization, 'Visible', 'on');

    % Hide the IVP solver panel visible
    set(handles.panel_IVPsolver, 'Visible', 'off')

    % Clear the top figure
    chebguiController.initialiseFigureTop(handles)

    % Always clear the bottom figure
    chebguiController.initialiseFigureBottom(handles)

    % Make the discretization panel visible
    set(handles.panel_discretization, 'Visible', 'on')

    % Set correct header to top figure
    set(handles.panel_figSol, 'Title', 'Solution')

    % Note: The line below is a nice way to disable to objects, rather than hide
    % them.
    % Enable all childrens of discretisation panel
    %     set(findall(handles.panel_discretization,  '-property',  'enable'),  ...
    %         'visible',  'on')
elseif ( strcmp(newMode, 'ivp') ) % Going into IVP mode
    % IVP mode is almost identical to BVP, so do the same adjustments, and then
    % minor corrections at the end:
    handles = chebguiController.switchMode(handles, 'bvp');

    % Set the type of the problem
    handles.guifile.type = 'ivp';

    % Change heading for BC/IC input field:
    set(handles.panel_BCs, 'Title', 'Initial/final conditions')

    % Hide the discretization panel
    set(handles.panel_discretization, 'Visible', 'off');

    % Make the IVP solver panel visible
    set(handles.panel_IVPsolver, 'Visible', 'on')

    set(handles.button_bvp, 'Value', 0)
    set(handles.button_ivp, 'Value', 1)
    % Enable IVP solver option
    set(handles.menu_ivpSolver, 'Enable', 'on');

    % If we're solving in time-stepping mode, hide the initial guess box:
    if ( ~isempty(strfind(handles.guifile.options.ivpSolver, 'ode')) )
        set(handles.panel_initialGuess,'Visible','off');
    end

elseif ( strcmp(newMode, 'pde') ) % Going into PDE mode
    handles.guifile.type = 'pde';

    set(handles.button_bvp, 'Value', 0)
    set(handles.button_ivp, 'Value', 0)
    set(handles.button_pde, 'Value', 1)
    set(handles.button_eig, 'Value', 0)

    % Hide the iter_list box:
    handles = hideIterList(handles);

    % Show the initial guess panel, and ensure it has the correct title:
    set(handles.panel_initialGuess,'Visible','on','Title','Initial condition');

    set(handles.toggle_useLatest, 'Visible', 'off')
    set(handles.panel_DEs, 'Title', 'Differential equations')

    set(handles.input_GUESS, 'Enable', 'On')
    set(handles.toggle_useLatest, 'Value', 0)
    set(handles.toggle_useLatest, 'Enable', 'off')

    set(handles.panel_timedomain, 'Visible', 'on')

    set(handles.button_realplot, 'Visible', 'off')
    set(handles.button_imagplot, 'Visible', 'off')
    set(handles.popupmenu_bottomFig, 'Visible', 'off')

    set(handles.panel_eigopts, 'Visible', 'Off')

    % Switch from LBC and RBC fields to BC
    handles = toggleBCinput(handles, 'on', 'off');

    % Change the list of available options
    % Disable ODE menu options
    set(handles.menu_odedampednewton, 'Enable', 'Off')
    set(handles.menu_odeplotting, 'Enable', 'Off')
    % Disable IVP solver option
    set(handles.menu_ivpSolver, 'Enable', 'off');
    % Enable PDE menuoptions
    set(handles.menu_pdeSolver, 'Enable', 'On')
    set(handles.menu_pdeplotting, 'Enable', 'On')
    set(handles.menu_pdeholdplot, 'Enable', 'On')
    set(handles.menu_pdefix, 'Enable', 'On')
    set(handles.menu_fixN, 'Enable', 'On')

    % Clear the top figure
    chebguiController.initialiseFigureTop(handles)

    % Always clear the bottom figure
    chebguiController.initialiseFigureBottom(handles)

    % Hide the discretization and IVP solver panels
    set(handles.panel_discretization, 'Visible', 'off')
    set(handles.panel_IVPsolver, 'Visible', 'off')

    % Set correct header to top figure
    set(handles.panel_figSol, 'Title', 'Initial condition')

else % Going into EIG mode
    handles.guifile.type = 'eig';

    set(handles.button_bvp, 'Value', 0)
    set(handles.button_ivp, 'Value', 0)
    set(handles.button_pde, 'Value', 0)
    set(handles.button_eig, 'Value', 1)

    set(handles.toggle_useLatest, 'Visible', 'off')
    set(handles.panel_DEs, 'Title', 'Differential operator')
    set(handles.text_initial, 'String', 'Look for')
    set(handles.toggle_useLatest, 'Enable', 'off')

    set(handles.panel_timedomain, 'Visible', 'off')

    set(handles.button_realplot, 'Visible', 'on')
    set(handles.button_realplot, 'Value', 1)
    set(handles.button_imagplot, 'Visible', 'on')
    set(handles.button_imagplot, 'Value', 0)
    set(handles.popupmenu_bottomFig, 'Visible', 'off')

    set(handles.panel_eigopts,'Visible','On')
    if ( ~isempty(handles.guifile.sigma) )
        switch ( handles.guifile.sigma )
            case ''
                set(handles.popupmenu_sigma, 'Value', 1);
            case 'lm'
                set(handles.popupmenu_sigma, 'Value', 2);
            case 'sm'
                set(handles.popupmenu_sigma, 'Value', 3);
            case 'lr'
                set(handles.popupmenu_sigma, 'Value', 4);
            case 'sr'
                set(handles.popupmenu_sigma, 'Value', 5);
            case 'li'
                set(handles.popupmenu_sigma, 'Value', 6);
            case 'si'
                set(handles.popupmenu_sigma, 'Value', 7);
        end
    else
        set(handles.popupmenu_sigma, 'Value', 1)
    end

    if ( isfield(handles.guifile.options,'numeigs') ...
        && ~isempty(handles.guifile.options.numeigs) )
        set(handles.edit_eigN, 'String', handles.guifile.options.numeigs);
    else
        set(handles.edit_eigN, 'String', 6);
    end

    % Hide the initial guess panel, and ensure it has the correct title:
    set(handles.panel_initialGuess,'Visible','off');

    % Change heading for BC/IC input field:
    set(handles.panel_BCs, 'Title', 'Boundary conditions')

    % Hide the iter_list box:
    handles = hideIterList(handles);

    % Switch from LBC and RBC fields to BC
    handles = toggleBCinput(handles, 'off', 'on');

    % Change the list of available options.

    % Disable ODE options
    set(handles.menu_odedampednewton, 'Enable', 'Off')
    set(handles.menu_odeplotting, 'Enable', 'Off')

    % Disable IVP solver option
    set(handles.menu_ivpSolver, 'Enable', 'off');

    % Disable PDE options
    set(handles.menu_pdeSolver, 'Enable', 'Off')
    set(handles.menu_pdeplotting, 'Enable', 'Off')
    set(handles.menu_pdeholdplot, 'Enable', 'Off')
    set(handles.menu_pdefix, 'Enable', 'Off')
    set(handles.menu_fixN, 'Enable', 'Off')

    % Make the discretization panel visible
    set(handles.panel_discretization, 'Visible', 'on')

    % Hide the IVP solver panel
    set(handles.panel_IVPsolver, 'Visible', 'off')

    % Set correct header to top figure
    set(handles.panel_figSol, 'Title', 'Eigenvalues (imag vs real)')

    % Clear the top figure
    chebguiController.initialiseFigureTop(handles)

    % Always clear the bottom figure
    chebguiController.initialiseFigureBottom(handles)

end

end

function handles = toggleBCinput(handles, onOff1, onOff2)
set(handles.input_LBC, 'Visible', onOff1)
set(handles.panel_leftBCs, 'Visible', onOff1)
set(handles.input_RBC, 'Visible', onOff1)
set(handles.panel_rightBCs, 'Visible', onOff1)
set(handles.input_BC,  'Visible', onOff2)
set(handles.panel_BCs,  'Visible', onOff2)
end

function handles = hideIterList(handles)
set(handles.iter_list, 'Visible', 'off')
set(handles.iter_list, 'String', '')
set(handles.iter_list, 'Value', 0)
set(handles.iter_text, 'Visible', 'off')
set(handles.iter_text, 'String', '')
end


function [data] = ft_denoise_ssp(cfg, data)

% FT_DENOISE_SSP projects out topographies based on ambient noise on
% Neuromag/Elekta/MEGIN systems. These topographies are estimated during maintenance
% visits from the engineers of MEGIN
%
% Use as
%   [data] = ft_denoise_ssp(cfg, data)
% where data should come from FT_PREPROCESSING and the configuration
% should contain
%   cfg.ssp        = 'all' or a cell array of SSP names to apply (default = 'all')
%   cfg.trials     = 'all' or a selection given as a 1xN vector (default = 'all')
%   cfg.updatesens = 'no' or 'yes' (default = 'yes')
%
% To facilitate data-handling and distributed computing you can use
%   cfg.inputfile   =  ...
%   cfg.outputfile  =  ...
% If you specify one of these (or both) the input data will be read from a *.mat
% file on disk and/or the output data will be written to a *.mat file. These mat
% files should contain only a single variable, corresponding with the
% input/output structure.
%
% See also FT_PREPROCESSING, FT_DENOISE_SYNTHETIC, FT_DENOISE_PCA

% Copyright (C) 2004-2022, Gianpaolo Demarchi, Lau
% Møller Andersen, Robert Oostenveld, Jan-Mathijs Schoffelen
%
% 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$

% 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, 'forbidden',  {'trial'}); % prevent accidental typos, see issue 1729
cfg = ft_checkconfig(cfg, 'required',   {'ssp'});

% set the defaults
cfg.ssp        = ft_getopt(cfg, 'ssp', 'all');
cfg.trials     = ft_getopt(cfg, 'trials', 'all', 1);
cfg.updatesens = ft_getopt(cfg, 'updatesens', 'yes');

% store the original type of the input data
dtype = ft_datatype(data);

% check if the input data is valid for this function
% this will convert timelocked input data to a raw data representation if needed
data = ft_checkdata(data, 'datatype', 'raw', 'feedback', 'yes', 'hassampleinfo', 'yes');

% check whether it is neuromag data
if ~ft_senstype(data, 'neuromag')
  ft_error('SSP vectors can only be applied to neuromag data');
end

% select trials of interest
tmpcfg = keepfields(cfg, {'trials', 'showcallinfo', 'trackcallinfo', 'trackusage', 'trackdatainfo', 'trackmeminfo', 'tracktimeinfo', 'checksize'});
data   = ft_selectdata(tmpcfg, data);
% restore the provenance information
[cfg, data] = rollback_provenance(cfg, data);

% remember the original channel ordering
labelold = data.label;

% apply the balancing to the MEG data and to the gradiometer definition
current = data.grad.balance.current;
desired = cfg.ssp;

if ~strcmp(current, 'none')
  % first undo/invert the previously applied balancing
  try
    current_montage = data.grad.balance.(current);
  catch
    ft_error('unknown balancing for input data');
  end
  fprintf('converting the data from "%s" to "none"\n', current);
  data = ft_apply_montage(data, current_montage, 'keepunused', 'yes', 'inverse', 'yes');
  if istrue(cfg.updatesens)
    fprintf('converting the sensor description from "%s" to "none"\n', current);
    data.grad = ft_apply_montage(data.grad, current_montage, 'keepunused', 'yes', 'inverse', 'yes');
    data.grad.balance.current = 'none';
  end
end % if current

if ~strcmp(desired, 'none')
  % then apply the desired balancing
  if strcmp(desired, 'all')
    desireds = fieldnames(data.grad.balance);
  else
      desireds = cfg.ssp;
    if ~iscell(desireds)
        ft_error('cfg.ssp must be a cell array of projector names')
    end

  end
  for desired_index = 1:length(desireds)
    desired = desireds{desired_index};
    if ~strcmp(desired, 'current')
      try
        desired_montage = data.grad.balance.(desired);
      catch
        ft_error('unknown balancing for input data');
      end
      fprintf('converting the data from "none" to "%s"\n', desired);
      data = ft_apply_montage(data, desired_montage, 'keepunused', 'yes', 'balancename', desired);
      if istrue(cfg.updatesens)
        fprintf('converting the sensor description from "none" to "%s"\n', desired);
        data.grad = ft_apply_montage(data.grad, desired_montage, 'keepunused', 'yes', 'balancename', desired);
      end
    end % if desired
  end
end

% reorder the channels to stay close to the original ordering
[selold, selnew] = match_str(labelold, data.label);
if numel(selnew)==numel(labelold)
  for i=1:numel(data.trial)
    data.trial{i} = data.trial{i}(selnew,:);
  end
  data.label = data.label(selnew);
else
  ft_warning('channel ordering might have changed');
end

% convert back to input type if necessary
switch dtype
  case 'timelock'
    data = ft_checkdata(data, 'datatype', 'timelock');
  otherwise
    % keep the output as it is
end

% do the general cleanup and bookkeeping at the end of the function
ft_postamble debug

ft_postamble previous   data
ft_postamble provenance data
ft_postamble history    data
ft_postamble savevar    data


function test_bug2482

% MEM 2gb
% WALLTIME 00:10:00
% DEPENDENCY ft_definetrial ft_preprocessing ft_trialfun_brainvision_segmented

%% define the trials

headerfile = dccnpath('/home/common/matlab/fieldtrip/data/test/bug2482/001 P11 M1 004_Seg_fs6.vhdr');
datafile = dccnpath('/home/common/matlab/fieldtrip/data/test/bug2482/001 P11 M1 004_Seg_fs6.eeg');

cfg = [];
cfg.trialfun = 'ft_trialfun_brainvision_segmented';
cfg.trigformat = 'DIN%d';

cfg.dataset = headerfile;
cfg1 = ft_definetrial(cfg);

cfg.dataset = datafile;
cfg2 = ft_definetrial(cfg);

if ~isequal(cfg1.trl, cfg2.trl)
  error('different trl matrix generated when specifying data file or headerfile as cfg.dataset');
end

%% read data

data = ft_preprocessing(cfg1);

%% test to see whether ERP is fine
% no need to run this every time, just a one time check (ES 3-mar-2014)
% cfg = [];
% cfg.channel = 'Cz';
% cfg.vartrllength = 2;
% tl = ft_timelockanalysis(cfg, data);
%
% cfg = [];
% cfg.ylim = [-50 50];
% ft_singleplotER(cfg,tl);


function r = mrdivide(p,q)
%RDIVIDE this function divides the x, y, and z values of the structures that I use in
% the FVtool.
%
% SYNOPSIS:
%
%
% PARAMETERS:
%
%
% RETURNS:
%
%
% EXAMPLE:
%
% SEE ALSO:
%

% Copyright (c) 2012-2016 Ali Akbar Eftekhari
% See the license file

if isa(p, 'FaceVariable') && (~isa(q, 'FaceVariable'))
    r = (1/q)*p;
else
    error('FVMtool: Wrong use of mrdivide for a face variable. Try using ./ instead.');
end


classdef CarlaEnvironment < matlab.System & matlab.system.mixin.Propagates
    % Untitled Add summary here
    %
    % This template includes the minimum set of functions required
    % to define a System object with discrete state.

    % Public, tunable properties
    properties
        % Other actors
        npc_to_spawn = 20;
    end

    properties(DiscreteState)

    end

    % Pre-computed constants
    properties(Access = private)
        % Sensors resolution
        width = 1920;
        height = 1080;

        tesla;
        npc_list;

        keyboard_handle;

        rgb;
        module_rgb;
        time_last_update = 0;
    end

    methods(Access = protected)
        function setupImpl(obj)
            % Perform one-time calculations, such as computing constants
            port = int16(2000);
            client = py.carla.Client('localhost', port);
            client.set_timeout(2.0);
            world = client.get_world();

            % Spawn Vehicle
            blueprint_library = world.get_blueprint_library();
            car_list = py.list(blueprint_library.filter("model3"));
            car_bp = car_list{1};
            spawn_point = py.random.choice(world.get_map().get_spawn_points());
            obj.tesla = world.spawn_actor(car_bp, spawn_point);
            obj.tesla.set_autopilot(true);

            % Spawn NPC's
            npc_bps = blueprint_library.filter("vehicle");

            i = 1;
            while i <= obj.npc_to_spawn
                try
                    npc_bp = py.random.choice(npc_bps);
                    spawn_point = py.random.choice(world.get_map().get_spawn_points());
                    obj.npc_list{i} = world.spawn_actor(npc_bp, spawn_point);
                    obj.npc_list{i}.set_autopilot(true);
                catch
                    % In case spawing fails due to collision, try again
                    i = i - 1;
                end
                i = i + 1;
            end

            % RGB
            blueprint = world.get_blueprint_library().find('sensor.camera.rgb');
            blueprint.set_attribute('image_size_x', num2str(obj.width))
            blueprint.set_attribute('image_size_y', num2str(obj.height))

            transform = py.carla.Transform(py.carla.Location(pyargs('x',0.8, 'z',1.7)));
            obj.rgb = world.spawn_actor(blueprint, transform, pyargs('attach_to',obj.tesla));

            obj.module_rgb = sensorBind(obj.rgb, "rgb", "rgb", "array");

            % Handle keyboard
            callstr = 'set(gcbf, ''Userdata'', get(gcbf, ''Currentkey'')) ; uiresume ' ;
            obj.keyboard_handle = figure( 'name', 'Press a key', ...
                                           'keypressfcn', callstr, ...
                                           'windowstyle', 'modal', ...
                                           'numbertitle', 'off', ...
                                           'position', [0 0 1 1], ...
                                           'userdata', 'timeout');
            set(obj.keyboard_handle,'Visible','on');
        end

        function [RGB] = stepImpl(obj)
            % RGB
            RGB = uint8(py.getattr(obj.module_rgb, 'array'));

            % Handle keyboard
            dt = cputime - obj.time_last_update;

            try
                keyPressed = get(obj.keyboard_handle,'Userdata');
                processKeyboard(obj.tesla, keyPressed, dt);

                % Reset the pressed key
                set(obj.keyboard_handle,'Userdata', char(0));
            catch
                obj.tesla.set_autopilot(true);
            end

            % Update time
            obj.time_last_update = obj.time_last_update + dt;
            pause(0.025);
        end

        function [RGB] = isOutputComplexImpl(~)
            RGB = false;
        end

        function [RGB] = getOutputSizeImpl(obj)
            RGB = [obj.height obj.width 3];
        end

        function [RGB] = getOutputDataTypeImpl(~)
            RGB = 'uint8';
        end

        function [RGB] = isOutputFixedSizeImpl(~)
            RGB = true;
        end

        function resetImpl(~)
            % Initialize / reset discrete-state properties
        end
    end

    methods(Access= public)
        function delete(obj)
            % Delete the car from the Carla world
            if ~isempty(obj.tesla)
                obj.tesla.destroy();
            end

            % Delete NPCs
            if ~isempty(obj.npc_list)
                for i=1:obj.npc_to_spawn
                    obj.npc_list{i}.destroy();
                end
            end

            % RGB camera
            if ~isempty(obj.rgb)
                obj.rgb.destroy();
            end

            % Close the figure if it still exists
            if ~isempty(obj.keyboard_handle)
                close(obj.keyboard_handle);
            end

        end
    end
end


function varargout=phon2sone(varargin)
%
% For calling details please see v_phon2sone.m
%
% This dummy routine is included for backward compatibility only
% and will be removed in a future release of voicebox. Please use
% v_phon2sone.m in future and/or update with v_voicebox_update.m
%
%      Copyright (C) Mike Brookes 2018
%      Version: $Id: phon2sone.m 10863 2018-09-21 15:39:23Z dmb $
%
if nargout
    varargout=cell(1,nargout);
    [varargout{:}]=v_phon2sone(varargin{:});
else
    v_phon2sone(varargin{:});
end


function ui = mrViewAddMap(ui, newMR);
%
% Add a new map to a ui struct.
% ui = mrViewAddMap(ui,newMR);
%
% ras 09/2005
if notDefined('ui'),	ui = mrViewGet;				end
if ishandle(ui),		ui = get(ui, 'UserData');	end

% allow map to be a struct array of new maps, and recursively add them:
if length(newMR) > 1
	for i = 1:length(newMR)
		ui = mrViewAddMap(ui, newMR(i));
	end
	return
end

% integer check
if ~isa(newMR.data,'double'), newMR.data = double(newMR.data); end

if isempty(ui.maps) % first map loaded
	ui.maps = newMR;
else                % add to other maps
	% check if name exists; if so, make unique
	exNames = {ui.maps.name}';
	test = strmatch(newMR.name,exNames);
	if ~isempty(test)
		newMR.name = sprintf('%s (%i)',newMR.name,length(test)+1);
	end

	ui.maps(end+1).baseXform = []; % will initialize new entry

	% copy fields over, in a memory-efficient way (?)
	for f = fieldnames(newMR)'
		ui.maps(end).(f{1}) = newMR.(f{1});
		newMR.(f{1}) = []; % clear to save memory
	end
end
ui.maps(end).baseXform = mrBaseXform(ui.mr, ui.maps(end));

% if loading a map for the first time, open
% a new overlay for the map:
if length(ui.maps)==1
	ui = mrViewAddOverlay(ui);
end

% also add the map to any popup lists of maps which
% may exist for overlays:
for o = 1:length(ui.overlays)
	if isfield(ui.overlays(o),'mapPopup') & ...
			ishandle(ui.overlays(o).mapPopup)
		set(ui.overlays(o).mapPopup,'String',{ui.maps.name});

		for j = 1:length(ui.overlays(o).threshMap)
			str = get(ui.overlays(o).threshMap(j),'String');
			str{end+1} = ui.maps(end).name;
			set(ui.overlays(o).threshMap(j),'String',str);
		end
	end
end

% update the info panel to include the new map as an option:
if checkfields(ui,'panels','info') & ishandle(ui.panels.info)
	ui = mrViewSet(ui,'infopanel');
end

ui = mrViewRefresh(ui);

return


function [dat] = read_neuralynx_dma(filename, begsample, endsample, channel)

% READ_NEURALYNX_DMA reads specified samples and channels data from a Neuralynx DMA log file
%
% Use as
%    [hdr] = read_neuralynx_dma(filename)
%    [dat] = read_neuralynx_dma(filename, begsample, endsample)
%    [dat] = read_neuralynx_dma(filename, begsample, endsample, chanindx)
%
% The channel specification can be a vector with indices, or a single string with the value
%    'all', 'stx', 'pid', 'siz', 'tsh', 'tsl',
%    'cpu', 'ttl', 'x01',  ...,  'x10'
%
% This function returns the electrophysiological data in AD units
% and not in uV. You should look up the details of the headstage and
% the Neuralynx amplifier and scale the values accordingly.

% Copyright (C) 2005-2008, 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$

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The data is simply a stream of constant size records,  the size of the
% record is dependant on the number of Input Boards in the system.  8 in your
% case, there are 32 - 32 bit integers from each Input Board.
%
% // Digital Lynx Packets look like this for a 1 board system:
% // stx (or SOP)    0x00000800
% // Packet ID       0x00000001
% // siz             0x0000002A   (# A/D data ints + #extra wds = 32+10)
% // TimeStamp Hi    1 32 bit word
% // TimeStamp Low   1 32 bit word
% // cpu             1 32 bit word
% // ttl             1 32 bit word
% // 10 extras      10 32 bit words
% // A/D data       32 32 bit words per board
% // CRC             1 32 bit XOR of the entire packet including stx
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

needhdr = (nargin==1);
needdat = (nargin>=2);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% since Cheetah 4.80 the DMS log files have a 16384 byte header
% determine whether that is the case in this file
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fid = fopen(filename, 'rb', 'ieee-le');
buf = fread(fid, 10, 'uchar=>uchar');
if all(buf(1:4)==35)
  % the file starts with "####"
  hdroffset = 16384;
elseif all(buf>31 & buf<127)
  % the file does not start with "####" but the header seems to be ascii anyway
  hdroffset = 16384;
else
  hdroffset = 0;
end

if hdroffset
  % read the ascii header from the file, it does not contain much usefull information
  orig = neuralynx_getheader(filename);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% since Cheetah 5.0 the DMA log file does not always start with a complete
% packet but can start with an incomplete "junk" packet after the header.
% The junk due to that incomplete packet should then also be skipped.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if hdroffset
  % skip the standard ascii header
  fseek(fid, hdroffset, 'bof');
  % read a single block
  buf = fread(fid, 274, 'uint32=>uint32');
  % search for the first known values of a proper packet
  junk = find((buf(1:(end-1))==2048) & (buf(2:(end-0))==1), 1) - 1;
  if ~isempty(junk)
    % add the additional junk samples to the header offset
    hdroffset  = hdroffset + junk*4;
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% since modifying our hardware from 256 to 32 channel (19 March 2007), the
% number of channels in a DMA log file can vary. Start with the assumption
% that the file is from the 256 channel system with 8 boards that we have
% in Nijmegen and verify the CRC
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
nboards    = 8;
nchanboard = 32;
blocksize  = nboards*nchanboard+18; % in 4 byte words
fseek(fid, hdroffset, 'bof');
% read a single block
buf = fread(fid, blocksize, 'uint32=>uint32');
% determine the number of boards by systematically checking the CRC value
while (nboards>0)
  if neuralynx_crc(buf(1:blocksize-1))==buf(blocksize)
    % the CRC is correct for this number of boards
    break
  else
    nboards    = nboards - 1;           % decrease by one
    blocksize  = nboards*nchanboard+18; % in 4 byte words
  end
end
fclose(fid);

if ~nboards
  ft_error('could not determine the number of boards and channels');
end

% deal with ascii and numeric input for the channel selection
if nargin>3 && ~ischar(channel)
  chanindx = channel;
  channel = 'selection';
elseif nargin>3 && ischar(channel)
  switch channel
    case 'stx'
      chanindx = 1;
    case 'pid'
      chanindx = 2;
    case 'siz'
      chanindx = 3;
    case 'tsh'
      chanindx = 4;
    case 'tsl'
      chanindx = 5;
    case 'cpu'
      chanindx = 6;
    case 'ttl'
      chanindx = 7;
    case 'x01'
      chanindx = 8;
    case 'x02'
      chanindx = 9;
    case 'x03'
      chanindx = 10;
    case 'x04'
      chanindx = 11;
    case 'x05'
      chanindx = 12;
    case 'x06'
      chanindx = 13;
    case 'x07'
      chanindx = 14;
    case 'x08'
      chanindx = 15;
    case 'x09'
      chanindx = 16;
    case 'x10'
      chanindx = 17;
    case 'crc'
      chanindx = blocksize;
    case 'all'
      chanindx = 1:blocksize;
    otherwise
      ft_error('unknown value in channel');
  end
elseif nargin<4
  channel = 'all';
  chanindx = 1:blocksize;
end

if needhdr
  % these have to be hardcoded, since the DMA logfile does not contain header information
  hdr              = [];
  if hdroffset
    % remember the ascii header from the file, it does not contain much usefull information
    hdr.orig       = orig;
  end
  hdr.Fs           = 32556;                   % sampling frequency
  hdr.nChans       = nboards*nchanboard;      % number of analog channels
  hdr.nSamples     = inf;                     % number of samples per trial
  hdr.nSamplesPre  = 0;                       % number of pre-trigger samples in each trial
  hdr.nTrials      = 1;                       % number of trials
  hdr.label        = {};                      % cell-array with labels of each channel
  for i=1:hdr.nChans
    chanlabel{i} = sprintf('csc%03d', i);
  end
  statuslabel = {
    'stx'
    'pid'
    'siz'
    'tsh'
    'tsl'
    'cpu'
    'ttl'
    'x01'
    'x02'
    'x03'
    'x04'
    'x05'
    'x06'
    'x07'
    'x08'
    'x09'
    'x10'
    };
  hdr.label       = cat(1, statuslabel(:), chanlabel(:), {'crc'});  % concatenate all channel labels
  hdr.nChans      = length(hdr.label);                              % this includes all channels
  % determine the length of the file, expressed in samples
  fid = fopen(filename, 'rb', 'ieee-le');
  fseek(fid, 0, 'eof');
  hdr.nSamples = floor((ftell(fid)-hdroffset)/(blocksize*4));

  % determine the timestamp of the first and of the last sample
  datoffset = 0*blocksize;
  fseek(fid, hdroffset + datoffset, 'bof');
  buf = fread(fid, blocksize, 'uint32=>uint32');
  beg_stx = buf(1);
  beg_tsh = buf(4);
  beg_tsl = buf(5);
  datoffset = (hdr.nSamples-1)*blocksize*4;
  fseek(fid, hdroffset + datoffset, 'bof');
  buf = fread(fid, blocksize, 'uint32=>uint32');
  end_stx = buf(1);
  end_tsh = buf(4);
  end_tsl = buf(5);
  fclose(fid);
  % check that the junk at the beginning was correctly detected
  if (beg_stx~=2048)
    ft_error('problem with STX at the begin of the file');
  end
  % check that the file is truely continuous, i.e. no gaps with junk in between
  if (end_stx~=2048)
    ft_error('problem with STX at the end of the file');
  end
  % combine the two uint32 words into a uint64
  hdr.FirstTimeStamp = timestamp_neuralynx(beg_tsl, beg_tsh);
  hdr.LastTimeStamp  = timestamp_neuralynx(end_tsl, end_tsh);
  hdr.TimeStampPerSample = double(hdr.LastTimeStamp-hdr.FirstTimeStamp)./(hdr.nSamples-1);  % this should be double, since it can be fractional

  % only return the header information
  dat = hdr;
  dat.orig.Offset = hdroffset;

elseif length(chanindx)>1
  % read the desired samples for all channels
  fid = fopen(filename, 'rb', 'ieee-le');
  datoffset = (begsample-1)*blocksize*4;
  fseek(fid, hdroffset + datoffset, 'bof');  % skip the header and samples that do not have to be read
  % read the data
  dat = fread(fid, [blocksize (endsample-begsample+1)], 'int32=>int32');
  fclose(fid);
  if size(dat,2)<(endsample-begsample+1)
    ft_error('could not read all samples');
  end
  if ~strcmp(channel, 'all')
    % select the subset of desired channels
    dat = dat(chanindx,:);
  end

elseif length(chanindx)==1
  % read the desired samples for only one channel
  fid = fopen(filename, 'rb', 'ieee-le');
  datoffset = (begsample-1)*blocksize*4;
  fseek(fid, hdroffset + datoffset, 'bof');  % skip the header and samples that do not have to be read
  fseek(fid, (chanindx-1)*4, 'cof');         % skip to the channel of interest
  % Note that the last block with 274*4 bytes can sometimes be incomplete, which is relevant when endsample=inf
  dat = fread(fid, [1 (endsample-begsample+1)], 'int32=>int32', (nboards*32+18-1)*4);
  if size(dat,2)<(endsample-begsample+1)
    ft_error('could not read all samples');
  end
  fclose(fid);
end


%maps label strings to integers
classdef Labeling < handle

    properties (Access = public, Constant)
        kIgnoreClass = -2;
        kInvalidClass = -1;
        kNullClass = 0;
        kNullClassStr = 'NULL';
        kIgnoreStr = 'ignore';
    end

    properties (GetAccess = public)
        numClasses;
        classNames;
    end

    properties (Access = private)
        classesMap;
    end

    methods (Access = public)
        function obj = Labeling(classNames)
            obj.classNames = classNames;
            if ~isempty(classNames)
                obj.numClasses = length(classNames);
                obj.createLabeling(classNames);
            end
        end

        function valid = isValidLabel(obj,labelStr)
            valid = isKey(obj.classesMap,labelStr);
        end

        function classStr = stringForClassAtIdx(obj,idx)
            if idx == Labeling.kNullClass
                classStr = Labeling.kNullClassStr;
            elseif idx == Labeling.kIgnoreClass
                classStr = Labeling.kIgnoreStr;
            else
                classStr = obj.classNames{idx};
            end
        end

        function idx = idxOfClassWithString(obj,classStr)
            if isempty(obj.classesMap)
                idx = [];
            else
                if ~isKey(obj.classesMap,classStr)
                    fprintf('%s: %s\n',Constants.kUndefinedClassError,classStr);
                    idx = [];
                else
                    idx = obj.classesMap(classStr);
                end
            end
        end
    end

    methods (Static)
        function b = ShouldIgnoreLabels(labels)
            b = (labels == Labeling.kIgnoreClass | labels == Labeling.kInvalidClass);
        end

        function classStr = StringForClass(class, classNames)
            if class == Labeling.kNullClass
                classStr = Labeling.kNullClassStr;
            else
                classStr = classNames{class};
            end
        end
    end

    methods (Access = private)
        function createLabeling(obj,classNames)
            if ~isempty(classNames)
                nClasses = length(classNames);
                obj.classesMap = containers.Map(classNames,int8(1:nClasses));
                obj.classesMap(Labeling.kIgnoreStr) = Labeling.kIgnoreClass;
                obj.classesMap(Labeling.kNullClassStr) = Labeling.kNullClass;
            end
        end
    end
end


% pop_writeeeg - write EEGLAB dataset to disk in EDF/GDF or BDF format
%
% pop_writeeeg( EEG ) % pops up a window
% pop_writeeeg( EEG, filename, 'key', 'val' )
%
% Inputs:
%  EEG        - EEGLAB dataset
%  filename   - [string] filename
%
% Optional keys (same as writeeeg):
%  'TYPE'         - ['GDF'|'EDF'|'BDF'|'CFWB'|'CNT'] file format for writing
%                   default is 'EDF'.
%  See writeeeg for more information
%
% Author: Arnaud Delorme, SCCN, UCSD/CERCO, 2009
%         Based on BIOSIG, sopen and swrite

% Copyright (C) 22 March 2002 Arnaud Delorme, Salk Institute, 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 [command] = pop_writeeeg(EEG, filename, varargin);
command = '';

if nargin < 2
	% ask user
	[filename, filepath] = uiputfile('*.*', 'Enter a file name -- pop_writeeeg()');
	if filename == 0 return; end;
	filename = fullfile(filepath,filename);

    % file format
    % -----------
    fileformats = { 'EDF' 'GDF' 'BDF' };
    uilist = { { 'style' 'text' 'String' 'File format' } ...
               { 'style' 'listbox' 'string' strvcat(fileformats) 'value' 1 } };
    geom = [1 1];
    result = inputgui( 'geometry', geom, 'uilist', uilist, 'helpcom', 'pophelp(''pop_writeeeg'')', ...
                     'title', 'Write data using BIOSIG -- pop_writeeeg()', 'geomvert', [1 2.5]);
    if length(result) == 0 return; end;

    options = { 'TYPE' fileformats{result{1}} };
else
    options = varargin;
end;

warning('off', 'MATLAB:intConvertNonIntVal');
if ~isempty(EEG.chanlocs)
    tmpchanlocs = EEG.chanlocs;
    writeeeg(filename, EEG.data, EEG.srate, 'label', { tmpchanlocs.labels }, 'EVENT', EEG.event, options{:});
else
    writeeeg(filename, EEG.data, EEG.srate, 'EVENT', EEG.event, options{:});
end;
warning('on', 'MATLAB:intConvertNonIntVal');

command = sprintf('pop_writeeeg(EEG, ''%s'', %s);', filename, vararg2str(options));

return;


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Copyright (C) 2010, John T. Ramshur, jramshur@gmail.com
%
% This file is part of HRVAS
%
% HRVAS 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.
%
% HRVAS 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 HRVAS.  If not, see <http://www.gnu.org/licenses/>.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function batchHRV(opt)
%batchHRV: function that calculates hrv on all ibi files in selected
%           directory
%
%Inputs:
%
%Outputs:
%

%check inputs
% if (nargin < 1) || ~isstruct(opt)
%
% end

    %choose file containing HRV analysis options
    reply = input('Enter full file path of HRV analysis option file: ', 's');
    if isempty(reply) || exist(reply,'file')~=2
        error('Please choose valid file path!')
        return;
    end
    opt=load(reply);
    opt=opt.settings;

    %choose dir containing input files
    reply = input('Enter dir path containing IBI files: ', 's');
    if isempty(reply) || exist(reply,'dir')~=7
        error('Please choose valid input dir path!')
        return;
    end

    %check input directory
    fileList = dir(fullfile(reply, '*.ibi')); %get list of files
    fileList(any([fileList.isdir],1))=[]; %remove folders/dir from the list
    fnames = {fileList.name}; %get file names only from fileList structure
    %build array of full file paths
    fpaths=cell(length(fnames),1);
    for ff=1:length(fnames)
        fpaths{ff}=fullfile(reply,fnames{ff});
    end

    %display results of input dir
    disp([reply ' contains ' num2str(length(fpaths)) ' .ibi files.'])

    %choose output file name to save hrv reslts
    outPath = input('Enter file name for exported HRV data: ', 's');
    if isempty(outPath)
        error('Please choose valid input dir path!')
        return;
    end

    %Batch process HRV
    hrv=batchGetHRV(fpaths,opt);

    %Export/save HRV
    saveHRV(hrv,opt,fpaths,outPath)
    disp('batchHRV Done!')

end

function saveHRV(hrv,opt,fList,outPath)
       exportHRV(outPath,fList,hrv,opt)
end

function hrv=batchGetHRV(fList,opt)
    %Preallocate hrv array
    %hrv=repmat(struct('b',0,'a',0),1,length(fList));

    %display time remaining
    disp('Processing: 0% complete.')
    tic; avgElapsed=0;

    %get hrv for each file
    nFiles=length(fList);
    for f=1:nFiles
        hrv(f)=getHRV(fList{f},opt);

        %calculate remaining time for waitbar
        elapsedTime=toc; %total time elapsed since start
        %average time elapsed to process a single file
        avgElapsed=elapsedTime/f;
        %time remaining in processing (min)
        timeRem=ceil(avgElapsed*(nFiles-f)/60);
        bar=round(f/nFiles*100);
        disp(['Processing: ' num2str(bar) ...
            '% complete. (~' num2str(timeRem) ' min)'])
    end

end

function output=getHRV(f,settings)

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % LOAD IBI
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    nIBI=[]; dIBI=[];
    IBI=loadIBI(f,settings);

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %Preprocess Data
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    %build cell array of locate artifacts methods
    methods={}; methInput=[];
    if settings.ArtLocatePer
        methods=[methods,'percent'];
        methInput=[methInput,settings.ArtLocatePerVal];
    end
    if settings.ArtLocateSD
        methods=[methods,'sd'];
        methInput=[methInput,settings.ArtLocateSDVal];
    end
    if settings.ArtLocateMed
        methods=[methods,'median'];
        methInput=[methInput,settings.ArtLocateMedVal];
    end
    %determine which window/span to use
    if strcmpi(settings.ArtReplace,'mean')
        replaceWin=settings.ArtReplaceMeanVal;
    elseif strcmpi(settings.ArtReplace,'median')
        replaceWin=settings.ArtReplaceMedVal;
    else
        replaceWin=0;
    end

    %Note: We don't need to use all the input arguments,but we will let the
    %function handle all inputs
    [dIBI,nIBI,trend,art] = preProcessIBI(IBI, ...
        'locateMethod', methods, 'locateInput', methInput, ...
        'replaceMethod', settings.ArtReplace, ...
        'replaceInput',replaceWin, ...
        'detrendMethod', settings.Detrend, ...
        'smoothMethod', settings.SmoothMethod, ...
        'smoothSpan', settings.SmoothSpan, ...
        'smoothDegree', settings.SmoothDegree, ...
        'polyOrder', settings.PolyOrder, ...
        'waveletType', ...
        [settings.WaveletType num2str(settings.WaveletType2)], ...
        'waveletLevels', settings.WaveletLevels, ...
        'lambda', settings.PriorsLambda,...
        'resampleRate',settings.Interp,...
        'meanCorrection',true);

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %Calculate HRV
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    output.ibiinfo.count=size(IBI,1); % total # of ibi
    output.ibiinfo.outliers=sum(art); % number of outliers

    %Time-Domain (using non-detrented ibi)
    output.time=timeDomainHRV(nIBI,settings.SDNNi*60,settings.pNNx);
    %output.time.mean=round(mean(nIBI(:,2).*1000)*10)/10;
    %output.time.meanHR=round(mean(60./nIBI(:,2))*10)/10;

    %Freq-Domain
    output.freq=freqDomainHRV(dIBI,settings.VLF,settings.LF, ...
        settings.HF,settings.AROrder,settings.WinWidth, ...
        settings.WinOverlap,settings.Points,settings.Interp);

    %Nonlinear (using non-detrented ibi)
    output.nl=nonlinearHRV(nIBI,settings.m,settings.r, ...
        settings.n1,settings.n2,settings.breakpoint);
    %Poincare
    output.poincare=poincareHRV(nIBI);

    %Time-Freq
    output.tf=timeFreqHRV(dIBI,nIBI,settings.VLF,settings.LF, ...
        settings.HF,settings.AROrder, settings.tfWinSize, ...
        settings.tfOverlap,settings.Points,settings.Interp, ...
        {'ar','lomb','wavelet'});
    %%%%%%%%%%%%%%%%%%%%%%%

    clear  nIBI dIBI IBI

end

function ibi=loadIBI(f,opt)
    if ~exist(f,'file')
        error(['Error opening file: ' f])
        return
    end

    ibi=[];
    DELIMITER = ',';
    HEADERLINES = opt.headerSize;

    %read ibi
    tmpData = importdata(f, DELIMITER, HEADERLINES);
    if HEADERLINES>0
        tmpData=tmpData.data;
    end

    %check ibi dimentions
    [rows cols] = size(tmpData);
    if rows==1
        tmpData=tmpData';
        ibi=zeros(cols,2);
        tmp=cumsum(tmpData);
        ibi(2:end,1)=tmp(1:end-1);
        ibi(:,2)=tmpData;
    elseif cols==1
        ibi=zeros(rows,2);
        tmp=cumsum(tmpData);
        ibi(2:end,1)=tmp(1:end-1);
        ibi(:,2)=tmpData;
    elseif rows<cols
        ibi=tmpData';
    else
        ibi=tmpData;
    end
    clear tmpData
end


function [success] = omparameter (modelname,name,wert);
% Change parameter in *_init.txt file; Returns linenumber replaced if
% succeeded, -1 if not.
% SYNTAX: [linenumber] = omparameter(modelname,parameter,value)
% Beispiel: omparameter('package.model','stop value',10)
%
% Feedback/problems: Christian Schaad, ingenieurbuero@christian-schaad.de

success=-1;
inputfile=[modelname,'_init_original.xml'];
outputfile=[modelname,'_init.xml'];
%def_output=['outputFormat   = "mat"'];
%plt_output=['outputFormat   = "plt"'];

fid=fopen(inputfile);
i=0;
while 1
    i=i+1;
    tline0 = fgetl(fid);
    if ~ischar(tline0), break, end
    tline= [tline0,char(10)];
    %if ~isempty(strfind(tline,def_output));
    %tline=[plt_output,char(10)];
    %disp('MAT-Output changed to PLT-Output')
    %end
    if ~isempty(strfind(tline,['name = "',name,'"',char(10)]))
    for k=0:7
    dataset(i+k).string=tline;
    tline0 = fgetl(fid);
    tline= [tline0,char(10)];
    end
    i=i+k+1;

    tline=['<Real start="',wert,'" fixed="true" />',char(10)	];
    %disp(tline)
    success=i;
    end

    dataset(i).string=tline;
    clear tline tline0;

end
fclose(fid);

fid=fopen(outputfile,'w');
for j=1:i-1
fprintf(fid,[dataset(j).string]);
end
fclose(fid);
switch success
    case -1
        error(['Parameter ',name,' not found!']);
end;
disp(['Replaced line number ',num2str(success),', parameter ',num2str(name),' with ',num2str(wert) ]);


function v = WindowFeatureNameCompare(f1,f2)

v = [];

if isempty(f1) || isempty(f2),
  return;
end

iscell1 = iscell(f1{1});
iscell2 = iscell(f2{1});

if iscell1 && iscell2,
  if numel(f1) ~= numel(f2),
    error('Inputs f1 and f2 do not match');
  else
    v = false(size(f1));
    for i = 1:numel(f1),
      if numel(f1{i}) == numel(f2{i}),
        vcurr = true;
        for j = 1:numel(f1{i}),
          if strcmp(class(f1{i}{j}),class(f2{i}{j})),
            if isnumeric(f1{i}{j}),
              if ~all(f1{i}{j} == f2{i}{j}),
                vcurr = false;
                break;
              end
            else
              if ~strcmp(f1{i}{j},f2{i}{j}),
                vcurr = false;
                break;
              end
            end
          end
        end
        v(i) = vcurr;
      end
    end
  end
  return;
end

if iscell2,
  v = WindowFeatureNameCompare(f2,f1);
  return;
end

if iscell1,
  v = false(size(f1));
  for i = 1:numel(f1),
    if numel(f1{i}) == numel(f2),
      vcurr = true;
      for j = 1:numel(f1{i}),
        if strcmp(class(f1{i}{j}),class(f2{j})),
          if isnumeric(f1{i}{j}),
            if ~all(f1{i}{j} == f2{j}),
              vcurr = false;
              break;
            end
          else
            if ~strcmp(f1{i}{j},f2{j}),
              vcurr = false;
              break;
            end
          end
        end
      end
      v(i) = vcurr;
    end
  end
  return;
end

v = true;
for j = 1:numel(f1),
  if strcmp(class(f1{j}),class(f2{j})),
    if isnumeric(f1{j}),
      if ~all(f1{j} == f2{j}),
        v = false;
        break;
      end
    else
      if ~strcmp(f1{j},f2),
        v = false;
        break;
      end
    end
  end
end


% LoadGUI

% manually check that directories are correct in 'FishExplorer2\dir setup'

clear all;close all;clc
% path(pathdef);

%%
% scriptName = mfilename('fullpath');
% [currentpath, filename, fileextension]= fileparts(scriptName);
% code_dir = currentpath;

%% setup dir
file_masterdir = 'C:\Users\Xiu\Dropbox (Personal)';
if ~exist(file_masterdir,'dir')
    file_masterdir = 'C:\Users\xiuye\Dropbox';
end
code_dir = fullfile(file_masterdir,'FishExplorer2');

% SET CUSTOM PATH example:
% code_dir = 'C:\Users\xiuye\Dropbox\FishExplorer-master';

addpath(genpath(code_dir));

cd(code_dir)

%% setup
global VAR; %#ok<NUSED>
load_dir = GetOutputDataDir();
load(fullfile(load_dir,'VAR_new.mat'),'VAR'); % stores all clustering indices
VAR = CompileVARnames(VAR);

set(0, 'defaultUicontrolFontName', 'Arial');
set(0, 'defaultUitableFontName', 'Arial');
set(0, 'defaultUipanelFontName', 'Arial');
set(0, 'defaultAxesFontName', 'Arial');
set(0, 'defaultTextFontName', 'Arial');

%% Start GUI
% Run this, or press F5 in 'GUI_FishExplorer.m'
[hGUI,fcns] = GUI_FishExplorer;

% to push new functions to GUI, called with function 'push_cIX_gIX':
% hfig = GUI_FishExplorer(data_dir,name_CONSTs,name_MASKs,VAR,flag_script,var_script)

%%
% to get handle of local functions from GUI to use in workspace
% (call by using 'f.FunctionName')
f = [];
for i = 1:length(fcns),
    eval(['f.' char(fcns{i}) ' = fcns{i};']);
end

%%
% to recover after closing figure:
% global EXPORT_autorecover;

%% demo: load data without visualizaing in GUI (only using same infrastructure)
if false,
    %%
    h0 = figure;
    InitializeAppData(h0);
    i_fish = 3;
    [cIX,gIX,M,stim,behavior,M_0] = LoadSingleFishDefault(i_fish,h0);

    figure('Position',[50,100,800,1000]);
    I = LoadCurrentFishForAnatPlot(h0);
    DrawCellsOnAnat(I);

    % filename = fullfile(saveDir, num2str(i_fish));
    % saveas(gcf, filename, 'png');
end

%%
% MASKs = getappdata(hGUI,'MASKs');
% Masks = MASKs.MaskDatabaseNames';


% The COBRAToolbox: testRestrictModelsToFields.m
%
% Purpose:
%     - test the restrictModelsToFields function
%
% Authors:
%     - Jacek Wachowiak
global CBTDIR
% save the current path
currentDir = pwd;

% initialize the test
fileDir = fileparts(which('testRestrictModelsToFields'));
cd(fileDir);

% test variables
models{1} = getDistributedModel('ecoli_core_model.mat');
models{2} = getDistributedModel('Abiotrophia_defectiva_ATCC_49176.xml');

fieldNames = fieldnames(models{1});
fieldNames2 = fieldnames(models{2});

%test whether fields are removed:
commonfields = intersect(fieldNames,fieldNames2);
restrictedModels = restrictModelsToFields(models, commonfields);

for i = 1:numel(models)
    assert(isempty(setxor(commonfields,fieldnames(restrictedModels{i}))));
end

%Test whether random fields are retained.

fieldsKept = commonfields([1,2,3]);
restrictedModels = restrictModelsToFields(models, fieldsKept);
for i = 1:numel(models)
    assert(isempty(setxor(fieldsKept,fieldnames(restrictedModels{i}))));
end

%leave all fields in
allFields = union(fieldNames,fieldNames2);
restrictedModels = restrictModelsToFields(models, allFields);

% test
assert(isSameCobraModel(restrictedModels{1}, models{1}));
assert(isSameCobraModel(restrictedModels{2}, models{2}));

% change to old directory
cd(currentDir);


function [channel] = ft_channelselection(desired, datachannel, senstype)

% FT_CHANNELSELECTION makes a selection of EEG and/or MEG channel labels. This
% function translates the user-specified list of channels into channel labels as they
% occur in the data. This channel selection procedure can be used throughout
% FieldTrip.
%
% You can specify a mixture of real channel labels and of special strings, or index
% numbers that will be replaced by the corresponding channel labels. Channels that
% are not present in the raw datafile are automatically removed from the channel
% list.
%
% The order of the channels in the list that is returned corresponds to the order in
% the data.
%
% E.g. the desired input specification can be:
%   'all'        is replaced by all channels in the datafile
%   'gui'        this will pop up a graphical user interface to select the channels
%   'C*'         is replaced by all channels that match the wildcard, e.g. C1, C2, C3, ...
%   '*1'         is replaced by all channels that match the wildcard, e.g. C1, P1, F1, ...
%   'M*1'        is replaced by all channels that match the wildcard, e.g. MEG0111, MEG0131, MEG0131, ...
%   'meg'        is replaced by all MEG channels (works for CTF, 4D, Neuromag and Yokogawa)
%   'megref'     is replaced by all MEG reference channels (works for CTF and 4D)
%   'meggrad'    is replaced by all MEG gradiometer channels (works for Yokogawa and Neuromag306)
%   'megplanar'  is replaced by all MEG planar gradiometer channels (works for Neuromag306)
%   'megmag'     is replaced by all MEG magnetometer channels (works for Yokogawa and Neuromag306)
%   'eeg'        is replaced by all recognized EEG channels (this is system dependent)
%   'eeg1020'    is replaced by 'Fp1', 'Fpz', 'Fp2', 'F7', 'F3', ...
%   'eog'        is replaced by all recognized EOG channels
%   'ecg'        is replaced by all recognized ECG channels
%   'nirs'       is replaced by all channels recognized as NIRS channels
%   'emg'        is replaced by all channels in the datafile starting with 'EMG'
%   'lfp'        is replaced by all channels in the datafile starting with 'lfp'
%   'mua'        is replaced by all channels in the datafile starting with 'mua'
%   'spike'      is replaced by all channels in the datafile starting with 'spike'
%   10           is replaced by the 10th channel in the datafile
%
% Other channel groups are
%   'EEG1010'    with approximately 90 electrodes
%   'EEG1005'    with approximately 350 electrodes
%   'EEGREF'     for mastoid and ear electrodes (M1, M2, LM, RM, A1, A2)
%   'MZ'         for MEG zenith
%   'ML'         for MEG left
%   'MR'         for MEG right
%   'MLx', 'MRx' and 'MZx' with x=C,F,O,P,T for left/right central, frontal, occipital, parietal and temporal
%
% You can also exclude channels or channel groups using the following syntax
%   {'all', '-POz', '-Fp1', -EOG'}
%
% See also FT_PREPROCESSING, FT_SENSLABEL, FT_MULTIPLOTER, FT_MULTIPLOTTFR,
% FT_SINGLEPLOTER, FT_SINGLEPLOTTFR

% Copyright (C) 2003-2021, 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$

% this is to avoid a recursion loop
persistent recursion

if isempty(recursion)
  recursion = false;
end

if nargin<3
  % the actual senstype will be determined further down
  % postponing the detection speeds up some common use patterns, such as 'all' and []
  senstype = [];
end

if iscell(datachannel)
  % this is the expected format of the input
  datachantype = {};
elseif ischar(datachannel)
  datachannel = {datachannel};
  datachantype = {};
elseif isstruct(datachannel) && isfield(datachannel, 'label')
  % it looks like a header structure
  hdr = datachannel;
  datachannel = hdr.label;
  datachantype = ft_chantype(hdr);
else
  ft_error('please specify the data channels as a cell-array');
end

if length(datachannel)~=length(unique(datachannel))
  ft_warning('discarding non-unique channel names');
  sel = false(size(datachannel));
  for i=1:length(datachannel)
    sel(i) = sum(strcmp(datachannel, datachannel{i}))==1;
  end
  datachannel = datachannel(sel);
  if ~isempty(datachantype)
    datachantype = datachantype(sel);
  end
end

if isempty(desired)
  % return an empty selection
  channel = {};
  return
elseif isequal(desired, 'all') || isequal(desired, {'all'})
  % this is a very common use pattern that can be dealt with quickly
  % ensure that the output is a column vector
  channel = datachannel(:);
  return
elseif isnumeric(desired)
  % remove channels that fall outside the range
  desired = desired(desired>=1 & desired<=numel(datachannel));
  % change the numeric index into the channel name
  channel = datachannel(desired);
  return
elseif ischar(desired)
  % ensure that a single input argument like 'all' also works
  desired = {desired};
elseif ~iscell(desired)
  ft_error('please specify the desired channels as a cell-array or a string');
end

% start with the list of desired channels, this will be pruned/expanded further down
channel = desired;

% ensure that both inputs are column vectors
channel     = channel(:);
datachannel = datachannel(:);

% remove channels that occur more than once, this sorts the channels alphabetically
[channel, indx] = unique(channel);
% undo the sorting, make the order identical to that of the data channels
[dum, indx] = sort(indx);
channel = channel(indx);

[dataindx, chanindx] = match_str(datachannel, channel);
if length(chanindx)==length(channel)
  % there is a perfect match between the channels and the datachannels, only some reordering is needed
  channel = channel(chanindx);
  % no need to look at channel groups
  return
end

% initialize all the system-specific variables to empty
labelall       = {};
labelreg       = {};
labelmeg       = {};
labelecg       = {};
labelemg       = {};
labeleeg       = {};
label102       = {};
label101       = {};
label100       = {};
labelchwilla   = {};
labelbha       = {};
labelref       = {};
labelmegref    = {};
labelmeggrad   = {};
labelmegplanar = {};
labelmegmag    = {};
labelmegrefa   = {};
labelmegrefc   = {};
labelmegrefg   = {};
labelmegrefl   = {};
labelmegrefr   = {};
labelmegrefm   = {};
labeleog       = {};
labelmz        = {};
labelml        = {};
labelmr        = {};
labelmlc       = {};
labelmlf       = {};
labelmlo       = {};
labelmlp       = {};
labelmlt       = {};
labelmrc       = {};
labelmrf       = {};
labelmro       = {};
labelmrp       = {};
labelmrt       = {};
labelmzc       = {};
labelmzf       = {};
labelmzo       = {};
labelmzp       = {};
labellfp       = {};
labelmua       = {};
labelspike     = {};
labelnirs      = {};

% define the known groups with channel labels
labelall    = datachannel;
label1020   = ft_senslabel('eeg1020'); % use external helper function
label1010   = ft_senslabel('eeg1010'); % use external helper function
label1005   = ft_senslabel('eeg1005'); % use external helper function
labelchwilla = {'Fz', 'Cz', 'Pz', 'F7', 'F8', 'LAT', 'RAT', 'LT', 'RT', 'LTP', 'RTP', 'OL', 'OR', 'FzA', 'Oz', 'F7A', 'F8A', 'F3A', 'F4A', 'F3', 'F4', 'P3', 'P4', 'T5', 'T6', 'P3P', 'P4P'}';
labelbham   = {'P9', 'PPO9h', 'PO7', 'PPO5h', 'PPO3h', 'PO5h', 'POO9h', 'PO9', 'I1', 'OI1h', 'O1', 'POO1', 'PO3h', 'PPO1h', 'PPO2h', 'POz', 'Oz', 'Iz', 'I2', 'OI2h', 'O2', 'POO2', 'PO4h', 'PPO4h', 'PO6h', 'POO10h', 'PO10', 'PO8', 'PPO6h', 'PPO10h', 'P10', 'P8', 'TPP9h', 'TP7', 'TTP7h', 'CP5', 'TPP7h', 'P7', 'P5', 'CPP5h', 'CCP5h', 'CP3', 'P3', 'CPP3h', 'CCP3h', 'CP1', 'P1', 'Pz', 'CPP1h', 'CPz', 'CPP2h', 'P2', 'CPP4h', 'CP2', 'CCP4h', 'CP4', 'P4', 'P6', 'CPP6h', 'CCP6h', 'CP6', 'TPP8h', 'TP8', 'TPP10h', 'T7', 'FTT7h', 'FT7', 'FC5', 'FCC5h', 'C5', 'C3', 'FCC3h', 'FC3', 'FC1', 'C1', 'CCP1h', 'Cz', 'FCC1h', 'FCz', 'FFC1h', 'Fz', 'FFC2h', 'FC2', 'FCC2h', 'CCP2h', 'C2', 'C4', 'FCC4h', 'FC4', 'FC6', 'FCC6h', 'C6', 'TTP8h', 'T8', 'FTT8h', 'FT8', 'FT9', 'FFT9h', 'F7', 'FFT7h', 'FFC5h', 'F5', 'AFF7h', 'AF7', 'AF5h', 'AFF5h', 'F3', 'FFC3h', 'F1', 'AF3h', 'Fp1', 'Fpz', 'Fp2', 'AFz', 'AF4h', 'F2', 'FFC4h', 'F4', 'AFF6h', 'AF6h', 'AF8', 'AFF8h', 'F6', 'FFC6h', 'FFT8h', 'F8', 'FFT10h', 'FT10'};
labelref    = {'M1', 'M2', 'LM', 'RM', 'A1', 'A2'}';
labeleeg    = datachannel(startsWith(datachannel, 'EEG'));               % anything that starts with EEG
labeleog    = datachannel(startsWith(datachannel, 'EOG'));               % anything that starts with EOG
labeleog    = [labeleog(:); {'HEOG', 'VEOG', 'VEOG-L', 'VEOG-R', 'hEOG', 'vEOG', 'Eye_Ver', 'Eye_Hor'}'];     % or any of these
labelecg    = datachannel(strncmp('ECG', datachannel, length('ECG')));
labelemg    = datachannel(strncmp('EMG', datachannel, length('EMG')));
labellfp    = datachannel(strncmp('lfp', datachannel, length('lfp')));
labelmua    = datachannel(strncmp('mua', datachannel, length('mua')));
labelspike  = datachannel(strncmp('spike', datachannel, length('spike')));
% for NIRS there are multiple options, either using the terminology transmitter/receiver versus source/detector, and then with either order of the two
option1 = ~cellfun(@isempty, regexp(datachannel, sprintf('%s%s', regexptranslate('wildcard','Rx*-Tx*[*]'), '$')));
option2 = ~cellfun(@isempty, regexp(datachannel, sprintf('%s%s', regexptranslate('wildcard','Tx*-Rx*[*]'), '$')));
option3 = ~cellfun(@isempty, regexp(datachannel, sprintf('%s%s', regexptranslate('wildcard','D*-S*[*]'), '$')));
option4 = ~cellfun(@isempty, regexp(datachannel, sprintf('%s%s', regexptranslate('wildcard','S*-D*[*]'), '$')));
labelnirs = datachannel(option1 | option2 | option3 | option4);

% use regular expressions to deal with the wildcards
labelreg = false(size(datachannel));
findreg  = [];
for i=1:length(channel)
  if length(channel{i}) < 1
    continue;
  end

  if strcmp((channel{i}(1)), '-')
    % skip channels to be excluded
    continue;
  end

  rexp = sprintf('%s%s%s', '^', regexptranslate('wildcard',channel{i}), '$');
  lreg = ~cellfun(@isempty, regexp(datachannel, rexp));
  if any(lreg)
    labelreg = labelreg | lreg;
    findreg  = [findreg; i];
  end
end

if ~isempty(findreg)
  findreg  = unique(findreg); % remove multiple occurances due to multiple wildcards
  labelreg = datachannel(labelreg);
end

if isempty(senstype)
  senstype = ft_senstype(datachannel);
end

switch senstype

  case {'yokogawa', 'yokogawa160', 'yokogawa160_planar', 'yokogawa64', 'yokogawa64_planar', 'yokogawa440', 'yokogawa440_planar'}
    % Yokogawa axial gradiometers channels start with AG, hardware planar gradiometer
    % channels start with PG, magnetometers start with M
    megax    = strncmp('AG', datachannel, length('AG'));
    megpl    = strncmp('PG', datachannel, length('PG'));
    megmag   = strncmp('M',  datachannel, length('M' ));
    megind   = logical( megax + megpl + megmag);
    labelmeg      = datachannel(megind);
    labelmegmag   = datachannel(megmag);
    labelmeggrad  = datachannel(megax | megpl);
    %%
    %    labeleeg  = datachannel(strncmp('EEG', datachannel, length('EEG')));
    eeg_A = myregexp('^A[^G]*[0-9hzZ]$', datachannel);
    eeg_P = myregexp('^P[^G]*[0-9hzZ]$', datachannel);
    eeg_T = myregexp('^T[^R]*[0-9hzZ]$', datachannel);
    eeg_E = myregexp('^E$', datachannel);
    eeg_Z = myregexp('^[zZ]$', datachannel);
    eeg_M = myregexp('^M[0-9]$', datachannel);
    eeg_O = myregexp('^[BCFION]\w*[0-9hzZ]$', datachannel);
    eeg_EEG = myregexp('^EEG[0-9][0-9][0-9]$', datachannel);
    eegind = logical( eeg_A + eeg_P + eeg_T + eeg_E + eeg_Z + eeg_M + eeg_O + eeg_EEG );
    clear eeg_A eeg_P eeg_T eeg_E eeg_Z eeg_M eeg_O eeg_EEG
    labeleeg      = datachannel(eegind);
    labeleog    = [ labeleog(:); datachannel(myregexp('^EO[0-9]$', datachannel)) ];  % add 'EO'
    labelecg    = [ labelecg(:); datachannel(myregexp('^X[0-9]$', datachannel)) ];   % add 'X'

  case {'ctf64'}
    labelml     = datachannel(~cellfun(@isempty, regexp(datachannel, '^SL')));    % left    MEG channels
    labelmr     = datachannel(~cellfun(@isempty, regexp(datachannel, '^SR')));    % right   MEG channels
    labelmeg    = cat(1, labelml, labelmr);
    labelmegref = [datachannel(strncmp('B'  , datachannel, 1));
      datachannel(strncmp('G'  , datachannel, 1));
      datachannel(strncmp('P'  , datachannel, 1));
      datachannel(strncmp('Q'  , datachannel, 1));
      datachannel(strncmp('R'  , datachannel, length('G'  )))];

  case {'ctf', 'ctf275', 'ctf151', 'ctf275_planar', 'ctf151_planar'}
    % all CTF MEG channels start with "M"
    % all CTF reference channels start with B, G, P, Q or R
    % all CTF EEG channels start with "EEG"
    labelmeg    = datachannel(strncmp('M'  , datachannel, length('M'  )));
    labelmegref = [datachannel(strncmp('B'  , datachannel, 1));
      datachannel(strncmp('G'  , datachannel, 1));
      datachannel(strncmp('P'  , datachannel, 1));
      datachannel(strncmp('Q'  , datachannel, 1));
      datachannel(strncmp('R'  , datachannel, length('G'  )))];
    labeleeg  = datachannel(strncmp('EEG', datachannel, length('EEG')));

    % Not sure whether this should be here or outside the switch or
    % whether these specifications should be supported for systems
    % other than CTF.
    labelmz   = datachannel(strncmp('MZ' , datachannel, length('MZ' )));    % central MEG channels
    labelml   = datachannel(strncmp('ML' , datachannel, length('ML' )));    % left    MEG channels
    labelmr   = datachannel(strncmp('MR' , datachannel, length('MR' )));    % right   MEG channels
    labelmlc  = datachannel(strncmp('MLC', datachannel, length('MLC')));
    labelmlf  = datachannel(strncmp('MLF', datachannel, length('MLF')));
    labelmlo  = datachannel(strncmp('MLO', datachannel, length('MLO')));
    labelmlp  = datachannel(strncmp('MLP', datachannel, length('MLP')));
    labelmlt  = datachannel(strncmp('MLT', datachannel, length('MLT')));
    labelmrc  = datachannel(strncmp('MRC', datachannel, length('MRC')));
    labelmrf  = datachannel(strncmp('MRF', datachannel, length('MRF')));
    labelmro  = datachannel(strncmp('MRO', datachannel, length('MRO')));
    labelmrp  = datachannel(strncmp('MRP', datachannel, length('MRP')));
    labelmrt  = datachannel(strncmp('MRT', datachannel, length('MRT')));
    labelmzc  = datachannel(strncmp('MZC', datachannel, length('MZC')));
    labelmzf  = datachannel(strncmp('MZF', datachannel, length('MZF')));
    labelmzo  = datachannel(strncmp('MZO', datachannel, length('MZO')));
    labelmzp  = datachannel(strncmp('MZP', datachannel, length('MZP')));

  case {'bti', 'bti248', 'bti248grad', 'bti148', 'bti248_planar', 'bti148_planar'}
    % all 4D-BTi MEG channels start with "A"
    % all 4D-BTi reference channels start with M or G

    labelmeg     = datachannel(myregexp('^A[0-9]+$', datachannel));
    labelmegref  = [datachannel(myregexp('^M[CLR][xyz][aA]*$', datachannel)); datachannel(myregexp('^G[xyz][xyz]A$', datachannel)); datachannel(myregexp('^M[xyz][aA]*$', datachannel))];
    labelmegrefa = datachannel(~cellfun(@isempty,strfind(datachannel, 'a')));
    labelmegrefc = datachannel(strncmp('MC', datachannel, 2));
    labelmegrefg = datachannel(myregexp('^G[xyz][xyz]A$', datachannel));
    labelmegrefl = datachannel(strncmp('ML', datachannel, 2));
    labelmegrefr = datachannel(strncmp('MR', datachannel, 2));
    labelmegrefm = datachannel(myregexp('^M[xyz][aA]*$', datachannel));

  case {'neuromag122' 'neuromag122alt', 'neuromag122_combined'}
    % all neuromag MEG channels start with MEG
    % all neuromag EEG channels start with EEG
    labelmeg = datachannel(strncmp('MEG', datachannel, length('MEG')));
    labeleeg = datachannel(strncmp('EEG', datachannel, length('EEG')));

  case {'neuromag306' 'neuromag306alt', 'neuromag306_combined'}
    % all neuromag MEG channels start with MEG
    % all neuromag EEG channels start with EEG
    % all neuromag306 gradiometers follow pattern MEG*2,MEG*3
    % all neuromag306 magnetometers follow pattern MEG*1
    labelmeg = datachannel(strncmp('MEG', datachannel, length('MEG')));
    labeleeg = datachannel(strncmp('EEG', datachannel, length('EEG')));

    labelmeggrad   = labelmeg(~cellfun(@isempty, regexp(labelmeg, '^MEG.*[23]$')));
    labelmegmag    = labelmeg(~cellfun(@isempty, regexp(labelmeg, '^MEG.*1$')));
    labelmegplanar = labelmeggrad;

  case {'ant128', 'biosemi64', 'biosemi128', 'biosemi256', 'egi32', 'egi64', 'egi128', 'egi256', 'eeg1020', 'eeg1010', 'eeg1005', 'ext1020'}
    if ~ft_senstype(datachannel, 'unknown')
      % use an external helper function to define the list with EEG channel names
      labeleeg = ft_senslabel(ft_senstype(datachannel));
    end

  case {'itab153' 'itab28' 'itab28_old'}
    % all itab MEG channels start with MAG
    labelmeg = datachannel(strncmp('MAG', datachannel, length('MAG')));

  case{'qzfm_gen2'}
    % This is for use with QZFM_Gen2 Optically Pumped Magnetometers manufactured by QuSpin Inc.
    % SPECS: https://quspin.com/qzfm-gen-2-update/

    labelmeg    = datachannel(strncmp('meg', datachantype, 3));
    labelmegref = datachannel(strncmp('refmag', datachantype, 3));

    % All channels measuring tangential fields are end with TAN
    % All channels measuring radial fields are end with RAD

    % This is specific to data collected from UCL. Also see:
    % https://www.fieldtriptoolbox.org/getting_started/opm_fil/
    labelmegtan = labelmeg(~cellfun(@isempty, regexp(labelmeg, '.*TAN$')));
    labelmegrad = labelmeg(~cellfun(@isempty, regexp(labelmeg, '.*RAD$')));

  otherwise
    if ~isempty(datachantype)
      labelmeg = datachannel(strncmp('meg', datachantype, 3));
      labeleeg = datachannel(strncmp('eeg', datachantype, 3));
    end

end % switch ft_senstype

% figure out if there are bad channels or channel groups that should be excluded
findbadchannel = strncmp('-', channel, length('-'));      % bad channels start with '-'
badchannel = channel(findbadchannel);
if ~isempty(badchannel)
  for i=1:length(badchannel)
    badchannel{i} = badchannel{i}(2:end);                 % remove the '-' from the channel label
  end
  badchannel = ft_channelselection(badchannel, datachannel); % support exclusion of channel groups
end

% determine if any of the known groups is mentioned in the channel list
findall        = find(strcmp(channel, 'all'));
% findreg (for the wildcards) is dealt with in the channel group specification above
findmeg        = find(strcmpi(channel, 'MEG'));
findemg        = find(strcmpi(channel, 'EMG'));
findecg        = find(strcmpi(channel, 'ECG'));
findeeg        = find(strcmpi(channel, 'EEG'));
findeeg1020    = find(strcmpi(channel, 'EEG1020'));
findeeg1010    = find(strcmpi(channel, 'EEG1010'));
findeeg1005    = find(strcmpi(channel, 'EEG1005'));
findeegchwilla = find(strcmpi(channel, 'EEGCHWILLA'));
findeegbham    = find(strcmpi(channel, 'EEGBHAM'));
findeegref     = find(strcmpi(channel, 'EEGREF'));
findmegref     = find(strcmpi(channel, 'MEGREF'));
findmeggrad    = find(strcmpi(channel, 'MEGGRAD'));
findmegplanar  = find(strcmpi(channel, 'MEGPLANAR'));
findmegmag     = find(strcmpi(channel, 'MEGMAG'));
findmegrefa    = find(strcmpi(channel, 'MEGREFA'));
findmegrefc    = find(strcmpi(channel, 'MEGREFC'));
findmegrefg    = find(strcmpi(channel, 'MEGREFG'));
findmegrefl    = find(strcmpi(channel, 'MEGREFL'));
findmegrefr    = find(strcmpi(channel, 'MEGREFR'));
findmegrefm    = find(strcmpi(channel, 'MEGREFM'));
findmegtan     = find(strcmpi(channel, 'MEGTAN'));
findmegrad     = find(strcmpi(channel, 'MEGRAD'));
findeog        = find(strcmpi(channel, 'EOG'));
findmz         = find(strcmp(channel, 'MZ' ));
findml         = find(strcmp(channel, 'ML' ));
findmr         = find(strcmp(channel, 'MR' ));
findmlc        = find(strcmp(channel, 'MLC'));
findmlf        = find(strcmp(channel, 'MLF'));
findmlo        = find(strcmp(channel, 'MLO'));
findmlp        = find(strcmp(channel, 'MLP'));
findmlt        = find(strcmp(channel, 'MLT'));
findmrc        = find(strcmp(channel, 'MRC'));
findmrf        = find(strcmp(channel, 'MRF'));
findmro        = find(strcmp(channel, 'MRO'));
findmrp        = find(strcmp(channel, 'MRP'));
findmrt        = find(strcmp(channel, 'MRT'));
findmzc        = find(strcmp(channel, 'MZC'));
findmzf        = find(strcmp(channel, 'MZF'));
findmzo        = find(strcmp(channel, 'MZO'));
findmzp        = find(strcmp(channel, 'MZP'));
findnirs       = find(strcmpi(channel, 'NIRS'));
findlfp        = find(strcmpi(channel, 'lfp'));
findmua        = find(strcmpi(channel, 'mua'));
findspike      = find(strcmpi(channel, 'spike'));
findgui        = find(strcmpi(channel, 'gui'));

% remove any occurences of groups in the channel list
channel([
  findall
  findreg
  findmeg
  findemg
  findecg
  findeeg
  findeeg1020
  findeeg1010
  findeeg1005
  findeegchwilla
  findeegbham
  findeegref
  findmegref
  findmeggrad
  findmegplanar
  findmegmag
  findeog
  findmz
  findml
  findmr
  findmlc
  findmlf
  findmlo
  findmlp
  findmlt
  findmrc
  findmrf
  findmro
  findmrp
  findmrt
  findmzc
  findmzf
  findmzo
  findmzp
  findlfp
  findmua
  findspike
  findnirs
  findgui
  ]) = [];

% add the full channel labels to the channel list
if findall,        channel = [channel; labelall]; end
if findreg,        channel = [channel; labelreg]; end
if findmeg,        channel = [channel; labelmeg]; end
if findecg,        channel = [channel; labelecg]; end
if findemg,        channel = [channel; labelemg]; end
if findeeg,        channel = [channel; labeleeg]; end
if findeeg1020,    channel = [channel; label1020]; end
if findeeg1010,    channel = [channel; label1010]; end
if findeeg1005,    channel = [channel; label1005]; end
if findeegchwilla, channel = [channel; labelchwilla]; end
if findeegbham,    channel = [channel; labelbham]; end
if findeegref,     channel = [channel; labelref]; end
if findmegref,     channel = [channel; labelmegref]; end
if findmeggrad,    channel = [channel; labelmeggrad]; end
if findmegplanar,  channel = [channel; labelmegplanar]; end
if findmegmag,     channel = [channel; labelmegmag]; end
if findmegrefa,    channel = [channel; labelmegrefa]; end
if findmegrefc,    channel = [channel; labelmegrefc]; end
if findmegrefg,    channel = [channel; labelmegrefg]; end
if findmegrefl,    channel = [channel; labelmegrefl]; end
if findmegrefr,    channel = [channel; labelmegrefr]; end
if findmegrefm,    channel = [channel; labelmegrefm]; end
if findmegtan,     channel = [channel; labelmegtan]; end
if findmegrad,     channel = [channel; labelmegrad]; end
if findeog,        channel = [channel; labeleog]; end
if findmz ,        channel = [channel; labelmz ]; end
if findml ,        channel = [channel; labelml ]; end
if findmr ,        channel = [channel; labelmr ]; end
if findmlc,        channel = [channel; labelmlc]; end
if findmlf,        channel = [channel; labelmlf]; end
if findmlo,        channel = [channel; labelmlo]; end
if findmlp,        channel = [channel; labelmlp]; end
if findmlt,        channel = [channel; labelmlt]; end
if findmrc,        channel = [channel; labelmrc]; end
if findmrf,        channel = [channel; labelmrf]; end
if findmro,        channel = [channel; labelmro]; end
if findmrp,        channel = [channel; labelmrp]; end
if findmrt,        channel = [channel; labelmrt]; end
if findmzc,        channel = [channel; labelmzc]; end
if findmzf,        channel = [channel; labelmzf]; end
if findmzo,        channel = [channel; labelmzo]; end
if findmzp,        channel = [channel; labelmzp]; end
if findlfp,        channel = [channel; labellfp]; end
if findmua,        channel = [channel; labelmua]; end
if findspike,      channel = [channel; labelspike]; end
if findnirs,       channel = [channel; labelnirs]; end

% remove channel labels that have been excluded by the user
badindx = match_str(channel, badchannel);
channel(badindx) = [];

% remove channel labels that are not present in the data
chanindx = match_str(channel, datachannel);
channel  = channel(chanindx);

if findgui
  indx = select_channel_list(datachannel, match_str(datachannel, channel), 'Select channels');
  channel = datachannel(indx);
end

% remove channels that occur more than once, this sorts the channels alphabetically
channel = unique(channel);

if isempty(channel) && ~recursion
  % try whether only lowercase channel labels makes a difference
  recursion = true;
  channel   = ft_channelselection(desired, lower(datachannel));
  recursion = false;
  % undo the conversion to lowercase, this sorts the channels alphabetically
  [c, ia, ib] = intersect(channel, lower(datachannel));
  channel = datachannel(ib);
end

if isempty(channel) && ~recursion
  % try whether only uppercase channel labels makes a difference
  recursion = true;
  channel = ft_channelselection(desired, upper(datachannel));
  recursion = false;
  % undo the conversion to uppercase, this sorts the channels alphabetically
  [c, ia, ib] = intersect(channel, lower(datachannel));
  channel = datachannel(ib);
end

% undo the sorting, make the order identical to that of the data channels
[tmp, indx] = match_str(datachannel, channel);
channel = channel(indx);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% helper function
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function match = myregexp(pat, list)
match = false(size(list));
for i=1:numel(list)
  match(i) = ~isempty(regexp(list{i}, pat, 'once'));
end


%ISOLATE_AXES Isolate the specified axes in a figure on their own
%
% Examples:
%   fh = isolate_axes(ah)
%   fh = isolate_axes(ah, vis)
%
% This function will create a new figure containing the axes specified, and
% also their associated legends and colorbars. The axes specified must all
% be in the same figure, but they will generally only be a subset of the
% axes in the figure.
%
% IN:
%    ah - An array of axes handles, which must come from the same figure.
%    vis - A boolean indicating whether the new figure should be visible.
%          Default: false.
%
% OUT:
%    fh - The handle of the created figure.

% Copyright (C) Oliver Woodford 2011

% Thank you to Rosella Blatt for reporting a bug to do with axes in GUIs

function fh = isolate_axes(ah, vis)
% Make sure we have an array of handles
if ~all(ishandle(ah))
    error('ah must be an array of handles');
end
% Check that the handles are all for axes, and are all in the same figure
fh = ancestor(ah(1), 'figure');
nAx = numel(ah);
for a = 1:nAx
    if ~strcmp(get(ah(a), 'Type'), 'axes')
        error('All handles must be axes handles.');
    end
    if ~isequal(ancestor(ah(a), 'figure'), fh)
        error('Axes must all come from the same figure.');
    end
end
% Tag the axes so we can find them in the copy
old_tag = get(ah, 'Tag');
if nAx == 1
    old_tag = {old_tag};
end
set(ah, 'Tag', 'ObjectToCopy');
% Create a new figure exactly the same as the old one
fh = copyfig(fh); %copyobj(fh, 0);
if nargin < 2 || ~vis
    set(fh, 'Visible', 'off');
end
% Reset the axes tags
for a = 1:nAx
    set(ah(a), 'Tag', old_tag{a});
end
% Find the objects to save
ah = findall(fh, 'Tag', 'ObjectToCopy');
if numel(ah) ~= nAx
    close(fh);
    error('Incorrect number of axes found.');
end
% Set the axes tags to what they should be
for a = 1:nAx
    set(ah(a), 'Tag', old_tag{a});
end
% Keep any legends and colorbars which overlap the subplots
lh = findall(fh, 'Type', 'axes', '-and', {'Tag', 'legend', '-or', 'Tag', 'Colorbar'});
nLeg = numel(lh);
if nLeg > 0
    ax_pos = get(ah, 'OuterPosition');
    if nAx > 1
        ax_pos = cell2mat(ax_pos(:));
    end
    ax_pos(:,3:4) = ax_pos(:,3:4) + ax_pos(:,1:2);
    leg_pos = get(lh, 'OuterPosition');
    if nLeg > 1;
        leg_pos = cell2mat(leg_pos);
    end
    leg_pos(:,3:4) = leg_pos(:,3:4) + leg_pos(:,1:2);
    for a = 1:nAx
            % Overlap test
            ah = [ah; lh(leg_pos(:,1) < ax_pos(a,3) & leg_pos(:,2) < ax_pos(a,4) &...
                         leg_pos(:,3) > ax_pos(a,1) & leg_pos(:,4) > ax_pos(a,2))];
    end
end
% Get all the objects in the figure
axs = findall(fh);
% Delete everything except for the input axes and associated items
delete(axs(~ismember(axs, [ah; allchildren(ah); allancestors(ah)])));
return

function ah = allchildren(ah)
ah = allchild(ah);
if iscell(ah)
    ah = cell2mat(ah);
end
ah = ah(:);
return

function ph = allancestors(ah)
ph = [];
for a = 1:numel(ah)
    h = get(ah(a), 'parent');
    while h ~= 0
        ph = [ph; h];
        h = get(h, 'parent');
    end
end
return

function fh = copyfig(fh)
% Is there a legend?
if isempty(findobj(fh, 'Type', 'axes', 'Tag', 'legend'))
    % Safe to copy using copyobj
    fh = copyobj(fh, 0);
else
    % copyobj will change the figure, so save and then load it instead
    tmp_nam = [tempname '.fig'];
    hgsave(fh, tmp_nam);
    fh = hgload(tmp_nam);
    delete(tmp_nam);
end
return