function vw = drawROIsMontage(vw)
%
% vw = drawROIsMontage(vw)
%
% Draw the ROIs on a montage view (e.g. several
% flat levels / inplane slices at once).
%
% This function should be called only if
% vw.showROIs is non-zero.  If showROIs=1, draw only the
% selected ROI.  If showROIs=2, draw all the ROIs.
% 09/04 ras, off drawROIs.

% clear line handles for all ROIs (ras 06/06, see selectROI)
for r=1:length(vw.ROIs), vw.ROIs(r).lineHandles = []; end

% set line width parameter
w = 0.5;

s = vw.selectedROI;
n = length(vw.ROIs);

%%%%% get order of ROIs to display
if s
    order = [1:s-1,s+1:n,s];
else
    order = 1:n;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Main loop: draw ROIs according to prefs  %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for r = order   % loop through ROIs that are selected for display
    if (r==vw.selectedROI)
        % Selected ROI: now a settable param, ras 05/05
        coords = vw.ROIs(r).coords;
        color = viewGet(vw,'selRoiColor');
    else
        % Non-selected ROI, color from ROIs substruct
        % If showROIs~=2, then set coords=[] so that nothing will be
        % drawn.
        if (vw.ui.showROIs==-2)
            coords = vw.ROIs(r).coords;
        else
            coords = [];
        end
        thisCol=vw.ROIs(r).color;
        % If it's a 'text' color, translate it...
        if (ischar(thisCol))
        nColEntries=length(thisCol);

        for thisColEntry=1:nColEntries
            thisColValue=thisCol(thisColEntry);
            colRGB=[0 0 0];
            switch (thisColValue)
                case 'y', colorRGB = colRGB+[1 1 0];
                case 'm', colorRGB = colRGB+[1 0 1];
                case 'c', colorRGB = colRGB+[0 1 1];
                case 'r', colorRGB = colRGB+[1 0 0];
                case 'g', colorRGB = colRGB+[0 1 0];
                case 'b', colorRGB = colRGB+[0 0 1];
                case 'w', colorRGB = colRGB+[1 1 1];
                case 'k', colorRGB = colRGB+[0 0 0];
                otherwise, colorRGB = [1 1 1];
            end % end switch statement
        end % end loop
            color=colorRGB./nColEntries;
        else
            color=thisCol;
        end

    end

    % Draw the lines around each pixel, w=1/2 because you don't
    % want to connect the centers of the pixels, rather you want to
    % draw around each pixel, e.g, from (x-.5,y-.5) to (x+.5,y-.5).
    if ~isempty(coords)

        % The FLAT view can have a 'rotateImageDegrees' field that
        % specifies a rotation angle for L and R.
        % If this is set, then we have to transform the ROIs by this amount as
        % well to make them register with the anatomy and functional data
        if (strcmp(vw.viewType,'Flat'))
            coords=rotateCoords(vw,coords);
        end

        % convert to coordinates of the montage image
        coords = coords2Montage(vw,coords);
        x = coords(1,:);
        y = coords(2,:);

        % draw boxes around the voxels
        hold on

        % if the view is set to flip the image, then we need to
        % flip the ROI too
        if viewGet(vw, 'flip up down'),
            height = size(vw.ui.image, 1);
            x = height - x + 1;
        end

        for i=1:size(coords,2);
            l(i) = line([y(i)-w, y(i)+w, y(i)+w, y(i)-w, y(i)-w],...
                        [x(i)-w, x(i)-w, x(i)+w, x(i)+w, x(i)-w], ...
                        'Color',color);
        end
        hold off

%         % remember line handles for quick refreshing
%         vw.ROIs(r).lineHandles = l;
    end
end

return;


%DEFINE_MAPPING Define untrained or fixed mapping
%
%   W = DEFINE_MAPPING(ARGIN,TYPE,NAME,PAR)
%
% INPUT
%   ARGIN   - Cell array with arguments of calling routine
%   TYPE    - Mapping type, 'fixed', 'untrained (default)' or 'combiner'
%   NAME    - Name of the mapping, default name of calling routine
%   PAR     - Additional parameters for the name of the mapping
%
% OUTPUT
%   W       - Mapping
%
% DESCRIPTION
% This routine fascilitates the definition of untrained, fixed and
% combiners in order to make the definition of mappings more readable.
%
% SEE ALSO (PRTools Guide)
% MAPPINGS, PRMAPPING, TRAINED_CLASSIFIER, TRAINED_MAPPING, MAPPING_TASK

% Copyright: Robert P.W. Duin, prtools@rduin.nl

function w = define_mapping(varargin)

[pars,type,mapname] = setdefaults(varargin,[],'untrained',[]);
fname = callername;
if isempty(mapname)
  mapname = fname;
end
if (length(varargin)>3)
   mapname = sprintf(mapname,varargin{4:end});
end
if numel(pars) < 2
  w = prmapping(fname,type);
else
  w = prmapping(fname,type,pars(2:end));
end
w = setname(w,mapname);
return

%CALLERNAME
%
%	NAME = CALLERNAME
%
% Returns the name the calling function

function name = callername

[ss ,i] = dbstack;
if length(ss) < 3
	name = [];
else
	name = ss(3).name;
end


%kmscalar_sub 'Scalar Subtract: Output = Input Matrix - Constant'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros mscalar_sub.pane file
%
% Parameters:
% InputFile: i1 'Input Matrix', required: 'Input matrix'
% OutputFile: o 'Output ', required: 'Output matrix'
%
% Example: o = kmscalar_sub(i1, {'i1','';'o',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% mscalar_sub - Output = Input Matrix - Constant
%
%  DESCRIPTION
% .I mscalar_sub
% subtracts a specified constant from each component in a matrix.
% "mscalar_sub\fR is really a pane object that uses the \fIkarith2\fR operator
% in the DATAMANIP toolbox to actually perform the operation, so the man page for
% "karith2\fR should be consulted for additional details regarding the treatment
% of maps, masks, etc.
%
%
%
%  EXAMPLES
%
%  "SEE ALSO"
% DATAMANIP::karith2(1)  DATAMANIP::ksub(1)
%
%  RESTRICTIONS
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993 - 1997, Khoral Research, Inc. ("KRI")  All rights reserved.
%

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

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


function epo= proc_appendEpochs(epo1, epo2)
%PROC_APPENDEPOCHS - appends two or more structs of epoched data.
%
%Synopsis:
% EPO= proc_appendEpochs(EPO1, EPO2)
% EPO= proc_appendEpochs(EPOCELL)
%
%Arguments:
% EPOCELL         - cell array of epoched data
% EPO1, EPO2      - epoched data to be appended
%
%Returns:
% EPO             - appended epoched data
%
%Description:
% Appends the epochs of 'EPO2' to 'EPO1' (or appends all epochs of ERPCELL)
%
% SEE  proc_segmentation, mrk_mergerMarkers, proc_appendCnt,
%      proc_appendChannels

%epo1 = misc_history(epo1);

misc_checkType(epo1, 'STRUCT(x clab)|CELL{STRUCT}');
misc_checkTypeIfExists('epo2', 'STRUCT(x clab)');

if iscell(epo1),
  Cepo= epo1;
  epo1= Cepo{1};
  for ii= 2:length(Cepo),
    epo1= proc_appendEpochs(epo1, Cepo{ii});
  end
  epo=epo1;
  return
end

if isempty(epo1),
  epo= epo2;
  return;
elseif isempty(epo2),
  epo= epo1;
  return;
end

% begin sthf
if isfield(epo1, 'ndims')
  ndim = max(3, epo1.ndims);
else
  ndim = max(3, ndims(epo1.x));
end

if size(epo1.x,ndim-2)~=size(epo2.x,ndim-2),
  error('interval length mismatch');
end
if size(epo1.x,ndim-1)~=size(epo2.x,ndim-1),
  error('number of channels mismatch');
end
if ( ndim == 4 ) && ( size(epo1.x,ndim-3)~=size(epo2.x,ndim-3) ),
  error('number of frequencies mismatch');
end

epo= mrkutil_appendMarkersExcludingTime(epo1, epo2);
epo.x= cat(ndim, epo1.x, epo2.x);

% We could add functionality to struct_areFieldsEqual to return as second
% argument, which fields do not match. Then we could give here a more
% precise warning.
if ~struct_areFieldsEqual(epo1, epo2, {'fs','clab', 't'})
  warning('epochs are inconsistent wrt ''fs'', ''clab'', or ''t''.');
end
epo= struct_copyFields(epo, epo1, {'fs','clab','t'});

further_fields= {'xUnit', 'yUnit'};
for Fld= further_fields,
  if ~struct_areFieldsEqual(epo1, epo2, Fld)
    warning(sprintf('epochs are inconsistent wrt ''%s''.', Fld{1}));
  end
  epo= struct_copyFields(epo, epo1, Fld);
end

if isfield(epo1, 'mrk_info') && isfield(epo2, 'mrk_info'),
  epo.mrk_info= mrkutil_appendEventInfo(epo1.mrk_info, epo2.mrk_info);
end

% The following code should be superflutious in future
if isfield(epo1, 'p') && isfield(epo2, 'p')
  epo.p= cat(ndim, epo1.p, epo2.p);
end
if isfield(epo1, 'sgnlogp') && isfield(epo2, 'sgnlogp')
  epo.sgnlogp= cat(ndim, epo1.sgnlogp, epo2.sgnlogp);
end
if isfield(epo1, 'se') && isfield(epo2, 'se')
  epo.se= cat(ndim, epo1.se, epo2.se);
end
if isfield(epo1, 'sigmask') && isfield(epo2, 'sigmask')
  epo.sigmask= cat(ndim, epo1.sigmask, epo2.sigmask);
end
if isfield(epo1, 'crit') && isfield(epo2, 'crit')
  epo.crit= cat(1, epo1.crit, epo2.crit);
end
if isfield(epo1, 'df') && isfield(epo2, 'df')
  epo.df= cat(1, epo1.df, epo2.df);
end


function theTable = SQL_Add(addWhat,inputFile,forDatabase,beVocal)
% SQL_Add   Interpret a structured input file of time series, operations,
%           or master operations.
%
% By default adds the results to a linked mySQL database.
%
%---INPUTS:
% addWhat: 'mops' (for master operations), 'ops' (for operations), or 'ts'
%             (for time series)
% inputFile: the filename of the tab-delimited textfile to be read in [default
%            = INP_ts.txt or INP_ops.txt or INP_mops.txt]
%            The input file should be formatted with whitespace as a delimiter
%            between the entries to import.
% forDatabase: if true (default) write the results of interpreting the input file
%               to the default linked mySQL database for hctsa.
% beVocal: if true (default) gives user feedback on the input process.

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

% ------------------------------------------------------------------------------
%% Check inputs, set defaults:
% ------------------------------------------------------------------------------

% addWhat: 'ts', 'mops', or 'ops'
if nargin < 1 || isempty(addWhat) || ~ismember(addWhat,{'ops','ts','mops'})
    error(['Error setting first input argument -- should be ''ts'' for TimeSeries ' ...
                ', ''ops'' for Operations, or ''mops'' for Master Operations']);
end

% inputFile
if nargin < 2 || isempty(inputFile)
    % Default filenames:
    switch inputFile
    case 'ts'
        inputFile = 'INP_ts.txt';
    case 'ops'
        inputFile = 'INP_ops.txt';
    case 'mops'
        inputFile = 'INP_mops.txt';
    end
end
if ~exist(inputFile,'file')
    error('Unknown file ''%s''',inputFile);
end

if nargin < 3 || isempty(forDatabase)
    forDatabase = false;
end
if nargin < 4
    beVocal = true; % Give user feedback by default:
end

% ------------------------------------------------------------------------------
% Display welcome message:
% ------------------------------------------------------------------------------
if beVocal
    fprintf(1,'Using input file: %s.\n',inputFile);
end
ticker = tic;

% ------------------------------------------------------------------------------
%% Open database connection
% ------------------------------------------------------------------------------
if forDatabase
    [dbc,databaseName] = SQL_OpenDatabase();
end

% ------------------------------------------------------------------------------
% Define strings to unify the different strands of code for time series /
% operations
% ------------------------------------------------------------------------------
switch addWhat
    case 'ts'
        % Check that the time series table exists in the database:
        theWhat = 'time series';
        theid = 'ts_id';
        thekid = 'tskw_id';
        theTable = 'TimeSeries';
        theKeywordTable = 'TimeSeriesKeywords';
        theRelTable = 'TsKeywordsRelate';
        maxL = 50000; % the longest time series length accepted in the database
    case 'ops'
        theWhat = 'operations';
        theid = 'op_id';
        thekid = 'opkw_id';
        theTable = 'Operations';
        theKeywordTable = 'OperationKeywords';
        theRelTable = 'OpKeywordsRelate';
    case 'mops'
        theWhat = 'master operations';
        theid = 'mop_id';
        theTable = 'MasterOperations';
end

% ------------------------------------------------------------------------------
% Check that the table exists in the datbase
% ------------------------------------------------------------------------------
if forDatabase
    existString = ['SHOW TABLES LIKE ''' theTable ''''];
    [output,emsg] = mysql_dbquery(dbc,existString);
    if isempty(output) % Table doesn't exist
        error(['Table %s doesn''t exist in the database %s.\n' ...
                    'Use: (1) install.m to set the database system up from scratch,\n' ...
                    '(2) SQL_CreateAllTables to create empty tables that can later be filled with custom libraries of operations,\n' ...
                    '(3) SQL_Reset to drop all tables in the database, and repopulate all tables with the default library of operations.'],...
                    theTable,databaseName);
    end
end

% ------------------------------------------------------------------------------
%% Open and read the input file
% ------------------------------------------------------------------------------

% Determine if input is a .mat file or an input text file based on filename extension:
if strcmp(inputFile(end-3:end),'.mat');
    isMatFile = true;
else
    isMatFile = false;
end

if ~isMatFile
    % Specified a input text file
    fid = fopen(inputFile);
    if (fid==-1)
        error('Could not load the specified input text file ''%s''',inputFile)
    end
    switch addWhat
    case 'ts' % Read the time series input file:
        if beVocal
            fprintf(1,['Need to format %s (Time Series input file) as: Name ' ...
                                                                'Keywords\n'],inputFile);
            fprintf(1,'Assuming no header line\n');
            fprintf(1,'Use whitespace as a delimiter and \\n for new lines...\n');
            fprintf(1,'(Be careful that no additional whitespace is in any fields...)\n');
        end
        formatSpec = '%s%s';
    case 'ops' % Read the operations input file:
        if beVocal
            fprintf(1,['Need to format %s (Operations input file) as: OperationCode ' ...
                                            'OperationName OperationKeywords\n'],inputFile);
            fprintf(1,'Assuming no header lines\n');
            fprintf(1,'Use whitespace as a delimiter and \\n for new lines...\n');
            fprintf(1,'(Be careful that no additional whitespace is in any fields...)\n');
        end
        formatSpec = '%s%s%s';
    case 'mops' % Read the master operations input file:
        if beVocal
            fprintf(1,'Need to format %s (Master Operations input file) as: MasterCode MasterLabel\n',inputFile);
            fprintf(1,'Assuming no header lines\n');
            fprintf(1,'Use whitespace as a delimiter and \\n for new lines...\n');
            fprintf(1,'(Be careful that no additional whitespace is in any fields...)\n');
        end
        formatSpec = '%s%s';
    end
    dataIn = textscan(fid,formatSpec,'CommentStyle','#','EndOfLine','\r\n','CollectOutput',true);
    fclose(fid);

    % ------------------------------------------------------------------------------
    % Show the user what's been imported:
    % ------------------------------------------------------------------------------
    dataIn = dataIn{1}; % Collect one big matrix of cells
    numItems = size(dataIn,1); % Number of items in the input file

    if numItems == 0
        error('The input file ''%s'' seems to be empty??',inputFile)
    end

    if beVocal
        fprintf(1,'Found %u %s in %s, I think. Take a look:\n\n',numItems,theWhat,inputFile);
        switch addWhat
        case 'ts'
            fprintf(1,'%s\t%s\n','-Name-','-Keywords-');
            fprint_ts = @(x)fprintf('%s\t%s\n',dataIn{x,1},dataIn{x,2});
        case 'ops'
            fprintf(1,'%s\t%s\t%s\n','-Operation Name-','-Master Label-','-Operation Keywords-');
            fprint_ops = @(x) fprintf('%s\t%s\t%s\n',dataIn{x,1},dataIn{x,2},dataIn{x,3});
        case 'mops'
            fprintf(1,'%s\t%s\n','-Master Code-','-Master Label-');
            fprint_mops = @(x) fprintf('%s\t%s\n',dataIn{x,1},dataIn{x,2});
        end

        for i = 1:min(3,numItems)
            switch addWhat
            case 'ts', fprint_ts(i);
            case 'ops', fprint_ops(i);
            case 'mops', fprint_mops(i);
            end
        end

        if numItems > 3
            fprintf(1,'..................(%u).....................\n',max(numItems-6,0));
            for i = max(numItems-2,4):numItems
                switch addWhat
                case 'ts', fprint_ts(i);
                case 'ops', fprint_ops(i);
                case 'mops', fprint_mops(i);
                end
            end
        end

        fprintf(1,'\nHow does it look? Make sure the metadata matches the headings\n');

        % Ask the question:
        if strcmp(addWhat,'ts')
            if forDatabase
                reply = input(['If we go on, we will attempt to read all time series ' ...
                            'from file and add all ' ...
                            'data to the database.\n<<<Type ''y'' to continue...>>> '],'s');
            else
                reply = input(['If we go on, we will attempt to read all time series ' ...
                            'from file and add all ' ...
                            'data to HCTSA.mat\n<<<Type ''y'' to continue...>>> '],'s');
            end
        else
            if forDatabase
                reply = input(['If we go on, we will attempt to add all ' ...
                            'data to the database.\n<<<Type ''y'' to continue...>>> '],'s');
            else
                reply = input(['If we go on, we will attempt to add all ' ...
                            'data to HCTSA.mat\n<<<Type ''y'' to continue...>>> '],'s');
            end
        end

        if ~strcmp(reply,'y')
            fprintf(1,'I didn''t think so. Come back later...\n');
            return
        end
    end

    if beVocal
        fprintf(1,'%s read.\n',inputFile);
    end

else
    % .mat file input is only allowed when importing time series
    if ~strcmp(addWhat,'ts')
        error(['.mat file input type only supported for importing time series. ' ...
                'Please specify a text file for importing master operations or operations.']);
    end

    % Load the 3 cells specifying the data:
    if ~exist(inputFile,'file')
        error('Could not load specified input .mat file: %s',inputFile);
    end
    inputData = load(inputFile,'timeSeriesData','labels','keywords');

    % Check that they're all as they should be:
    if ~isfield(inputData,'timeSeriesData') || ~isfield(inputData,'labels') || ~isfield(inputData,'keywords') ...
                || ~(iscell(inputData.timeSeriesData) || isnumeric(inputData.timeSeriesData)) ...
                || ~iscell(inputData.labels) || ~iscell(inputData.keywords)
        error(['Incorrectly formatted input file, %s\nExpecting input file to ' ...
                    'contain: ''timeSeriesData'' (cell or matrix), ' ...
                    '''labels'' (cell), and ''keywords'' (cell).'],inputFile);
    end

    % Get number of time series (as numItems):
    if iscell(inputData.timeSeriesData)
        numItems = length(inputData.timeSeriesData);
    else
        % Specified a matrix of time-series data
        numItems = size(inputData.timeSeriesData,1);
    end
    if beVocal
        fprintf(1,['We have %u time series (rows) in your data matrix, timeSeriesData ' ...
                                    '(loaded from %s).\n'],numItems,inputFile);
        if forDatabase
            fprintf(1,['Will store time-series data from matlab file in the database to an' ...
                        ' accuracy of 6 significant figures...\n']);
        end
    end

    % Check sizes match:
    if length(inputData.labels) ~= numItems || length(inputData.keywords) ~= numItems
        fprintf(1,'%u time series, %u labels, %u keywords in %s.\n',numItems,...
                    length(inputData.labels),length(inputData.keywords),inputFile);
        error('All cells in the input file %s must be the same length.',inputFile);
    end

    % Plot some to screen
    if beVocal
        plotNum = min(5,numItems); % display as many as the first 5 time series to demonstrate
        figure('color','w','WindowStyle','docked');
        for j = 1:plotNum
            subplot(plotNum,1,j);
            if iscell(inputData.timeSeriesData)
                plot(inputData.timeSeriesData{j},'k');
            else
                plot(inputData.timeSeriesData(j,:),'k');
            end
            title(sprintf('[%u/%u] %s (%s)',j,numItems,inputData.labels{j},inputData.keywords{j}),'interpreter','none')
            if j==plotNum
                xlabel('Time (samples)')
            end
            drawnow
        end

        if forDatabase
            reply = input(sprintf(['Does this look ok for the first %u time series?\nIf we continue, ' ...
                'we will attempt to add all %u time series in the input file' ...
                ' to the database.\n<<<Type ''y'' to continue...>>> '],plotNum,numItems),'s');
        else
            reply = input(sprintf(['Does this look ok for the first %u time series?\n' ...
                                    '<<<Type ''y'' to continue...>>> '],plotNum),'s');
        end
        if ~strcmp(reply,'y')
            fprintf(1,'I didn''t think so. Come back later...\n');
            return
        end
        close
    end

    % Ok, so we have inputData.timeSeriesData, inputData.labels, and inputData.keywords
end

% ------------------------------------------------------------------------------
% Construct a table of metadta for the time series / operations /
% master operations and fill a cell, toAdd, containing mySQL INSERT commands for
% each item in the input file.
% ------------------------------------------------------------------------------
if forDatabase
    % Define an inline function to add escape strings to format mySQL queries
    if forDatabase
        esc = @RA_sqlescapestring;
        % Initialize:
        toAdd = cell(numItems,1);
    end
    if beVocal
        fprintf(1,'Preparing mySQL statements to add %u %s to the database %s...',...
                    numItems,theWhat,databaseName);
    end
end

% Prepare local IDs:
ID = (1:numItems)';

switch addWhat
case 'ts' % Prepare toAdd cell for time series
    if beVocal
        figure('color','w','WindowStyle','docked');
    end
    % Record whether data was added or not (not too long and no missing values)
    wasGood = false(1,numItems);

    % Initialize:
    Name = cell(numItems,1);
    Keywords = cell(numItems,1);
    Length = zeros(numItems,1);
    Data = cell(numItems,1);
    for j = 1:numItems
        % Assign filename and keywords strings to this time series, and load it
        if isMatFile
            Name{j} = inputData.labels{j};
            Keywords{j} = inputData.keywords{j}; % Take out inverted commas from keywords lists
            if iscell(inputData.timeSeriesData)
                Data{j} = inputData.timeSeriesData{j};
                if size(Data{j},2) > size(Data{j},1)
                    fprintf(1,'Transposing time series\n');
                    Data{j} = Data{j}';
                end
                if size(Data{j},2) ~= 1
                    error('Multivariate time-series input? Each element of timeSeriesData must be univariate');
                end
            else
                Data{j} = inputData.timeSeriesData(j,:)'; % column vector
            end
        else
            Name{j} = dataIn{j,1};
            Keywords{j} = regexprep(dataIn{j,2},'\"',''); % Take out inverted commas from keywords lists
            % Read the time series from its filename:
            try
                Data{j} = dlmread(Name{j});
            catch emsg
                fprintf(1,'%s\n',emsg.message);
                error(['\nCould not read the data file for ''%s''.',...
                        ' Check that it''s in the path.'],Name{j})
            end
        end

        % Check that label is not empty:
        if isempty(Name{j})
            warning(['\n[%u/%u] This time series is assigned an empty label' ...
                        ' and will not be added...'],j,numItems)
            beep; continue
        end

        % Assign the length of the time series
        Length(j) = length(Data{j});

        % TEST 1: Is the time series longer than the maximum allowed value?
        if Length(j) > maxL
            warning(['\n[%u/%u]%s contains %u samples, this framework can efficiently ' ...
                'deal with time series up to %u samples\n',...
                '[Note that this maximum length can be modified in SQL_Add]\n',...
                'Skipping this time series...'],...
                j,numItems,Name{j},Length(j),maxL)
            beep; continue
        end
        % TEST 2: Does the time series contains any NaN of Inf values?
        if any(isnan(Data{j})) || any(~isfinite(Data{j}))
            warning(['\n[%u/%u] The time series: ''%s'' contains special values' ...
                        ' (e.g., NaN or Inf)...\nThis time series will not be added...'], ...
                        j,numItems,Name{j})
            beep; continue
        end

        % Passed both tests! Assign wasGood = true
        wasGood(j) = true;

        % If storing in a database, need to reassign the time-series data as text
        % (which will be stored as singles in the case of a .mat file data)
        % If making for a local mat file, keep the same precision as input.
        if forDatabase
            % Want time-series data as a comma-delimited string:
            if isMatFile
                xText = sprintf('%.6g,',Data{j}); % keeps 6 figures of accuracy
                xText = xText(1:end-1); % remove trailing comma
            else
                % Read in the time series from file as strings using textscan
                fid = fopen(Name{j});
                timeSeriesData_text = textscan(fid,'%s');
                fclose(fid);
                % Turn the time series into a comma-delimited string
                timeSeriesData_text = timeSeriesData_text{1}; % cell of time series values as strings
                xText = ''; % make a comma-delimited text version of the time series as xText
                for k = 1:length(timeSeriesData_text)
                    xText = [xText,',',timeSeriesData_text{k}];
                end
                xText = xText(2:end);
            end
            Data{j} = xText;
            % Prepare the data to be added to the database in an INSERT command:
            toAdd{j} = sprintf('(''%s'',''%s'',%u,''%s'')',...
                    esc(Name{j}),esc(Keywords{j}),Length{j},Data{j});
        end

        if beVocal
            % Plot the time series
            numSubplots = min(numItems,4);
            ax = subplot(numSubplots,1,mod(j-1,numSubplots)+1);
            plot(Data{j},'-k');
            ax.XLim = [1,Length(j)];
            titleText = sprintf('[%u/%u] %s (%u), keywords = %s',j,numItems,...
                            Name{j},Length(j),Keywords{j});
            title(titleText,'interpreter','none');
            fprintf(1,'\n%s --- loaded successfully.',titleText);
            pause(5e-3); % Wait 5ms to show the plotted time series!
        end
    end

    %-------------------------------------------------------------------------------
    % All data in -> TimeSeries table
    TimeSeries = table(ID,Name,Keywords,Length,Data);

    % Check for duplicates on the name field:
    if length(unique(TimeSeries.Name)) < height(TimeSeries)
        error('Input file contains duplicate names.');
    end

    % Check whether at least some passed the quality checks
    if ~any(wasGood)
        fprintf(1,'NONE of the %u time series in the input file passed quality checks.\n',...
                                length(wasGood));
        return
    end

    if beVocal
        % Tell me about it:
        if forDatabase
            textShow = ', ready to be uploaded to the mySQL database';
        else
            textShow = '';
        end
        fprintf(1,'\nAll time-series data loaded; %u/%u passed quality tests%s.\n',...
                        sum(wasGood),length(wasGood),textShow);
        if any(~wasGood)
            input(sprintf('[List %u time series that failed... (press any key)]',sum(~wasGood)),'s');
            iNoGood = find(~wasGood);
            for i = 1:length(iNoGood)
                if ~isempty(TimeSeries.Length(iNoGood(i)))
                    lengthText = sprintf(', N = %u',TimeSeries.Length(iNoGood(i)));
                else
                    lengthText = '';
                end
                fprintf(1,'*NOT UPLOADING:* [%u] %s (%s)%s\n',iNoGood(i),...
                    TimeSeries.Name{iNoGood(i)},TimeSeries.Keywords{iNoGood(i)},...
                    lengthText);
            end
            input(sprintf('[press any key to continue to add the remaining %u time series]',...
                                                        sum(wasGood)),'s');
        end
    end

case 'mops'
    % Prepare metadata for master operations
    Code = cell(numItems,1);
    Label = cell(numItems,1);
    for j = 1:numItems
        Code{j} = dataIn{j,1};
        Label{j} = dataIn{j,2};
        if forDatabase
            toAdd{j} = sprintf('(''%s'', ''%s'')',esc(Label{j}),esc(Code{j}));
        end
    end
    % Convert to table of metadata:
    MasterOperations = table(ID,Label,Code);
    if beVocal, fprintf(1,' Done.\n'); end

case 'ops'
    % Prepare metadata table for operations
    CodeString = cell(numItems,1);
    Name = cell(numItems,1);
    Keywords = cell(numItems,1);
    Label = cell(numItems,1);
    for j = 1:numItems
        CodeString{j} = dataIn{j,1};
        Name{j} = dataIn{j,2};
        Keywords{j} = dataIn{j,3};
        Label{j} = strtok(CodeString{j},'.');
        if forDatabase
            toAdd{j} = sprintf('(''%s'', ''%s'',''%s'',''%s'')',...
                    esc(Name{j}),esc(CodeString{j}),...
                    esc(Label{j}),esc(Keywords{j}));
        end
    end
    Operations = table(ID,Name,Label,Keywords,CodeString);
    if beVocal, fprintf(1,' Done.\n'); end

    % Check for duplicates in the input file:
    [uniqueOpNames,ia] = unique(Operations.Name);
    if length(uniqueOpNames) < height(Operations)
        warning(['Input file contains %u duplicate entries, which are being removed.\n' ...
                        'Inputting %u -> %u operations...'], ...
            height(Operations)-length(uniqueOpNames),...
            height(Operations),length(uniqueOpNames));
        % Check for duplicates:
        nameTable = tabulate(Operations.Name);
        isDuplicate = find([nameTable{:,2}] > 1);
        fprintf(1,'E.g., %s is a duplicate\n',nameTable{isDuplicate(1),1});
        % Only keep the unique ones:
        Operations = Operations(ia,:);
        numItems = height(Operations);
        fprintf(1,'We now have %u operations to input...\n',numItems);
        if forDatabase
            toAdd = toAdd(ia);
        end
    end
end

% ------------------------------------------------------------------------------
% If not writing to a database, then we're done
% ------------------------------------------------------------------------------
switch addWhat
case 'ts'
    theTable = TimeSeries(wasGood,:);
    % Note that IDs are according to the original input file
case 'mops'
    theTable = MasterOperations;
case 'ops'
    theTable = Operations;
end
if ~forDatabase
    fprintf(1,'Returning a table with metadata for %u %s.\n',height(theTable),theWhat);
    return
end

%-------------------------------------------------------------------------------
% From here on is for mySQL data import:
% ------------------------------------------------------------------------------
% Check for duplicates:
if beVocal
    fprintf(1,'Checking for duplicates already in the database... ');
end
switch addWhat
case 'ts'
    existingNames = mysql_dbquery(dbc,sprintf('SELECT Name FROM TimeSeries'));
    isDuplicate = ismember(theTable.Name,existingNames);
case 'ops'
    existingOperationNames = mysql_dbquery(dbc,'SELECT Name FROM Operations');
    isDuplicate = ismember(theTable.Name,existingOperationNames);
case 'mops'
    existingMasterLabels = mysql_dbquery(dbc,'SELECT MasterLabel FROM MasterOperations');
    isDuplicate = ismember(theTable.Label,existingMasterLabels);
end
if beVocal, fprintf(1,'Done.\n'); end

% ------------------------------------------------------------------------------
% Tell the user about duplicates
% ------------------------------------------------------------------------------
if all(isDuplicate)
    fprintf(1,'All %u %s from %s already exist in %s---no new %s to add!\n',...
                    numItems,theWhat,inputFile,databaseName,theWhat);
    return
elseif sum(isDuplicate) > 0
    if beVocal
        fprintf(1,'I found %u duplicate %s already in the database %s!\n',...
                        sum(isDuplicate),theWhat,databaseName);
        fprintf(1,'There are %u new %s to add to %s.\n',...
                        sum(~isDuplicate),theWhat,databaseName);
    end
end

% ------------------------------------------------------------------------------
% Incorporate isDuplicate with wasGood
% ------------------------------------------------------------------------------
if strcmp(addWhat,'ts')
    isBad = (isDuplicate | ~wasGood);
    if all(isBad)
        fprintf(1,['All input time series either already exist in the database, ' ...
                    'or did not pass the required quality checks. Exiting.']);
        return
    end
else
    isBad = isDuplicate;
end

% ------------------------------------------------------------------------------
%% Select the maximum id already in the table
% ------------------------------------------------------------------------------
maxId = mysql_dbquery(dbc,sprintf('SELECT MAX(%s) FROM %s',theid,theTable));
if isempty(maxId) || isempty(maxId{1}) || isnan(maxId{1})
    % No time series exist in the database yet
    maxId = 0;
else
    maxId = maxId{1}; % the maximum id -- the new items will have ids greater than this
end

% ------------------------------------------------------------------------------
%% Assemble and execute the INSERT queries
% ------------------------------------------------------------------------------
fprintf('Adding %u new %s to the %s table in %s...',...
                    sum(~isBad),theWhat,theTable,databaseName)
switch addWhat
case 'ts' % Add time series to the TimeSeries table, X at a time
          % (so as not to exceed the max_allowed_packet when transmitting the
          % time-series data).
          % An appropriate chunk size will depend on the length of time series
          % in general...
          % A kind of big problem if you add some here and then fail, because
          % then there will be inconsistencies in the Results table.
          % Safer would be to initialize results as you go in case you get a
          % fail at some chunk number... :/
    maxLength = max(TimeSeries.Length);
    % 4 at a time works for 20,000 sample time series using default mySQL settings.
    % Calibrate to this:
    numPerChunk = max([floor(20000/maxLength*4),1]); % no fewer than 1 per chunk
    numPerChunk = min([numPerChunk,500]); % no more than 500 per chunk
    SQL_AddChunked(dbc,['INSERT INTO TimeSeries (Name, Keywords, Length, ' ...
                                    'Data) VALUES'],toAdd(~isBad),numPerChunk);
case 'ops' % Add operations to the Operations table 500 at a time
    SQL_AddChunked(dbc,['INSERT INTO Operations (Name, Code, MasterLabel, ' ...
                                    'Keywords) VALUES'],toAdd(~isBad),500);
case 'mops' % Add master operations to the MasterOperations table 500 at a time
    SQL_AddChunked(dbc,['INSERT INTO MasterOperations (MasterLabel, ' ...
                                'MasterCode) VALUES'],toAdd(~isBad),500);
end
fprintf(1,' Done.\n');

% ------------------------------------------------------------------------------
% Add new entries to the Results table
% ------------------------------------------------------------------------------
if ~strcmp(addWhat,'mops')
    resultsTic = tic;
    fprintf(1,'Updating the Results table in %s...(This could take a while)...',databaseName);
    if strcmp(addWhat,'ts') && height(TimeSeries) > 1000
        fprintf(1,'\n(e.g., ~10 hours for 20,000 time series with 8,000 operations---please be patient!)...')
    end
    % The following turns out to be quite slow when adding to an existing database.
    % Maybe it does the cross join before filtering on ID. So if you have a large
    % database already, it takes ages to do the cross join, only to filter out most
    % of it anyway...?
    switch addWhat
    case 'ts'
        [~,emsg] = mysql_dbexecute(dbc,sprintf(['INSERT INTO Results (ts_id,op_id) SELECT t.ts_id,o.op_id ' ...
                    'FROM TimeSeries t CROSS JOIN Operations o ON t.ts_id > %u ORDER BY t.ts_id, o.op_id'],maxId));
    case 'ops'
        [~,emsg] = mysql_dbexecute(dbc,sprintf(['INSERT INTO Results (ts_id,op_id) SELECT t.ts_id,o.op_id ' ...
                    'FROM TimeSeries t CROSS JOIN Operations o ON o.op_id > %u ORDER BY t.ts_id, o.op_id'],maxId));
    end
    if ~isempty(emsg)
        fprintf(1,' Error. This is really really not good.\n%s',emsg);
        keyboard
    else
        fprintf(1,' initialized in %s!\n',BF_TheTime(toc(resultsTic)));
    end
end

if ~strcmp(addWhat,'mops')
    % ------------------------------------------------------------------------------
    % Update the keywords table
    % ------------------------------------------------------------------------------
    fprintf(1,'Updating the %s table in %s...',theKeywordTable,databaseName);

    % First find unique keywords from new time series by splitting against commas
    switch addWhat
    case 'ts'
        kws = TimeSeries.Keywords(~isBad);
    case 'ops'
        kws = Operations.Keywords(~isBad);
    end

    % Split into each individual keyword:
    kwSplit = regexp(kws,',','split','ignorecase');
    ukws = unique(horzcat(kwSplit{:}));
    nkw = length(ukws); % The number of unique keywords in the new set of time series
    if beVocal
        fprintf(1,'\nI found %u unique keywords in the %u new %s in %s...',...
                        nkw,sum(~isBad),theWhat,inputFile);
    end

    % How many overlap with existing keywords??:
    allkws = mysql_dbquery(dbc,sprintf('SELECT Keyword FROM %s',theKeywordTable));
    if ~isempty(allkws) % the table may be empty, in which case all keywords will be new
        isNew = ~ismember(ukws,allkws);
        % cellfun(@(x)~isempty(x),regexp(ukws,allkws,'ignorecase')); % ignore case for keywords
    else
        isNew = ones(nkw,1); % All are new
    end

    if sum(isNew) > 0
        if beVocal
            fprintf(1,['\nIt turns out that %u keywords are completely new and will be added ' ...
                        'to the %s table in %s...'],sum(isNew),theKeywordTable,databaseName);
        end
        % Add the new keywords to the Keywords table
        insertString = sprintf('INSERT INTO %s (Keyword,NumOccur) VALUES',theKeywordTable);
        fisNew = find(isNew); % Indicies of new keywords
        toAdd = cell(sum(isNew),1);
        for k = 1:sum(isNew);
            toAdd{k} = sprintf('(''%s'',0)',ukws{fisNew(k)});
        end
        SQL_AddChunked(dbc,insertString,toAdd,100);
        fprintf(1,' Added %u new keywords!\n',sum(isNew));
    else
        if beVocal
            fprintf(1,['\nIt turns out that all new keywords already exist in ' ...
                    'the %s table in %s -- there are no new keywords to add\n'],...
                    theKeywordTable,databaseName);
        end
    end

    % ------------------------------------------------------------------------------
    %% Fill new keyword relationships
    % ------------------------------------------------------------------------------
    fprintf(1,'Writing new keyword relationships to the %s table in %s...', ...
                                            theRelTable,databaseName);

    % Try doing it from scratch...:
    switch addWhat
    case 'ts'
        allNames = BF_cat(TimeSeries.Name(~isBad),',','''');
    case 'ops'
        allNames = BF_cat(Operations.Name(~isBad),',','''');
    end

    % ourids: ids matching time series or operations
    ourids = mysql_dbquery(dbc,sprintf('SELECT %s FROM %s WHERE Name IN (%s)',theid, ...
                                                        theTable,allNames));
    ourids = vertcat(ourids{:});

    % ourkids: kw_ids matching keywords
    ourkids = mysql_dbquery(dbc,sprintf('SELECT %s FROM %s WHERE Keyword IN (%s)', ...
                                            thekid,theKeywordTable,BF_cat(ukws,',','''')));
    ourkids = vertcat(ourkids{:});
    addCell = {};
    for i = 1:length(kwSplit)
        for j = 1:length(kwSplit{i})
            try
                addCell{end+1} = sprintf('(%u,%u)',ourids(i),ourkids(strcmp(kwSplit{i}{j},ukws)));
            catch
                keyboard
            end
        end
    end
    % Add them all in 1000-sized chunks
    SQL_AddChunked(dbc,sprintf('INSERT INTO %s (%s,%s) VALUES',theRelTable,theid,thekid),addCell,1000);

    % Update Nmatches in the keywords table
    fprintf(1,' Done.\nNow computing all match counts for all keywords...\n');
    SQL_FlushKeywords(addWhat);
end

% ------------------------------------------------------------------------------
%% Update links between operations and master operations
% ------------------------------------------------------------------------------
if ismember(addWhat,{'mops','ops'}) % there may be new links
    % Add mop_ids to Operations table
    fprintf(1,'Evaluating links between operations and master operations...'); tic
    updateString = ['UPDATE Operations AS o SET o.mop_id = (SELECT mop_id FROM MasterOperations AS m ' ...
                        'WHERE m.MasterLabel = o.MasterLabel) WHERE mop_id IS NULL'];
    [~,emsg] = mysql_dbexecute(dbc,updateString);

    if isempty(emsg)
        fprintf(' Done.\n');
    else
        error('\nOops! Error finding links between Operations and MasterOperations:\n%s\n',emsg);
    end

    updateString = sprintf(['UPDATE MasterOperations AS m SET NPointTo = ' ...
                    '(SELECT COUNT(o.mop_id) FROM Operations AS o WHERE m.mop_id = o.mop_id)']);
    [~,emsg] = mysql_dbexecute(dbc,updateString);
    if ~isempty(emsg)
        error('Error counting NPointTo operations for mop_id = %u\n%s\n',M_ids(k),emsg);
    end

end

% ------------------------------------------------------------------------------
%% Close database
% ------------------------------------------------------------------------------
SQL_CloseDatabase(dbc)

% ------------------------------------------------------------------------------
%% Tell the user all about it
% ------------------------------------------------------------------------------
fprintf('All tasks completed in %s.\nRead %s then added %u %s into %s.\n', ...
            BF_TheTime(toc(ticker)),inputFile,sum(~isBad),theWhat,databaseName);

if strcmp(addWhat,'ts') && ~isMatFile
    fprintf(1,['**The imported data are now in %s and no longer ' ...
                    'need to be in the Matlab path**\n'],databaseName);
end

end


function [SourceValues, GridAtlas, RowNames] = bst_source_orient(iVertices, nComponents, GridAtlas, SourceValues, Function, DataType, RowNames)
% BST_SOURCE_ORIENT: Constrain source orientation for an unconstrained or mixed source model.
%
% USAGE:  SourceValues = bst_source_orient(iVertices=[], nComponents, GridAtlas, SourceValues, Function, DataType=[], RowNames=[])
%
% INPUT:
%    - iVertices    : Array of vertex indices of the source space, to reference to rows in Results.GridLoc (volume) or Surface.Vertices (surface)
%                     If empty, use all the vertices
%    - nComponents  : Number of entries per vertex in SourceValues (1,2,3)
%                     If 0, the number varies, the properties of each region are defined in input GridAtlas
%    - GridAtlas    : Set of scouts that defines the properties of the source space regions, when nComponents=0
%                     GridAtlas.Scouts(i).Region(2) is the source type (V=volume, S=surface, D=dba, X=exclude)
%                     GridAtlas.Scouts(i).Region(3) is the orientation constrain (U=unconstrained, C=contrained, L=loose)
%    - SourceValues : [Nvertices x Nsensors] or [Nvertices x Ntime], source values
%    - Function     : Name of the function to apply to group multiple components {'sum', 'sum_power', 'rms', 'max', 'pca', 'mean'}
%    - DataType     : Type of data being processed {'data', 'results', 'scouts', 'matrix'}
%    - RowNames     : Description of signals being processed: {empty, array of doubles, array of cells}
%
% OUTPUT:
%    - SourceValues : Constrained source values
%    - GridAtlas    : Modified atlas (unconstrained regions transformed into constrained regions)
%    - RowNames     : Description of the new list of signals

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Francois Tadel, 2014

% Parse inputs
if (nargin < 7) || isempty(RowNames)
	RowNames = [];
end
if (nargin < 6) || isempty(DataType)
	DataType = [];
end
if (nargin < 5) || isempty(Function)
	Function = 'none';
end
if (nargin < 4) || isempty(SourceValues)
	SourceValues = [];
end
if (nargin < 3) || isempty(GridAtlas)
	GridAtlas = [];
end
if (nargin < 2) || isempty(nComponents)
	error('Invalid call');
end

% === MIXED SOURCE MODELS ===
if (nComponents == 0)
    % Check that GridAtlas is defined
    if isempty(GridAtlas) || ~isfield(GridAtlas, 'Scouts') || ~isfield(GridAtlas.Scouts, 'Vertices')
        error('GridAtlas variable is empty');
    end
    % Initialize blocks of indices
    SourceBlocks = {};
    RowNamesBlocks = {};
    % Loop on all the regions
    for iScout = 1:length(GridAtlas.Scouts)
        % Get the vertices for this scouts
        if ~isempty(iVertices)
            iVertGrid = intersect(iVertices, GridAtlas.Scouts(iScout).GridRows);
        else
            iVertGrid = GridAtlas.Scouts(iScout).GridRows;
        end
        % Convert to indices in the source matrix
        iVertSource = bst_convert_indices(iVertGrid, nComponents, GridAtlas, 0);
        % If no vertices to read from this region: skip
        if isempty(iVertSource)
            continue;
        end
        % Get correpsonding row indices based on the type of region (constrained or unconstrained)
        switch (GridAtlas.Scouts(iScout).Region(3))
            case 'C'
                SourceBlocks{end+1} = SourceValues(iVertSource,:,:,:);
            case {'U','L'}
                % Apply grouping function
                SourceBlocks{end+1} = ApplyFunction(SourceValues(iVertSource,:,:,:), 1:3:length(iVertSource), 2:3:length(iVertSource), 3:3:length(iVertSource), Function);
                % If the row names are defined
                if ~isempty(RowNames) && iscell(RowNames)
                    RowNamesBlocks{end+1} = RemoveComponentTag(DataType, reshape(RowNames,1,[]), size(SourceBlocks{end},1), iVertSource);
                end
                % Set that the region is now constrained
                GridAtlas.Scouts(iScout).Region(3) = 'C';
            otherwise
                error(['Invalid region "' GridAtlas.Scouts(iScout).Region '"']);
        end
    end
    % Concatenate all the blocks together
    SourceValues = cat(1, SourceBlocks{:});
    if ~isempty(RowNames) && iscell(RowNames)
        RowNames = cat(2, RowNamesBlocks{:});
    end
    % Modify the grid/row correspondance matrix
    if ~isempty(GridAtlas.Grid2Source)
        GridAtlas.Grid2Source = speye(size(SourceValues,1));
    end

% === SIMPLE SOURCE MODELS ===
else
    % Select only a few vertices
    if ~isempty(iVertices)
        % Convert to indices in the source matrix
        iVertSource = bst_convert_indices(iVertices, nComponents, GridAtlas, 0);
    else
        iVertSource = 1:size(SourceValues,1);
    end
    % Group all the components
    switch (nComponents)
        case 1
            % Keep only the vertices of interest
            SourceValues = SourceValues(iVertSource,:,:,:);
        case 2
            % Apply grouping function
            SourceValues = ApplyFunction(SourceValues(iVertSource,:,:,:), 1:2:length(iVertSource), 2:2:length(iVertSource), [], Function);
            % If the row names are defined
            if ~isempty(RowNames) && iscell(RowNames)
                RowNames = RemoveComponentTag(DataType, reshape(RowNames,1,[]), size(SourceValues,1), iVertSource);
            end
        case 3
            % Apply grouping function
            SourceValues = ApplyFunction(SourceValues(iVertSource,:,:,:), 1:3:length(iVertSource), 2:3:length(iVertSource), 3:3:length(iVertSource), Function);
            % If the row names are defined
            if ~isempty(RowNames) && iscell(RowNames)
                RowNames = RemoveComponentTag(DataType, reshape(RowNames,1,[]), size(SourceValues,1), iVertSource);
            end
    end
end

% Numeric row names: just number the new signals
if ~isempty(RowNames) && ~iscell(RowNames)
    RowNames = 1:size(SourceValues,1);
end

end

%% ====== APPLY FUNCTION =====
function Values = ApplyFunction(Values, i1, i2, i3, Function)
    switch (Function)
        case 'max'
            if ~isempty(i3)
                Values = max(cat(5, Values(i1,:,:,:), Values(i2,:,:,:), Values(i3,:,:,:)), [], 5);
            else
                Values = max(cat(5, Values(i1,:,:,:), Values(i2,:,:,:)), [], 5);
            end
        case 'min'
            if ~isempty(i3)
                Values = min(cat(5, Values(i1,:,:,:), Values(i2,:,:,:), Values(i3,:,:,:)), [], 5);
            else
                Values = min(cat(5, Values(i1,:,:,:), Values(i2,:,:,:)), [], 5);
            end
        case 'absmax'
            if ~isempty(i3)
                Values = bst_max(cat(5, Values(i1,:,:,:), Values(i2,:,:,:), Values(i3,:,:,:)), 5);
            else
                Values = bst_max(cat(5, Values(i1,:,:,:), Values(i2,:,:,:)), 5);
            end
        case 'mean'
            if ~isempty(i3)
                Values = (Values(i1,:,:,:) + Values(i2,:,:,:) + Values(i3,:,:,:)) / 3;
            else
                Values = (Values(i1,:,:,:) + Values(i2,:,:,:)) / 2;
            end
        case 'sum'
            if ~isempty(i3)
                Values = Values(i1,:,:,:) + Values(i2,:,:,:) + Values(i3,:,:,:);
            else
                Values = Values(i1,:,:,:) + Values(i2,:,:,:);
            end
        case 'rms'
            if ~isempty(i3)
                Values = sqrt(Values(i1,:,:,:).^2 + Values(i2,:,:,:).^2 + Values(i3,:,:,:).^2);
            else
                Values = sqrt(Values(i1,:,:,:).^2 + Values(i2,:,:,:).^2);
            end
        case 'sum_power'
            if ~isempty(i3)
                Values = abs(Values(i1,:,:,:)).^2 + abs(Values(i2,:,:,:)).^2 + abs(Values(i3,:,:,:)).^2;
            else
                Values = abs(Values(i1,:,:,:)).^2 + abs(Values(i2,:,:,:)).^2;
            end
        case 'pca'
            if ~isempty(i3)
                Values = bst_scout_value(Values, 'none', [], 3, 'pca', 0);
            else
                Values = bst_scout_value(Values, 'none', [], 2, 'pca', 0);
            end
        case 'none'
            % Nothing to do
        otherwise
            error(['Invalid function "' Function '".']);
    end
end

%% ===== REMOVE COMPONENT TAG =====
function RowNames = RemoveComponentTag(DataType, RowNames, nRows, iRows)
    % Select one row name every three
    if (length(iRows) == 3 * nRows) && (max(iRows) <= length(RowNames))
        RowNames = RowNames(iRows(1:3:end));
    end
    % Remove the ".1" appended to the scouts names
    if (isempty(DataType) || ismember(DataType, {'matrix','scout'})) && iscell(RowNames) && ischar(RowNames{1}) && (length(RowNames{1}) > 2) && strcmp(RowNames{1}(end-1:end), '.1')
        RowNames = cellfun(@(c)c(1:end-2), RowNames, 'UniformOutput', 0);
    end
end


function x = solve_tril(T,b)
% SOLVE_TRIL      Left division by lower triangular matrix.
% SOLVE_TRIL(T,b) is the same as T\b but requires T to be lower triangular
% and runs faster.

error('You must run install_lightspeed in order to use this function.')


classdef PTKCoronalAnalysis < PTKPlugin
    % PTKCoronalAnalysis. Plugin for performing analysis of density using bins
    % along the anterior-posterior axis
    %
    %     This is a plugin for the Pulmonary Toolkit. Plugins can be run using
    %     the gui, or through the interfaces provided by the Pulmonary Toolkit.
    %     See PTKPlugin.m for more information on how to run plugins.
    %
    %     Plugins should not be run directly from your code.
    %
    %     PTKAxialAnalysis divides the cranial-caudal axis into bins and
    %     performs analysis of the tissue density, air/tissue fraction and
    %     emphysema percentaein each bin.
    %
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2013.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    properties
        ButtonText = 'Coronal<br>analysis'
        ToolTip = 'Performs density analysis in bins along the anterior-posterior axis'
        Category = 'Analysis'

        Context = PTKContextSet.Any
        AllowResultsToBeCached = true
        AlwaysRunPlugin = false
        PluginType = 'DoNothing'
        HidePluginInDisplay = true
        FlattenPreviewImage = false
        PTKVersion = '2'
        ButtonWidth = 6
        ButtonHeight = 1
        GeneratePreview = false
    end

    methods (Static)
        function results = RunPlugin(dataset, context, reporting)

            % Get the density image
            roi = dataset.GetResult('PTKLungROI', PTKContext.LungROI);
            if ~roi.IsCT
                reporting.ShowMessage('PTKCoronalAnalysis:NotCTImage', 'Cannot perform density analysis as this is not a CT image');
                return;
            end

            % Get a mask for the current region to analyse
            context_mask = dataset.GetTemplateMask(context);

            % Create a region mask excluding the airways
            context_no_airways = dataset.GetResult('PTKGetMaskForContextExcludingAirways', context);

            % Divide the lung into bins along the cranial-caudal axis
            bins = dataset.GetResult('PTKDivideLungsIntoCoronalBins', PTKContext.Lungs);

            results = PTKMultipleRegionAnalysis(bins, roi, context_mask, context_no_airways, 'Coronal distance from lung edge (mm)', reporting);
        end

    end
end


function [TorF, vstr, rdate] = have_feature_isequaln()
%HAVE_FEATURE_ISEQUALN  Detect availability/version info for ISEQUALN
%
%   Feature detection function implementing 'isequaln' tag for HAVE_FEATURE
%   to detect support for ISEQUALN function.
%
%   See also HAVE_FEATURE, ISEQUALN.

%   MP-Opt-Model
%   Copyright (c) 2004-2020, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MP-Opt-Model.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://github.com/MATPOWER/mp-opt-model for more info.

TorF = exist('isequaln') ~= 0;
if TorF
    if have_feature('matlab')
        %% introduced after 7.10 (R2010a) and by 7.14 (R2012a)
        v = have_feature('matlab', 'all');
    else
        %% introduced in Octave 4.4 (not in 4.2.2)
        v = have_feature('octave', 'all');
    end
    vstr  = v.vstr;
    rdate = v.date;
else
    vstr = '';
    rdate = '';
end


function modelEFM = efmSubmodelExtractionAsSBML(model, rxnsForSubmodel, outputFileName, remFlag, ubiquitousMets)
% This function takes an input array containing reaction indices (in an EFM) and extracts as a sub-model (SBML file) which can be visualised in Cytoscape
%
% USAGE:
%    modelEFM = extractSBMLFromEFM(model, data, outputFileName); % without optional inputs
%    modelEFM = extractSBMLFromEFM(model, data, outputFileName, remFlag, ubiquitousMets); % with optional inputs
%
% INPUTS:
%    model:              COBRA model that was used for EFM calculation
%    rxnsForSubmodel:    array of reaction indices (such as those in an EFM)
%    outputFileName:     file name of the output sbml file e.g., <name>.xml
%
% OPTIONAL INPUTS:
%    remFlag:           boolean indicating whether ubiquitous metabolites should be removed
%    ubiquitousMets:    list of metabolites to remove.
%                       An example list of ubiquitous metabolites:
%                       ubiquitousMets = {'h';'h2';'fe3';'fe2';'h2o';'na1';'atp';'datp';'hco3';'pi';'adp';'dadp';'nadp';'nadph';'coa';'o2';'nad';'nadh';'ppi';'pppi';'amp';'so4';'fad';'fadh2';'udp';'dudp';'co2';'h2o2';'nh4';'ctp';'utp';'gtp';'cdp';'gdp';'dcdp';'dgdp';'dtdp';'dctp';'dttp';'dutp';'dgtp';'cmp';'gmp';'ump';'dcmp';'dtmp';'dgmp';'dump';'damp';'cl'};
%
% OUTPUTS:
%    modelEFM:    submodel containing reactions, metabolites and genes in the EFM of interest
%
% EXAMPLE:
%    data = [1 2 3 4 5]; % select first 5 reactions
%    modelEFM = extractSBMLFromEFM(model, data) ;
%
% .. Author: Last modified: Chaitra Sarathy, 1 Oct 2019

if nargin < 4
    remFlag = 0;
    ubiquitousMets = [];
end

%remove reactions other than those in EFM
rxnRemoveList = model.rxns(setdiff(1:length(model.rxns), rxnsForSubmodel));

% write a model with the reactions (and corresponding metabolites) from the
% EFM
modelEFM = removeRxns(model, rxnRemoveList);

if (remFlag)
    % Define ubiquitous metabolites
%     ubiquitousMets = {'h';'h2';'fe3';'fe2';'h2o';'na1';'atp';'datp';'hco3';'pi';'adp';'dadp';'nadp';'nadph';'coa';'o2';'nad';'nadh';'ppi';'pppi';'amp';'so4';'fad';'fadh2';'udp';'dudp';'co2';'h2o2';'nh4';'ctp';'utp';'gtp';'cdp';'gdp';'dcdp';'dgdp';'dtdp';'dctp';'dttp';'dutp';'dgtp';'cmp';'gmp';'ump';'dcmp';'dtmp';'dgmp';'dump';'damp';'cl'};

    % Get compartments in the model so that ubiquitous molecules from all compartments can be removed
    [~, uniqComps] = getCompartment(model.mets);
    temp = cellfun(@(x) strcat(x, '[', uniqComps, ']'), ubiquitousMets,'UniformOutput' ,0);
    listOfAbundantMets = vertcat(temp{:});

    % Remove metabolites and unused genes, if any
    modelEFM = removeMetabolites(modelEFM, listOfAbundantMets, true);
end

% the unused genes in the model do not get removed, so remove mannually
modelEFM = removeUnusedGenes(modelEFM);

writeCbModel(modelEFM, 'format','sbml', 'fileName', outputFileName);

end


classdef TestPolarToCart
    %TestPolarToCart

    methods (Static)
        function test_radians
            theta = linspace(0, pi, 10);
            rho = rand(size(theta));
            [x, y] = cv.polarToCart(rho, theta);
            validateattributes(x, {class(theta)}, {'size',size(theta)});
            validateattributes(y, {class(theta)}, {'size',size(theta)});

            theta = single(theta);
            rho = single(rho);
            [x, y] = cv.polarToCart(rho, theta);
            validateattributes(x, {class(theta)}, {'size',size(theta)});
            validateattributes(y, {class(theta)}, {'size',size(theta)});
        end

        function test_degrees
            theta = linspace(0, 180, 10);
            rho = rand(size(theta));
            [x, y] = cv.polarToCart(rho, theta, 'Degrees',true);
            validateattributes(x, {class(theta)}, {'size',size(theta)});
            validateattributes(y, {class(theta)}, {'size',size(theta)});
        end

        function test_error_argnum
            try
                cv.polarToCart();
                throw('UnitTest:Fail');
            catch e
                assert(strcmp(e.identifier,'mexopencv:error'));
            end
        end
    end

end


% STD_SELCOMP - Helper function for STD_ERPPLOT, STD_SPECPLOT
%                       and STD_ERSPPLOT to select specific
%                       components prior to plotting.
% Usage:
%  >> std_selcomp( STUDY, data, cluster, setinds, compinds, comps)
%
% Inputs:
%  STUDY -  EEGLAB STUDY structure.
%  data  -  [cell array] mean data for each subject group and/or data
%           condition. For example, to compute mean ERPs statistics from a
%           STUDY for epochs of 800 frames in two conditions from three
%           groups of 12 subjects,
%           >> data = { [800x12] [800x12] [800x12];... % 3 groups, cond 1
%                       [800x12] [800x12] [800x12] };  % 3 groups, cond 2
% cluster - [integer] cluster index
% setinds - [cell array] set indices for each of the last dimension of the
%           data cell array.
%           >> setinds = { [12] [12] [12];... % 3 groups, cond 1
%                          [12] [12] [12] };  % 3 groups, cond 2
% compinds - [cell array] component indices for each of the last dimension
%           of the data cell array.
%           >> compinds = { [12] [12] [12];... % 3 groups, cond 1
%                           [12] [12] [12] };  % 3 groups, cond 2
% comps    - [integer] find and select specific component index in array
%
% Output:
%  data       - [cell array] data array with the subject or component selected
%  subject    - [string] subject name (for component selection)
%  comp_names - [cell array] component names (for component selection)
%
% Author: Arnaud Delorme, CERCO, CNRS, 2006-
%
% See also: STD_ERPPLOT, STD_SPECPLOT and STD_ERSPPLOT

% Copyright (C) 2006 Arnaud Delorme
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function [data, subject, comp_names] = std_selcomp(STUDY, data, clust, setinds, compinds, compsel)

if nargin < 2
    help std_selcomp;
    return;
end

optndims = ndims(data{1});
comp_names = {};
subject    = '';

% find and select group
% ---------------------
if isempty(compsel), return; end
sets   = STUDY.cluster(clust).sets(:,compsel);
comps  = STUDY.cluster(clust).comps(compsel);
%grp    = STUDY.datasetinfo(sets(1)).group;
%grpind = strmatch( grp, STUDY.group );
%if isempty(grpind), grpind = 1; end
%data = data(:,grpind);

% find component
% --------------
for c = 1:length(data(:))
    rminds = 1:size(data{c},optndims);

    for ind = length(compinds{c}):-1:1
        setindex = STUDY.design(STUDY.currentdesign).cell(setinds{c}(ind)).dataset;
        if compinds{c}(ind) == comps && any(setindex == sets)
            rminds(ind) = [];
        end
    end

    if optndims == 2
        data{c}(:,rminds) = []; %2-D
    elseif optndims == 3
        data{c}(:,:,rminds) = []; %3-D
    else
        data{c}(:,:,:,rminds) = []; %3-D
    end
    comp_names{c,1} = comps;
end
% for c = 1:size(data,1)
%     for ind = 1:length(compinds{1,grpind})
%         if compinds{1,grpind}(ind) == comps && any(setinds{1,grpind}(ind) == sets)
%             if optndims == 2
%                  data{c} = data{c}(:,ind);
%             else data{c} = data{c}(:,:,ind);
%             end
%             comp_names{c,1} = comps;
%         end
%     end
% end
subject = STUDY.datasetinfo(sets(1)).subject;


function test_suite=test_moxunit_util_regexp_matches()
    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 c=randchar(length)
    c=char(ceil(rand(1,length)*26+64));

function test_moxunit_util_regexp_matches_basics
    for needle_length=1:3

        %  make string to match
        needle=randchar(needle_length);
        assert_regexp_matches(needle,needle)

        for pat_length=1:4
            % make pattern that matches or does not match needle
            pat=randchar(pat_length);
            assert_regexp_matches([needle pat],needle)
            assert_regexp_matches([pat needle],needle)

            if needle_length==pat_length
                matcher=@assert_regexp_matches;
            else
                matcher=@assert_regexp_not_matches;
            end
            matcher(needle,sprintf('^%s$',...
                                        repmat('.',1,pat_length)))

            while true
                different_haystack=randchar(pat_length);
                match=bsxfun(@eq,different_haystack,needle');
                if all(~match(:))
                    break;
                end
            end

            assert_regexp_not_matches(needle,different_haystack)
        end
    end

function test_moxunit_util_regexp_matches_exceptions()
    aet=@(varargin)assertExceptionThrown(@()...
                        moxunit_util_regexp_matches(varargin{:}),'');
    bad_inputs={{[],''},... % first argument not a string
                 {'',[]},... % second argument not a string
                 };
    for k=1:numel(bad_inputs)
        args=bad_inputs{k};
        aet(args{:});
    end

function assert_regexp_matches(needle, pat)
    assertTrue(moxunit_util_regexp_matches(needle,pat));

function assert_regexp_not_matches(needle, pat)
    assertFalse(moxunit_util_regexp_matches(needle,pat));


function output = callpennlp(interfacedata)

% Retrieve needed data
options = interfacedata.options;
F_struc = interfacedata.F_struc;
c       = interfacedata.c;
K       = interfacedata.K;
x0      = interfacedata.x0;
Q       = interfacedata.Q;
lb      = interfacedata.lb;
ub      = interfacedata.ub;
monomtable = interfacedata.monomtable;

switch options.verbose
    case 0
        options.fmincon.Display = 'off';
    case 1
        options.fmincon.Display = 'final';
    otherwise
        options.fmincon.Display = 'iter';
end

% Do some pre-calc to be used in calls from pennlp
temp = sum(interfacedata.monomtable,2)>1;
temp = (sum(interfacedata.monomtable,2)==1 & sum(interfacedata.monomtable~=0,2)==1);
nonlinearindicies = find(full(~temp));
linearindicies = find(full(temp));
interfacedata.nonlinearindicies = nonlinearindicies;
interfacedata.linearindicies = linearindicies;

Infinity = 1.0E38;
if isempty(lb)
    lb = -Infinity*ones(length(linearindicies),1);
else
    lb(isinf(lb)) =  -Infinity;
end
if isempty(ub)
    ub = Infinity*ones(length(linearindicies),1);
else
    ub(isinf(ub)) =  Infinity;
end

% Numer of constraints
m = K.l+K.f;
n = length(linearindicies);

lb = lb(linearindicies);
ub = ub(linearindicies);

lbc =  0*ones(m,1);
ubc =  Infinity*ones(m,1);
ubc(1:K.f) = 0;

if isempty(x0)
    x0 = zeros(length(linearindicies),1);
else
    x0 = x0(linearindicies);
end

linearConstraints = ~any(F_struc(1:K.f+K.l,1+nonlinearindicies),2);
if ~isempty(linearConstraints)
    F = F_struc(1:K.f+K.l,:);
    F_struc = [F(~linearConstraints,:);F(linearConstraints,:);F_struc(K.f+K.l+1:end,:)];
    lbc = [lbc(~linearConstraints);lbc(linearConstraints)];
    ubc = [ubc(~linearConstraints);ubc(linearConstraints)];
end

functiondata.nonlinearindicies = nonlinearindicies;
functiondata.linearindicies = linearindicies;
functiondata.monomtable = monomtable;
functionGradientdata.nonlinearindicies = nonlinearindicies;
functionGradientdata.linearindicies = linearindicies;
functionGradientdata.monomtable = monomtable;
functionHessiandata.nonlinearindicies = nonlinearindicies;
functionHessiandata.linearindicies = linearindicies;
functionHessiandata.monomtable = monomtable;

constraintdata.nonlinearindicies = nonlinearindicies;
constraintdata.linearindicies = linearindicies;
constraintdata.monomtable = monomtable;
constraintGradientdata.nonlinearindicies = nonlinearindicies;
constraintGradientdata.linearindicies = linearindicies;
constraintGradientdata.monomtable = monomtable;
constraintHessiandata.nonlinearindicies = nonlinearindicies;
constraintHessiandata.linearindicies = linearindicies;
constraintHessiandata.monomtable = monomtable;

functiondata.F_struc = [interfacedata.f c(:)'];
constraintdata.F_struc = F_struc(1:K.l+K.f,:);start = K.f + K.l + 1;
functionGradientdata.F_struc   = F_struc(start:start+n-1,:);start = start+n;
functionHessiandata.F_struc    = F_struc(start:start+n^2-1,:);start = start+n^2;
constraintGradientdata.F_struc = F_struc(start:start+n*m-1,:);start = start+n*m;
constraintHessiandata.F_struc  = F_struc(start:end,:);start = start+n*m;

datasaver(functiondata,functionGradientdata,functionHessiandata,constraintdata,constraintGradientdata,constraintHessiandata)

Infinity = 1.0E38;
pen.nvars = n;
pen.nlin = length(find(linearConstraints));
pen.nconstr = m;
pen.nnz_gradient = n;
pen.nnz_hessian = (n+1)*n/2;
pen.lbv = lb(:)';
pen.ubv = ub(:)';
pen.lbc = lbc(:)';
pen.ubc = ubc(:)';
pen.xinit= x0(:)';
pen.my_f = 'pennlp_fun';
pen.my_f_gradient = 'pennlp_fungrad';
pen.my_f_hessian = 'pennlp_funhess';
pen.my_g = 'pennlp_con';
pen.my_g_gradient = 'pennlp_congrad';
pen.my_g_hessian =  'pennlp_conhess';

ops = struct2cell(options.pennlp);ops = [ops{1:end}];
pen.ioptions = [ops(1:2) options.verbose ops(3:15)];
if options.verbose>0
    pen.ioptions(3) = pen.ioptions(3)+1;
end
pen.doptions = ops(16:end);

%pen.ioptions = ops(1:15);
%pen.foptions = ops(16:end);
%pen.ioptions(4) = max(0,min(3,options.verbose+1));

%pen.ioptions = [100 100 2 0 0 0 1 0 0 2 0 0 0 -1 0 1];
%pen.doptions = [1.0E-7 1.0E0 1.0E-0 1.0E-2 5.0E-1 1.0E-1 1.0E-6 1.0E-12 1.0e-1 0.05 1.0 1.0 1.0];

if options.savedebug
    save pennlpdebug pen
end

showprogress('Calling PENNLP',options.showprogress);

solvertime = tic;
[obj,xout,duals,flag] = pennlpm(pen);
solvertime = toc(solvertime);

if isempty(nonlinearindicies)
    x = xout(:);
else
    x = zeros(length(interfacedata.c),1);
    for i = 1:length(linearindicies)
        x(linearindicies(i)) = xout(i);
    end
end

switch flag
    case 0
        problem = 0;
    case {1,6,7}
        problem = 4;
    otherwise
        problem = 9;
end

% Internal format for duals
D_struc = [];

% Save all data sent to solver?
if options.savesolverinput
    solverinput.pen = pen;
else
    solverinput = [];
end

% Save all data from the solver?
if options.savesolveroutput
    solveroutput.obj = obj;
    solveroutput.xout = xout;
    solveroutput.duals = duals;
    solveroutput.flag = flag;
else
    solveroutput = [];
end

% Standard interface
output = createOutputStructure(x,D_struc,[],problem,interfacedata.solver.tag,solverinput,solveroutput,solvertime);


function reply = default(query,value)
%DEFAULT gets response to IFISS prompt
%   reply = default(query,value);
%   input
%          query   character string: asks a question
%          value   integer: the default response
%
%   IFISS function: AR 31 August 2005, HCE 2 January 2010.
% Copyright (c) 2005 D.J. Silvester, H.C. Elman, A. Ramage (see readme.m)
global BATCH FID
if exist('BATCH') & BATCH==1,
   replycell=textscan(FID,'%f%*[^\n]',1);
   reply=deal(replycell{:});
   disp(query)
   disp(reply)
else
   if length(query)>=26 && strcmp(query(10:26),'timestep sequence'),
      reply=input([query,' : '],'s');
   else
      reply=input([query,' : ']);
   end
   if isempty(reply), reply=value; end
end
return


function kbinfo2(cmd)
% KBINFO keyboard information
%   This simple example assists you to understand how to get the keyboard information
%
%   Author: Fu-Sung Wang, E-mail: fusung@webmail.pme.nthu.edu.tw , Update: 23-Dec-2004 11:29:53
%   $Revision

%% Initialization
global Hfig Htxt;        % Htxt: text handle, Hfig: figure handle
global MAXWORDLEN;       % MATWORDLEN: maximum word length

%% Create figure and text, and MAXWORDLEN is also initialized
if nargin == 0           % no input argument needed
Hfig = figure('Name','Keyboard Infomation','Numbertitle','off','Menubar','none',...         % Hfig: figure handle
              'Color',[0.831373 0.815686 0.784314],'Resize','off','DoubleBuffer','on',...
              'Position',[150,150,220,400],'KeyPressFcn',[mfilename,'(''RUN'')']);
Htxt = uicontrol('Tag','typelist','Style', 'ListBox', ...                                      % Htxt: text handle
                 'Position',[0 0 220 400],'FontSize',10, ...
                 'HorizontalAlignment','Left','KeyPressFcn',[mfilename,'(''RUN'')']);
MAXWORDLEN = 200;       % maximum word length
end

%% Retrieve keyboard information
% keyIn = get(Hfig, 'CurrentCharacter');
keyIn = num2str(keyinfo');
rec = getappdata(Hfig,'rec');           % get value from figure object (Hfig)
rec = strvcat(rec,keyIn);                % string concatenation

%% Reset rec
if size(str2num(rec),1) > MAXWORDLEN
    rec = [];
    rec = keyIn;
end

%% Update data
set(Htxt,'String',rec);
len_str = size(str2num(rec),1);
set(Htxt,'Value',len_str);
set(Hfig,'Name',[num2str(len_str) ' / ' num2str(MAXWORDLEN)] );
setappdata(Hfig,'rec',rec);


function val = littleendian

% LITTLEENDIAN returns 1 (true) on a little endian machine, e.g. with an
% Intel or AMD, or 0 (false) otherwise
%
% Example
%   if (littleendian)
%     % do something, e.g. swap some bytes
%    end
%
% See also BIGENDIAN, SWAPBYTES, TYPECAST

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

val = (typecast(uint8([0 1]), 'uint16')==256);


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


function z = max( x, y )

% MAX   Maximum, z = max(x,y)

if isa(x,'tfocs_tuple')
    z = x;
    if isa(y,'tfocs_tuple')
        z.value_ = cellfun( @max, x.value_, y.value_, 'UniformOutput', false );
    elseif isscalar(y)
        z.value_ = cellfun( @max, x.value_, {y}, 'UniformOutput', false );
    else
        z.value_ = cellfun( @max, x.value_, {y}, 'UniformOutput', false );
    end
else
    z = y;
    if isscalar(x)
        z.value_ = cellfun( @max, {x}, y.value_, 'UniformOutput', false );
    else
        z.value_ = cellfun( @max, {x}, y.value_, 'UniformOutput', false );
    end
end

% TFOCS v1.3 by Stephen Becker, Emmanuel Candes, and Michael Grant.
% Copyright 2013 California Institute of Technology and CVX Research.
% See the file LICENSE for full license information.


function ma_updateDispAxis(handles, stateLog, orbitNumToPlot)
%ma_updateDispAxis Summary of this function goes here
%   Detailed explanation goes here
    hDispAxes = handles.dispAxes;
    hShowSoICheckBox = handles.showSoICheckBox;
    hShowChildrenCheckBox = handles.showChildrenCheckBox;
    hDispAxisTitleLabel = handles.dispAxisTitleLabel;
    hShowOtherSpacecraftCheckBox = handles.showOtherSpacecraftCheckBox;
    hShowChildBodyMarker = handles.showChildBodyMarker;

    if(isempty(orbitNumToPlot))
        orbitNumToPlot = 1;
        set(hDispAxes,'UserData',orbitNumToPlot);
    end

    showSoICheckBoxINT = get(hShowSoICheckBox,'value');
    if(showSoICheckBoxINT == 1)
        showSoI = true;
    else
        showSoI = false;
    end

    hShowChildrenCheckBoxINT = get(hShowChildrenCheckBox,'value');
    if(hShowChildrenCheckBoxINT == 1)
        showChildBodies = true;
    else
        showChildBodies = false;
    end

    hShowOtherSpacecraftCheckBoxINT = get(hShowOtherSpacecraftCheckBox,'value');
    if(hShowOtherSpacecraftCheckBoxINT == 1)
        showOtherSC = true;
    else
        showOtherSC = false;
    end

    showChildBodyMarkerINT = get(hShowChildBodyMarker,'value');
    if(showChildBodyMarkerINT == 1)
        showChildMarker = true;
    else
        showChildMarker = false;
    end

    axes(hDispAxes);
    cla(gca);
    maData = getappdata(handles.ma_MainGUI,'ma_data');
    celBodyData = getappdata(handles.ma_MainGUI,'celBodyData');
    plotStateLog(stateLog, handles, showSoI, showChildBodies, showChildMarker, showOtherSC, orbitNumToPlot, hDispAxisTitleLabel, maData, celBodyData);
end


function [val] = filetype_check_header(filename, head, offset)

% FILETYPE_CHECK_HEADER helper function to determine the file type
% by reading the first number of bytes of a file and comparing them
% to a known string (c.f. magic number).

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

% these are for speeding up subsequent calls with the same input arguments
persistent previous_argin previous_argout

if nargin<3
  offset = 0;
end

current_argin = {filename, head, offset};
if ~isempty(previous_argin) && isequal(current_argin, previous_argin)
  % don't do the detection again, but return the previous value from cache
  val = previous_argout;
  return
end

if iscell(filename)
  % compare the header of multiple files
  val = zeros(size(filename));
  for i=1:length(filename)
    val(i) = filetype_check_header(filename{i}, head, offset);
  end
elseif isfolder(filename)
  % a directory cannot have a header
  val = false;
elseif ~exist(filename, 'file')
  val = false;
  cache = false; % the file does not exist now, but can exist later
else
  % read the first few bytes from the file and compare them to the desired header
  fid = fopen(filename, 'rb');
  if fid<0
    ft_warning('could not open %s', filename);
    val = false;
  else
    fseek(fid, offset, 'cof');
    if iscell(head)
      len = zeros(size(head));
      for i=1:length(head)
        len(i) = length(head{i});
      end
      [str, siz] = fread(fid, max(len), 'uint8');
      fclose(fid);
      for i=1:length(head)
        val = all(str(1:len(i))==head{i}(:));
        if val
          break
        end
      end
    else
      [str, siz] = fread(fid, length(head), 'uint8=>char');
      fclose(fid);
      if siz~=length(head)
        ft_warning('could not read the header from %s', filename);
        val = false;
      else
        val = all(str(:)==head(:));
      end
    end
  end
end

% remember the current input and output arguments, so that they can be
% reused on a subsequent call in case the same input argument is given
current_argout  = val;
previous_argin  = current_argin;
previous_argout = current_argout;

return % main()


function [TorF, vstr, rdate] = have_feature_lu_vec()
%HAVE_FEATURE_LU_VEC  Detect availability/version info for LU vector support
%
%   Feature detection function implementing 'lu_vec' tag for HAVE_FEATURE
%   to detect support for LU(..., 'vector') syntax.
%
%   See also HAVE_FEATURE, LU.

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

vstr = '';
rdate = '';
if have_feature('matlab') && have_feature('matlab', 'vnum') < 7.003
    TorF = 0;     %% lu(..., 'vector') syntax not supported
else
    TorF = 1;
end


function C= cprintf(fmt, varargin)
%CPRINTF - Print array into cell array of string
%
%Synopsis:
%  cprintf(FORMAT, A, ...)
%
%Arguments
%  FORMAT - String that describes the format of the output as in sprintf
%
%Returns:
%  C - Cell array of strings
%
%Examples:
%  cprintf('chan #%d', 1:8)
%  cprintf('log(%d)= %f', 1:5, log(1:5))
%  cprintf('candidate #%d: %s', [1:3]', {'abraham','bebraham','zebraham'})

if isempty(varargin),
  C= {};
  return;
end

len= cellfun(@numel, varargin);
if any(diff(len)),
  error('all arguments must have the same number of elements');
end

N= len(1);
C= cell(N, 1);
Nv= length(varargin);
args= cell(1, Nv);
for n= 1:N,
  for m= 1:Nv,
    v= varargin{m};
    if iscell(v),
      args{m}= v{n};
    else
      args{m}= v(n);
    end
  end
  C{n}= sprintf(fmt, args{:});
end
C= reshape(C, size(varargin{1}));


function list = GenesReactions(genelist,rxns)
% Returns genes in model and the associative reactions.
%
% USAGE:
%
%    list = GenesReactions(genelist, rxns)
%
% INPUTS:
%    genelist:    list of genes
%    rxns:        reactions
%
% OUTPUT:
%    list:        genes in model and the associative reactions
%
% .. Author: - Stefan G. Thorleifsson 2011
%
% .. rBioNet is published under GNU GENERAL PUBLIC LICENSE 3.0+
% .. Thorleifsson, S. G., Thiele, I., rBioNet: A COBRA toolbox extension for
% .. reconstructing high-quality biochemical networks, Bioinformatics, Accepted.
% .. rbionet@systemsbiology.is

GPRs = rxns(:,6);
Sg = size(genelist);
list = cell(Sg(1),2);
list(:,1) = genelist;
S = size(rxns);

for i = 1:S(1)
    genes = GPR2Genes({GPRs{i}});
    if ~isempty(genes)
        SG = size(genes);
        for k = 1:SG(2)
            line = find(strcmp(genes{k},genelist));
            if isempty(line)
                msgbox(['Gene ' genes{k} ' is not in genelist....' rxns{i,2}],...
                    'My bad....the programmer.','help');
            else
                if isempty(list{line,2})
                    list{line,2} = rxns{i,2};
                else
                    rxn = list{line,2};
                    list{line,2} = [rxn ', ' rxns{i,2}];
                end
            end
        end
    end
end


function [val]=gy(x,quant)

% indicator function for quantiles values
% returns 1 if the value 'x' is lower than or equal to the threshold value 'quant'
% returns 0 otherwise

val=x<=quant;


function ShowImageCell(imageCell, n, m, figurename, imageNames)
% ShowImageCell(imageCell, n, m, figurename, imageNames)
%
% Generate a figure with thumbnails of the images in the imageCell.
%
% imageCell:            Cell array with images which can be displayed
%                       with imshow.
% n:                    number of thumbnail rows per figure.
% m:                    number of thumbnail columns per figure.
% figurename:           Name of the figures (optional).
%
%     Jasper Uijlings - 2013

totImages = length(imageCell);
numFigures = ceil(totImages / (n * m));

if nargin < 4
    figurename = 'untitled';
end

if nargin < 5
    imageNames = cell(length(imageCell));
end

if ~iscell(imageNames)
    imageNamesC = cell(length(imageNames));
    for i=1:length(imageNames)
        imageNamesC{i} = sprintf('%g', imageNames(i));
    end
    imageNames = imageNamesC;
end

idx = 1;
screenSize = get(0, 'ScreenSize');

for i=1:numFigures
    if ispc
        figure('Position', [1, 1, screenSize(3), screenSize(4)], 'Name', figurename);
%         figure('Position', [1 49 1920 946] , 'Name', figurename);
    else
        figure('Position', [1, 1, screenSize(3)/2, screenSize(4)], 'Name', figurename);
    end
    clf;
    for j = 1:n * m
        if(idx <= totImages)
            subplot(n, m, j);
            imshow(imageCell{idx});
            xlabel(imageNames{idx});
            idx = idx + 1;
        end
    end
end


%kkfraction 'Output = Fractional Part of Input'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros kfraction.pane file
%
% Parameters:
% InputFile: i 'Input ', required: 'Input data object'
% OutputFile: o 'Output', required: 'Resulting output data object'
%
% Example: o = kkfraction(i, {'i','';'o',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% kfraction - Output = Fractional Part of Input
%
%  DESCRIPTION
%
% The "Fractional Part" operator returns the fractional part of
% each data point in the input data object, \fBInput".
%
% Executing "Fractional Part" runs the program \fIkarith1\fP
% with the -fract flag.
%
%  "\fBData Type"" 5
% .cI $DATAMANIP/repos/shared/man/sections/value_type_1input
%
%  "\fBMap Data"" 5
% .cI $DATAMANIP/repos/shared/man/sections/map_1input
%
%  "\fBValidity Mask"" 5
% .cI $DATAMANIP/repos/shared/man/sections/mask_1input
%
%  "\fBExplicit Location and Time Data"" 5
% .cI $DATAMANIP/repos/shared/man/sections/loc_and_time_1input
%
%  "\fBFailure Modes""
% .cI $DATAMANIP/repos/shared/man/sections/fail_1input
%
%
%
%  EXAMPLES
%
%  "SEE ALSO"
% DATAMANIP::karith1
%
%  RESTRICTIONS
% Operations on complex data are not supported at this time.
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993 - 1997, Khoral Research, Inc. ("KRI")  All rights reserved.
%

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

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


%  Utility function that transforms a string whose evaluation would give a
%  matrix, into a cell array.
%
%  designed for use with Ben Petschel stuff on Grobner basis
%