% std_readersp() - load ERSP measures for data channels or  for all
%                  components of a specified cluster. This function is
%                  also being used to read ITC and ERPimage data.
% Usage:
%   >> [STUDY, erspdata, times, freqs, erspbase] = ...
%                   std_readersp(STUDY, ALLEEG, varargin);
% Inputs:
%       STUDY - studyset structure containing some or all files in ALLEEG
%      ALLEEG - vector of loaded EEG datasets
%
% Optional inputs:
%  'design'    - [integer] read files from a specific STUDY design. Default
%                is empty (use current design in STUDY.currentdesign).
%  'channels'  - [cell] list of channels to import {default: none}
%  'clusters'  - [integer] list of clusters to import {[]|default: all but
%                the parent cluster (1) and any 'NotClust' clusters}
%  'singletrials' - ['on'|'off'] load single trials spectral data (if
%                available). Default is 'off'.
%  'forceread' - ['on'|'off'] Force rereading data from disk.
%                Default is 'off'.
%  'subject'   - [string] select a specific subject {default:all}
%  'component' - [integer] select a specific component in a cluster
%                 {default:all}
%  'datatype'  - {'ersp'|'itc'|'erpim'} This function is used to read all
%                2-D STUDY matrices stored on disk (not only ERSP). It may
%                read ERSP ('ersp' option), ITC ('itc' option) or ERPimage
%                data ('erpim' option).
%
% ERSP specific options:
%  'timerange' - [min max] time range {default: whole measure range}
%  'freqrange' - [min max] frequency range {default: whole measure range}
%  'subbaseline' - ['on'|'off'] subtract the ERSP baseline for paired
%                conditions. The conditions for which baseline is removed
%                are indicated on the command line. See help
%                std_studydesign for more information about paired and
%                unpaired variables.
%
% ERPimage specific option:
%   This function is used to read all 2-D STUDY matrices stored on disk
%   (this includes ERPimages). It therefore takes as input specific
%   ERPimage options. Note that the 'singletrials' optional input is
%   irrelevant for ERPimages (which are always stored as single trials).
%   'concatenate' - ['on'|'off'] read concatenated ERPimage data ('on') or
%                   stacked ERPimage data. See help std_erpimage for more
%                   information.
%   'timerange'   - [min max] time range {default: whole measure range}
%   'trialrange'  - [min max] read only a specific range of the ERPimage
%                   output trials {default: whole measure range}
% Output:
%  STUDY    - updated studyset structure
%  erspdata - [cell array] ERSP data (the cell array size is
%             condition x groups). This may also be ITC data or ERPimage
%             data (see above).
%  times    - [float array] array of time points
%  freqs    - [float array] array of frequencies. For ERPimage this
%             contains trial indices.
%  erspbase - [cell array] baseline values
%  events   - [cell array] events (ERPimage only).
%
% Author: Arnaud Delorme, CERCO, 2006-

% Copyright (C) Arnaud Delorme, 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 [STUDY, erspdata, alltimes, allfreqs, erspbase, events, unitPower] = std_readersp(STUDY, ALLEEG, varargin)

if nargin < 2
    help std_readersp;
    return;
end
events = {};
unitPower = 'dB';
if ~isstruct(ALLEEG) % old calling format
    dataset = ALLEEG;
    EEG = STUDY(dataset);
    comp = varargin{1};
    if length(varargin) > 1, timelim = varargin{2}; else timelim = []; end;
    if length(varargin) > 2, freqlim = varargin{3}; else freqlim = []; end;
    filebase = fullfile(EEG.filepath, EEG.filename(1:end-4));
    if comp < 0
        error('Old format function call, channel reading not supported');
        [ersp params alltimes allfreqs] = std_readfile(filebase, 'channels', -comp, 'timelimits', timelim, 'freqlimits', freqlim);
    else
        [ersp     params alltimes allfreqs] = std_readfile(filebase, 'components', comp, 'timelimits', timelim, 'freqlimits', freqlim, 'measure', 'ersp');
        [erspbase params alltimes allfreqs] = std_readfile(filebase, 'components', comp, 'timelimits', timelim, 'freqlimits', freqlim, 'measure', 'erspbase');
    end;
    STUDY = ersp;
    erspdata = allfreqs;
    allfreqs = params;
    return;
end;

STUDY = pop_erspparams( STUDY, 'default');
STUDY = pop_erpimparams(STUDY, 'default');
[opt moreopts] = finputcheck( varargin, { ...
    'design'        'integer' []             STUDY.currentdesign;
    'channels'      'cell'    []             {};
    'clusters'      'integer' []             [];
    'trialrange'    'real'    []             STUDY.etc.erpimparams.trialrange;
    'freqrange'     'real'    []             STUDY.etc.erspparams.freqrange;
    'timerange'     'real'    []             NaN;
    'singletrials'  'string'  { 'on','off' } 'off';
    'forceread'     'string'  { 'on','off' } 'off';
    'concatenate'   'string'  { 'on','off' } STUDY.etc.erpimparams.concatenate;
    'subbaseline'   'string'  { 'on','off' } STUDY.etc.erspparams.subbaseline;
    'component'     'integer' []             [];
    'infotype'      'string'  { 'ersp','itc','erpim' } 'ersp'; ... % deprecated
    'datatype'      'string'  { 'ersp','itc','erpim' } 'ersp'; ...
    'subject'       'string'  []             '' }, ...
    'std_readersp', 'ignore');
if isstr(opt), error(opt); end;
if ~strcmpi(opt.infotype, 'ersp'), opt.datatype = opt.infotype; end;
if strcmpi(opt.datatype, 'erpim'), if isnan(opt.timerange), opt.timerange = STUDY.etc.erpimparams.timerange; end;
                                   opt.freqrange = opt.trialrange;
                                   ordinate      = 'trials';
else                               if isnan(opt.timerange) opt.timerange = STUDY.etc.erspparams.timerange; end;
                                   ordinate      = 'freqs';
end;
nc = max(length(STUDY.design(opt.design).variable(1).value),1);
ng = max(length(STUDY.design(opt.design).variable(2).value),1);
paired1 = STUDY.design(opt.design).variable(1).pairing;
paired2 = STUDY.design(opt.design).variable(2).pairing;

dtype = opt.datatype;

% find channel indices
% --------------------
if ~isempty(opt.channels)
     allChangrp = lower({ STUDY.changrp.name });
     finalinds = std_chaninds(STUDY, opt.channels);
else finalinds = opt.clusters;
end;

for ind = 1:length(finalinds)
    erspbase = cell( nc, ng );

    % find indices
    % ------------
    if ~isempty(opt.channels)
        tmpstruct = STUDY.changrp(finalinds(ind));
        allinds       = tmpstruct.allinds;
        setinds       = tmpstruct.setinds;
    else
        tmpstruct = STUDY.cluster(finalinds(ind));
        allinds       = tmpstruct.allinds;
        setinds       = tmpstruct.setinds;
    end;

    % check if data is already here
    % -----------------------------
    if strcmpi(dtype, 'erpim') % ERP images
        dataread = 0;
        eqtf  = isequal( STUDY.etc.erpimparams.timerange , opt.timerange) && ...
                isequal( STUDY.etc.erpimparams.trialrange, opt.trialrange);
        if isfield(tmpstruct, 'erpimdata') && eqtf && ~isempty(tmpstruct.erpimdata)
            dataread = 1;
        end;
    else
        dataread = 0;
        eqtf  = isequal( STUDY.etc.erspparams.timerange, opt.timerange) && ...
                isequal( STUDY.etc.erspparams.freqrange, opt.freqrange);
        eqtfb = isequal( STUDY.etc.erspparams.subbaseline, opt.subbaseline) && eqtf;
        if strcmpi(opt.singletrials,'off')
            if isfield(tmpstruct, [ dtype 'data']) && eqtfb && ~isempty(getfield(tmpstruct, [ dtype 'data']))
                dataread = 1;
            end;
        else
            if isfield(tmpstruct, [ dtype 'datatrials']) && eqtf && ~isempty(getfield(tmpstruct, [ dtype 'datatrials']))
                if ~isempty(opt.channels) && strcmpi(getfield(tmpstruct, [ dtype 'trialinfo' ]), opt.subject)
                    dataread = 1;
                elseif isempty(opt.channels) && isequal(getfield(tmpstruct, [ dtype 'trialinfo' ]), opt.component)
                    dataread = 1;
                end;
            end;
        end;
    end;

    if dataread && strcmpi(opt.forceread, 'off')
        disp('Using pre-loaded data. To force rereading data from disk use the ''forceread'' flag');
    else

        if strcmpi(dtype, 'erpim') % ERP images

            if strcmpi(opt.singletrials, 'on')
                error( [ 'Single trial loading option not supported with STUDY ERP-image' 10 '(there is no such thing as a single-trial ERPimage)' ]);
            end;
            % read the data and select channels
            % ---------------------------------
            setinfo = STUDY.design(opt.design).cell;
            erpim    = cell( nc, ng );
            events   = cell( nc, ng );
            for c = 1:nc
                for g = 1:ng
                    if ~isempty(setinds{c,g})
                        if ~isempty(opt.channels), opts = { 'channels',    allChangrp(allinds{c,g}(:)), 'timelimits', opt.timerange, 'triallimits', opt.trialrange, 'concatenate', opt.concatenate };
                        else                       opts = { 'components',  allinds{c,g}(:), 'timelimits', opt.timerange, 'triallimits', opt.trialrange, 'concatenate', opt.concatenate };
                        end;
                        [erpim{c, g} tmpparams alltimes alltrials events{c,g}] = std_readfile( setinfo(setinds{c,g}(:)), 'measure', 'erpim', opts{:});
                        fprintf('.');
                    end;
                end;
            end;
            if strcmpi(opt.concatenate, 'on'), alltrials = []; end;
            fprintf('\n');
            ersp     = erpim;
            allfreqs = alltrials;

        else % ERSP/ITC

            % reserve arrays
            % --------------
            events   = {};
            ersp     = cell( nc, ng );
            erspinds = cell( nc, ng );

            % find total nb of trials
            % THIS CODE IS NOT NECESSARY ANY MORE (SEE BUG 1170)
            % -----------------------
            %setinfo = STUDY.design(opt.design).cell;
            %tottrials = cell( nc, ng );
            %if strcmpi(opt.singletrials, 'on')
            %    for indSet = 1:length(setinfo)
            %        condind = std_indvarmatch( setinfo(indSet).value{1}, STUDY.design(opt.design).variable(1).value );
            %        grpind  = std_indvarmatch( setinfo(indSet).value{2}, STUDY.design(opt.design).variable(2).value );
            %        if isempty(tottrials{condind, grpind}), tottrials{condind, grpind} = sum(cellfun(@length, setinfo(indSet).trials));
            %        else       tottrials{condind, grpind} = tottrials{condind, grpind} + sum(cellfun(@length, setinfo(indSet).trials));
            %        end;
            %    end;
            %end;

            % read the data and select channels
            % ---------------------------------
            fprintf('Reading all %s data:', upper(dtype));
            setinfo = STUDY.design(opt.design).cell;
            if strcmpi(opt.singletrials, 'on')
                for c = 1:nc
                    for g = 1:ng
                        if ~isempty(opt.channels)
                            allsubjects = { STUDY.design(opt.design).cell.case };
                            if ~isempty(opt.subject), inds = strmatch( opt.subject, allsubjects(setinds{c,g}));
                            else inds = 1:length(allinds{c,g}); end;
                        else
                            if ~isempty(opt.component) inds = find( allinds{c,g} == STUDY.cluster(finalinds(ind)).comps(opt.component));
                            else inds = 1:length(allinds{c,g}); end;
                        end;
                        if ~isempty(inds)
                            count{c, g} = 1;
                            for indtmp = 1:length(inds)
                                setindtmp = STUDY.design(opt.design).cell(setinds{c,g}(inds(indtmp)));
                                tmpopts = { 'measure', 'timef' 'timelimits', opt.timerange, 'freqlimits', opt.freqrange };
                                if ~isempty(opt.channels), [ tmpersp tmpparams alltimes allfreqs] = std_readfile(setindtmp, 'channels', allChangrp(allinds{c,g}(inds(indtmp))), tmpopts{:});
                                else                       [ tmpersp tmpparams alltimes allfreqs] = std_readfile(setindtmp, 'components',          allinds{c,g}(inds(indtmp)),  tmpopts{:});
                                end;
                                indices = [count{c, g}:count{c, g}+size(tmpersp,3)-1];
                                if indtmp == 1
                                    ersp{c, g} = permute(tmpersp, [2 1 3]);
                                else ersp{c, g}(:,:,indices) = permute(tmpersp, [2 1 3]);
                                end;
                                erspinds{c, g}(1:2,indtmp) = [ count{c, g} count{c, g}+size(tmpersp,3)-1 ];
                                count{c, g} = count{c, g}+size(tmpersp,3);
                                if size(tmpersp,3) ~= sum(cellfun(@length, setindtmp.trials))
                                    error( sprintf('Wrong number of trials in datafile for design index %d\n', setinds{c,g}(inds(indtmp))));
                                end;
                            end;
                        end;
                    end;
                end;
            else
                for c = 1:nc
                    for g = 1:ng
                        if ~isempty(setinds{c,g})
                            if ~isempty(opt.channels), opts = { 'channels',  allChangrp(allinds{c,g}(:)), 'timelimits', opt.timerange, 'freqlimits', opt.freqrange };
                            else                       opts = { 'components',           allinds{c,g}(:) , 'timelimits', opt.timerange, 'freqlimits', opt.freqrange };
                            end;
                            if strcmpi(dtype, 'ersp')
                                 erspbase{c, g}                             = std_readfile( setinfo(setinds{c,g}(:)), 'measure', 'erspbase', opts{:});
                                 [ ersp{c, g} tmpparams alltimes allfreqs ] = std_readfile( setinfo(setinds{c,g}(:)), 'measure', 'ersp'    , opts{:});
                            else [ ersp{c, g} tmpparams alltimes allfreqs ] = std_readfile( setinfo(setinds{c,g}(:)), 'measure', 'itc'     , opts{:});
                                 ersp{c, g} = ersp{c, g};
                            end;
                            fprintf('.');
                            %ersp{c, g}      = permute(ersp{c, g}           , [3 2 1]);
                            %erspbase{c, g}  = 10*log(permute(erspbase{c, g}, [3 2 1]));
                        end;
                    end;
                end;
            end;
            fprintf('\n');

            % compute ERSP or ITC if trial mode
            % (since only the timef have been loaded)
            % ---------------------------------------
            if strcmpi(opt.singletrials, 'on')
                tmpparams2      = fieldnames(tmpparams); tmpparams2 = tmpparams2';
                tmpparams2(2,:) = struct2cell(tmpparams);
                precomp.times = alltimes;
                precomp.freqs = allfreqs;
                precomp.recompute = dtype;
                for c = 1:nc
                    for g = 1:ng
                        if ~isempty(ersp{c,g})
                            precomp.tfdata = permute(ersp{c,g}, [2 1 3]);
                            if strcmpi(dtype, 'itc')
                                [tmp ersp{c,g}] = newtimef(zeros(ALLEEG(1).pnts,2), ALLEEG(1).pnts, [ALLEEG(1).xmin ALLEEG(1).xmax]*1000, ...
                                    ALLEEG(1).srate, [], tmpparams2{:}, 'precomputed', precomp, 'verbose', 'off');
                            elseif strcmpi(dtype, 'ersp')
                                [ersp{c,g} tmp] = newtimef(zeros(ALLEEG(1).pnts,2), ALLEEG(1).pnts, [ALLEEG(1).xmin ALLEEG(1).xmax]*1000, ...
                                    ALLEEG(1).srate, [], tmpparams2{:}, 'precomputed', precomp, 'verbose', 'off');
                            end;
                            ersp{c,g} = permute(ersp{c,g}, [2 1 3]);
                        end;
                    end;
                end;
            end;

            % compute average baseline across groups and conditions
            % -----------------------------------------------------
            if strcmpi(opt.subbaseline, 'on') && strcmpi(dtype, 'ersp')
                if strcmpi(opt.singletrials, 'on')
                    disp('WARNING: no ERSP baseline may not be subtracted when using single trials');
                else
                    disp('Recomputing baseline...');
                    if strcmpi(paired1, 'on') && strcmpi(paired2, 'on')
                        disp('Removing ERSP baseline for both indep. variables');
                        meanpowbase = computeerspbaseline(erspbase(:), opt.singletrials);
                        ersp        = removeerspbaseline(ersp, erspbase, meanpowbase);
                    elseif strcmpi(paired1, 'on')
                        disp('Removing ERSP baseline for first indep. variables (second indep. var. is unpaired)');
                        for g = 1:ng        % ng = number of groups
                            meanpowbase = computeerspbaseline(erspbase(:,g), opt.singletrials);
                            ersp(:,g)   = removeerspbaseline(ersp(:,g), erspbase(:,g), meanpowbase);
                        end;
                    elseif strcmpi(paired2, 'on')
                        disp('Removing ERSP baseline for second indep. variables (first indep. var. is unpaired)');
                        for c = 1:nc        % ng = number of groups
                            meanpowbase = computeerspbaseline(erspbase(c,:), opt.singletrials);
                            ersp(c,:)   = removeerspbaseline(ersp(c,:), erspbase(c,:), meanpowbase);
                        end;
                    else
                        disp('Not removing ERSP baseline (both indep. variables are unpaired');
                    end;
                end;
            end;
        end;

%         if strcmpi(opt.statmode, 'common')
%             % collapse the two last dimensions before computing significance
%             % i.e. 18 subject with 4 channels -> same as 4*18 subjects
%             % --------------------------------------------------------------
%             disp('Using all channels for statistics...');
%             for c = 1:nc
%                 for g = 1:ng
%                     ersp{c,g} = reshape( ersp{c,g}, size(ersp{c,g},1), size(ersp{c,g},2), size(ersp{c,g},3)*size(ersp{c,g},4));
%                 end;
%             end;
%         end;

        % copy data to structure
        % ----------------------
        if ~isempty(events)
            tmpstruct = setfield(tmpstruct, [ dtype 'events' ], events);
        end;
        tmpstruct = setfield(tmpstruct, [ dtype ordinate ], allfreqs);
        tmpstruct = setfield(tmpstruct, [ dtype 'times'  ], alltimes);
        if strcmpi(opt.singletrials, 'on')
            tmpstruct = setfield(tmpstruct, [ dtype 'datatrials' ], ersp);
            tmpstruct = setfield(tmpstruct, [ dtype 'subjinds' ], erspinds);
            tmpstruct = setfield(tmpstruct, [ dtype 'times' ], alltimes);
            if ~isempty(opt.channels)
                 tmpstruct = setfield(tmpstruct, [ dtype 'trialinfo' ], opt.subject);
            else tmpstruct = setfield(tmpstruct, [ dtype 'trialinfo' ], opt.component);
            end;
        else
            tmpstruct = setfield(tmpstruct, [ dtype 'data' ], ersp);
            if strcmpi(dtype, 'ersp')
                tmpstruct = setfield(tmpstruct, [ dtype 'base' ], erspbase);
            end;
        end;

        % copy results to structure
        % -------------------------
        fields = { [ dtype 'data'     ] [ dtype 'events' ] [ dtype ordinate ] [ dtype 'datatrials' ] ...
                   [ dtype 'subjinds' ] [ dtype 'base'   ] [ dtype 'times'  ] [ dtype 'trialinfo'  ]  'allinds' 'setinds' };
        for f = 1:length(fields)
            if isfield(tmpstruct, fields{f}),
                tmpdata = getfield(tmpstruct, fields{f});
                if ~isempty(opt.channels)
                     STUDY.changrp = setfield(STUDY.changrp, { finalinds(ind) }, fields{f}, tmpdata);
                else STUDY.cluster = setfield(STUDY.cluster, { finalinds(ind) }, fields{f}, tmpdata);
                end;
            end;
        end;
    end;
end;

% output units
% -----------
if exist('tmpparams') ~= 1
    tmpparams = []; ctmp = 1;
    while isempty(tmpparams) && ctmp <= length(STUDY.design(opt.design).cell)
        try
            if ~isempty(opt.channels), [tmpersp tmpparams] = std_readfile(STUDY.design(opt.design).cell(ctmp), 'channels', {STUDY.changrp(1).name}, 'measure', opt.datatype);
            else                       [tmpersp tmpparams] = std_readfile(STUDY.design(opt.design).cell(ctmp), 'components', STUDY.cluster(finalinds(end)).allinds{1,1}(1), 'measure', opt.datatype);
            end;
        catch
        end
        ctmp = ctmp + 1;
    end
end;
if ~isfield(tmpparams, 'baseline'), tmpparams.baseline = 0;     end;
if ~isfield(tmpparams, 'scale'   ), tmpparams.scale    = 'log'; end;
if ~isfield(tmpparams, 'basenorm'), tmpparams.basenorm = 'off'; end;
if strcmpi(tmpparams.scale, 'log')
    if strcmpi(tmpparams.basenorm, 'on')
        unitPower = '10*log(std.)'; % impossible
    elseif isnan(tmpparams.baseline)
        unitPower = '10*log10(\muV^{2}/Hz)';
    else
        unitPower = 'dB';
    end;
else
    if strcmpi(tmpparams.basenorm, 'on')
        unitPower = 'std.';
    elseif isnan(tmpparams.baseline)
        unitPower = '\muV^{2}/Hz';
    else
        unitPower = '% of baseline';
    end;
end;

% return structure
% ----------------
if nargout <2
    return
end
allinds   = finalinds;
if ~isempty(opt.channels)
    structdat = STUDY.changrp;
    erspdata  = cell(nc, ng);
    events    = {};
    for ind =  1:length(erspdata(:))
        if strcmpi(opt.singletrials, 'on')
             tmpdat = getfield(structdat(allinds(1)), [ dtype 'datatrials' ]);
        else tmpdat = getfield(structdat(allinds(1)), [ dtype 'data' ]);
        end;
        if ndims(tmpdat{ind}) == 2, erspdata{ind} = zeros([ size(tmpdat{ind}) 1 length(allinds)]);
        else                        erspdata{ind} = zeros([ size(tmpdat{ind}) length(allinds)]);
        end;
        for index = 1:length(allinds)
            if strcmpi(opt.singletrials, 'on')
                 tmpdat = getfield(structdat(allinds(index)), [ dtype 'datatrials' ]);
            else tmpdat = getfield(structdat(allinds(index)), [ dtype 'data' ]);
            end;
            erspdata{ind}(:,:,:,index) = tmpdat{ind};
            allfreqs = getfield(structdat(allinds(index)), [ dtype ordinate ]);
            alltimes = getfield(structdat(allinds(index)), [ dtype 'times'  ]);
            if isfield(structdat, [ dtype 'events' ])
                events   = getfield(structdat(allinds(index)), [ dtype 'events' ]);
            end;
            compinds = structdat(allinds(index)).allinds;
            setinds  = structdat(allinds(index)).setinds;
        end;
        erspdata{ind} = permute(erspdata{ind}, [1 2 4 3]); % time freqs elec subjects
    end;
    if ~isempty(opt.subject) && strcmpi(opt.singletrials,'off')
        erspdata = std_selsubject(erspdata, opt.subject, setinds, { STUDY.design(opt.design).cell.case }, 2);
    end;
else
    if strcmpi(opt.singletrials, 'on')
         erspdata = getfield(STUDY.cluster(allinds(1)), [ dtype 'datatrials' ]);
    else erspdata = getfield(STUDY.cluster(allinds(1)), [ dtype 'data' ]);
    end;
    allfreqs = getfield(STUDY.cluster(allinds(1)), [ dtype ordinate ]);
    alltimes = getfield(STUDY.cluster(allinds(1)), [ dtype 'times'  ]);
    if isfield(STUDY.cluster, [ dtype 'events' ])
        events   = getfield(STUDY.cluster(allinds(1)), [ dtype 'events' ]);
    end;
    compinds = STUDY.cluster(allinds(1)).allinds;
    setinds  = STUDY.cluster(allinds(1)).setinds;
    if ~isempty(opt.component) && length(allinds) == 1 && strcmpi(opt.singletrials,'off')
        erspdata = std_selcomp(STUDY, erspdata, allinds, setinds, compinds, opt.component);
    end;
end;

% compute ERSP baseline
% ---------------------
function meanpowbase = computeerspbaseline(erspbase, singletrials)

    try
        len = length(erspbase(:));
        count = 0;
        for index = 1:len
            if ~isempty(erspbase{index})
                if strcmpi(singletrials, 'on')
                    if count == 0, meanpowbase = mean(erspbase{index},3);
                    else           meanpowbase = meanpowbase + mean(erspbase{index},3);
                    end;
                else
                    if count == 0, meanpowbase = erspbase{index};
                    else           meanpowbase = meanpowbase + erspbase{index};
                    end;
                end;
                count = count+1;
            end;
        end;
        meanpowbase = reshape(meanpowbase  , [size(meanpowbase,1) 1 size(meanpowbase,2)])/count;
    catch,
        error([ 'Problem while subtracting common ERSP baseline.' 10 ...
                'Common baseline subtraction is performed based on' 10 ...
                'pairing settings in your design. Most likelly, one' 10 ...
                'independent variable should not have its data paired.' ]);
    end;

% remove ERSP baseline
% ---------------------
function ersp = removeerspbaseline(ersp, erspbase, meanpowbase)
    convert2log = 0;
    for g = 1:size(ersp,2)        % ng = number of groups
        for c = 1:size(ersp,1)
            if ~isempty(erspbase{c,g}) && ~isempty(ersp{c,g})
                erspbasetmp = reshape(erspbase{c,g}, [size(meanpowbase,1) 1 size(meanpowbase,3)]);
                if any(erspbasetmp(:) > 1000)
                    convert2log = 1;
                end;
                tmpmeanpowbase = repmat(meanpowbase, [1 size(ersp{c,g},2) 1]);
                if convert2log
                     ersp{c,g} = ersp{c,g} - repmat(10*log10(erspbasetmp), [1 size(ersp{c,g},2) 1 1]) + 10*log10(tmpmeanpowbase);
                else ersp{c,g} = ersp{c,g} - repmat(erspbasetmp, [1 size(ersp{c,g},2) 1 1]) + tmpmeanpowbase;
                end;
            end;
        end;
    end;


function [Operations,MasterOperations] = TS_LinkOperationsWithMasters(Operations,MasterOperations)
% TS_LinkOperationsWithMasters    Link Operations with MasterOperations using Label field

% ------------------------------------------------------------------------------
% Copyright (C) 2020, Ben D. Fulcher <ben.d.fulcher@gmail.com>,
% <http://www.benfulcher.com>
%
% If you use this code for your research, please cite the following two papers:
%
% (1) B.D. Fulcher and N.S. Jones, "hctsa: A Computational Framework for Automated
% Time-Series Phenotyping Using Massive Feature Extraction, Cell Systems 5: 527 (2017).
% DOI: 10.1016/j.cels.2017.10.001
%
% (2) B.D. Fulcher, M.A. Little, N.S. Jones, "Highly comparative time-series
% analysis: the empirical structure of time series and their methods",
% J. Roy. Soc. Interface 10(83) 20130048 (2013).
% DOI: 10.1098/rsif.2013.0048
%
% This work is licensed under the Creative Commons
% Attribution-NonCommercial-ShareAlike 4.0 International License. To view a copy of
% this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/ or send
% a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View,
% California, 94041, USA.
% ------------------------------------------------------------------------------

numOps = height(Operations);
numMops = height(MasterOperations);

% ------------------------------------------------------------------------------
% Match operations to a master ID
% ------------------------------------------------------------------------------
for i = 1:numOps
    theMasterMatch = strcmp(Operations.Label{i},MasterOperations.Label);
    if sum(theMasterMatch)==0
        error('No master match for operation: %s',Operations.Name{i});
    end
    Operations.MasterID(i) = MasterOperations.ID(theMasterMatch);
end

% No longer need the label field from the Operations table
Operations(:,'Label') = [];

%-------------------------------------------------------------------------------
% Check that all master operations are required
%-------------------------------------------------------------------------------
mastersNeeded = ismember(MasterOperations.ID,Operations.MasterID);
if ~all(mastersNeeded)
    warning(['%u/%u master operations are not used by the %u operations' ...
                         ' and will be removed.'],...
                        sum(~mastersNeeded),numMops,numOps);
    MasterOperations = MasterOperations(mastersNeeded,:);
end

end


function [xsens , xsens_fields ] = xsens_read(file, row_lines, columns)
% xsens_read: reads .cvs files created by Xsens software.
%
% INPUT
%   fname: .cvs file name (string).
%   row_lines: number of rows in file.
%   columns: maximum column to be read.
%
% OUTPUT
%   xsens: data structure where each field is a column found in the file.
%   xsens_fields: cell vector with the names of each field found in the file.
%
%   Copyright (C) 2014, Rodrigo Gonzalez, all rights reserved.
%
%   This file is part of NaveGo, an open-source MATLAB toolbox for
%   simulation of integrated navigation systems.
%
%   NaveGo is free software: you can redistribute it and/or modify
%   it under the terms of the GNU Lesser General Public License (LGPL)
%   version 3 as published by the Free Software Foundation.
%
%   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 Lesser General Public License for more details.
%
%   You should have received a copy of the GNU Lesser General Public
%   License along with this program. If not, see
%   <http://www.gnu.org/licenses/>.
%
% Reference:
%
%
% Version: 002
% Date:    2020/10/30
% Author:  Rodrigo Gonzalez <rodralez@frm.utn.edu.ar>
% URL:     https://github.com/rodralez/navego

disp('xsens_read: processing data...')

%% OPEN FILE

xsens_f = fopen(file, 'r');
if xsens_f == -1
    error('xsens_read: ERROR: %s not found', file)
else
    fprintf('xsens_read: Loading %s...\n', file)
end

fprintf('xsens_read: %s has %d lines.\n', file, row_lines)

%% HEADER

header_rows = 13;

xsens_header = cell(header_rows,1);
for a = 1:header_rows
    xsens_header{a,1} = fgets(xsens_f);
end

%% FIELDS

xsens_line = fgets(xsens_f);
xsens_line = strrep(xsens_line,'[','_');    % Chance '[' for '_'
xsens_line = strrep(xsens_line,']','');     % Delete ']'

xsens_fields = textscan(xsens_line, '%s', 'Delimiter', ',' , 'EmptyValue', 0);

xsens_fields = xsens_fields{1};
xsens_fields(83) = {'GNSSLongitude'};
xsens_fields(84) = {'GNSSLatitude'};

[N,~] = size (xsens_fields);

fprintf('xsens_read: %s has %d columns.\n', file, N);

fprintf('xsens_read: only %d columns will be processed.\n', columns);

%% GET DATA

% Set pointer back to the beginning of file
% fseek(xsens_f,0,'bof');

% Pattern for textscan()
formatSpec = repmat('%f ', 1, N);

% Correction of numbers of rows
row_lines = row_lines - header_rows;

% Preallocation
xsens_imu = zeros(row_lines, columns);
xsens_gnss = zeros(floor(row_lines/2), columns);
xsens_ahrs = zeros(floor(row_lines/2), columns);
xsens_mag = zeros(floor(row_lines/2), columns);
xsens_att = zeros(floor(row_lines/2), columns);
xsens_baro = zeros(floor(row_lines/2), columns);

% Index for data allocation inside the while loop.
a = 1;  % index for reading IMU data
% b
c = 1;  % index for reading GNSS data
% d
e = 1;  % index for reading MAG data
% f
g = 1;  % index for reading AHRS data
% h
i = 1;  % index for reading ATTITUDE data
% j
k = 1;  % index for reading BARO data
% l

rows_block = 75000;		% Default vauel for rows_block

if rows_block > row_lines
    rows_block = floor(row_lines / 5);
end

fprintf('xsens_read: processing %s...\n', file)

loop_line = 1;
loop_ctr = 0;

while ~feof(xsens_f)

    fprintf('xsens_read: processing line %d...\n',  loop_line)
    loop_ctr = loop_ctr + 1;
    loop_line = loop_ctr * rows_block;

    data_c = textscan(xsens_f, formatSpec, rows_block, 'Delimiter',',');
    data = cell2mat(data_c(1:columns));

    % Delete rows where date is NaN for IMU data
    idl = ~isnan(data(: , 18));     % Column 18 is Acc_X
    data_imu = data(idl , :);

    % Delete rows where the difference between two adjacent times is negative
    idl = diff(data_imu(: , 2)) > 0;
    idl = [true; idl];
    data_imu = data_imu(idl , :);

    % Delete rows where date is NaN for GNSS data
    idl = ~isnan(data(: , 70));     % Column 70 is NUTimeOfWeek
    data_gnss = data(idl , :);

    % Delete rows where date is NaN for MAG data
    idl = ~isnan(data(: , 33));     % Column 33 is Mag_X
    data_mag = data(idl , :);

    % Delete rows where date is NaN for AHRS data
    idl = ~isnan(data(: , 24));     % Column 24 is AccHR_X
    data_ahrs = data(idl , :);

    % Delete rows where date is NaN for ATTITUDE data
    idl = ~isnan(data(: , 44));     % Column 44 is Quat_q0
    data_att = data(idl , :);

    % Delete rows where date is NaN for BARO data
    idl = ~isnan(data(: , 43));     % Column 43 is Pressure
    data_baro = data(idl , :);

    [M, ~] = size( data_imu );
    b = a + M - 1;
    xsens_imu(a:b , :) = data_imu;
    a = b + 1;

    [M, ~] = size( data_gnss );
    d = c + M - 1;
    xsens_gnss(c:d , :) = data_gnss;
    c = d + 1;

    [M, ~] = size( data_mag );
    f = e + M - 1;
    xsens_mag(e:f , :) = data_mag;
    e = f + 1;

    [M, ~] = size( data_ahrs );
    h = g + M - 1;
    xsens_ahrs(g:h , :) = data_ahrs;
    g = h + 1;

    [M, ~] = size( data_att);
    j = i + M - 1;
    xsens_att(i:j , :) = data_att;
    i = j + 1;

    [M, ~] = size( data_baro);
    l = k + M - 1;
    xsens_baro(k:l , :) = data_baro;
    k = l + 1;

    clear data_c data data_vld idl data_imu data_gnss data_mag data_ahrs

end

fclose(xsens_f);

% Delete epmty rows
idl = xsens_imu(: , 1) ~= 0.0 ;
xsens_imu = xsens_imu(idl , :);

idl = xsens_gnss(: , 1) ~= 0.0 ;
xsens_gnss = xsens_gnss(idl , :);

idl = xsens_mag(: , 1) ~= 0.0 ;
xsens_mag = xsens_mag(idl , :);

idl = xsens_ahrs(: , 1) ~= 0.0 ;
xsens_ahrs = xsens_ahrs(idl , :);

idl = xsens_att(: , 1) ~= 0.0 ;
xsens_att = xsens_att(idl , :);

idl = xsens_baro(: , 1) ~= 0.0 ;
xsens_baro = xsens_baro(idl , :);

%% MATRIX TO STRUCTURE

xsens = struct;

% IMU DATA
for a=1:23
    xsens.(xsens_fields{a}) = xsens_imu(:, a);
end

for a=27:29
    xsens.(xsens_fields{a}) = xsens_imu(:, a);
end

for a=36:42
    xsens.(xsens_fields{a}) = xsens_imu(:, a);
end

for a=60:66
    xsens.(xsens_fields{a}) = xsens_imu(:, a);
end

% AHRS DATA
for a=24:26
    xsens.(xsens_fields{a}) = xsens_ahrs(:, a);
end

for a=30:32
    xsens.(xsens_fields{a}) = xsens_ahrs(:, a);
end

% MAG DATA
for a=33:35
    xsens.(xsens_fields{a}) = xsens_mag(:, a);
end

% ATTITUDE DATA
for a=44:59
    xsens.(xsens_fields{a}) = xsens_att(:, a);
end

% BARO DATA
xsens.(xsens_fields{43}) = xsens_baro(:, 43);

% GNSS DATA
for a=70:columns
    xsens.(xsens_fields{a}) = xsens_gnss(:, a);
end

xsens.SampleTimeFine        = xsens_imu(:, 2);
xsens.AHRSSampleTimeFine    = xsens_ahrs(:, 2);
xsens.MagSampleTimeFine     = xsens_mag(:, 2);
xsens.AttitudeSampleTimeFine = xsens_att(:, 2);
xsens.BaroSampleTimeFine    = xsens_baro(:, 2);
xsens.GNSSSampleTimeFine    = xsens_gnss(:, 2);

% FREQUENCIES
dti = median(diff(xsens.SampleTimeFine)) * 10e-5;
xsens.freq_imu = (1/dti);

dta = median(diff(xsens.AHRSSampleTimeFine)) * 10e-5;
xsens.freq_ahrs = (1/dta);

dtm = median(diff(xsens.MagSampleTimeFine)) * 10e-5;
xsens.freq_mag = (1/dtm);

dtt = median(diff(xsens.AttitudeSampleTimeFine)) * 10e-5;
xsens.freq_att = (1/dtt);

dtb = median(diff(xsens.BaroSampleTimeFine)) * 10e-5;
xsens.freq_baro = (1/dtb);

dtg = median(diff(xsens.NUTimeOfWeek)) * 10e-4;
xsens.freq_gnss = (1/dtg);

% Header
xsens.header = xsens_header;

disp('xsens_read: data is ready.')

end


function [all_surf_handles, pcl, ncl] = surface(obj, varargin)
% Render image data on brain surfaces; options for cutaways and canonical surfaces
%
% *Usage:*
%   [all_surf_handles, pcl, ncl] = surface(obj)
%   [all_surf_handles, pcl, ncl] = surface(r, ['cutaways', any optional inputs to surface_cutaway])
%
% This function uses region.surface to create surface figures.
% See help region.surface for options.
%
% :Examples:
% ::
%
%    % Create an initial surface plot from an fmri_data object:
%    han = surface(regionmasks{2});
%
%    % Now add a second region in green:
%    cluster_surf(region(regionmasks{2}), {[0 1 0]}, han, 5);
%
%    % Use optional arguments taken by surface_cutaway:
%    poscm = colormap_tor([1 .3 0], [1 1 0]); % orange to yellow
%    [all_surf_handles, pcl, ncl] = surface(t, 'cutaway', 'ycut_mm', -30, 'pos_colormap', poscm, 'existingfig');
%    [all_surf_handles2, pcl, ncl] = surface(t, 'foursurfaces', 'pos_colormap', poscm, 'neg_colormap', negcm);
%    [all_surf_handles2, pcl, ncl] = surface(t, 'foursurfaces', 'existingfig', 'color_upperboundpercentile', 95, 'color_lowerboundpercentile', 5, 'neg_colormap', colormap_tor([0 0 1], [.3 0 .5]));
%
%    % Use mediation_brain_surface_figs and re-make colors
%    all_surf_handles = mediation_brain_surface_figs([]);
%    surface(t2, 'cutaway', 'surface_handles', all_surf_handles, 'color_upperboundpercentile', 95, 'color_lowerboundpercentile', 5, 'neg_colormap', colormap_tor([0 0 1], [.2 0 .5]));
%

% :Programmers' notes:
% 9-8-2020 fixed weird bug that broke this somehow. Maybe someone deleted a line of code and committed?

if size(obj.dat, 2) > 1
    obj = mean(obj);
end

if isa(obj, 'atlas')

    r = atlas2region(obj, 'noverbose');

else

    r = region(obj, 'noverbose');

end

[all_surf_handles, pcl, ncl] = surface(r, varargin{:});

end

% Unique color option
% % Get unique color indices and expand to 256 colors for render_on_surface
% % expand
%
% obj.dat = double(obj.dat);
%
% len = max(obj.dat);
% rgbcell = scn_standard_colors(len);
%
% newvec = round(linspace(1, len, 256))';
%
% newcolors = rgbcell(newvec);
%
% newcm = cat(1, newcolors{:});
%
% render_on_surface(obj, hh, 'colormap', newcm);
%
% % works, but need to turn off edge effects!


%MAPPING_TASK Find task of actual mapping call
%
%   STATE = MAPPING_TASK(ARGIN,TASK)
%
% INPUT
%   ARGIN   - Arguments of a mapping call
%   TASK    - 'definition','fixed execution','training',
%             'trained execution'
%
% OUTPUT
%   STATE   - TRUE or FALSE
%
% DESCRIPTION
% This routine facilitates the parsing of calls to PRTools mapping
% routines.
%
% SEE ALSO (PRTools Guide)
% DATASETS, MAPPINGS, DEFINE_MAPPING, TRAINED_CLASSIFIER, TRAINED_MAPPING

% Copyright: Robert P.W. Duin, r.p.w.duin@37steps.com

function state = mapping_task(argin,task)

if nargin < 2
  error('No task specified')
end

state = false;
switch lower(task)
  case {'definition'}
    if isempty(argin) || (iscell(argin) && isempty(argin{1}))
      state = true;
    end
  case {'fixed execution','fixed_execution','fixedexecution'}
    if (nargin > 0) && (isdouble(argin{1}) || isa(argin{1},'prdataset')) && ...
        (numel(argin) == 1 || ~ismapping(argin{2}))
      state = true;
    end
  case ('training')
    if (nargin > 0) && (isdouble(argin{1}) || isa(argin{1},'prdataset')) && ...
        (numel(argin)==1 || ~ismapping(argin{2}) || isuntrained(argin{2}))
      state = true;
    end
  case {'execution','trained execution','trained_execution','trainedexecution'}
    if (nargin > 1) && (isdouble(argin{1}) || isa(argin{1},'prdataset')) && ...
        ismapping(argin{2})
      state = true;
    end
  case {'combiner'}
    if (nargin > 0) && (ismapping(argin{1}))
      state = true;
    end
  otherwise
    error('Wrongly specified mapping task')
end

return


function pot = scgpot(ddom, cheaddom, ctaildom, node_sizes, scgpotc)
% SCGPOT Make a stable CG potential.
% pot = scgpot(ddom, cheaddom, ctaildom, node_sizes, scgpotc)
%
% ddom is discrete nodes contains in the potential
% cheaddom is head nodes constains in the potential
% ctaildom is tail nodes contains in the potential
% node_sizes(i) is the size of the i'th node.
% scgpotc is list of scgcpot objects.

pot.ddom = ddom;
pot.cheaddom = cheaddom;
pot.ctaildom = ctaildom;
pot.domain = myunion(ddom, myunion(cheaddom, ctaildom));
pot.dsizes = node_sizes(pot.ddom);
pot.dsize = prod(node_sizes(pot.ddom));
pot.cheadsizes = node_sizes(pot.cheaddom);
pot.cheadsize = sum(node_sizes(pot.cheaddom));
pot.ctailsizes = node_sizes(pot.ctaildom);
pot.ctailsize = sum(node_sizes(pot.ctaildom));

if nargin < 5
    scgpotc = cell(1, pot.dsize);
    for i=1:pot.dsize
        scgpotc{i} = scgcpot(pot.cheadsize, pot.ctailsize);
    end
end
pot.scgpotc = scgpotc;

pot = class(pot, 'scgpot');


% //This software is licensed under the BSD 3 Clause license: http://opensource.org/licenses/BSD-3-Clause
%
%
% //Copyright (c) 2013, University of Oxford
% //All rights reserved.
%
% //Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
%
% //Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
% //Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
% //Neither the name of the University of Oxford nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
% //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

%   The method implemented in this file has been patented by their original
%   authors. Commercial use of this code is thus strongly not
%   recocomended.
%
% //Authors: 	Gari D Clifford -
% //            Roberta Colloca -
% //			Julien Oster	-

function AFEv = comput_AFEv2(segment)

%comput_AFEv takes the RR intervals segment (column vector)
%and computes AFEv

%Inputs
%segment:   RR intervals segment (column vector)

%Output
%AFEv:   feature for detection of Atrial Fibrillation

%Compute dRR intervals series
dRR=comp_dRR(segment);

%Compute metrics
[OriginCount,IrrEv,PACEv]=metrics(dRR);

%Compute AFEvidence
AFEv=IrrEv-OriginCount-2*PACEv;

end


%IM_FEATURES Fixed mapping computing image features by the Matlab image toolbox
%
%		F = IM_FEATURES(A,GRAY,FEATURES)
%
% INPUT
%   A        Dataset with binary object images dataset
%   GRAY     Gray-valued images (matched with A, optional)
%   FEATURES Features to be computed
%
% OUTPUT
%   F        Dataset with computed features
%
% This function is a *replacement* for the function IM_MEASURE that is
% based on the DipLib measure.m. This implementation is using the Matlab
% function REGIONPROPS from the image toolbox. Use HELP REGIONPROPS to
% find out which features are exactly supported.
% In each image of the measurement set GRAY the features given in FEATURES
% are measured. In A a segmented version of GRAY has to be supplied.
% When no GRAY is supplied, the binary images in A are used.
%
% Use FEATURES = 'all' for computing all features.
%
% SEE ALSO
% DATASETS, DATAFILES, REGIONPROPS

% Copyright: D.M.J.Tax, D.M.J.Tax@prtools.org.
% Faculty EWI, Delft University of Technology
% P.O. Box 5031, 2600 GA Delft, The Netherlands

function b = im_features(a,gray,features)

if nargin < 3  features = []; end
if nargin < 2  gray = []; end

if nargin < 1 | isempty(a)
   b = prmapping(mfilename,'fixed',{gray,features});
   b = setname(b,'Image features');
elseif isa(a,'prdataset')
   if (nargin < 3 | isempty(features)) & ~isdataset(gray)
      features = gray;
      gray = a;
   end
   if ~strcmp(class(a),class(gray))
      error('Binary and gray images should be both datasets or datafiles')
   end
   fsize = getfeatsize(a);
   if any(getfeatsize(gray) ~= fsize)
      error('Image structures of binary and gray images should be identical')
   end
   if length(fsize) == 2, fsize = [fsize 1]; end
   if size(a,1) ~= size(gray,1)
      error('Same number of binary and gray images expected')
   end
   if isempty(features)
      features = 'all';
   end
   % first generate the correct feature labels, and a structure PROPS
   % that can be used in REGIONPROPS of Matlab:
   im = data2im(a(1,:));
   [props,featlab] = getlabfromregionprops(im,data2im(gray(1,:)),features);
   % RD 27Nov13, compute dat size before
   ftrial = getfeatfromregionprops(im,data2im(gray(1,:)),props);
   out = zeros(size(a,1),numel(ftrial));
   % Run over all images, and compute the features:
   for n = 1:size(a,1)
     out(n,:) = getfeatfromregionprops(data2im(a,n),data2im(gray,n),props);
   end
   % store in a dataset:
   %b = prdataset(out,getlabels(a));
   b = prdataset(out);
   b = setlablist(b,getlablist(a));
   b = setnlab(b,getnlab(a));
   b = setfeatlab(b,featlab);
   b = setprior(b,getprior(a,0));
   b = setname(b,getname(a));

elseif isa(a,'double')
   if (nargin < 3 | isempty(features)) & ~isdataset(gray)
      features = gray;
      gray = a;
   end
   [props,featlab] = getlabfromregionprops(a,gray,features);
   b = getfeatfromregionprops(a,gray,props);
else
   error('Wrong input')
end

return

% [props,featlab] = getlabfromregionprops(im,gray,features)
%
% Generate a structure PROPS and a cell-array FEATLAB that contains the
% features that are extracted from the images. PROPS is used in the
% Matlab function REGIONPROPS.
function [props,featlab] = getlabfromregionprops(im,gray,features)

% compute the properties:
%keyboard
thr = min(im(:)) + (max(im(:))-min(im(:)))/2;
r = regionprops((im>thr),gray,features);
props = fieldnames(r);
% we do it complicated like this, because bwprops could have been 'all',
% and by this we now get all possible (black and white) properties

% remove the things that we are not interested in:
% RD 27Nov13, PixelValues added
rmfeatures = {'PixelList', 'SubarrayIdx', 'ConvexHull','ConvexImage', ...
   'Image', 'FilledImage', 'PixelIdxList', 'Extrema', 'PixelValues'};
props = setdiff(props,rmfeatures);

% generate the feature labels
featlab = {};
nr = 0;
for i=1:length(props)
   nrf = size(getfield(r,props{i}),2);
   if nrf>1 % there are more measurements per single property
      for j=1:nrf
         nr = nr+1;
         featlab{nr} = [props{i},num2str(j)];
      end
   else % one measurement per property
      nr = nr+1;
      featlab{nr} = props{i};
   end
end
featlab = strvcat(featlab);

return

%   f = getfeatfromregionprops(im,gray,props)
%
% Compute the features F from the images IM. Which features are computed
% is defined in PROPS.
function f = getfeatfromregionprops(im,gray,props)

thr = min(im(:)) + (max(im(:))-min(im(:)))/2;
r = regionprops((im>thr),gray,props);
f = [];
for i=1:length(props)
   f = [f getfield(r,props{i})];
end


classdef unbndfun < classicfun
%UNBNDFUN    Represent global functions on an unbounded interval [-inf inf] or
% a semi-infinite interval [-inf b] or [a inf].
%
% Constructor inputs:
%   UNBNDFUN(OP) constructs a UNBNDFUN object from the function handle OP on the
%   domain determined by the default in CHEBFUNPREF by mapping the domain to
%   [-1, 1] and constructing a ONEFUN object to represent the function
%   prescribed by OP.  OP should be vectorised (i.e., accept a vector input)
%   and output a vector of the same length as its input.
%
%   UNBNDFUN(OP, DATA) constructs an UNBNDFUN object using the data supplied in
%   the DATA structure.  DATA fields used by UNBNDFUN are:
%     DATA.DOMAIN       (Default:  Determined by CHEBFUNPREF)
%         A row vector with two elements in increasing order defining the
%         construction domain.  At least one element must be infinite.
%   In addition, UNBNDFUN may modify the following DATA fields before passing
%   them on to the ONEFUN constructor:
%     DATA.HSCALE       (Default:  Determined by DATA.DOMAIN)
%         Horizontal construction scale.
%     DATA.EXPONENTS    (Default:  Empty)
%         Exponents describing the behavior of the function at the endpoints of
%         the construction domain.  (See SINGFUN.)
%     DATA.SINGTYPE     (Default:  Empty)
%         Types of endpoint singularities to search for.  (See SINGFUN.)
%   If any fields in DATA are empty or not supplied, or if DATA itself is empty
%   or not supplied, appropriate default values are set.  Any fields in DATA
%   which are not recognized will be passed as-is to the ONEFUN constructor.
%
%   UNBNDFUN(OP, DATA, PREF) overrides the default behavior with that given by
%   the preferences in the structure or CHEBFUNPREF object PREF. See
%   CHEBFUNPREF for details.
%
% See also CLASSICFUN, CHEBFUNPREF, ONEFUN.

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

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% UNBNDFUN Class Description:
%
% The UNBNDFUN class represents global functions on the infinite or
% semi-infinite interval [-inf, b], [a, inf], or [-inf, inf]. It achieves this
% by taking a onefun on [-1, 1] and applying a nonlinear mapping.
%
% Note that all binary UNBNDFUN operators (methods which can take two UNBNDFUN
% arguments) assume that the domains of the UNBNDFUN objects agree. The methods
% will not throw warnings if assumption is violated, but the results will not be
% meaningful under that circumstance.
%
% Class diagram: [<<CLASSICFUN>>] <>-- [<<onefun>>]
%                       ^
%                       |
%                   [unbndfun]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %% CLASS CONSTRUCTOR:
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    methods ( Access = public, Static = false )

        function obj = unbndfun(op, data, pref)

            % Parse inputs.
            if ( (nargin < 1) || isempty(op) )
                obj.domain = [];
                obj.mapping = [];
                obj.onefun = [];
                return
            end

            if ( (nargin < 2) || isempty(data) )
                data = struct();
            end

            if ( (nargin < 3) || isempty(pref) )
                pref = chebfunpref();
            else
                pref = chebfunpref(pref);
            end

            data = parseDataInputs(data, pref);

            % Check domain
            if ( ~all(size(data.domain) == [1, 2]) || (diff(data.domain) <= 0) )
                error('CHEBFUN:UNBNDFUN:unbndfun:domain',...
                    ['Domain argument should be a row vector with two ', ...
                    'entries in increasing order.']);
            elseif ( ~any(isinf(data.domain)) )
                error('CHEBFUN:UNBNDFUN:unbndfun:boundedDomain',...
                    'Domain argument should be unbounded.');
            end

            % Remap the OP to be a function on [-1, 1].
            unbndmap = unbndfun.createMap(data.domain);
            if ( isa(op, 'function_handle') )
                op = @(x) op(unbndmap.For(x));
            elseif ( isnumeric(op) )
                if ( ~any(op(:)) )
                    op = @(x) zeros(length(x), size(op, 2));
                else
                    %[TODO]: Implement this.
                    error('CHEBFUN:UNBNDFUN:unbndfun:inputValues',...
                        ['UNBNDFUN does not support non-zero construction ' ...
                         'from values.']);
                end
            end

            % Deal with exponents for singular functions.
            if ( isempty(data.exponents) )
                % The user hasn't supplied exponents, but functions on
                % unbounded domains are often singular once remapped to [-1,
                % 1].  Try to detect this by seeing if the function is infinite
                % at either endpoint and, if so, enable singularity detection.
                lVal = feval(op, -1);
                rVal = feval(op, 1);
                if ( any(isinf([lVal rVal])) )
                    pref.blowup = true;
                    singType = pref.blowupPrefs.defaultSingType;
                    data.singType = {singType, singType};
                end
            else
                % Remapping to [-1, 1] negates exponents, which are given with
                % respect to the function on the infinite domain.
                ind = isinf(data.domain);
                pref.blowup = true;
                data.exponents(ind) = -data.exponents(ind);
            end

            % Call the ONEFUN constructor:
            obj.onefun = onefun.constructor(op, data, pref);

            % Add the domain and mapping:
            obj.domain = data.domain;
            obj.mapping = unbndmap;
        end

    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %% STATIC METHODS:
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    methods ( Access = public, Static = true )

        % Retrieve and modify preferences for this class.
        prefs = pref(varargin);

        % Noninear map from [-1, 1] to the domain of the UNBNDFUN.
        m = createMap(domain);

        % Make a UNBNDFUN (constructor shortcut):
        f = make(varargin);

    end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% PRIVATE METHODS IMPLEMENTED IN THIE FILE:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function data = parseDataInputs(data, pref)
%PARSEDATAINPUTS   Parse inputs from the DATA structure and assign defaults.

if ( ~isfield(data, 'domain') || isempty(data.domain) )
    data.domain = pref.domain;
end

if ( ~isfield(data, 'hscale') || isempty(data.hscale) )
    % TODO:  Why is the hscale of an unbounded domain always 1?
    data.hscale = 1;
end

if ( ~isfield(data, 'exponents') || isempty(data.exponents) )
    data.exponents = [];
end

if ( ~isfield(data, 'singType') || isempty(data.singType) )
    data.singType = [];
end

end


function wrapperColorCues(inName, outName)
  I = imread(inName);

  dt = load('/work3/sgupta/eccv14-code/piotr-structured-edges-pami/models/forest/modelBsds.mat');
  model = dt.model;

  %% set detection parameters (can set after training)
  model.opts.multiscale=1;          % for top accuracy set multiscale=1
  model.opts.sharpen=0;             % for top speed set sharpen=0
  model.opts.nTreesEval=4;          % for top speed set nTreesEval=1
  model.opts.nThreads=4;            % max number threads for evaluation
  model.opts.nms=0;                 % set to true to enable nms

  [Es] = edgesDetect(I, model, zeros([size(I(:,:,1)), 0]));
  E = Es;
  save(outName, 'E', 'Es');
end


classdef IpoptApplication < SolverApplication
    % IpoptApplication defines an interface application class for IPOPT solvers
    %
    %
    % @author Ayonga Hereid @date 2016-10-22
    %
    % Copyright (c) 2016, AMBER Lab
    % All right reserved.
    %
    % Redistribution and use in source and binary forms, with or without
    % modification, are permitted only in compliance with the BSD 3-Clause
    % license, see
    % http://www.opensource.org/licenses/bsd-license.php

    %% Private properties
    properties (Access=public)

        % A structure contains the information of objective functions
        %
        % @type struct
        Objective

        % A sturcture contains the information of constraints
        %
        % @type struct
        Constraint

        % The nonlinear programming object
        %
        % @type NonlinearProgram
        Nlp
    end

    %% Public methods
    methods (Access = public)

        function obj = IpoptApplication(nlp, new_opts)
            % The default constructor function
            %
            % Parameters:
            %  nlp: the NLP problem object to be solved
            %  @type NonlinearProgram
            %  new_opts: the new solver options @type struct

            obj = obj@SolverApplication();

            % ipopt options
            options.initialguess = 'typical';

            % default IPOPT options
            options.ipopt.mu_strategy      = 'adaptive';
            options.ipopt.max_iter         = 1000;
            options.ipopt.tol              = 1e-3;
            options.ipopt.linear_solver    = 'ma57';
            options.ipopt.ma57_automatic_scaling = 'yes';
            options.ipopt.linear_scaling_on_demand = 'no';
            options.ipopt.ma57_pre_alloc = 2;
            %             options.ipopt.alpha_for_y = 'bound-mult';
            options.ipopt.recalc_y = 'yes';
            options.ipopt.recalc_y_feas_tol = 1e-3;
            %             options.ipopt.bound_relax_factor = 1e-3;
            %             options.ipopt.fixed_variable_treatment = 'RELAX_BOUNDS';
            %             options.ipopt.derivative_test = 'first-order';
            %             options.ipopt.point_perturbation_radius = 0;
            %             options.ipopt.derivative_test_perturbation = 1e-8;
            % options.ipopt.derivative_test_print_all = 'yes';
            options.ipopt.print_level = 5;
            options.ipopt.print_timing_statistics = 'yes';
            %             options.ipopt.print_options_documentation = 'yes';

            if nlp.Options.DerivativeLevel == 2
                % user-defined Hessian function is provide
                options.ipopt.hessian_approximation = 'exact';
            else
                options.ipopt.hessian_approximation = 'limited-memory';
                options.ipopt.limited_memory_update_type = 'bfgs';  % {bfgs}, sr1
                options.ipopt.limited_memory_max_history = 10;  % {6}
            end

            if nargin > 1
                options.ipopt = struct_overlay(options.ipopt,new_opts,{'AllowNew',true});
            end

            if exist(['sparse2.',mexext],'file') == 3
                options.UseMexSparse = true;
            else
                options.UseMexSparse = false;
            end

            obj.Options = options;
            obj.Nlp = nlp;
            obj = initialize(obj);

        end

    end

    % function definitions
    methods

        [obj] = initialize(obj);

        [sol, info] = optimize(obj, x0);

    end

end


% THIS SOFTWARE AND ANY ACCOMPANYING DOCUMENTATION IS RELEASED "AS IS."  THE U.S. GOVERNMENT MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, CONCERNING THIS SOFTWARE AND ANY ACCOMPANYING DOCUMENTATION, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT WILL THE U.S. GOVERNMENT BE LIABLE FOR ANY DAMAGES, INCLUDING ANY LOST PROFITS, LOST SAVINGS OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE, OR INABILITY TO USE, THIS SOFTWARE OR ANY ACCOMPANYING DOCUMENTATION, EVEN IF INFORMED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.
%
% get_zc.m
% Purpose: returns Zc for given alpha
% Change History:
%	021100 tdr created

function zc = get_zc(alpha)

zc=norminv(1-(alpha/2),0,1);


function display(b)
% bsarray/display: display of bsarray object
% usage: display(b)
%
% arguments:
%   b - bsarray object
%

% author: Nathan D. Cahill
% email: ndcahill@gmail.com
% date: 18 April 2008

n = b.tensorOrder;

switch n
    case 0
        str = sprintf([ ...
            'DataArray:     [ Empty ] double array\n',...
            'Coefficients:  [ Empty ] double array\n',...
            'Degree:          Empty\n',...
            'Centred:         Empty\n',...
            'Element Spacing: Empty\n',...
            'Lambda:          Empty\n']);
    case 1
        str = sprintf([ ...
            'DataArray:     [ %d x %d ] double array\n',...
            'Coefficients:  [ %d x %d ] double array\n',...
            'Degree:          %d\n',...
            'Centred:         %d\n',...
            'Element Spacing: %g\n',...
            'Lambda:          %g\n'],...
            b.dataSize(1),b.dataSize(2),...
            b.coeffsSize(1),b.coeffsSize(2),...
            b.degree(1),b.centred(1),b.elementSpacing(1),b.lambda(1));
    case 2
        str = sprintf([ ...
            'DataArray:       [ %d x %d ] double array\n',...
            'Coefficients:    [ %d x %d ] double array\n',...
            'Degree:          [ %d %d ]\n',...
            'Centred:         [ %d %d ]\n',...
            'Element Spacing: [ %g %g ]\n',...
            'Lambda:          [ %g %g ]\n'],...
            b.dataSize(1),b.dataSize(2),...
            b.coeffsSize(1),b.coeffsSize(2),...
            b.degree(1),b.degree(2),...
            b.centred(1),b.centred(2),...
            b.elementSpacing(1),b.elementSpacing(2),...
            b.lambda(1),b.lambda(2));
    case 3
        str = sprintf([ ...
            'DataArray:       [ %d x %d x %d ] double array\n',...
            'Coefficients:    [ %d x %d x %d ] double array\n',...
            'Degree:          [ %d %d %d ]\n',...
            'Centred:         [ %d %d %d ]\n',...
            'Element Spacing: [ %g %g %g ]\n',...
            'Lambda:          [ %g %g %g ]\n'],...
            b.dataSize(1),b.dataSize(2),b.dataSize(3),...
            b.coeffsSize(1),b.coeffsSize(2),b.coeffsSize(3),...
            b.degree(1),b.degree(2),b.degree(3),...
            b.centred(1),b.centred(2),b.centred(3),...
            b.elementSpacing(1),b.elementSpacing(2),b.elementSpacing(3),...
            b.lambda(1),b.lambda(2),b.lambda(3));
    otherwise
        str = sprintf([...
            'DataArray:       [ %d - D double array ]\n',...
            'Coefficients:    [ %d - D double array ]\n',...
            'Degree:          [ ',repmat('%d ',1,numel(b.degree)),']\n',...
            'Centred:         [ ',repmat('%d ',1,numel(b.centred)),']\n',...
            'Element Spacing: [ ',repmat('%g ',1,numel(b.elementSpacing)),']\n',...
            'Lambda:          [ ',repmat('%g ',1,numel(b.lambda)),']\n'],...
            n,n,b.degree,b.centred,b.elementSpacing,b.lambda);
end

if isequal(get(0,'FormatSpacing'),'compact')
    disp([inputname(1) ' =']);
    disp(str);
else
    disp(' ');
    disp([inputname(1) ' =']);
    disp(' ');
    disp(str);
end


function om = init_indexed_name(om, set_type, name, dim_list)
%INIT_INDEXED_NAME  Initializes the dimensions for an indexed named set.
%
%   OM.INIT_INDEXED_NAME(SET_TYPE, NAME, DIM_LIST)
%
%   Initializes the dimensions for an indexed named variable, constraint
%   or cost set.
%
%   Variables, constraints and costs are referenced in OPT_MODEL in terms
%   of named sets. The specific type of named set being referenced is
%   given by SET_TYPE, with the following valid options:
%       SET_TYPE = 'var'   => variable set
%       SET_TYPE = 'lin'   => linear constraint set
%       SET_TYPE = 'nle'   => nonlinear equality constraint set
%       SET_TYPE = 'nli'   => nonlinear inequality constraint set
%       SET_TYPE = 'qdc'   => quadratic cost set
%       SET_TYPE = 'nlc'   => nonlinear cost set
%       SET_TYPE = 'cost'  => legacy cost set
%
%   Indexed Named Sets
%
%   A variable, constraint or cost set can be identified by a single NAME,
%   such as 'Pmismatch', or by a name that is indexed by one or more indices,
%   such as 'Pmismatch(3,4)'. For an indexed named set, before adding the
%   indexed variable, constraint or cost sets themselves, the dimensions of
%   the indexed set must be set by calling INIT_INDEXED_NAME, where
%   DIM_LIST is a cell array of the dimensions.
%
%   Examples:
%       %% linear constraints with indexed named set 'R(i,j)'
%       om.init_indexed_name('lin', 'R', {2, 3});
%       for i = 1:2
%         for j = 1:3
%           om.add_lin_constraint('R', {i, j}, A{i,j}, ...);
%         end
%       end
%
%   See also OPT_MODEL, ADD_VAR, ADD_LIN_CONSTRAINT, ADD_NLN_CONSTRAINT,
%            ADD_QUAD_COST, ADD_NLN_COST and ADD_LEGACY_COST.

%   MATPOWER
%   Copyright (c) 2008-2020, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MATPOWER.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://matpower.org for more info.

%% call parent method (also checks for valid type for named set)
om = init_indexed_name@opt_model(om, set_type, name, dim_list);

%% add type-specific info about this named set
switch set_type
    case 'cost'         %% cost set
        %% use column vector if single dimension
        if length(dim_list) == 1
            dim_list = {dim_list{:}, 1};
        end
        empty_cell  = cell(dim_list{:});
        om.cost.data.N.(name)   = empty_cell;
        om.cost.data.Cw.(name)  = empty_cell;
        om.cost.data.vs.(name)  = empty_cell;
end


classdef GlobalBaseInertialFrame < AbstractReferenceFrame
    %GlobalBaseInertialFrame Summary of this class goes here
    %   Detailed explanation goes here

    properties
        celBodyData
    end

    properties(Constant)
        typeEnum = ReferenceFrameEnum.BodyCenteredInertial
    end

    methods
        function obj = BodyCenteredInertialFrame(celBodyData)
            obj.celBodyData = celBodyData;
        end

        function [posOffsetOrigin, velOffsetOrigin, angVelWrtOrigin, rotMatToInertial] = getOffsetsWrtInertialOrigin(obj, time, ~, ~)
            posOffsetOrigin = repmat([0;0;0], [1, length(time)]);
            velOffsetOrigin = repmat([0;0;0], [1, length(time)]);
            [angVelWrtOrigin, rotMatToInertial] = obj.getAngVelWrtOriginAndRotMatToInertial(time, [], []);
        end

        function rotMatToInertial = getRotMatToInertialAtTime(~, time, ~, ~)
            rotMatToInertial = repmat(eye(3), [1, 1, length(time)]);
        end

        function [angVelWrtOrigin, rotMatToInertial] = getAngVelWrtOriginAndRotMatToInertial(obj, time, vehElemSet, bodyInfoInertialOrigin)
            angVelWrtOrigin = repmat([0;0;0], [1, length(time)]);
            rotMatToInertial = obj.getRotMatToInertialAtTime(time, vehElemSet, bodyInfoInertialOrigin);
        end

        function tf = frameOriginIsACelBody(obj)
            tf = false;
        end

        function bodyInfo = getOriginBody(~)
            error('Not supported.');
        end

        function setOriginBody(~, ~)
            %nothing to do
        end

        function nameStr = getNameStr(~)
            nameStr = sprintf('Global Base Inertial Frame');
        end

        function newFrame = editFrameDialogUI(obj, ~)
            newFrame = obj;
        end
    end

    methods
        function bool = eq(A,B)
            bool = eq@handle(A,B);
        end

        function bool = ne(A,B)
            bool = ne@handle(A,B);
        end
    end
end


function p = presolveOneMagicRound(p);

p = presolve_bounds_from_domains(p);
p = presolve_bounds_from_modelbounds(p);
p = propagate_bounds_from_convex_quadratic_ball(p);
p = propagate_bounds_from_evaluations(p);
p = update_monomial_bounds(p);
p = propagate_bounds_from_equalities(p);
p = presolve_bounds_from_inequalities(p);
p = propagate_bounds_from_evaluations(p);
p = update_monomial_bounds(p);
p = propagate_bounds_from_evaluations(p);
p = update_monomial_bounds(p);
p = propagate_bounds_from_arbitrary_quadratics(p);


function pageplot(mode,option)
% PAGEPLOT Update all graphs on current page.
%          PAGEPLOT manages the updating of all the currently viewed
%          axes objects.

% Author: Craig Borghesani
% Date: 10/18/94
% Revised: 11/13/94
% Copyright (c) 1999, Prentice-Hall

% obtain handle information
f = gcf;
ui_data = get(f,'userdata');
ui_han = ui_data{1};
sys_axes = ui_han(12);
cur_sys = get(ui_han(30),'userdata');
cur_page = get(ui_han(31),'userdata');
cur_axs = get(ui_han(32),'userdata');
font_size = get(ui_han(42),'userdata');
page_setup = get(ui_han(34),'userdata');
page_layout = get(ui_han(35),'userdata');

plant_mat = get(ui_han(3+cur_sys),'userdata');
for_mat = get(ui_han(6+cur_sys),'userdata');
bac_mat = get(ui_han(9+cur_sys),'userdata');
sys_res = get(ui_han(cur_sys),'userdata');

plot_type = page_setup(:,cur_page); plot_type(find(plot_type==0)) = [];
plot_hand = page_layout(:,cur_page); plot_hand(find(plot_hand==0)) = [];

if mode == 0, % update all visible plots
 freqplot(plot_hand(find(plot_type>0 & plot_type<5)),option);
 rootplot(plot_hand(find(plot_type==5)),option);
 gainplot(plot_hand(find(plot_type>5 & plot_type<8)),option)
 timeplot(plot_hand(find(plot_type==8)),option);

elseif mode == 1, % only frequency response plots
 freqplot(plot_hand(find(plot_type>0 & plot_type<5)),option);

elseif mode == 2, % only root locus plots
 rootplot(plot_hand(find(plot_type==5)),option);
 gainplot(plot_hand(find(plot_type>5 & plot_type<8)),option)

elseif mode == 3, % only time response plots
 timeplot(plot_hand(find(plot_type==8)),option);

elseif mode == 4, % only gain plots
 gainplot(plot_hand(find(plot_type>5 & plot_type<8)),option)

end

% display system information
% option == 13 - switching systems
% option == 14 - changing pages
% option == 15 - changing page layouts
% option == [] - changing transfer function

if ~length(option) | any(option == [13:15]),

 data = get(cur_axs,'userdata');
 environ = data(1);
 if all(environ~=[5:7]),
  systemin(environ, sys_axes, font_size, sys_res, plant_mat, for_mat, bac_mat);
 end

end


function asa136_test ( )

%*****************************************************************************80
%
%% ASA136_TEST tests ASA136.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'ASA136_TEST\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Test the ASA136 library.\n' );

  asa136_test01 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'ASA136_TEST\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


% UTILS_OPTCREATE
% Create a structure of options given fieldName - value pairs in args as:
% args = {'field1', value1, 'field2', value,...};
% This function can be used as a template in different implementations.
% This can be done by:
% a) providing here an extra field {'optionsType', your_options_type}
% b) having an implementation of a function:
%  ['defaults_' your_options_type]
% which returns default values for this type of options
%
% COPYRIGHT: Andreas C. Damianou, 2012, 2013
% VARGPLVM
function options = util_optCreate(args1, args2)

options = [];

if nargin < 1
    return
end

if isstruct(args1)
    % In this case, the struct is initialised with another struct given in
    % arg1. Then, args2 (if present) can just alter specific fields or add.
    allfields = fieldnames(args1);
    for i=1:length(allfields)
        options.(allfields{i}) = args1.(allfields{i});
    end
    if nargin > 1
        for i = 1:2:length(args2)
            options.(args2{i}) = args2{i+1};
        end
    end
else
    for i = 1:2:length(args1)
        options.(args1{i}) = args1{i+1};
    end
end

%--- This can change depending on the implementation needs ----------

%-- Set with default values whatever is not already set
% Default values
if isfield(options, 'optionsType')
    fhandle = str2func(['defaults_' options.optionsType]);
    defaults = fhandle();
else
    defaults = {};
end
%----------------------------------------------------------------------

for i = 1:2:length(defaults)
    if ~isfield(options, defaults{i})
        options.(defaults{i}) = defaults{i+1};
    end
end


function [chansel, trlsel, cfg] = rejectvisual_summary(cfg, data)

% SUBFUNCTION for ft_rejectvisual

% Copyright (C) 2005-2006, Markus Bauer, Robert Oostenveld
% Copyright (C) 2006-2022, 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$

if ft_platform_supports('matlabversion', '2014b', inf)
  % make the figure large enough to hold stuff and place it centered at the top of the
  % screen where it would appear by default
  pos = get(groot, 'DefaultFigurePosition'); % groot was introduced in R2014b
  w = 800;
  h = 600;
  x = pos(1) + pos(3)/2 - w/2;
  y = pos(2) + pos(4)/2 - h/2;
  cfg.position = ft_getopt(cfg, 'position', [x y w h]);
end

% determine the initial selection of trials
ntrl = length(data.trial);
if isequal(cfg.trials, 'all') % support specification like 'all'
  cfg.trials = 1:ntrl;
elseif isempty(cfg.trials)
  cfg.trials = 1:ntrl;
elseif isnumeric(cfg.trials)
  % use the selection as it is
end
trlsel = false(1, ntrl);
trlsel(cfg.trials) = true;

% determine the initial selection of channels
nchan = length(data.label);
cfg.channel = ft_channelselection(cfg.channel, data.label); % support specification like 'all'
chansel = false(1, nchan);
chansel(match_str(data.label, cfg.channel)) = true;

% compute the sampling frequency from the first two timepoints
fsample = 1/mean(diff(data.time{1}));

% % select the specified latency window from the data
% % here it is done BEFORE filtering and metric computation
% for i=1:ntrl
%   begsample = nearest(data.time{i}, cfg.latency(1));
%   endsample = nearest(data.time{i}, cfg.latency(2));
%   data.time{i} = data.time{i}(begsample:endsample);
%   data.trial{i} = data.trial{i}(:, begsample:endsample);
% end
if ischar(cfg.latency)
  cfg.latency(1) = min(cellfun(@min, data.time));
  cfg.latency(2) = max(cellfun(@max, data.time));
end

% compute the offset from the time axes
offset = zeros(ntrl, 1);
for i=1:ntrl
  offset(i) = time2offset(data.time{i}, fsample);
end

% set up guidata info
info                = [];
info.data           = data;
info.cfg            = cfg;
info.metric         = cfg.metric;
info.previousmetric = 'none';
info.level          = nan(nchan, ntrl);
info.ntrl           = ntrl;
info.nchan          = nchan;
info.trlsel         = trlsel;
info.chansel        = chansel;
info.fsample        = fsample;
info.offset         = offset;
info.quit           = 0;

if isfield(cfg, 'neighbours')
  % prepare the neighbours, load from disk, make channel selection, etc.
  tmpcfg = keepfields(cfg, {'neighbours'});
  info.cfg.neighbours = ft_prepare_neighbours(tmpcfg, data);
  % creates a NxN Boolean matrix that describes whether channels are connected as neighbours
  info.cfg.connectivity = channelconnectivity(info.cfg, data);
else
  info.cfg.connectivity = [];
end

h = create_figure(info);

% Compute initial metric...
compute_metric(h);

while ishandle(h)
  redraw(h);
  info = guidata(h);
  if info.quit == 0
    uiwait(h);
  else
    chansel = info.chansel;
    trlsel  = info.trlsel;
    cfg     = info.cfg;
    delete(h);
    break;
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function h = create_figure(info)
% Creates the GUI and plots the data for the first time.
% All additional changes are done by manipulating the properties of the
% specific graphical objects
h = open_figure(keepfields(info.cfg, {'figure', 'position', 'visible', 'renderer', 'figurename', 'title'}));

% define three axes
info.axes(1) = axes('position', [0.100 0.650 0.375 0.300]);  % summary
info.axes(2) = axes('position', [0.575 0.650 0.375 0.300]);  % channels
info.axes(3) = axes('position', [0.100 0.250 0.375 0.300]);  % trials
% callback function (for toggling trials/channels) is set later, so that
% the user cannot try to toggle trials while nothing is present on the
% plots

% set up radio buttons for choosing metric
bgcolor = get(h, 'color');

metriclist = {'var' 'std' 'min' 'max' 'maxabs' 'range' 'kurtosis' '1/var' 'zvalue' 'maxzvalue' 'neighbexpvar' 'neighbcorr' 'neighbstdratio' 'db'};

uicontrol(h, 'Units', 'normalized', 'position', [0.575 0.50 0.24 0.04], 'Style', 'text', 'HorizontalAlignment', 'left', 'backgroundcolor', get(h, 'color'), 'string', 'Metric used:'); % text string for metric
uicontrol(h, 'Units', 'normalized', 'position', [0.725 0.51 0.20 0.04], 'Style', 'popupmenu', 'backgroundcolor', bgcolor, 'string', metriclist,       'HandleVisibility', 'off', 'callback', @change_metric); % popup menu for metric
uicontrol(h, 'Units', 'normalized', 'position', [0.575 0.46 0.24 0.04], 'Style', 'text', 'HorizontalAlignment', 'left', 'backgroundcolor', get(h, 'color'), 'string', 'Plot trial:');
info.plottrltxt = uicontrol(h, 'Units', 'normalized', 'position', [0.725 0.47 0.20 0.04], 'Style', 'edit', 'HorizontalAlignment', 'left', 'backgroundcolor', [1 1 1], 'callback', @plot_trials); % editbox for trial plotting

% editboxes for manually specifying which channels/trials to toggle on or off
uicontrol(h, 'Units', 'normalized', 'position', [0.575 0.42 0.24 0.04], 'Style', 'text', 'HorizontalAlignment', 'left', 'backgroundcolor', get(h, 'color'), 'string', 'Toggle trial:');
uicontrol(h, 'Units', 'normalized', 'position', [0.725 0.43 0.20 0.04], 'Style', 'edit', 'HorizontalAlignment', 'left', 'backgroundcolor', [1 1 1], 'callback', @toggle_trials, 'tag', 'edit_toggle_trials');
uicontrol(h, 'Units', 'normalized', 'position', [0.575 0.38 0.24 0.04], 'Style', 'text', 'HorizontalAlignment', 'left', 'backgroundcolor', get(h, 'color'), 'string', 'Toggle channel:');
uicontrol(h, 'Units', 'normalized', 'position', [0.725 0.39 0.20 0.04], 'Style', 'edit', 'HorizontalAlignment', 'left', 'backgroundcolor', [1 1 1], 'callback', @toggle_channels, 'tag', 'edit_toggle_channels');

info.excludetrllbl  = uicontrol(h, 'Units', 'normalized', 'position', [0.575 0.34 0.24 0.04], 'Style', 'text', 'HorizontalAlignment', 'left', 'backgroundcolor', get(h, 'color'), 'string', sprintf('Rejected trials: %i/%i', sum(info.trlsel==0), info.ntrl));
info.excludetrltxt  = uicontrol(h, 'Units', 'normalized', 'position', [0.605 0.30 0.45 0.04], 'Style', 'text', 'HorizontalAlignment', 'left', 'backgroundcolor', get(h, 'color'), 'Enable', 'Inactive');
info.excludechanlbl = uicontrol(h, 'Units', 'normalized', 'position', [0.575 0.26 0.28 0.04], 'Style', 'text', 'HorizontalAlignment', 'left', 'backgroundcolor', get(h, 'color'), 'string', sprintf('Rejected channels: %i/%i', sum(info.chansel==0), info.nchan));
info.excludechantxt = uicontrol(h, 'Units', 'normalized', 'position', [0.605 0.22 0.45 0.04], 'Style', 'text', 'HorizontalAlignment', 'left', 'backgroundcolor', get(h, 'color'), 'Enable', 'Inactive');

% instructions
instructions = sprintf('Drag the mouse over the channels or trials you wish to exclude');
uicontrol(h, 'Units', 'normalized', 'position', [0.575 0.125 0.35 0.08], 'Style', 'text', 'HorizontalAlignment', 'left', 'backgroundcolor', get(h, 'color'), 'string', instructions, 'FontWeight', 'bold', 'ForegroundColor', 'r');

% logbox
info.output_box = uicontrol(h, 'Units', 'normalized', 'position', [0.00 0.00 1.00 0.1], 'Style', 'edit', 'HorizontalAlignment', 'left', 'Max', 3, 'Min', 1, 'Enable', 'inactive', 'FontName', get(0, 'FixedWidthFontName'), 'FontSize', 9, 'ForegroundColor', [0 0 0], 'BackgroundColor', [1 1 1]);

% quit button
uicontrol(h, 'Units', 'normalized', 'position', [0.825 0.11 0.10 0.04], 'string', 'quit', 'callback', @quit);

% store the updated info in the figure
guidata(h, info);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function compute_metric(h)
info = guidata(h);
tmp = info.level(info.chansel, info.trlsel);
if isequal(info.metric, info.previousmetric) && all(~isnan(tmp(:)))
  % there is no reason to recompute the metric
  return
end

if contains(info.metric, 'zvalue')
  % cellmean and cellstd (see FT_DENOISE_PCA) would work instead of for-loops, but they are too memory-intensive
  runsum = zeros(info.nchan, 1);
  runss  = zeros(info.nchan, 1);
  runnum = 0;
  for i=1:info.ntrl
    % not entirely sure whether info.data.time{i} is correct, so I am constructing it here on the fly
    dat = preproc(info.data.trial{i}, info.data.label, offset2time(info.offset(i), info.fsample, size(info.data.trial{i}, 2)), info.cfg.preproc);
    runsum = runsum + nansum(dat, 2);
    runss  = runss  + nansum(dat.^2, 2);
    runnum = runnum + sum(isfinite(dat), 2);
  end
  mval = runsum./runnum;
  sd   = sqrt(runss./runnum - (runsum./runnum).^2);
else
  mval = [];
  sd   = [];
end

update_log(info.output_box, sprintf('Computing %s...', info.metric));
ft_progress('init', info.cfg.feedback, sprintf('computing %s', info.metric));
level = nan(info.nchan, info.ntrl);
for i=1:info.ntrl
  ft_progress(i/info.ntrl, 'computing %s %d of %d\n', i, info.metric, info.ntrl);
  % not entirely sure whether info.data.time{i} is correct, so I am constructing it here on the fly
  dat = preproc(info.data.trial{i}, info.data.label, offset2time(info.offset(i), info.fsample, size(info.data.trial{i}, 2)), info.cfg.preproc);
  val = artifact_level(dat, info.metric, mval, sd, info.cfg.connectivity);
  if isvector(val)
    level(:,i) = val;
  else
    level(:,i) = nanmedian(val);
  end
end

ft_progress('close');
update_log(info.output_box, 'Done.');

info.level = level;
info.previousmetric = info.metric;
guidata(h, info);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%s%%%%
function redraw(h)
info  = guidata(h);
% work with a copy of the data
level = info.level;

[maxperchan, maxpertrl, maxperchan_all, maxpertrl_all] = set_maxper(level, info.chansel, info.trlsel, info.metric);

% make the three figures
if gcf~=h, figure(h); end
% datacursormode on;

set(h, 'CurrentAxes', info.axes(1))
cla(info.axes(1));
switch info.cfg.viewmode
  case {'remove', 'toggle'}
    tmp = level;
    tmp(~info.chansel, :) = nan;
    tmp(:, ~info.trlsel)  = nan;
    imagesc(tmp, 'AlphaData', ~isnan(tmp));
    caxis([min(tmp(:)) max(tmp(:))]);
  case 'hide'
    imagesc(level(info.chansel==1, info.trlsel==1));
    if ~all(info.trlsel)
      set(info.axes(1), 'Xtick', []);
    end
    if ~all(info.chansel)
      set(info.axes(1), 'Ytick', []);
    end
end % switch
axis ij;
% colorbar;
title(info.cfg.method);
ylabel('channel number');
xlabel('trial number');

set(h, 'CurrentAxes', info.axes(2))
cla(info.axes(2));
switch info.cfg.viewmode
  case 'remove'
    plot(maxperchan(info.chansel==1),     find(info.chansel==1), '.');
    xmin = min(maxperchan);
    xmax = max(maxperchan);
    ymin = 1;
    ymax = info.nchan;
  case 'toggle'
    plot(maxperchan_all(info.chansel==1), find(info.chansel==1), '.');
    hold on;
    plot(maxperchan_all(info.chansel==0), find(info.chansel==0), 'o');
    hold off;
    xmin = min(maxperchan_all);
    xmax = max(maxperchan_all);
    ymin = 1;
    ymax = info.nchan;
  case 'hide'
    xmin = min(maxperchan);
    xmax = max(maxperchan);
    ymin = 1;
    ymax = sum(info.chansel==1);
    plot(maxperchan(info.chansel==1), 1:ymax, '.');
    if ~all(info.chansel)
      set(info.axes(2), 'Ytick', []);
    end
end % switch
% don't try to rescale the axes if they are empty
if any(info.chansel) && any(info.trlsel)
  % ensure that the horizontal and vertical range increase, also when negative
  % see https://github.com/fieldtrip/fieldtrip/issues/1150
  axis(fixrange([0.8*xmin 1.2*xmax ymin-0.5 ymax+0.5]));
end
axis ij;
set(info.axes(2), 'ButtonDownFcn', @toggle_visual);  % needs to be here; call to axis resets this property
ylabel('channel number');

set(h, 'CurrentAxes', info.axes(3))
cla(info.axes(3));
switch info.cfg.viewmode
  case 'remove'
    plot(find(info.trlsel==1), maxpertrl(info.trlsel==1), '.');
    xmin = 1;
    xmax = info.ntrl;
    ymin = min(maxpertrl);
    ymax = max(maxpertrl);
  case 'toggle'
    plot(find(info.trlsel==1), maxpertrl_all(info.trlsel==1), '.');
    hold on;
    plot(find(info.trlsel==0), maxpertrl_all(info.trlsel==0), 'o');
    hold off;
    xmin = 1;
    xmax = info.ntrl;
    ymin = min(maxpertrl_all);
    ymax = max(maxpertrl_all);
  case 'hide'
    xmin = 1;
    xmax = sum(info.trlsel==1);
    ymin = min(maxpertrl);
    ymax = max(maxpertrl);
    plot(1:xmax, maxpertrl(info.trlsel==1), '.');
    if ~all(info.trlsel)
      set(info.axes(3), 'Xtick', []);
    end
end % switch
% don't try to rescale the axes if they are empty
if any(info.chansel) && any(info.trlsel)
  % ensure that the horizontal and vertical range increase, also when negative
  % see https://github.com/fieldtrip/fieldtrip/issues/1150
  axis(fixrange([xmin-0.5 xmax+0.5 0.8*ymin 1.2*ymax]));
end
set(info.axes(3), 'ButtonDownFcn', @toggle_visual);  % needs to be here; call to axis resets this property
xlabel('trial number');

% put excluded trials/channels in their respective edit boxes
set(info.excludechanlbl, 'string', sprintf('Channels to exclude: %i/%i', sum(info.chansel==0), info.nchan));
set(info.excludetrllbl, 'string', sprintf('Trials to exclude: %i/%i', sum(info.trlsel==0), info.ntrl));

if ~all(info.trlsel)
  excludetrltxt = sprintf('%d, ', find(~info.trlsel));
  excludetrltxt = excludetrltxt(1:end-2);
  set(info.excludetrltxt, 'String', excludetrltxt, 'FontAngle', 'normal', 'ButtonDownFcn', @toggle_trials_fill);
else
  set(info.excludetrltxt, 'String', 'No trials to exclude', 'FontAngle', 'italic');
end

if ~all(info.chansel)
  if false % isfield(info.data, 'label')
    excludechantxt = sprintf('%s, ', info.data.label{~info.chansel});
  else
    excludechantxt = sprintf('%d, ', find(~info.chansel));
  end
  excludechantxt = excludechantxt(1:end-2);
  set(info.excludechantxt, 'String', excludechantxt, 'FontAngle', 'normal', 'ButtonDownFcn', @toggle_channels_fill);
else
  set(info.excludechantxt, 'String', 'No channels to exclude', 'FontAngle', 'italic');
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function toggle_trials(h, eventdata)
info = guidata(h);

% process input from the "toggle trials" textbox
text = get(h, 'string');
set(h, 'string', '');
trls = handle_edit_input(text);

if isempty(trls)
  update_log(info.output_box, sprintf('Please enter one or more trials'));
  uiresume
  return
elseif any(trls<1)
  update_log(info.output_box, sprintf('ERROR: Trial value too small!'));
  uiresume
  return
elseif any(trls>length(info.trlsel))
  update_log(info.output_box, sprintf('ERROR: Trial value too large!'));
  uiresume
  return
else
  info.trlsel(trls) = ~info.trlsel(trls);
  % recalculate the metric
  compute_metric(h)
  guidata(h, info);
end
uiresume

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function toggle_trials_fill(h, eventdata)
info = guidata(h);
excludetrltxt = sprintf('%d, ', find(~info.trlsel));
excludetrltxt = excludetrltxt(1:end-2);
set(findobj('tag', 'edit_toggle_trials'), 'string', excludetrltxt)
set(info.plottrltxt, 'string', excludetrltxt)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function toggle_channels(h, eventdata)
info = guidata(h);

% process input from the "toggle channels" textbox
text = get(h, 'string');
set(h, 'string', '');
chans = handle_edit_input(text);                      % this can be 'all' or 'megref'
chans = ft_channelselection(chans, info.data.label);  % this is a cell-array of strings
chans = match_str(info.data.label, chans);            % this is a list of numbers

if isempty(chans)
  update_log(info.output_box, sprintf('Please enter one or more channels'));
  uiresume
  return
elseif any(chans<1)
  update_log(info.output_box, sprintf('ERROR: Channel value too small!'));
  uiresume
  return
elseif any(chans>length(info.data.label))
  update_log(info.output_box, sprintf('ERROR: Channel value too large!'));
  uiresume
  return
else
  info.chansel(chans) = ~info.chansel(chans);
  % recalculate the metric
  compute_metric(h)
  guidata(h, info);
end
uiresume

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function toggle_channels_fill(h, eventdata)
info = guidata(h);
excludechantxt = sprintf('%d, ', find(~info.chansel));
excludechantxt = excludechantxt(1:end-2);
set(findobj('tag', 'edit_toggle_channels'), 'string', excludechantxt)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function toggle_visual(h, eventdata)
% copied from FT_SELECT_BOX, but without the waitforbuttonpress command since here it is triggered by the ButtonDown event
point1 = get(gca, 'CurrentPoint');    % button down detected
rbbox;                                % this draws the rubber-band box
point2 = get(gca, 'CurrentPoint');    % button up detected
point1 = point1(1, 1:2);              % extract x and y
point2 = point2(1, 1:2);
x = sort([point1(1) point2(1)]);
y = sort([point1(2) point2(2)]);

g     = get(gca, 'Parent');
info  = guidata(g);

[maxperchan, maxpertrl, maxperchan_all, maxpertrl_all] = set_maxper(info.level, info.chansel, info.trlsel, info.metric);

switch gca
  case info.axes(1)
    % visual selection in the summary plot is not supported

  case info.axes(2)
    % the visual selection was made in the channels plot
    switch info.cfg.viewmode
      case 'toggle'
        chanlabels = 1:info.nchan;
        toggle = ...
          chanlabels >= y(1) & ...
          chanlabels <= y(2) & ...
          maxperchan_all(chanlabels)' >= x(1) & ...
          maxperchan_all(chanlabels)' <= x(2);
        info.chansel(toggle) = ~info.chansel(toggle);

      case 'remove'
        chanlabels     = 1:info.nchan;
        toggle = ...
          chanlabels >= y(1) & ...
          chanlabels <= y(2) & ...
          maxperchan(chanlabels)' >= x(1) & ...
          maxperchan(chanlabels)' <= x(2);
        info.chansel(toggle) = false;

      case 'hide'
        chanlabels = 1:sum(info.chansel==1);
        [junk, origchanlabels] = find(info.chansel==1);
        toggle = ...
          chanlabels >= y(1) & ...
          chanlabels <= y(2) & ...
          maxperchan(origchanlabels)' >= x(1) & ...
          maxperchan(origchanlabels)' <= x(2);
        info.chansel(origchanlabels(toggle)) = false;
    end

  case info.axes(3)
    % the visual selection was made in the trials plot
    switch info.cfg.viewmode
      case 'toggle'
        trllabels = 1:info.ntrl;
        toggle = ...
          trllabels >= x(1) & ...
          trllabels <= x(2) & ...
          maxpertrl_all(trllabels) >= y(1) & ...
          maxpertrl_all(trllabels) <= y(2);
        info.trlsel(toggle) = ~info.trlsel(toggle);

      case 'remove'
        trllabels = 1:info.ntrl;
        toggle = ...
          trllabels >= x(1) & ...
          trllabels <= x(2) & ...
          maxpertrl(trllabels) >= y(1) & ...
          maxpertrl(trllabels) <= y(2);
        info.trlsel(toggle) = false;

      case 'hide'
        trllabels = 1:sum(info.trlsel==1);
        [junk, origtrllabels] = find(info.trlsel==1);
        toggle = ...
          trllabels >= x(1) & ...
          trllabels <= x(2) & ...
          maxpertrl(origtrllabels) >= y(1) & ...
          maxpertrl(origtrllabels) <= y(2);
        info.trlsel(origtrllabels(toggle)) = false;
    end

end % switch gca

% recalculate the metric
compute_metric(h);
guidata(h, info);
uiresume

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function quit(h, eventdata)
info = guidata(h);
info.quit = 1;
guidata(h, info);
uiresume

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function change_metric(h, eventdata)
info = guidata(h);
%info.metric = get(eventdata.NewValue, 'string');
info.metric = h.String{h.Value};
guidata(h, info);
compute_metric(h);
uiresume

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function update_log(h, new_text)
new_text        = [datestr(now, 13) '# ' new_text];
curr_text       = get(h, 'string');
size_curr_text  = size(curr_text, 2);
size_new_text   = size(new_text, 2);
if size_curr_text > size_new_text
  new_text        = [new_text blanks(size_curr_text-size_new_text)];
else
  curr_text   = [curr_text repmat(blanks(size_new_text-size_curr_text), size(curr_text, 1), 1)];
end
set(h, 'String', [new_text; curr_text]);
drawnow

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [maxperchan, maxpertrl, maxperchan_all, maxpertrl_all] = set_maxper(level, chansel, trlsel, metric)
if ismember(metric, {'var', 'std', 'max', 'maxabs', 'range', 'kurtosis', '1/var', 'zvalue', 'maxzvalue', 'neighbstdratio'})
  % take the maximum
  extreme = @max;
elseif ismember(metric, {'min', 'neighbexpvar', 'neighbcorr'})
  % take the minimum
  extreme = @min;
end
% determine the extreme value
maxperchan_all = extreme(level, [], 2);
maxpertrl_all  = extreme(level, [], 1);
% determine the extreme value over the remaining selection
level(~chansel, :) = nan;
level(:, ~trlsel)  = nan;
maxperchan = extreme(level, [], 2);
maxpertrl  = extreme(level, [], 1);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function plot_trials(h, eventdata)
info = guidata(h);

% process input from the "plot trials" textbox
text = get(h, 'string');
set(h, 'string', '');
trls = handle_edit_input(text);

if isempty(trls)
  update_log(info.output_box, sprintf('Please enter one or more trials'));
  uiresume
  return
elseif any(trls<1)
  update_log(info.output_box, sprintf('ERROR: Trial value too small!'));
  uiresume
  return
elseif any(trls>length(info.trlsel))
  update_log(info.output_box, sprintf('ERROR: Trial value too large!'));
  uiresume
  return
else
  update_log(info.output_box, 'Making multiplot of individual trials ...');
end

cfg_mp = [];
% disable hashing of input data (speeds up things)
cfg_mp.trackcallinfo = 'no';
cfg_mp.layout   = info.cfg.layout;
cfg_mp.channel  = info.data.label(info.chansel);
cfg_mp.dataname = info.cfg.dataname;
cfg_mp.ylim     = info.cfg.ylim;
currfig = gcf;
for n = 1:length(trls)
  % ft_multiplotER should be able to make the selection, but fails due to http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2978
  % that bug is hard to fix, hence it is solved here with a work-around
  cfg_sd = [];
  cfg_sd.trials = trls(n);
  tmpdata = ft_selectdata(cfg_sd, info.data);

  figure()
  cfg_mp.interactive = 'yes';
  ft_multiplotER(cfg_mp, tmpdata);
  title(sprintf('Trial %i', trls(n)));
end
figure(currfig);
update_log(info.output_box, 'Done.');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function range = fixrange(range)
% ensure that the horizontal and vertical range always increase
% also when both are negative, or both are the same, or both are or zero
% see https://github.com/fieldtrip/fieldtrip/issues/1150
if range(1)>range(2)
  % swap them
  range([1 2]) = range([2 1]);
elseif range(1)==range(2)
  if range(1)==0
    % move them a little bit apart from each other
    range([1 2]) = range([1 2]) + [-eps +eps];
  else
    % move them a little bit apart from each other, scaled with the value of interest
    range([1 2]) = range([1 2]) + [-eps +eps]*range(1);
  end
end
if range(3)>range(4)
  % swap them
  range([3 4]) = range([4 3]);
elseif range(3)==range(4)
  if range(3)==0
    % move them a little bit apart from each other
    range([3 4]) = range([3 4]) + [-eps +eps];
  else
    % move them a little bit apart from each other, scaled with the value of interest
    range([3 4]) = range([3 4]) + [-eps +eps]*range(3);
  end
end


function SO3F = cat(dim,varargin)
% overloads cat

% remove empty arguments
varargin(cellfun('isempty',varargin)) = [];
SO3F = varargin{1};
bw = SO3F.bandwidth;

for i = 2:numel(varargin)

  bw2 = varargin{i}.bandwidth;
  if bw > bw2
    varargin{i}.bandwidth = bw;
  else
    bw = bw2;
    SO3F.bandwidth = bw2;
  end

  ensureCompatibleSymmetries(SO3F,varargin{i});

  SO3F.fhat = cat(1+dim, SO3F.fhat, varargin{i}.fhat);
end


function Accuracy=P300_Ncorrect(smt,filepath,subject_info,spellerText_on)

file=fullfile(filepath,subject_info.subject,subject_info.session, 'log');
% get log file
list=ls(sprintf('%s\\*_p300_param*', file));
load_file=fullfile(file,list(end,:));
load(load_file);

score=0;
for i=1:length(spellerText_on)
    if strcmp(SAVE{i}.char(1),spellerText_on(i))
        score=score+1;
    end
end

Accuracy=score/length(spellerText_on);
disp(Accuracy);

for i=1:length(spellerText_on)
    a(i)=SAVE{i}.char(1);
    disp(SAVE{i}.char(1));
end
end