function [boxes, scores] = run_gop(im, num_proposals)

  if ~isdeployed
    old_path = path;
    addpath('/path/to/geodesic/gop_matlab/matlab');
  end

  interp_data = load('/path/to/gop_num_candidates_interpolation_data.mat');
  interp_data.num_candidates = [-1; interp_data.num_candidates; 1e10];
  interp_data.all_params = [interp_data.all_params(1,:); interp_data.all_params; interp_data.all_params(end,:)];
  params = interp1(interp_data.num_candidates, interp_data.all_params, num_proposals);
  assert(~any(isnan(params)));
  N_S = params(1);
  N_T = params(2);

  boxes = gop_wrapper(im, N_S, N_T);
  scores = [];

  if ~isdeployed
    path(old_path);
  end
end

function boxes = gop_wrapper(im, N_S, N_T)
% reimplementation of eval_box.py
  gop_mex( 'setDetector', 'MultiScaleStructuredForest("/path/to/geodesic/gop_matlab/data/sf.dat")' );
  data_path = '/path/to/geodesic/gop_matlab/data/';
  max_iou = 0.7;
  args = {};
  if N_S > 3
    args = [args {'seed', [data_path 'seed_final.dat']}];
  end
  if N_T >= 5
    max_iou = 0.8;
  end
  if N_T > 6
    max_iou = 0.9;
  end
  if N_S > 40
    args = [args {'unary', N_S, N_T, 'seedUnary()', 'backgroundUnary({0,1,15})', ...
                  'unary', 0, N_T,   'seedUnary()', 'backgroundUnary({0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15})', 0.1, 1}];
  elseif N_S > 1
    args = [args {'unary', N_S, N_T, 'seedUnary()', 'backgroundUnary({0,15})'}];
  else
    args = [args {'unary', N_S, N_T, 'seedUnary()', 'backgroundUnary({15})'}];
  end

  args = [{'max_iou', max_iou}, args];
  p = Proposal(args{:});
  tic();
  os = OverSegmentation( im );
  props = p.propose( os );
  boxes = double(os.maskToBox( props ));
  toc();
end


classdef BankAngleTermCondOptimizationVariable < AbstractOptimizationVariable
    %BankAngleTermCondOptimizationVariable Summary of this class goes here
    %   Detailed explanation goes here

    properties
        varObj(1,1) BankAngleTermCondition = BankAngleTermCondition(0);

        lb(1,1) double = 0;
        ub(1,1) double = 0;

        useTf(1,1) = false;
    end

    methods
        function obj = BankAngleTermCondOptimizationVariable(varObj)
            obj.varObj = varObj;
            obj.varObj.optVar = obj;

            obj.id = rand();
        end

        function x = getXsForVariable(obj)
            x = [];

            if(obj.useTf)
                x = obj.varObj.targetBankAngle;
            end
        end

        function [lb, ub] = getBndsForVariable(obj)
            lb = obj.lb(obj.useTf);
            ub = obj.ub(obj.useTf);
        end

        function [lb, ub] = getAllBndsForVariable(obj)
            lb = obj.lb;
            ub = obj.ub;
        end

        function setBndsForVariable(obj, lb, ub)
            obj.lb = lb;
            obj.ub = ub;
        end

        function useTf = getUseTfForVariable(obj)
            useTf = obj.useTf;
        end

        function setUseTfForVariable(obj, useTf)
            obj.useTf = useTf;
        end

        function updateObjWithVarValue(obj, x)
            obj.varObj.targetBankAngle = x;
        end

        function nameStrs = getStrNamesOfVars(obj, evtNum, varLocType)
            nameStrs = {sprintf('Event %i Bank Angle Termination Condition', evtNum)};
        end

        function varsStoredInRad = getVarsStoredInRad(obj)
            varsStoredInRad = true;
        end
    end
end


function test_suite=test_meeg_senstype_collection
% tests for cosmo_meeg_senstype_collection
%
% #   For CoSMoMVPA's copyright information and license terms,   #
% #   see the COPYING file distributed with CoSMoMVPA.           #
    try % assignment of 'localfunctions' is necessary in Matlab >= 2016
        test_functions=localfunctions();
    catch % no problem; early Matlab versions can use initTestSuite fine
    end
    initTestSuite;

function test_meeg_senstype_collection_
    if cosmo_skip_test_if_no_external('fieldtrip')
        return;
    end

    % get senstype properties
    % order is:
    % - senstype name
    % - acquisition system
    % - sensor type
    % - number of rows in channels
    % - number of columns in channels
    % - first and last channel label

    senstype_props=get_senstype_properties();

    % test each one
    n=numel(senstype_props);

    clear('cosmo_meeg_senstype_collection');
    stc=cosmo_meeg_senstype_collection();
    stc_cached=cosmo_meeg_senstype_collection();
    assertEqual(stc,stc_cached);
    for k=1:n
        prop=senstype_props{k};
        key=prop{1};
        is_required=numel(prop)>=7 && prop{7};

        if isfield(stc,key)
            sens=prop{2};
            type=prop{3};
            size_=[prop{4:5}];
            labels=prop{6}(:);

            assert(isfield(stc,key));
            st=stc.(key);

            assertEqual(st.sens,sens);
            assertEqual(st.type,type);
            assertEqual(size(st.label),size_);
            assertEqual(st.label([1;end]),labels);
        elseif is_required
            error('Missing key %s',key);
        end
    end

function test_meeg_senstype_collection_ft_regr_2016june
    if cosmo_skip_test_if_no_external('fieldtrip')
            return;
    end

    % since the following commit, ft_senstype supports
    %     ft_senslabel('neuromag306_combined')
    % but its output is different than was expected in
    % cosmo_meeg_senstype_collection. In particular the recent commit
    % includes the magnetometers, whereas the meeg_senstype
    % does not include those. This test is added as check for
    % such regressions

    % FieldTrip (https://github.com/fieldtrip/fieldtrip.git)
    % commit 882dba3426db583f7f4f9ac0cdf4eb3c26aaefc1
    % Author: Robert Oostenveld <r.oostenveld@gmail.com>
    % Date:   Wed Jun 22 12:47:47 2016 +0200
    %
    %     ENH - improve combined planar MEG sensor handling, see
    %     http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3144

    stc=cosmo_meeg_senstype_collection();
    label=stc.neuromag306_planar_combined.label;
    assertEqual(size(label),[102 1]);

    present_labels={'MEG 2642+2643','MEG 0112+0113'};
    absent_labels={'MEG0111'',MEG0112','MEG0113',...
                    'MEG2641'',MEG2642','MEG2643'};
    assert(all(cosmo_match(present_labels,label(:))));
    assert(~any(cosmo_match(absent_labels,label(:))));

function props=get_senstype_properties()

    props={{ 'biosemi64',...
                    'biosemi64','eeg',...
                    64,1,{'A1','B32'}},...
            {'biosemi128',...
                    'biosemi128','eeg',...
                    128,1,{'A1','D32'}},...
            {'biosemi256',...
                    'biosemi256','eeg',...
                    256,1,{'A1','H32'}},...
            {'bti148',...
                    'bti148','meg_axial',...
                    148,1,{'A1','A148'}},...
            {'bti148_planar',...
                    'bti148','meg_planar',...
                    148,2,{'A1_dH','A148_dV'}},...
            {'bti148_planar_combined',...
                    'bti148','meg_planar_combined',...
                    148,1,{'A1','A148'},false},...  % not required
            {'bti248',...
                    'bti248','meg_axial',...
                    248,1,{'A1','A248'}},...
            {'bti248_planar',...
                    'bti248','meg_planar',...
                    248,2,{'A1_dH','A248_dV'}},...
            {'bti248_planar_combined',...
                    'bti248','meg_planar_combined',...
                    248,1,{'A1','A248'},false},...  % not required
            {'ctf151',...
                    'ctf151','meg_axial',...
                    151,1,{'MLC11','MZP02'}},...
            {'ctf151_planar',...
                    'ctf151','meg_planar',...
                    151,2,{'MLC11_dH','MZP02_dV'}},...
            {'ctf151_planar_combined',...
                    'ctf151','meg_planar_combined',...
                    151,1,{'MLC11','MZP02'}},...
            {'ctf275',...
                    'ctf275','meg_axial',...
                    275,1,{'MLC11','MZP01'}},...
            {'ctf275_planar',...
                    'ctf275','meg_planar',...
                    275,2,{'MLC11_dH','MZP01_dV'}},...
            {'ctf275_planar_combined',...
                    'ctf275','meg_planar_combined',...
                    275,1,{'MLC11','MZP01'}},...
            {'eeg1005',...
                    'ext1020','eeg',...
                    343,1,{'Fp1','T6'}},...
            {'eeg1010',...
                    'ext1020','eeg',...
                    94,1,{'Fp1','T6'}},...
            {'eeg1020',...
                    'ext1020','eeg',...
                    29,1,{'Fp1','T6'}},...
            {'egi32',...
                    'egi32','eeg',...
                    34,1,{'E1','Cz'}},...
            {'egi64',...
                    'egi64','eeg',...
                    66,1,{'E1','Cz'}},...
            {'egi128',...
                    'egi128','eeg',...
                    130,1,{'E1','Cz'}},...
            {'egi256',...
                    'egi256','eeg',...
                    258,1,{'E1','Cz'}},...
            {'neuromag122_planar_combined',...
                    'neuromag122','meg_planar_combined',...
                    61,1,{'MEG 001+002','MEG 121+122'}},...
            {'neuromag306_planar_combined',...
                    'neuromag306','meg_planar_combined',...
                    102,1,{'MEG 0112+0113','MEG 2642+2643'}},...
            {'itab153',...
                    'itab153','meg',...
                    153,1,{'MAG_000','MAG_152'}},...
            {'itab153_planar',...
                    'itab153','meg_planar',...
                    153,2,{'MAG_000_dH','MAG_152_dV'}},...
            {'itab153_planar_combined',...
                    'itab153','meg_planar_combined',...
                    153,1,{'MAG_000','MAG_152'}},...
            {'yokogawa64',...
                    'yokogawa64','meg_axial',...
                    64,1,{'AG001','AG064'}},...
            {'yokogawa64_planar',...
                    'yokogawa64','meg_planar',...
                    64,2,{'AG001_dH','AG064_dV'}},...
            {'yokogawa64_planar_combined',...
                    'yokogawa64','meg_planar_combined',...
                    64,1,{'AG001','AG064'}},...
            {'yokogawa160',...
                    'yokogawa160','meg_axial',...
                    160,1,{'AG001','AG160'}},...
            {'yokogawa160_planar',...
                    'yokogawa160','meg_planar',...
                    160,2,{'AG001_dH','AG160_dV'}},...
            {'yokogawa160_planar_combined',...
                    'yokogawa160','meg_planar_combined',...
                    160,1,{'AG001','AG160'}},...
            {'yokogawa440',...
                    'yokogawa440','meg_axial',...
                    412,1,{'AG001','RM412'}},...
            {'yokogawa440_planar',...
                    'yokogawa440','meg_planar',...
                    210,2,{'AG001_dH','AG392_dV'}},...
            {'yokogawa440_planar_combined',...
                    'yokogawa440','meg_planar_combined',...
                    210,1,{'AG001','AG392'}},...
            {'neuromag122alt_planar_combined',...
                    'neuromag122','meg_planar_combined',...
                    61,1,{'MEG001+002','MEG121+122'}},...
            {'neuromag306alt_planar_combined',...
                    'neuromag306','meg_planar_combined',...
                    102,1,{'MEG0112+0113','MEG2642+2643'}},...
            {'neuromag306_planar',...
                    'neuromag306','meg_planar',...
                    102,2,{'MEG 0112','MEG 2643'}},...
            {'neuromag306_mag',...
                    'neuromag306','meg_axial',...
                    102,1,{'MEG 0111','MEG 2641'}},...
            {'neuromag306alt_planar',...
                    'neuromag306','meg_planar',...
                    102,2,{'MEG0112','MEG2643'}},...
            {'neuromag306alt_mag',...
                    'neuromag306','meg_axial',...
                    102,1,{'MEG0111','MEG2641'}},...
            {'neuromag122_planar',...
                    'neuromag122','meg_planar',...
                    61,2,{'MEG 001','MEG 122'}},...
            {'neuromag122alt_planar',...
                    'neuromag122','meg_planar',...
                    61,2,{'MEG001','MEG122'}}};

    % the data anobe was produced by the code below
    %
    % sc=cosmo_meeg_senstype_collection();
    % names=fieldnames(sc);
    %
    % names={'biosemi64','biosemi128','biosemi256',...
    %         'bti148','bti148_planar','bti148_planar_combined',...
    %         'bti248','bti248_planar','bti248_planar_combined',...
    %         'ctf151','ctf151_planar','ctf151_planar_combined',...
    %         'ctf275','ctf275_planar','ctf275_planar_combined',...
    %         'eeg1005','eeg1010','eeg1020',...
    %         'egi32','egi64','egi128','egi256',...
    %         'neuromag122_planar_combined',...
    %         'neuromag306_planar_combined',...
    %         'itab153','itab153_planar','itab153_planar_combined',...
    %         'yokogawa64','yokogawa64_planar','yokogawa64_planar_combined',...
    %         'yokogawa160','yokogawa160_planar',...
    %                             'yokogawa160_planar_combined',...
    %         'yokogawa440','yokogawa440_planar',...
    %                             'yokogawa440_planar_combined',...
    %         'neuromag122alt_planar_combined',...
    %         'neuromag306alt_planar_combined',...
    %         'neuromag306_planar',...
    %         'neuromag306_mag',...
    %         'neuromag306alt_planar',...
    %         'neuromag306alt_mag',...
    %         'neuromag122_planar',...
    %         'neuromag122alt_planar'};
    % for k=1:numel(names)
    %     name=names{k};
    %     s=sc.(name);
    %     fprintf(['{''%s'',...\n\t\t''%s'',''%s'',...\n\t\t'...
    %                 '%d,%d,{''%s'',''%s''}},...\n'],...
    %             name,s.sens,s.type,size(s.label),s.label{1},s.label{end})
    % end
    %


function [facecolor, linestyle, marker] = getFaceColorForSRMethod(srMethodName)

    srMethods = {'nn', 'bicubic', 'ebsr', 'scsr', 'nbsrf', 'aplus', 'srcnn', 'drcn', 'vdsr', 'sesr', 'nuisr', 'wnuisr', 'hysr', 'dbrsr', 'l1btv', 'bepsr', 'irwsr', 'bvsr', 'srb', 'vsrnet'};

    % Get face color for the SR method.
    colorMap = jet(30);
    facecolor = [colorMap(1:10,:); colorMap(21:30,:)];
    facecolor = facecolor( strcmp(srMethodName, srMethods), :);

    if nargout > 1
        % Get line style for the SR method.
        linestyle = cellstr(char('-', ':', '-.', '--', '-', ':', '-.', '--', '-', ':', '-.', '--', '-', ':', '-.', '--', '-', ':', '-.', '--'));
        linestyle = linestyle{ strcmp(srMethodName, srMethods) };
    end

    if nargout > 2
        % Get marker for the SR method.
        marker = ['o', 'x', '+', '*', 's', 'd', 'v', '^', '<', '>', 'o', 'x', '+', '*', 's', 'd', 'v', '^', '<', '>'];
        marker = marker(strcmp(srMethodName, srMethods));
    end


classdef prtOptionsClusterPlot
    % xxx Need Help xxx

    properties

        nSamplesPerDim = [500 100 20]; % Number of samples to use for plotting
        colorsFunction = @prtPlotUtilClassColors; % Colors function handle

        twoClassColorMapFunction = @prtPlotUtilTwoClassColorMap; % Two class colormap function handle
    end

    methods
        function obj = prtOptionsClusterPlot(varargin)
            obj = prtUtilAssignStringValuePairs(obj,varargin{:});
        end
    end
end


function fcn_decodeCommandMoveRobot(str)
%% About:
% This function is used to decode the command string, and then it is used
% to move the robot along the decoded instruction.

%% Areguments:
% str: command string

% Copyright: Mohammad SAFEEA, 13th-Jul-2018

global read_state_var;
% check connection
if fcn_isConnected()
else
    message='Error in function (fcn_decodeCommandMoveRobot), not connected to the robot !!!';
    fcn_errorMessage(message);
    return;
end

% Turn off state read
read_state_var=false;

% decode the motion command
if strncmpi('moveLine',str,max(size('moveLine')))
    moveLinePTP(str);
elseif strncmpi('moveJoints',str,max(size('moveJoints')))
    moveJointsPTP(str);
elseif startsWith(str,'OuputPin')
    setOutputsOfMediaFlange(str);
else
end

% Turn on state read
read_state_var=true;
end

function moveLinePTP(str)
    global iiwa;
    delimiter='_';
    C = fcn_tokenize(str,delimiter);
    for i=2:7
        pos{i-1}=str2num(C{i});
    end
    relVel=10; % velocity mm/sec
    iiwa.movePTPLineEEF(pos, relVel);
end

function moveJointsPTP(str)
    global iiwa;
    delimiter='_';
    C = fcn_tokenize(str,delimiter);
    for i=2:8
        jPos{i-1}=str2num(C{i});
    end
    relVel=0.2; % overrised velocity
    iiwa.movePTPJointSpace(jPos, relVel);
end

%% Control touch-pneumatic media flange output
function setOutputsOfMediaFlange(str)
    global iiwa;
    off={'OuputPin_11_OFF','OuputPin_12_OFF','OuputPin_1_OFF','OuputPin_2_OFF'};
    on={'OuputPin_11_ON','OuputPin_12_ON','OuputPin_1_ON','OuputPin_2_ON'};
    % pin 11
    if strncmpi(off{1},str,max(size(str)))
        iiwa.setPin11Off();
        return;
    end
    if strncmpi(on{1},str,max(size(str)))
        iiwa.setPin11On();
        return;
    end
    % pin 12
	if strncmpi(off{2},str,max(size(str)))
        iiwa.setPin12Off();
        return;
    end
    if strncmpi(on{2},str,max(size(str)))
        iiwa.setPin12On();
        return;
    end
    % pin 1
    if strncmpi(off{3},str,max(size(str)))
        iiwa.setPin1Off();
        return;
    end
    if strncmpi(on{3},str,max(size(str)))
        iiwa.setPin1On();
        return;
    end
    % pin 2
    if strncmpi(off{4},str,max(size(str)))
        iiwa.setPin2Off();
        return;
    end
    if strncmpi(on{4},str,max(size(str)))
        iiwa.setPin2On();
        return;
    end
end


function y = cvx_constant( x )
error( nargchk( 1, 1, nargin ) );
y = x;

% Copyright 2010 Michael C. Grant and Stephen P. Boyd.
% See the file COPYING.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function[answer] = isfieldRec(struct, varargin)
% [answer] = isfieldRec(struct, varargin)
%
% Check if a struct has all the fields and subfields specified by their name strings.
% I.e. to see if struct a has child b with element c, call isfieldRec(a, 'b', 'c')
%
% Copyright by Holger Caesar, 2014

answer = true;
nargs = numel(varargin);

for i = 1 : nargs,
    fieldName = varargin{i};
    if ~isfield(struct, fieldName),
        answer = false;
        return;
    elseif i < nargs,
        struct = getfield(struct, fieldName);
    end;
end;


function sammi(model, parser, data, secondaries, options)
% Visualize the given model, set of reactions, and/or data using SAMMI.
% Documentation at: https://sammim.readthedocs.io/en/latest/index.html
%
% Citation: Schultz, A., & Akbani, R. (2019). SAMMI: A Semi-Automated
%     Tool for the Visualization of Metabolic Networks. Bioinformatics.
%
% USAGE:
% sammi(model,parser,data,secondaries,options)
%
% INPUT:
%   model: COBRA model to be visualized
%
% OPTIONAL INPUTS:
%   parser: How the model is to be parsed. There are four possible
%   options for this parameter. Default empty array.
%       *empty array: If this parameter is an empty arrray, all reaction
%       in the model will be loaded in a single map. Not advisable for
%       large maps.
%       *string: If this parameter is a characters array there are two
%       options. Either the parameter defines the path to a SAMMI map (JSON
%       file downloaded from a previous instance of SAMMI), in which case
%       the given map will be used, or the parameter defines a field in the
%       model struct, in which case this field will be used to parse the
%       model into subgraphs.
%       *cell array: If this parameter is a cell array, it should be a cell
%       array of strings containing reaction IDs. Only these reactions will
%       be included in a single SAMMI map.
%       *struct: If this model is a struct of length n, the model will be
%       parsed into n subgraphs. Each element of the struct should contain
%       two fields plus an additional optional one:
%           name: Name of the subgraph.
%           rxns: Reactions to be included in the subgraph.
%           flux: Optional field. Data to be mapped as reaction color.
%   data: Data to be mapped onto the model. Struct of length n. Defaults
%   to an empty array where no data is mapped. Element of the struct should
%   contain two fields:
%       type: A cell array of two strings. The firt string should be
%       either 'rxns', 'mets', or 'links' indicating which type of data
%       is to be mapped. The second string should be either 'color' or
%       'size', indicating how the data is to  be mapped. 'links' only
%       work with 'size', since link color is the same as the one of
%       the reaction it is assciated with.
%       data: a table object. VariableNames will be translated into
%       condition names, and RowNames should be reaction IDs for 'rxns'
%       and 'links' data, and metabolite IDs for 'mets' data. NaN values
%       will not be mapped.
%   secondaries: Cell array of strings of regular expressions. All
%   metabolites, in all subgraphs, matching any of the regular expressions
%   will be shelved. Default to empty array where no metabolites are
%   shelved.
%   options: Struct with the following fields:
%       htmlName: Name of the html file to be written and opened for the
%       visualization. Defaults to 'index_load'. Change this options to
%       write to a different html file that will not be overwritten by the
%       default option.
%       load: Load the html file in a new tab upon writing the file.
%       Default to true. If you would not like a new tab to open, set
%       this parameter to false and refresh a previously opened window. To
%       open a new window without re-running SAMMI use the openSammi
%       function.
%       jscode: String. Defaults to empty string. Additional JavaScript
%       code to run after loading the map. Can be any code to modify the
%       loaded map.
%
% OUTPUT:
%   No MATLAB output. Opens a browser window with the SAMMI visualization.
%
% EXAMPLES:
%   %1 Open model in single map
%   sammi(model)
%
%   %2 Open model as multiple subgraphs divided by subSystems
%   sammi(model,'subSystems')
%
%   %3 Open model as multiple subgraphs divided by subSystems, load two
%   %conditions with randomly generated data, and shelve hydrogen, water,
%   %and O2 upon loading.
%   rxntbl = array2table(randn(length(model.rxns),2),...
%       'VariableNames', {'condition1','condition2'},...
%       'RowNames', model.rxns);
%   data(1).type = {'rxns' 'color'};
%   data(1).data = rxntbl;
%   data(2).type = {'rxns' 'size'};
%   data(2).data = rxntbl;
%   secondaries = {'^h\[.\]$','^h20\[.\]$','^o2\[.\]$'};
%   sammi(model,'subSystems',data,secondaries)

if nargin < 2
    parser = [];
end
if nargin < 3
    data = [];
end
if nargin < 4
    secondaries = [];
end
if nargin < 5 || ~isfield(options,'htmlName')
    options.htmlName = 'index_load.html';
elseif isempty(regexp(options.htmlName,'\.html$'))
    options.htmlName = [options.htmlName '.html'];
end
if nargin < 5 || ~isfield(options,'load')
    options.load = true;
end
if nargin < 5 || ~isfield(options,'jscode')
    options.jscode = '';
end

%Read in index
sfolder = regexprep(which('sammi'),'sammi.m$','');
html = fileread([sfolder 'index.html']);

%Define options
if isstruct(parser)
    jsonstr = structParse(model,parser);
elseif ischar(parser) && exist(parser,'file') == 2 && ~isempty(regexp(parser,'\.json$','ONCE'))
    %Read map
    jsonstr = fileread(parser);
    jsonstr = strrep(jsonstr,'\','\\');
    %Add graph
    jsonstr = strcat('e = ',jsonstr,';\nreceivedTextSammi(JSON.stringify(e));');
elseif ischar(parser) && isfield(model,parser)
    ss = unique(model.(parser));
    if length(model.(parser)) == length(model.rxns)
        for i = 1:length(ss)
            dat(i).name = ss{i};
            dat(i).rxns = model.rxns(ismember(model.subSystems,ss{i}));
        end
    else
        for i = 1:length(ss)
            dat(i).name = ss{i};
            dat(i).rxns = model.rxns(sum(model.S(ismember(model.(parser),ss{i}),:)) ~= 0);
        end
    end
    jsonstr = structParse(model,dat);
elseif iscell(parser) || isempty(parser)
    if iscell(parser)
        %Keep only reactions we want
        model = removeRxns(model,model.rxns(~ismember(model.rxns,parser)));
    end
    %Convert model to sammi JSON string
    jsonstr = makeSAMMIJson(model);
    %Add graph
    jsonstr = strcat('e = ',jsonstr,';\nreceivedJSONwrapper(e)');
end

%Add data
for i = 1:length(data)
    if isequal(data(i).type{1},'rxns')
        if isequal(data(i).type{2},'color')
            datastring = makeSAMMIdataString(data(i).data);
            jsonstr = strcat(jsonstr,';\ndat = ',datastring,...
                ';\nreceivedTextFlux(dat)');
        elseif isequal(data(i).type{2},'size')
            datastring = makeSAMMIdataString(data(i).data);
            jsonstr = strcat(jsonstr,';\ndat = ',datastring,...
                ';\nreceivedTextSizeRxn(dat)');
        end
    end
    if isequal(data(i).type{1},'mets')
        if isequal(data(i).type{2},'color')
            datastring = makeSAMMIdataString(data(i).data);
            jsonstr = strcat(jsonstr,';\ndat = ',datastring,...
                ';\nreceivedTextConcentration(dat)');
        elseif isequal(data(i).type{2},'size')
            datastring = makeSAMMIdataString(data(i).data);
            jsonstr = strcat(jsonstr,';\ndat = ',datastring,...
                ';\nreceivedTextSizeMet(dat)');
        end
    end
    if isequal(data(i).type{1},'links')
        if isequal(data(i).type{2},'size')
            datastring = makeSAMMIdataString(data(i).data);
            jsonstr = strcat(jsonstr,';\ndat = ',datastring,...
                ';\nreceivedTextWidth(dat)');
        end
    end
end

%Shelve secondaries
if ~isempty(secondaries)
    secondaries = strrep(secondaries,'\','\\\\');
    jsonstr = strcat(jsonstr,';\nshelveList("(?:',strjoin(secondaries,')|(?:'),')");');
end

%Add last bit of code
jsonstr = strcat(jsonstr,';',options.jscode);

%Replace in html
html = strrep(html,'//MATLAB_CODE_HERE//',jsonstr);

%Account for speial characters
html = strrep(html,'%','%%');

%Write to file
fid = fopen([sfolder options.htmlName],'w');
fprintf(fid,html);
fclose(fid);

%Open window
if options.load
    web([sfolder options.htmlName],'-browser')
end
end

function jsonstr = structParse(model,parser)
    %Get only reactions we are using
    rx = {};
    for i = 1:length(parser); rx = unique(cat(1,rx,parser(i).rxns)); end
    model = removeRxns(model,model.rxns(~ismember(model.rxns,rx)));
    %Convert model to sammi JSON file
    jsonstr = makeSAMMIJson(model);
    %Add graph
    jsonstr = strcat('graph = ',jsonstr);
    %Make conversion vector
    convvec = makeSAMMIparseVector(parser);
    %Add parssing line
    jsonstr = strcat(jsonstr,';\ne = ',convvec,';\nfilterWrapper(e)');
end


function [tp_score,fp_score,totalPos,tp_points,fp_points,tp_idxs,fp_idxs,fp_dist,missing_recall] = computeTFP(dist,score,points,rectidxs_gt,rect_ignore,thresh_gt)

if (nargin < 5)
    rect_ignore = cell(length(dist),1);
end

if (nargin < 6)
    thresh_gt = 0.5;
end

assert(length(rectidxs_gt) == length(dist));

N = sum(cellfun('length',score));
fp_score = nan(N,1);
tp_score = nan(N,1);

fp_points = nan(N,2);
tp_points = nan(N,2);

fp_idxs = nan(N,1);
tp_idxs = nan(N,1);

fp_dist = nan(N,1);
missing_recall = cell(length(dist),1);

last_fpidx = 0;
last_tpidx = 0;
totalPos = 0;
nskipped = 0;

for imgidx = 1:length(dist)

%     if (imgidx == 212)
%         fprintf('blabla\n');
%     end
    assert(size(dist{imgidx},1) == size(score{imgidx},1));

    [minDist,minIdx] = min(dist{imgidx},[],2);
    match_gt = minDist <= thresh_gt;

    tp_img = nan(1,size(dist{imgidx},2));
    tp_score_img = -inf(1,size(dist{imgidx},2));

    fp_img = find(match_gt == 0);

    % exclude fp on not annotated people
    idxs_ignore = false(length(fp_img),1);
    if (~isempty(rect_ignore{imgidx}))
        for i=1:size(rect_ignore{imgidx},1)
            r = rect_ignore{imgidx}(i,:);
            condX1 = points{imgidx}(fp_img,1) >= repmat(r(1),length(fp_img),1);
            condX2 = points{imgidx}(fp_img,1) <= repmat(r(3),length(fp_img),1);
            condY1 = points{imgidx}(fp_img,2) >= repmat(r(2),length(fp_img),1);
            condY2 = points{imgidx}(fp_img,2) <= repmat(r(4),length(fp_img),1);
            s = condX1 + condX2 + condY1 + condY2;
            idxs_ignore(s == 4) = true;
        end
    end
    fp_img(idxs_ignore) = [];

    fp_score_img = score{imgidx}(fp_img);

    matchidx = find(match_gt == 1);

    nskipped_img = 0;
    for ridx = matchidx'

        % ignore tp w.r.t other rectangles
        if (ismember(minIdx(ridx),rectidxs_gt{imgidx}))

            if (isinf(tp_score_img(minIdx(ridx))))
                tp_img(minIdx(ridx)) = ridx;
                tp_score_img(minIdx(ridx)) = score{imgidx}(ridx);
            elseif (tp_score_img(minIdx(ridx)) < score{imgidx}(ridx))
                fp_img = [fp_img; tp_img(minIdx(ridx))];
                fp_score_img = [fp_score_img; tp_score_img(minIdx(ridx))];
                tp_img(minIdx(ridx)) = ridx;
                tp_score_img(minIdx(ridx)) = score{imgidx}(ridx);
            else
                fp_img = [fp_img; ridx];
                fp_score_img = [fp_score_img; score{imgidx}(ridx)];
            end
        else
            nskipped_img = nskipped_img + 1;
%             fprintf('not a member!\n');
        end
    end % rectangles

    % rectangles with the part which is not present in the image
    idxs_absent = find(sum(isnan(dist{imgidx}),1) == size(dist{imgidx},1));

    % relevant rectangles with present body part
    idxs_present = setdiff(rectidxs_gt{imgidx},idxs_absent);
%     idxs_present = rectidxs_gt{imgidx};
    totalPos = totalPos + length(idxs_present);

    idxs = find(isinf(tp_score_img));
    tp_score_img(idxs) = [];
    tp_img(idxs) = [];

    % relevant not found rectangles
    missing_recall{imgidx} = intersect(idxs,idxs_present);

    assert(length(tp_img) + length(fp_img) + nskipped_img + sum(idxs_ignore) == length(match_gt));

    idxsNaN = find(isnan(fp_score_img));
    if (~isempty(idxsNaN))
        fp_img(idxsNaN) = [];
        fp_score_img(idxsNaN) = [];
    end
    tp_score(last_tpidx+1:last_tpidx+length(tp_img)) = tp_score_img;
    fp_score(last_fpidx+1:last_fpidx+length(fp_img)) = fp_score_img;
    tp_points(last_tpidx+1:last_tpidx+length(tp_img),:) = points{imgidx}(tp_img,:);
    fp_points(last_fpidx+1:last_fpidx+length(fp_img),:) = points{imgidx}(fp_img,:);
    tp_idxs(last_tpidx+1:last_tpidx+length(tp_img)) = imgidx;
    fp_idxs(last_fpidx+1:last_fpidx+length(fp_img)) = imgidx;
    fp_dist(last_fpidx+1:last_fpidx+length(fp_img)) = minDist(fp_img);

    last_tpidx = last_tpidx+length(tp_img);
    last_fpidx = last_fpidx+length(fp_img);

    nskipped = nskipped + nskipped_img;
end

idxs = find(isnan(tp_score));
tp_score(idxs) = [];
tp_points(idxs,:) = [];
tp_idxs(idxs) = [];

idxs = find(isnan(fp_score));
fp_score(idxs) = [];
fp_points(idxs,:) = [];
fp_idxs(idxs) = [];
fp_dist(idxs) = [];

% assert(length(tp_score) + length(fp_score) + nskipped == N);

end


function display(SO3F,varargin)
% standard output

if check_option(varargin,'skipHeader')
  disp('  function handle component');
else
  displayClass(SO3F,inputname(1),[],'moreInfo',symChar(SO3F),varargin{:});
  if numel(SO3F) > 1, disp(['  size: ' size2str(SO3F)]); end
end

if SO3F.antipodal, disp('  antipodal: true'); end

% The computation may be to slow , For example:
% F = SO3FunHandle(@(rot) calcTaylor(inv(orientation(rot,cs))*eps,sS.symmetrise)
% try
%   m = mean(SO3F,'resolution',5*degree);
%   disp(['  weight: ' xnum2str(m(1))])
% end
disp(' ')

end


function spm_defaults
% Set the defaults which are used by SPM
%__________________________________________________________________________
%
% If you want to customise some defaults for your installation, do not
% modify this file directly, but create a file named spm_my_defaults.m
% instead, accessible from MATLAB search path; e.g., it can be saved in
% MATLAB Startup Folder: userhome/Documents/MATLAB.
%
% Example: create the following file to change the image file extension:
% ----------- file /home/karl/Documents/MATLAB/spm_my_defaults.m -----------
% global defaults
% defaults.images.format = 'img';
%--------------------------------------------------------------------------
%
% spm_defaults should not be called directly in any script or function
% (apart from SPM internals).
% To load the defaults, use spm('Defaults',modality).
% To get/set the defaults, use spm_get_defaults.
%
%                 ** This file should not be edited **
%__________________________________________________________________________
% Copyright (C) 1994-2018 Wellcome Trust Centre for Neuroimaging

% SPM
% $Id: spm_defaults.m 7503 2018-12-03 12:20:12Z guillaume $

global defaults

% Command Line Usage default
%==========================================================================
defaults.cmdline  = 0;

% User Interface defaults
%==========================================================================
defaults.ui.monitor = NaN;
defaults.ui.colour  = [0.58 0.77 0.57];
defaults.ui.fs      = 14;  % unused
defaults.ui.print   = 'ps';
defaults.renderer   = 'opengl';

% File format specific
%==========================================================================
% Note that defaults.analyze.flip is no longer used.  Specifying the
% left/right handedness of the voxel indices is now done entirely by
% spm_flip_analyze_images.m
defaults.images.format  = 'nii'; % options: 'img', 'nii'
defaults.mat.format     = '-v6'; % options: '-mat', '-v6', '-v7.0', '-v7.3'

% Toolboxes defaults
%==========================================================================
defaults.tbx.dir = { fullfile(spm('Dir'),'toolbox') };

% DICOM Import defaults
%==========================================================================
defaults.dicom.root = 'flat'; % Folder hierarchy

% fMRI design defaults
%==========================================================================
defaults.stats.fmri.t   = 16;
defaults.stats.fmri.t0  = 8;
defaults.stats.fmri.hpf = 128;
defaults.stats.fmri.cvi = 'AR(1)';
defaults.stats.fmri.hrf = [6 16 1 1 6 0 32];

% Mask defaults
%==========================================================================
defaults.mask.thresh    = 0.8;

% Stats defaults
%==========================================================================
defaults.stats.maxmem      = 2^30;
defaults.stats.maxres      = 64;
defaults.stats.resmem      = false;
defaults.stats.fmri.ufp    = 0.001;  % Upper tail F-probability
defaults.stats.pet.ufp     = 0.05;
defaults.stats.eeg.ufp     = 0.05;
defaults.stats.topoFDR     = 1;
defaults.stats.rft.nonstat = 0;
defaults.stats.results.volume.distmin =  8;
defaults.stats.results.volume.nbmax   =  3;
defaults.stats.results.svc.distmin    =  4;
defaults.stats.results.svc.nbmax      = 16;
defaults.stats.results.mipmat         = {fullfile(spm('dir'),'MIP.mat')};

% Filename prefix defaults
%==========================================================================
defaults.slicetiming.prefix           = 'a';
defaults.realign.write.prefix         = 'r';
defaults.coreg.write.prefix           = 'r';
defaults.unwarp.write.prefix          = 'u';
defaults.normalise.write.prefix       = 'w';
defaults.deformations.modulate.prefix = 'm';
defaults.smooth.prefix                = 's';
defaults.imcalc.prefix                = 'i';

% Realignment defaults
%==========================================================================
defaults.realign.estimate.quality = 0.9;
defaults.realign.estimate.interp  = 2;
defaults.realign.estimate.wrap    = [0 0 0];
defaults.realign.estimate.sep     = 4;
defaults.realign.estimate.fwhm    = 5;
defaults.realign.estimate.rtm     = 1;
defaults.realign.write.mask       = 1;
defaults.realign.write.interp     = 4;
defaults.realign.write.wrap       = [0 0 0];
defaults.realign.write.which      = [2 1];

% Unwarp defaults
%==========================================================================
defaults.unwarp.estimate.rtm      = 0;
defaults.unwarp.estimate.fwhm     = 4;
defaults.unwarp.estimate.basfcn   = [12 12];
defaults.unwarp.estimate.regorder = 1;
defaults.unwarp.estimate.regwgt   = 1e5;
defaults.unwarp.estimate.foe      = [4 5];
defaults.unwarp.estimate.soe      = [];
defaults.unwarp.estimate.rem      = 1;
defaults.unwarp.estimate.jm       = 0;
defaults.unwarp.estimate.noi      = 5;
defaults.unwarp.estimate.expround = 'Average';
%
% Unwarp uses defaults.realign.write defaults for writing.
%

% Coregistration defaults
%==========================================================================
defaults.coreg.estimate.cost_fun = 'nmi';
defaults.coreg.estimate.sep      = [4 2];
defaults.coreg.estimate.tol      = [0.02 0.02 0.02 0.001 0.001 0.001 0.01 0.01 0.01 0.001 0.001 0.001];
defaults.coreg.estimate.fwhm     = [7 7];
defaults.coreg.write.interp      = 4;
defaults.coreg.write.wrap        = [0 0 0];
defaults.coreg.write.mask        = 0;

% Spatial Normalisation defaults
%==========================================================================
defaults.normalise.write.preserve   = 0;
defaults.normalise.write.bb         = [[-78 -112 -70];[78 76 85]];
defaults.normalise.write.vox        = [2 2 2];
defaults.normalise.write.interp     = 4;

% Old Spatial Normalisation defaults
%==========================================================================
defaults.old.normalise.estimate.smosrc  = 8;
defaults.old.normalise.estimate.smoref  = 0;
defaults.old.normalise.estimate.regtype = 'mni';
defaults.old.normalise.estimate.weight  = '';
defaults.old.normalise.estimate.cutoff  = 25;
defaults.old.normalise.estimate.nits    = 16;
defaults.old.normalise.estimate.reg     = 1;
defaults.old.normalise.write.preserve   = 0;
defaults.old.normalise.write.bb         = [[-78 -112 -70];[78 76 85]];
defaults.old.normalise.write.vox        = [2 2 2];
defaults.old.normalise.write.interp     = 1;
defaults.old.normalise.write.wrap       = [0 0 0];
defaults.old.normalise.write.prefix     = 'w';

% VBM Preprocessing defaults
%==========================================================================
defaults.old.preproc.tpm     = cellstr(char(...
    fullfile(spm('Dir'),'toolbox','OldSeg','grey.nii'),...
    fullfile(spm('Dir'),'toolbox','OldSeg','white.nii'),...
    fullfile(spm('Dir'),'toolbox','OldSeg','csf.nii'))); % Prior probability maps
defaults.old.preproc.ngaus          = [2 2 2 4]'; % Gaussians per class
defaults.old.preproc.warpreg        = 1;          % Warping Regularisation
defaults.old.preproc.warpco         = 25;         % Warp Frequency Cutoff
defaults.old.preproc.biasreg        = 0.0001;     % Bias regularisation
defaults.old.preproc.biasfwhm       = 60;         % Bias FWHM
defaults.old.preproc.regtype        = 'mni';      % Affine Regularisation
defaults.old.preproc.fudge          = 5;          % Fudge factor, can not be set in batch GUI
defaults.old.preproc.samp           = 3;          % Sampling distance
defaults.old.preproc.output.GM      = [0 0 1];
defaults.old.preproc.output.WM      = [0 0 1];
defaults.old.preproc.output.CSF     = [0 0 0];
defaults.old.preproc.output.biascor = 1;
defaults.old.preproc.output.cleanup = 0;

% Smooth defaults
%==========================================================================
defaults.smooth.fwhm = [8 8 8];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%-Prevent users from making direct calls to spm_defaults
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
persistent runOnce
try
    if ~isdeployed && isempty(runOnce)
        d = dbstack;
        if isempty(intersect({'spm','spm_get_defaults'},{d.name}))
            fprintf(['Direct calls to spm_defauts are deprecated.\n' ...
                'Please use spm(''Defaults'',modality) ' ...
                'or spm_get_defaults instead.\n']);
            runOnce = 1;
        end
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%-Execute user-specified defaults files
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
def = defaults;
user_defaults = 'spm_my_defaults.m';
if exist(user_defaults,'file')
    if isdeployed && exist(fullfile(spm('Dir'),user_defaults),'file')
        user_defaults_file = cellstr(fullfile(spm('Dir'),user_defaults));
    else
        user_defaults_file = cellstr(which(user_defaults,'-ALL'));
    end
    for i=1:numel(user_defaults_file)
        try
            spm('run', user_defaults_file{i});
        catch
            lr = lasterror;
            warning(lr.message);
        end
    end
    if spm_check_version('matlab','8.0') >= 0, my_isequaln = @isequaln;
    else my_isequaln = @isequalwithequalnans; end
    if ~my_isequaln(def,defaults)
        fprintf('Defaults settings have been modified by file(s):\n');
        for i=1:numel(user_defaults_file)
            fprintf('  %s\n',user_defaults_file{i});
        end
        fn0 = fieldnames(def);
        mf = fn0(~cellfun(@(x) my_isequaln(def.(x),defaults.(x)),fn0));
        if ~isempty(mf)
            fprintf('Modified fields: ');
            for i=1:numel(mf)
                fprintf('%s ',mf{i});
            end
            fprintf('\n');
        end
    end
end


function aedat = ImportAedatDataVersion1or2(aedat)
%{
Code contributions from Gemma Taverni.

This is a sub-function of importAedat - it process the data where the aedat
file format is determined to be 1 or 2.
The .aedat file format is documented here:
http://inilabs.com/support/software/fileformat/
This function is based on a combination of the loadaerdat function and
sensor-specific address interpretation functions.
There is a single input "info", a structure with the following
fields:
	- beginningOfDataPointer - Points to the byte before the beginning of the
		data
	- fileHandle - handle of the open aedat file in question
	- fileFormat - indicates the version of the aedat file format - should
		be either 1 or 2
	- startTime (optional) - if provided, any data with a timeStamp lower
		than this will not be returned.
	- endTime (optional) - if provided, any data with a timeStamp higher than
		this time will not be returned.
	- startEvent (optional) Any events with a lower count that this will not be returned.
		APS samples, if present, are counted as events.
	- endEvent (optional) Any events with a higher count that this will not be returned.
		APS samples, if present, are counted as events.
	- source - a string containing the name of the chip class from
		which the data came. Options are:
		- dvs128
		- davis240a
		- davis240b
		- davis240c
		- davis128mono
		- davis128rgb
		- davis208rgbw
		- davis208mono
		- davis346rgb
		- davis346mono
		- davis346bsi
		- davis640rgb
		- davis640mono
		- hdavis640mono
		- hdavis640rgbw
		- das1
		'file' and 'network' origins are not acceptable - the chip class is
		necessary for the interpretation of the addresses in address-events.
	- dataTypes (optional) cellarray. If present, only data types specified
		in this cell array are returned. Options are:
		special; polarity; frame; imu6; imu9; sample; ear; config.
	- subtractResetRead - optional, only for aedat2 and DAVIS -

The output is a structure with 2 fields.
	- info - the input structure, embelished with other data
	- data a structure which contains one structure for each type of
		data present. These structures are named according to the type of
		data; the options are:
		- special
		- polarity
		- frame
		- imu6
		- sample
		- ear
		Other data types supported in aedat3.0 are not implemented
		because no chip class currently implements them.
		Within each of these structures, there are typically a set of column
			vectors containing timeStamp, a valid bit and then other data fields,
			where each vector has the same number of elements.
			There are some exceptionss to this.
			In detail the contents of these structures are:
		- special
			- valid (colvector bool)
			- timeStamp (colvector uint32)
			- address (colvector uint32)
		- polarity
			- valid (colvector bool)
			- timeStamp (colvector uint32)
			- x (colvector uint16)
			- y (colvector uint16)
			- polarity (colvector bool)
		- frame
			- valid (bool)
			- frame timeStamp start ???
			- frame timeStamp end ???
			- timeStampExposureStart (uint32)
			- timeStampExposureEnd (uint32)
			- samples (matrix of uint16 r*c, where r is the number of rows and c is
				the number of columns.)
			- xStart (only present if the frame doesn't start from x=0)
			- yStart (only present if the frame doesn't start from y=0)
			- roiId (only present if this frame has an ROI identifier)
			- colChannelId (optional, if its not present, assume a mono array)
		- imu6
			- valid (colvector bool)
			- timeStamp (colvector uint32)
			- accelX (colvector single)
			- accelY (colvector single)
			- accelZ (colvector single)
			- gyroX (colvector single)
			- gyroY (colvector single)
			- gyroZ (colvector single)
			- temperature (colvector single)
		- sample
			- valid (colvector bool)
			- timeStamp (colvector uint32)
			- sampleType (colvector uint8)
			- sample (colvector uint32)
		- ear
			- valid (colvector bool)
			- timeStamp (colvector uint32)
			- position (colvector uint8)
			- channel (colvector uint16)
			- neuron (colvector uint8)
			- filter (colvector uint8)

Implementation: There is an efficient implementation of startEvent and
EndEvent, since the correct file locations to read from can be determined
in advance.
However, the implementation of startTime and endTime is not efficient, since
the file is read and then the timestamps are processed.
It is not possible to do better than this, since a binary search through
the file to find the correct file locations in advance could fail due to
non-monotonic timestamps.
%}

dbstop if error

info = aedat.info;
importParams = aedat.importParams;

% The fileFormat dictates whether there are 6 or 8 bytes per event.
if info.fileFormat == 1
	numBytesPerAddress = 2;
	numBytesPerEvent = 6;
	addrPrecision = 'uint16';
else
	numBytesPerAddress = 4;
	numBytesPerEvent = 8;
	addrPrecision = 'uint32';
end

fileHandle = aedat.importParams.fileHandle;

% Go to the EOF to find out how long it is
fseek(fileHandle, 0, 'eof');

% Calculate the number of events
info.numEventsInFile = floor((ftell(fileHandle) - info.beginningOfDataPointer) / numBytesPerEvent);

% Check the startEvent and endEvent parameters
if isfield(importParams, 'startEvent')
    startEvent = importParams.startEvent;
else
    startEvent = 1;
end
if startEvent > info.numEventsInFile
	error([	'The file contains ' num2str(info.numEventsInFile) ...
			'; the startEvent parameter is ' num2str(startEvent) ]);
end
if isfield(importParams, 'endEvent')
	endEvent = importParams.endEvent;
else
	endEvent = info.numEventsInFile;
end

if endEvent > info.numEventsInFile
	disp([	'The file contains ' num2str(info.numEventsInFile) ...
			'; the endEvent parameter is ' num2str(endEvents) ...
			'; reducing the endEvent parameter accordingly.']);
		endEvent = info.numEventsInFile;
end
if startEvent >= endEvent
	error([	'The startEvent parameter is ' num2str(startEvent) ...
		', but the endEvent parameter is ' num2str(endEvent) ]);
end

if isfield(importParams, 'startPacket')
	error('The startPacket parameter is set, but range by packets is not available for .aedat version < 3 files')
end
if isfield(importParams, 'endPacket')
	error('The endPacket parameter is set, but range by events is not available for .aedat version < 3 files')
end

numEventsToRead = endEvent - startEvent + 1;

% Read addresses
disp('Reading addresses ...')
fseek(fileHandle, info.beginningOfDataPointer + numBytesPerEvent * startEvent, 'bof');
allAddr = uint32(fread(fileHandle, numEventsToRead, addrPrecision, 4, 'b'));

% Read timestamps
disp('Reading timestamps ...')
fseek(fileHandle, info.beginningOfDataPointer + numBytesPerEvent * startEvent + numBytesPerAddress, 'bof');
allTs = uint32(fread(fileHandle, numEventsToRead, addrPrecision, numBytesPerAddress, 'b'));

% Trim events outside time window
% This is an inefficent implementation, which allows for
% non-monotonic timestamps.

if isfield(importParams, 'startTime')
    disp('Trimming to start time ...')
	tempIndex = allTs >= startTime * 1e6;
	allAddr = allAddr(tempIndex);
	allTs	= allTs(tempIndex);
end

if isfield(importParams, 'endTime')
    disp('Trimming to end time ...')
	tempIndex = allTs <= endTime * 1e6;
	allAddr = allAddr(tempIndex);
	allTs	= allTs(tempIndex);
end

% Interpret the addresses
%{
- Split between DVS/DAVIS and DAS.
	For DAS1:
		- Special events - external injected events has never been
		implemented for DAS
		- Split between Address events and ADC samples
		- Intepret address events
		- Interpret ADC samples
	For DVS128:
		- Special events - external injected events are on bit 15 = 1;
		there is a more general label for special events which is bit 31 =
		1, but this has ambiguous interpretations; it is also overloaded
		for the stereo pair encoding - ignore this.
		- Intepret address events
	For DAVIS:
		- Special events
			- Interpret IMU events from special events
		- Interpret DVS events according to chip class
		- Interpret APS events according to chip class
%}

% Declare function for finding specific event types in eventTypes cell array
cellFind = @(string)(@(cellContents)(strcmpi(string, cellContents)));

% Create structure to put all the data in
data = struct;

%% DAS1

if strcmp(info.source, 'Das1')
	% DAS1
	sampleMask = hex2dec('1000');
	sampleLogical = bitand(allAddr, sampleMask);
	earLogical = ~sampleLogical;
	if (~isfield(importParams, 'dataTypes') || any(cellfun(cellFind('ear'), importParams.dataTypes))) && any(sampleLogical)
		% ADC Samples
		data.sample.timeStamp = allTs(sampleLogical);
		% Sample type
		sampleTypeMask = hex2dec('1c00'); % take ADC scanner sync and ADC channel together for this value - kludge - the alternative would be to introduce a special event type to represent the scanner wrapping around
		sampleTypeShiftBits = 10;
		data.sample.sampleType = uint8(bitshift(bitand(allAddr(sampleLogical), sampleTypeMask), -sampleTypeShiftBits));
		% Sample data
		sampleDataMask = hex2dec('3FF'); % take ADC scanner sync and ADC channel together for this value - kludge - the alternative would be to introduce a special event type to represent the scanner wrapping around
		data.sample.sample = uint32(bitand(allAddr(sampleLogical), sampleTypeMask));
	end
	if (~isfield(importParams, 'dataTypes') || any(cellfun(cellFind('ear'), importParams.dataTypes))) && any(earLogical)
		% EAR events
		data.ear.timeStamp = allTs(earLogical);
		% Filter (0 = BPF, 1 = SOS)
		filterMask     = hex2dec('0001');
		data.ear.filter = uint8(bitand(allAddr, filterMask));
		% Position (0 = left; 1 = right)
		positionMask   = hex2dec('0002');
		positionShiftBits = 1;
		data.ear.position = uint8(bitshift(bitand(allAddr, positionMask), -positionShiftBits));
		% Channel (0 (high freq) to 63 (low freq))
		channelMask = hex2dec('00FC');
		channelShiftBits = 2;
		data.ear.channel = uint16(bitshift(bitand(allAddr, channelMask), -channelShiftBits));
		% Neuron (in the range 0-3)
		neuronMask  = hex2dec('0300');
		neuronShiftBits = 8;
		data.ear.neuron = uint8(bitshift(bitand(allAddr, neuronMask), -neuronShiftBits));
    end

%% DVS128

elseif strcmp(info.source, 'Dvs128')
	% DVS128
	specialMask = hex2dec ('8000');
	specialLogical = boolean(bitand(allAddr, specialMask));
	polarityLogical = ~specialLogical;
	if (~isfield(importParams, 'dataTypes') || any(cellfun(cellFind('special'), importParams.dataTypes))) && any(specialLogical)
		% Special events
		data.special.timeStamp = allTs(specialLogical);
		% No need to create address field, since there is only one type of special event
	end
	if (~isfield(importParams, 'dataTypes') || any(cellfun(cellFind('polarity'), importParams.dataTypes))) && any(polarityLogical)
		% Polarity events
		data.polarity.timeStamp = allTs(polarityLogical); % Use the negation of the special mask for polarity events
		% Y addresses
		yMask = hex2dec('7F00');
		yShiftBits = 8;
		data.polarity.y = uint16(bitshift(bitand(allAddr(polarityLogical), yMask), -yShiftBits));
		% X addresses
		xMask = hex2dec('fE');
		xShiftBits = 1;
		data.polarity.x = uint16(bitshift(bitand(allAddr(polarityLogical), xMask), -xShiftBits));
		% Polarity bit
		polBit = 1;
		data.polarity.polarity = bitget(allAddr(polarityLogical), polBit) == 0;
    end

%% Davis

elseif (~isempty(strfind(info.source, 'Davis')) ...
        && strfind(info.source, 'Davis')) ...
       || (~isempty(strfind(info.source, 'SecDvs')) ...
           &&strfind(info.source, 'SecDvs'))
	% DAVIS
	% In the 32-bit address:
	% bit 32 (1-based) being 1 indicates an APS sample
	% bit 11 (1-based) being 1 indicates a special event
	% bits 11 and 32 (1-based) both being zero signals a polarity event
    disp('Constructing logical indices for event types ...')
	apsOrImuMask = hex2dec ('80000000');
	apsOrImuLogical = bitand(allAddr, apsOrImuMask);
	ImuOrPolarityMask = hex2dec ('800');
	ImuOrPolarityLogical = bitand(allAddr, ImuOrPolarityMask);
	signalOrSpecialMask = hex2dec ('400');
	signalOrSpecialLogical = bitand(allAddr, signalOrSpecialMask);
	frameLogical = apsOrImuLogical & ~ImuOrPolarityLogical;
	imuLogical = apsOrImuLogical & ImuOrPolarityLogical;
	polarityLogical = ~apsOrImuLogical & ~signalOrSpecialLogical;
	specialLogical = ~apsOrImuLogical & signalOrSpecialLogical;

	% These masks are used for both frames and polarity events, so are
	% defined outside of the following if statement
	yMask = hex2dec('7FC00000');
	yShiftBits = 22;
	xMask = hex2dec('003FF000');
	xShiftBits = 12;

%% Davis special events

	% Special events
	if (~isfield(importParams, 'dataTypes') || any(cellfun(cellFind('special'), importParams.dataTypes))) && any(specialLogical)
		disp('Importing special events ...')
        data.special.timeStamp = allTs(specialLogical);
		% No need to create address field, since there is only one type of special event
    end

%% Davis polarity events

	% Polarity (DVS) events
	if (~isfield(importParams, 'dataTypes') || any(cellfun(cellFind('polarity'), importParams.dataTypes))) && any(polarityLogical)
		disp('Importing polarity events ...')
		data.polarity.timeStamp = allTs(polarityLogical);
		% Y addresses
		data.polarity.y = uint16(bitshift(bitand(allAddr(polarityLogical), yMask), -yShiftBits));
		% X addresses
		data.polarity.x = uint16(bitshift(bitand(allAddr(polarityLogical), xMask), -xShiftBits));
		% Polarity bit
		polBit = 12;
		data.polarity.polarity = bitget(allAddr(polarityLogical), polBit) == 1;
	end

%% Davis frame events

	% NOTE This code currently only handles global shutter readout ...

	if (~isfield(importParams, 'dataTypes') || any(cellfun(cellFind('frame'), importParams.dataTypes))) && any(frameLogical)
		disp('Importing frames ...')
		% These two are defined in the format, but not actually necessary to establish the frame boundaries
		% frameLastEventMask = hex2dec ('FFFFFC00');
		% frameLastEvent = hex2dec     ('80000000'); %starts with biggest address

		frameSampleMask = bin2dec('1111111111');

		frameData = allAddr(frameLogical);
		frameTs = allTs(frameLogical);

		frameX = uint16(bitshift(bitand(frameData, xMask),-xShiftBits));
		frameY = uint16(bitshift(bitand(frameData, yMask),-yShiftBits));
		frameSignal = logical(bitand(frameData, signalOrSpecialMask));
		frameSample = uint16(bitand(frameData, frameSampleMask));

		% In general the ramp of address values could be in either
		% direction and either x or y could be the outer(inner) loop
		% Search for a discontinuity in both x and y simultaneously
		frameXDouble = double(frameX);
		frameYDouble = double(frameY);
		frameXDiscont = abs(frameXDouble(2 : end) - frameXDouble(1 : end - 1)) > 1;
		frameYDiscont = abs(frameYDouble(2 : end) - frameYDouble(1 : end - 1)) > 1;
		frameStarts = [1; find(frameXDiscont & frameYDiscont) + 1; length(frameData) + 1];
		% Now we have the indices of the first sample in each frame, plus
		% an additional index just beyond the end of the array
		numFrames = length(frameStarts) - 1;

		data.frame.reset = false(numFrames, 1);
		data.frame.timeStampStart = zeros(numFrames, 1, 'uint32');
		data.frame.timeStampEnd = zeros(numFrames, 1, 'uint32');
		data.frame.samples = cell(numFrames, 1);
		data.frame.xLength = zeros(numFrames, 1, 'uint16');
		data.frame.yLength = zeros(numFrames, 1, 'uint16');
		data.frame.xPosition = zeros(numFrames, 1, 'uint16');
		data.frame.yPosition = zeros(numFrames, 1, 'uint16');

		for frameIndex = 1 : numFrames
			disp(['Processing frame ' num2str(frameIndex)])
			% All within a frame should be either reset or signal. I could
			% implement a check here to see that that's true, but I haven't
			% done so; rather I just take the first value
			data.frame.reset(frameIndex) = ~frameSignal(frameStarts(frameIndex));

			% in aedat 2 format we don't have the four timestamps of aedat 3 format
			% We expect to find all the same timestamps;
			% nevertheless search for lowest and highest
			data.frame.timeStampStart(frameIndex) = min(frameTs(frameStarts(frameIndex) : frameStarts(frameIndex + 1) - 1));
			data.frame.timeStampEnd(frameIndex) = max(frameTs(frameStarts(frameIndex) : frameStarts(frameIndex + 1) - 1));

			tempXPosition = min(frameX(frameStarts(frameIndex) : frameStarts(frameIndex + 1) - 1));
			data.frame.xPosition(frameIndex) = tempXPosition;
			tempYPosition = min(frameY(frameStarts(frameIndex) : frameStarts(frameIndex + 1) - 1));
			data.frame.yPosition(frameIndex) = tempYPosition;
			data.frame.xLength(frameIndex) = max(frameX(frameStarts(frameIndex) : frameStarts(frameIndex + 1) - 1)) - data.frame.xPosition(frameIndex) + 1;
			data.frame.yLength(frameIndex) = max(frameY(frameStarts(frameIndex) : frameStarts(frameIndex + 1) - 1)) - data.frame.yPosition(frameIndex) + 1;
			% If we worked out which way the data is ramping in each
			% direction, and if we could exclude data loss, then we could
			% do some nice clean matrix transformations; but I'm just going
			% to iterate through the samples, putting them in the right
			% place in the array according to their address

			% first create a temporary array - there is no concept of
			% colour channels in aedat2
            %{
            Code before I learned about 'accumarray':
			tempSamples = zeros(data.frame.yLength(frameIndex), data.frame.xLength(frameIndex), 'uint16');
			for sampleIndex = frameStarts(frameIndex) : frameStarts(frameIndex + 1) - 1
				tempSamples(frameY(sampleIndex) - data.frame.yPosition(frameIndex) + 1, ...
							frameX(sampleIndex) - data.frame.xPosition(frameIndex) + 1) ...
							= frameSample(sampleIndex);
			end
			data.frame.samples{frameIndex} = tempSamples;
            %}
            sampleIndexRange = frameStarts(frameIndex) : frameStarts(frameIndex + 1) - 1;
            data.frame.samples{frameIndex} = accumarray(...
                [frameY(sampleIndexRange) - data.frame.yPosition(frameIndex) + 1 ...
                 frameX(sampleIndexRange) - data.frame.xPosition(frameIndex) + 1], ...
                 frameSample(sampleIndexRange), ...
                 [data.frame.yLength(frameIndex) data.frame.xLength(frameIndex)]);
		end
		% By default, subtract the reset read
		if isfield(importParams, 'subtractResetRead')
            subtractResetRead = importParams.subtractResetRead;
        else
            subtractResetRead = true;
        end
		if subtractResetRead && isfield(data.frame, 'reset')
            disp('Performing frame subtraction ...')
			% Make a second pass through the frames, subtracting reset
			% reads from signal reads
			frameCount = 0;
			for frameIndex = 1 : numFrames
				if data.frame.reset(frameIndex)
					resetFrame = data.frame.samples{frameIndex};
					resetXPosition = data.frame.xPosition(frameIndex);
					resetYPosition = data.frame.yPosition(frameIndex);
					resetXLength = data.frame.xLength(frameIndex);
					resetYLength = data.frame.yLength(frameIndex);
				else
					frameCount = frameCount + 1;
					% If a resetFrame has not yet been found,
					% push through the signal frame as is
					if ~exist('resetFrame', 'var')
						data.frame.samples{frameCount} ...
							= data.frame.samples{frameIndex};
					else
						% If the resetFrame and signalFrame are not the same size,
						% don't attempt subtraction
						% (there is probably a cleaner solution than this - could be improved)
						if resetXPosition ~= data.frame.xPosition(frameIndex) ...
							|| resetYPosition ~= data.frame.yPosition(frameIndex) ...
							|| resetXLength ~= data.frame.xLength(frameIndex) ...
							|| resetYLength ~= data.frame.yLength(frameIndex)
							data.frame.samples{frameCount} ...
								= data.frame.samples{frameIndex};
						else
							% Do the subtraction
							data.frame.samples{frameCount} ...
								= resetFrame - data.frame.samples{frameIndex};
                                			% This operation was on unsigned integers, set negatives to zero
                                			data.frame.samples{frameCount}(data.frame.samples{frameCount} > 32767) = 0;

						end
						% Copy over the rest of the info
						data.frame.xPosition(frameCount) = data.frame.xPosition(frameIndex);
						data.frame.yPosition(frameCount) = data.frame.yPosition(frameIndex);
						data.frame.xLength(frameCount) = data.frame.xLength(frameIndex);
						data.frame.yLength(frameCount) = data.frame.yLength(frameIndex);
						data.frame.timeStampStart(frameCount) = data.frame.timeStampStart(frameIndex);
						data.frame.timeStampEnd(frameCount) = data.frame.timeStampEnd(frameIndex);
					end
				end
			end
			% Clip the arrays
			data.frame.xPosition = data.frame.xPosition(1 : frameCount);
			data.frame.yPosition = data.frame.yPosition(1 : frameCount);
			data.frame.xLength = data.frame.xLength(1 : frameCount);
			data.frame.yLength = data.frame.yLength(1 : frameCount);
			data.frame.timeStampStart = data.frame.timeStampStart(1 : frameCount);
			data.frame.timeStampEnd = data.frame.timeStampEnd(1 : frameCount);
			data.frame.samples = data.frame.samples(1 : frameCount);
			data.frame = rmfield(data.frame, 'reset'); % reset is no longer needed
		end
	end
%% Davis IMU events

		% These come in blocks of 7, for the 7 different values produced in
		% a single sample; the following code recomposes these
		% 7 words are sent in series, these being 3 axes for accel, temperature, and 3 axes for gyro
	if (~isfield(importParams, 'dataTypes') || any(cellfun(cellFind('imu6'), importParams.dataTypes))) && any(imuLogical)
		disp('Importing imu6 events ...')
		if mod(nnz(imuLogical), 7) > 0
			%error('The number of IMU samples is not divisible by 7, so IMU samples are not interpretable')
            % There's a problem here, but chop off the last words and hope
            % for the best ...
		end
		data.imu6.timeStamp = allTs(imuLogical);
		data.imu6.timeStamp = data.imu6.timeStamp(1 : 7 : end - mod(nnz(imuLogical), 7));

		%Conversion factors
		accelScale = 1/8192;
		gyroScale = 1/65.5;
		temperatureScale = 1/340;
		temperatureOffset=35;

		imuDataMask = hex2dec('0FFFF000');
		imuDataShiftBits = 12;
        rawData = bitshift(bitand(allAddr(imuLogical), imuDataMask), -imuDataShiftBits);
        % Now RawData is uint32, but the data is a signed int in the ls 16 bits.
		rawData = uint16(rawData); % Now any negative indicators are in the MSB
        rawData = typecast(rawData, 'int16'); % Now the same numbers are interpretted as negatives
        rawData = double(rawData);
        % Now the data is floating point, ready for conversion to physical units

		data.imu6.accelX			= rawData(1 : 7 : end - mod(nnz(imuLogical), 7)) * accelScale;
		data.imu6.accelY			= rawData(2 : 7 : end - mod(nnz(imuLogical), 7)) * accelScale;
		data.imu6.accelZ			= rawData(3 : 7 : end - mod(nnz(imuLogical), 7)) * accelScale;
		data.imu6.temperature	= rawData(4 : 7 : end - mod(nnz(imuLogical), 7)) * temperatureScale + temperatureOffset;
		data.imu6.gyroX			= rawData(5 : 7 : end - mod(nnz(imuLogical), 7)) * gyroScale;
		data.imu6.gyroY			= rawData(6 : 7 : end - mod(nnz(imuLogical), 7)) * gyroScale;
		data.imu6.gyroZ			= rawData(7 : 7 : end - mod(nnz(imuLogical), 7)) * gyroScale;

	end

	% If you want to do chip-specific address shifts or subtractions,
	% this would be the place to do it.

elseif strfind(info.source, 'SecDvs')
	if (~isfield(importParams, 'dataTypes') || any(cellfun(cellFind('polarity'), importParams.dataTypes)))

		data.polarity.timeStamp = allTs;
		% Y addresses
		yMask = hex2dec('ff800');
		yShiftBits = 11;
		data.polarity.y = uint16(bitshift(bitand(allAddr, yMask), -yShiftBits));
		% X addresses
		xMask = hex2dec('7fe');
		xShiftBits = 1;
		data.polarity.x = uint16(bitshift(bitand(allAddr, xMask), -xShiftBits));
		% Polarity bit
		polBit = 1;
		data.polarity.polarity = bitget(allAddr, polBit) == 1;
    end
end

%% Pack data

% aedat.importParams is already there and should be unchanged
aedat.info = info;
aedat.data = data;

%% Find first and last time stamps

aedat = FindFirstAndLastTimeStamps(aedat);

%% Add NumEvents field for each data type

aedat = NumEventsByType(aedat);

disp('Import finished')


% The COBRAToolbox: testFEA.m
%
% Purpose:
%     - testFEA tests the Flux Enrichemnt Analysis
%     function
%
% Author:
%     - Marouen BEN GUEBILA 09/02/2017

global CBTDIR

%Test requirements
requiredToolboxes = {'bioinformatics_toolbox','statistics_toolbox'};
prepareTest('toolboxes',requiredToolboxes);

% save the current path
currentDir = pwd;

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

% load the model and reference data
load('testDataFEA.mat');
model = getDistributedModel('ecoli_core_model.mat');

% run FEA
resultCellFtest = FEA(model, 1:10, 'subSystems');

% assert equality of test results and reference data
assert(isequal(resultCellFtest, resultCellF));

% check when the groups argument is not a string
try
    resultCellFtest = FEA(1:10, model, 0);
catch ME
    assert(length(ME.message) > 0)
end

% check less than 3 input arguments
try
    resultCellFtest = FEA(model, 1:10);
catch ME
    assert(length(ME.message) > 0)
end

% check when the rxnSet is not a vector
try
    resultCellFtest = FEA(model, [1:10; 1:10], 'subSystems');
catch ME
    assert(length(ME.message) > 0)
end

% change the directory
cd(currentDir)


function [response] = plotly(varargin)
% plotly - create a graph in your plotly account
%   [response] = plotly(x1,y1,x2,y2,..., kwargs)
%   [response] = plotly({data1, data2, ...}, kwargs)
%       x1,y1 - arrays
%       data1 - a data struct with styling information
%       kwargs - an optional argument struct
%
% See also plotlylayout, plotlystyle, signin, signup
%
% For full documentation and examples, see https://plot.ly/api
origin = 'plot';
if isstruct(varargin{end})
    structargs = varargin{end};
    f = lower(fieldnames(structargs));
    if ~any(strcmp('filename',f))
        structargs.filename = NaN;
    end
    if ~any(strcmp('fileopt',f))
        structargs.fileopt = NaN;
    end
    args = varargin(1:(end-1));
else
    structargs = struct('filename', NaN,'fileopt',NaN);
    args = varargin(1:end);
end

response = makecall(args, origin, structargs);

end


function varargout = mesh(varargin)
%MESH   3-D mesh surface of a CHEBFUN2.
%   MESH is not supported for CHEBFUN2 objects, and so returns an error.
%
% See also SURF.

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

[varargout{1:nargout}] = mesh@separableApprox(varargin{:});

end


function m = uplus(k)
%  kronMatrix/uplus
%
%     +k = k
%

m = k;


function v = vec(a)

v = a(:);


  function fatrix2_check_dim1(x, dim)
%|function fatrix2_check_dim1(x, dim)
%|
%| check that array x has dimensions "dim"
%| account for the "trailing 1" of size() for 1d column vectors

if nargin < 2, ir_usage, end

siz = size(x);
if numel(siz) == numel(dim) + 1 && siz(end) == 1
	siz = siz(1:end-1);
end
if ~isequal(siz, dim)
	fail('siz "%s" vs dim "%s" mismatch', num2str(size(x)), num2str(dim))
end


function toms443_test ( )

%*****************************************************************************80
%
%% TOMS443_TEST tests the TOMS443 library.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    11 June 2014
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TOMS443_TEST\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Test the TOMS443 library.\n' );

  toms443_test01 ( );
  toms443_test02 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TOMS433_TEST\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


function configPolytopeSimplifier()
path = fileparts(mfilename('fullpath'));
addpath(fullfile(path, '..'));
config;

loadModular('CMatrix');


% std_precomp() - Precompute measures (ERP, spectrum, ERSP, ITC) for channels in a
%                 study. If channels are interpolated before computing the measures,
%                 the updated EEG datasets are also saved to disk. Called by
%                 pop_precomp(). Follow with pop_plotstudy(). See Example below.
% Usage:
% >> [STUDY ALLEEG customRes] = std_precomp(STUDY, ALLEEG, chanorcomp, 'key', 'val', ...);
%
% Required inputs:
%   STUDY        - an EEGLAB STUDY set of loaded EEG structures
%   ALLEEG       - ALLEEG vector of one or more loaded EEG dataset structures
%   chanorcomp   - ['components'|'channels'| or channel cell array] The string
%                  'components' forces the program to precompute all selected
%                  measures for components. The string 'channels' forces the
%                  program to compute all measures for all channels.
%                  A channel cell array containing channel labels will precompute
%                  the selected measures. Note that the name of the channel is
%                  not case-sensitive.
% Optional inputs:
%  'design'   - [integer] use specific study index design to compute measure.
%  'cell'     - [integer] compute measure only for a give data file.
%  'erp'      - ['on'|'off'] pre-compute ERPs for each dataset.
%  'spec'     - ['on'|'off'] pre-compute spectrum for each dataset.
%               Use 'specparams' to set spectrum parameters.
%  'ersp'     - ['on'|'off'] pre-compute ERSP for each dataset.
%               Use 'erspparams' to set time/frequency parameters.
%  'itc'      - ['on'|'off'] pre-compute ITC for each dataset.
%               Use 'erspparams' to set time/frequency parameters.
%  'scalp'    - ['on'|'off'] pre-compute scalp maps for components.
%  'allcomps' - ['on'|'off'] compute ERSP/ITC for all components ('off'
%               only use pre-selected components in the pop_study interface).
%  'erpparams'   - [cell array] Parameters for the std_erp function. See
%                  std_erp for more information.
%  'specparams'  - [cell array] Parameters for the std_spec function. See
%                  std_spec for more information.
%  'erspparams'  - [cell array] Optional arguments for the std_ersp function.
%  'erpimparams' - [cell array] Optional argument for std_erpimage. See
%                  std_erpimage for the list of arguments.
%  'recompute'   - ['on'|'off'] force recomputing ERP file even if it is
%                  already on disk.
%  'rmicacomps'  - ['on'|'off'|'processica'] remove ICA components pre-selected in
%                  each dataset (EEGLAB menu item, "Tools > Reject data using ICA
%                  > Reject components by map). This option is ignored when
%                  precomputing measures for ICA clusters. Default is 'off'.
%                  'processica' forces to process ICA components instead of
%                  removing them.
%  'rmclust'     - [integer array] remove selected ICA component clusters.
%                  For example, ICA component clusters containing
%                  artifacts. This option is ignored when precomputing
%                  measures for ICA clusters.
%  'savetrials'  - ['on'|'off'] save single-trials ERSP. Requires a lot of disk
%                  space (dataset space on disk times 10) but allow for refined
%                  single-trial statistics.
%  'customfunc'  - [function_handle] execute a specific function on each
%                  EEGLAB dataset of the selected STUDY design. The fist
%                  argument to the function is an EEGLAB dataset. Example is
%                  @(EEG)mean(EEG.data,3)
%                  This will compute the ERP for the STUDY design. EEG is the
%                  EEGLAB dataset corresponding to each cell design. It
%                  corresponds to a dataset computed dynamically based on
%                  the design selection. If 'rmclust', 'rmicacomps' or 'interp'
%                  are being used, the channel data is affected
%                  accordingly. Anonymous and non-anonymous functions may be
%                  used. The output is returned in CustomRes or saved on
%                  disk. The output of the custom function may be an numerical
%                  array or a structure.
%  'customparams' - [cell array] Parameters for the custom function above.
%  'customfileext' - [string] file extension for saving custom data. Use
%                    function to read custom data. If left empty, the
%                    result is returned in the customRes output. Note that
%                    if the custom function does not return a structure,
%                    the data is automatically saved in a variable named
%                    'data'.
%  'customclusters' - [integer array] load only specific clusters. This is
%                    used with SIFT. chanorcomp 3rd input must be 'components'.
%
% Outputs:
%   ALLEEG       - the input ALLEEG vector of EEG dataset structures, modified
%                  by adding preprocessing data as pointers to Matlab files that
%                  hold the pre-clustering component measures.
%   STUDY        - the input STUDY set with pre-clustering data added,
%                  for use by pop_clust()
%   customRes    - cell array of custom results (one cell for each pair of
%                  independent variables as defined in the STUDY design).
%                  If a custom file extension is specified, this variable
%                  is empty as the function assumes that the result is too
%                  large to hold in memory.
%
% Example:
%   >> [STUDY ALLEEG customRes] = std_precomp(STUDY, ALLEEG, { 'cz' 'oz' }, 'interp', ...
%               'on', 'erp', 'on', 'spec', 'on', 'ersp', 'on', 'erspparams', ...
%               { 'cycles' [ 3 0.5 ], 'alpha', 0.01, 'padratio' 1 });
%
%           % This prepares, channels 'cz' and 'oz' in the STUDY datasets.
%           % If a data channel is missing in one dataset, it will be
%           % interpolated (see eeg_interp()). The ERP, spectrum, ERSP, and
%           % ITC for each dataset is then computed.
%
% Example of custom call:
%   The function below computes the ERP of the EEG data for each channel and plots it.
%   >> [STUDY ALLEEG customres] = std_precomp(STUDY, ALLEEG, 'channels', 'customfunc', @(EEG,varargin)(mean(EEG.data,3)'));
%   >> std_plotcurve([1:size(customres{1},1)], customres, 'chanlocs', eeg_mergelocs(ALLEEG.chanlocs)); % plot data
%
%   The function below uses a data file to store the information then read
%   the data and eventyally plot it
%   >> [STUDY ALLEEG customres] = std_precomp(STUDY, ALLEEG, 'channels', 'customfunc', @(EEG,varargin)(mean(EEG.data,3)), 'customfileext', 'tmperp');
%   >> erpdata = std_readcustom(STUDY, ALLEEG, 'tmperp');
%   >> std_plotcurve([1:size(erpdata{1})], erpdata, 'chanlocs', eeg_mergelocs(ALLEEG.chanlocs)); % plot data
%
% Authors: Arnaud Delorme, SCCN, INC, UCSD, 2006-

% Copyright (C) Arnaud Delorme, SCCN, INC, UCSD, 2006, arno@sccn.ucsd.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, ALLEEG customRes ] = std_precomp(STUDY, ALLEEG, chanlist, varargin)

    if nargin < 2
        help std_precomp;
        return;
    end;

    if nargin == 2
        chanlist = 'channels'; % default to clustering the whole STUDY
    end
    customRes = [];
    Ncond = length(STUDY.condition);
    if Ncond == 0
        Ncond = 1;
    end

    g = finputcheck(varargin, { 'erp'         'string'  { 'on','off' }     'off';
                                'interp'      'string'  { 'on','off' }     'off';
                                'ersp'        'string'  { 'on','off' }     'off';
                                'recompute'   'string'  { 'on','off' }     'off';
                                'spec'        'string'  { 'on','off' }     'off';
                                'erpim'       'string'  { 'on','off' }     'off';
                                'scalp'       'string'  { 'on','off' }     'off';
                                'allcomps'    'string'  { 'on','off' }     'off';
                                'itc'         'string'  { 'on','off' }     'off';
                                'savetrials'  'string'  { 'on','off' }     'off';
                                'rmicacomps'  'string'  { 'on','off','processica' }     'off';
                                'cell'        'integer' []                 [];
                                'design'      'integer' []                 STUDY.currentdesign;
                                'rmclust'     'integer' []                 [];
                                'rmbase'      'integer' []                 []; % deprecated, for backward compatibility purposes, not documented
                                'specparams'        'cell'    {}                 {};
                                'erpparams'         'cell'    {}                 {};
                                'customfunc'  {'function_handle' 'integer' } { { } {} }     [];
                                'customparams'      'cell'    {}                 {};
                                'customfileext'     'string'  []                 '';
                                'customclusters'    'integer' []                 [];
                                'erpimparams'       'cell'    {}                 {};
                                'erspparams'        'cell'    {}                 {}}, 'std_precomp');
    if isstr(g), error(g); end;
    if ~isempty(g.rmbase), g.erpparams = { g.erpparams{:} 'rmbase' g.rmbase }; end;

    % union of all channel structures
    % -------------------------------
    computewhat = 'channels';
    if isstr(chanlist)
        if strcmpi(chanlist, 'channels')
            chanlist = [];
        else % components
            computewhat = 'components';
            if strcmpi(g.allcomps, 'on')
                chanlist = {};
                for index = 1:length(STUDY.datasetinfo)
                    chanlist = { chanlist{:} [1:size(ALLEEG(STUDY.datasetinfo(index).index).icaweights,1)] };
                end;
            else
                chanlist = { STUDY.datasetinfo.comps };
            end;
        end;
    end;
    if isempty(chanlist)
        alllocs = eeg_mergelocs(ALLEEG.chanlocs);
        chanlist = { alllocs.labels };
    elseif ~isnumeric(chanlist{1})
        alllocs = eeg_mergelocs(ALLEEG.chanlocs);
        [tmp c1 c2] = intersect_bc( lower({ alllocs.labels }), lower(chanlist));
        [tmp c2] = sort(c2);
        alllocs = alllocs(c1(c2));
    end;

    % test if interp and reconstruct channel list
    % -------------------------------------------
    if strcmpi(computewhat, 'channels')
        if strcmpi(g.interp, 'on')
            STUDY.changrp = [];
            STUDY = std_changroup(STUDY, ALLEEG, chanlist, 'interp');
            g.interplocs = alllocs;
        else
            STUDY.changrp = [];
            STUDY = std_changroup(STUDY, ALLEEG, chanlist);
            g.interplocs = struct([]);
        end;
    end;

    % components or channels
    % ----------------------
    if strcmpi(computewhat, 'channels')
         curstruct = STUDY.changrp;
    else curstruct = STUDY.cluster;
    end;

    % compute custom measure
    % ----------------------
    if ~isempty(g.customfunc)
        nc = max(length(STUDY.design(g.design).variable(1).value),1);
        ng = max(length(STUDY.design(g.design).variable(2).value),1);
        allinds = curstruct(1).allinds; % same for all channels and components (see std_selectdesign)
        setinds = curstruct(1).setinds; % same for all channels and components (see std_selectdesign)
        if ~isempty(g.customclusters)
            allinds = curstruct(g.customclusters).allinds; % same for all channels and components (see std_selectdesign)
            setinds = curstruct(g.customclusters).setinds; % same for all channels and components (see std_selectdesign)
        end;

        for cInd = 1:nc
            for gInd = 1:ng
                if ~isempty(setinds{cInd,gInd})
                    desset = STUDY.design(g.design).cell(setinds{cInd,gInd}(:));
                    for iDes = 1:length(desset)
                        if strcmpi(computewhat, 'channels')
                             [tmpchanlist opts] = getchansandopts(STUDY, ALLEEG, chanlist, desset(iDes).dataset, g);
                             TMPEEG = std_getdataset(STUDY, ALLEEG, 'design', g.design, 'cell', setinds{cInd,gInd}(iDes), opts{:}); % trial indices included in cell selection
                        else TMPEEG = std_getdataset(STUDY, ALLEEG, 'design', g.design, 'cell', setinds{cInd,gInd}(iDes), 'cluster', g.customclusters);
                        end;
                        addopts = { 'savetrials', g.savetrials, 'recompute', g.recompute }; % not currently used

                        tmpData = feval(g.customfunc, TMPEEG, g.customparams{:});
                        if isempty(g.customfileext)
                            resTmp(:,:,iDes) = tmpData;
                        else
                            fileName = [ desset(iDes).filebase '.' g.customfileext ];
                            clear data;
                            data.data = tmpData;
                            data.datafile   = computeFullFileName( { ALLEEG(desset(iDes).dataset).filepath }, { ALLEEG(desset(iDes).dataset).filename });
                            data.datatrials = desset(iDes).trials;
                            data.datatype = upper(g.customfileext);
                            if ~isempty(g.customparams) data.parameters = g.customparams; end;
                            std_savedat(fileName, data);
                        end;
                    end;
                    if isempty(g.customfileext)
                        customRes{cInd,gInd} = resTmp;
                    end;
                    clear resTmp;
                end;
            end;
        end;
    end;

    % compute ERPs
    % ------------
    if strcmpi(g.erp, 'on')
        % check dataset consistency
        % -------------------------
        allPnts = [ALLEEG([STUDY.design(g.design).cell.dataset]).pnts];
        if iscell(allPnts), allPnts = [ allPnts{:} ]; end;
        if length(unique(allPnts)) > 1
            error([ 'Cannot compute ERPs because datasets' 10 'do not have the same number of data points' ])
        end;

        for index = 1:length(STUDY.design(g.design).cell)
            if ~isempty(g.cell)
                 desset = STUDY.design(g.design).cell(g.cell);
            else desset = STUDY.design(g.design).cell(index);
            end;
            addopts = { 'savetrials', g.savetrials, 'recompute', g.recompute, 'fileout', desset.filebase, 'trialindices', desset.trials };
            if strcmpi(computewhat, 'channels')
                [tmpchanlist opts] = getchansandopts(STUDY, ALLEEG, chanlist, desset.dataset, g);
                std_erp(ALLEEG(desset.dataset), 'channels', tmpchanlist, opts{:}, addopts{:}, g.erpparams{:});
            else
                if length(desset.dataset)>1 && ~isequal(chanlist{desset.dataset})
                    error(['ICA decompositions must be identical if' 10 'several datasets are concatenated to build' 10 'the design, abording' ]);
                end;
                std_erp(ALLEEG(desset.dataset), 'components', chanlist{desset.dataset(1)}, addopts{:}, g.erpparams{:});
            end;
            if ~isempty(g.cell), break; end;
        end;
        if isfield(curstruct, 'erpdata')
            curstruct = rmfield(curstruct, 'erpdata');
            curstruct = rmfield(curstruct, 'erptimes');
        end;
    end;

    % compute spectrum
    % ----------------
    if strcmpi(g.spec, 'on')
        % check dataset consistency
        % -------------------------
        for index = 1:length(STUDY.design(g.design).cell)
            if ~isempty(g.cell)
                 desset = STUDY.design(g.design).cell(g.cell);
            else desset = STUDY.design(g.design).cell(index);
            end;
            addopts = { 'savetrials', g.savetrials, 'recompute', g.recompute, 'fileout', desset.filebase, 'trialindices', desset.trials };
            if strcmpi(computewhat, 'channels')
                [tmpchanlist opts] = getchansandopts(STUDY, ALLEEG, chanlist, desset.dataset, g);
                std_spec(ALLEEG(desset.dataset), 'channels', tmpchanlist, opts{:}, addopts{:}, g.specparams{:});
            else
                if length(desset.dataset)>1 && ~isequal(chanlist{desset.dataset})
                    error(['ICA decompositions must be identical if' 10 'several datasets are concatenated to build' 10 'the design, abording' ]);
                end;
                std_spec(ALLEEG(desset.dataset), 'components', chanlist{desset.dataset(1)}, addopts{:}, g.specparams{:});
            end;
            if ~isempty(g.cell), break; end;
        end;
        if isfield(curstruct, 'specdata')
            curstruct = rmfield(curstruct, 'specdata');
            curstruct = rmfield(curstruct, 'specfreqs');
        end;
    end;

    % compute spectrum
    % ----------------
    if strcmpi(g.erpim, 'on')
        % check dataset consistency
        % -------------------------
        allPnts = [ALLEEG([STUDY.design(g.design).cell.dataset]).pnts];
        if iscell(allPnts), allPnts = [ allPnts{:} ]; end;
        if length(unique(allPnts)) > 1
            error([ 'Cannot compute ERSPs/ITCs because datasets' 10 'do not have the same number of data points' ])
        end;

        % check consistency with parameters on disk
        % -----------------------------------------
        guimode = 'guion';
        tmpparams = {};
        tmpparams = g.erpimparams;
        if strcmpi(g.recompute, 'off')
            for index = 1:length(STUDY.design(g.design).cell)
                desset = STUDY.design(g.design).cell(index);
                if strcmpi(computewhat, 'channels')
                     filename = [ desset.filebase '.daterpim'];
                else filename = [ desset.filebase '.icaerpim'];
                end;
                [guimode, g.erpimparams] = std_filecheck(filename, g.erpimparams, guimode, { 'fileout' 'recompute', 'channels', 'components', 'trialindices'});
                if strcmpi(guimode, 'cancel'), return; end;
            end;
            if strcmpi(guimode, 'usedisk') || strcmpi(guimode, 'same'), g.recompute = 'off';
            else                                                        g.recompute = 'on';
            end;
            if ~isempty(g.erpimparams) && isstruct(g.erpimparams)
                tmpparams      = fieldnames(g.erpimparams); tmpparams = tmpparams';
                tmpparams(2,:) = struct2cell(g.erpimparams);
            end;
        end;

        % set parameters in ERPimage parameters
        % -------------------------------------
        STUDY = pop_erpimparams(STUDY, tmpparams{:}); % a little trashy as the function pop_erpimparams does not check the fields

        % compute ERPimages
        % -----------------
        for index = 1:length(STUDY.design(g.design).cell)
            if ~isempty(g.cell)
                 desset = STUDY.design(g.design).cell(g.cell);
            else desset = STUDY.design(g.design).cell(index);
            end;
            addopts = { 'recompute', g.recompute, 'fileout', desset.filebase, 'trialindices', desset.trials };
            if strcmpi(computewhat, 'channels')
                [tmpchanlist opts] = getchansandopts(STUDY, ALLEEG, chanlist, desset.dataset, g);
                std_erpimage(ALLEEG(desset.dataset), 'channels', tmpchanlist, opts{:}, addopts{:}, tmpparams{:});
            else
                if length(desset.dataset)>1 && ~isequal(chanlist{desset.dataset})
                    error(['ICA decompositions must be identical if' 10 'several datasets are concatenated to build' 10 'the design, abording' ]);
                end;
                std_erpimage(ALLEEG(desset.dataset), 'components', chanlist{desset.dataset(1)}, addopts{:}, tmpparams{:});
            end;
            if ~isempty(g.cell), break; end;
        end;
        if isfield(curstruct, 'erpimdata')
            curstruct = rmfield(curstruct, 'erpimdata');
            curstruct = rmfield(curstruct, 'erpimtimes');
            curstruct = rmfield(curstruct, 'erpimtrials');
            curstruct = rmfield(curstruct, 'erpimevents');
        end;
    end;

    % compute component scalp maps
    % ----------------------------
    if strcmpi(g.scalp, 'on') && ~strcmpi(computewhat, 'channels')
        for index = 1:length(STUDY.datasetinfo)

            % find duplicate
            % --------------
            found = [];
            ind1 = STUDY.datasetinfo(index).index;
            inds = strmatch(STUDY.datasetinfo(index).subject, { STUDY.datasetinfo(1:index-1).subject });
            for index2 = 1:length(inds)
                ind2 = STUDY.datasetinfo(inds(index2)).index;
                if isequal(ALLEEG(ind1).icawinv, ALLEEG(ind2).icawinv)
                    found = ind2;
                end;
            end;

            % make link if duplicate
            % ----------------------
            if ~isempty(g.cell)
                desset = STUDY.design(g.design).cell(g.cell);
                [path,tmp] = fileparts(desset.filebase);
            else path = ALLEEG(index).filepath;
            end;

            fprintf('Computing/checking topo file for dataset %d\n', ind1);
            if ~isempty(found)
                clear tmp;
                tmpfile1 = fullfile( path, [ ALLEEG(index).filename(1:end-3) 'icatopo' ]);
                tmp.file = fullfile( ALLEEG(found).filepath, [ ALLEEG(found).filename(1:end-3) 'icatopo' ]);
                std_savedat(tmpfile1, tmp);
            else
                std_topo(ALLEEG(index), chanlist{index}, 'none', 'recompute', g.recompute,'fileout',path);
            end;
        end;
        if isfield(curstruct, 'topo')
            curstruct = rmfield(curstruct, 'topo');
            curstruct = rmfield(curstruct, 'topox');
            curstruct = rmfield(curstruct, 'topoy');
            curstruct = rmfield(curstruct, 'topoall');
            curstruct = rmfield(curstruct, 'topopol');
        end;
    end;

    % compute ERSP and ITC
    % --------------------
    if strcmpi(g.ersp, 'on') || strcmpi(g.itc, 'on')
        % check dataset consistency
        % -------------------------
        allPnts = [ALLEEG([STUDY.design(g.design).cell.dataset]).pnts];
        if iscell(allPnts), allPnts = [ allPnts{:} ]; end;
        if length(unique(allPnts)) > 1
            error([ 'Cannot compute ERSPs/ITCs because datasets' 10 'do not have the same number of data points' ])
        end;

        if strcmpi(g.ersp, 'on') & strcmpi(g.itc, 'on'), type = 'both';
        elseif strcmpi(g.ersp, 'on')                   , type = 'ersp';
        else                                             type = 'itc';
        end;

        % check for existing files
        % ------------------------
        guimode = 'guion';
        [ tmpX tmpt tmpf g.erspparams ] = std_ersp(ALLEEG(1), 'channels', 1, 'type', type, 'recompute', 'on', 'getparams', 'on', 'savetrials', g.savetrials, g.erspparams{:});
        if strcmpi(g.recompute, 'off')
            for index = 1:length(STUDY.design(g.design).cell)
                desset = STUDY.design(g.design).cell(index);
                if strcmpi(computewhat, 'channels')
                     filename = [ desset.filebase '.datersp'];
                else filename = [ desset.filebase '.icaersp'];
                end;
                [guimode, g.erspparams] = std_filecheck(filename, g.erspparams, guimode, { 'plotitc' 'plotersp' 'plotphase' });
                if strcmpi(guimode, 'cancel'), return; end;
            end;
            if strcmpi(guimode, 'usedisk') || strcmpi(guimode, 'same'), g.recompute = 'off';
            else                                                        g.recompute = 'on';
            end;
        end;

        % check for existing files
        % ------------------------
        if isempty(g.erspparams),
            tmpparams = {};
        elseif iscell(g.erspparams),
            tmpparams = g.erspparams;
        else
            tmpparams      = fieldnames(g.erspparams); tmpparams = tmpparams';
            tmpparams(2,:) = struct2cell(g.erspparams);
        end;
        tmpparams = { tmpparams{:} 'recompute' g.recompute };
        for index = 1:length(STUDY.design(g.design).cell)
            if ~isempty(g.cell)
                 desset = STUDY.design(g.design).cell(g.cell);
            else desset = STUDY.design(g.design).cell(index);
            end;
            if strcmpi(computewhat, 'channels')
                [tmpchanlist opts] = getchansandopts(STUDY, ALLEEG, chanlist, desset.dataset, g);
                std_ersp(ALLEEG(desset.dataset), 'channels', tmpchanlist, 'type', type, 'fileout', desset.filebase, 'trialindices', desset.trials, opts{:}, tmpparams{:});
            else
                if length(desset.dataset)>1 && ~isequal(chanlist{desset.dataset})
                    error(['ICA decompositions must be identical if' 10 'several datasets are concatenated to build' 10 'the design, abording' ]);
                end;
                std_ersp(ALLEEG(desset.dataset), 'components', chanlist{desset.dataset(1)}, 'type', type, 'fileout', desset.filebase, 'trialindices', desset.trials, tmpparams{:});
            end;
            if ~isempty(g.cell), break; end;
        end;
        if isfield(curstruct, 'erspdata')
            curstruct = rmfield(curstruct, 'erspdata');
            curstruct = rmfield(curstruct, 'ersptimes');
            curstruct = rmfield(curstruct, 'erspfreqs');
        end;
        if isfield(curstruct, 'itcdata')
            curstruct = rmfield(curstruct, 'itcdata');
            curstruct = rmfield(curstruct, 'itctimes');
            curstruct = rmfield(curstruct, 'itcfreqs');
        end;
    end;

    % components or channels
    % ----------------------
    if strcmpi(computewhat, 'channels')
         STUDY.changrp = curstruct;
    else STUDY.cluster = curstruct;
    end;

    return;

    % find components in cluster for specific dataset
    % -----------------------------------------------
    function rmcomps = getclustcomps(STUDY, rmclust, settmpind);

        rmcomps   = cell(1,length(settmpind));
        for idat = 1:length(settmpind) % scan dataset for which to find component clusters
            for rmi = 1:length(rmclust) % scan clusters
                comps = STUDY.cluster(rmclust(rmi)).comps;
                sets  = STUDY.cluster(rmclust(rmi)).sets;
                indmatch = find(sets(:) == settmpind(idat));
                indmatch = ceil(indmatch/size(sets,1)); % get the column number
                rmcomps{idat} = [rmcomps{idat} comps(indmatch(:)') ];
            end;
            rmcomps{idat} = sort(rmcomps{idat});
        end;

    % make option array and channel list (which depend on interp) for any type of measure
    % ----------------------------------------------------------------------
    function [tmpchanlist, opts] = getchansandopts(STUDY, ALLEEG, chanlist, idat, g);

        opts = { };

        if ~isempty(g.rmclust) || strcmpi(g.rmicacomps, 'on') || strcmpi(g.rmicacomps, 'processica')
            rmcomps = cell(1,length(idat));
            if ~isempty(g.rmclust)
                rmcomps = getclustcomps(STUDY, g.rmclust, idat);
            end;
            if strcmpi(g.rmicacomps, 'on')
                for ind = 1:length(idat)
                    rmcomps{ind} = union_bc(rmcomps{ind}, find(ALLEEG(idat(ind)).reject.gcompreject));
                end;
            elseif strcmpi(g.rmicacomps, 'processica')
                for ind = 1:length(idat)
                    rmcomps{ind} = union_bc(rmcomps{ind}, find(~ALLEEG(idat(ind)).reject.gcompreject));
                end;
            end;
            opts = { opts{:} 'rmcomps' rmcomps };
        end;
        if strcmpi(g.interp, 'on')
            tmpchanlist = chanlist;
            allocs = eeg_mergelocs(ALLEEG.chanlocs);
            [tmp1 tmp2 neworder] = intersect_bc( {allocs.labels}, chanlist);
            [tmp1 ordertmp2] = sort(tmp2);
            neworder = neworder(ordertmp2);
            opts = { opts{:} 'interp' allocs(neworder) };
        else
            newchanlist = [];
            tmpchanlocs = ALLEEG(idat(1)).chanlocs;
            chanlocs = { tmpchanlocs.labels };
            for i=1:length(chanlist)
                newchanlist = [ newchanlist strmatch(chanlist{i}, chanlocs, 'exact') ];
            end;
            tmpchanlocs =  ALLEEG(idat(1)).chanlocs;
            tmpchanlist = { tmpchanlocs(newchanlist).labels };
        end;

    % compute full file names
    % -----------------------
    function res = computeFullFileName(filePaths, fileNames);
        for index = 1:length(fileNames)
            res{index} = fullfile(filePaths{index}, fileNames{index});
        end;