function [solversToUse] = prepareTest(varargin)
% Checks the prerequisites of the test, and returns solvers depending on
% the input parameters. If the requirements are NOT met, a
% COBRA:RequirementsNotMet error is thrown.
%
% USAGE:
%    [solversToUse] = prepareTest(varargin)
%
% OPTIONAL INPUTS:
%    varagin:      `ParameterName` value pairs with the following options:
%
%                   - `toolboxes` or `requiredToolboxes`: Names of required toolboxes (the license feature name).(default: {})
%                   - `minimalMatlabSolverVersion`: Minimal version of the optimization toolbox required to use the matlab solver.(default: 0)
%                   - `requiredSolvers`: Names of all solvers that MUST be available. If not empty, the resulting solvers struct will contain cell arrays (default: {})
%                   - `useSolversIfAvailable`: Names of solvers that should be used if available. If not empty, the resulting solvers struct will contain cell arrays (will not throw an error if not). (default: {})
%                   - `requireOneSolverOf`: Names of solvers, at least one of which has to be available
%                   - `excludeSolvers`: Names of solvers which should never be used for the test (because they fail)
%                   - `useMinimalNumberOfSolvers`: Always use only one solver. This option allows tests which only use FBA to generate input, but where no expicit linear programming code is present, to only validate on one solver (default: false).
%                   - `needsLP`: Whether a LP solver is required (default: false)
%                   - `needsMILP`: Whether a MILP solver is required (default: false)
%                   - `needsQP`: Whether a QP solver is required (default: false)
%                   - `needsMIQP`: Whether a MIQP solver is required (default: false)
%                   - `needsNLP`: Whether a NLP solver is required (default: false)
%                   - `needsEP`: Whether a EP solver is required (default: false)
%                   - `needsUnix`: Whether the test only works on a Unix system (macOS or Linux) (default: false)
%                   - `needsWindows`: Whether the test only works on a Windows system (default: false)
%                   - `needsMac`: Whether the test only works on a Mac system (default: false)
%                   - `needsLinux`: Whether the test only works on a Linux system (default: false)
%                   - `needsWebAddress`: Tests, whether the supplied url exists (default: '')
%                   - `needsWebRead`: Tests, whether webread can be used with the given url
%
% OUTPUTS:
%
%    solversToUse:  A struct with one field per solver type listing
%                   the solvers to use for that type of problem in a cell array.
%                   If neither of the 'useIfAvailable' nor the 'reqSolvers'
%                   parameter is provided, only at most one solver
%                   per type will be returned (i.e. the default
%                   solver for that type). See the examples below
%
% EXAMPLE:
%
%      % request a check for the parallel processing toolbox
%      >> solvers = prepareTest('requiredToolboxes', {'distrib_computing_toolbox'})
%      solvers =
%
%                struct with fields:
%
%                      LP: {'gurobi'}
%                    MILP: {'gurobi'}
%                      QP: {'gurobi'}
%                    MIQP: {'gurobi'}
%                     NLP: {'matlab'}
%                      EP: {'pdco'}
%
%      % request gurobi, ibm_cplex and tomlab if available
%      >> solvers = prepareTest('useIfAvailable', {'tomlab', 'ibm_cplex', 'gurobi'})
%      solvers =
%
%                struct with fields:
%
%                      LP: {2×1 cell}
%                    MILP: {2×1 cell}
%                      QP: {2×1 cell}
%                    MIQP: {'gurobi'}
%                     NLP: {'matlab'}
%                      EP: {'pdco'}
%
%

global CBT_MISSING_REQUIREMENTS_ERROR_ID
global OPT_PROB_TYPES

% some Matlab Toolboxes currently in use in the COBRA Toolbox.
% This might have to be extended in the future.
toolboxInfo = struct('statistics_toolbox', {{'Statistics and Machine Learning Toolbox', 'Statistics Toolbox'}}, ...
                     'bioinformatics_toolbox', {{'Bioinformatics Toolbox'}}, ...
                     'distrib_computing_toolbox', {{'Parallel Computing Toolbox'}}, ...
                     'optimization_toolbox', {{'Optimization Toolbox'}}, ...
                     'global_optimization_toolbox', {{'Global Optimization Toolbox'}}, ...
                     'image_toolbox', {{'Image Processing Toolbox'}}, ...
                     'gads_toolbox', {{'Global Optimization Toolbox'}});

%generate this on the fly rather than using a persistient variable - Ronan
availableSolvers = getAvailableSolversByType();

parser = inputParser();
parser.addParamValue('toolboxes', {}, @iscell);
parser.addParamValue('requiredToolboxes', {}, @iscell);
parser.addParamValue('minimalMatlabSolverVersion',0,@isnumeric);

parser.addParamValue('requiredSolvers', {}, @iscell);
parser.addParamValue('useSolversIfAvailable', {}, @iscell);
parser.addParamValue('requireOneSolverOf', {}, @iscell);
parser.addParamValue('excludeSolvers', {}, @(x) iscell(x) || ischar(x) );
parser.addParamValue('useMinimalNumberOfSolvers', false, @(x) islogical(x) || x == 1 || x == 0);
parser.addParamValue('needsLP', false, @(x) islogical(x) || x == 1 || x == 0);
parser.addParamValue('needsMILP', false, @(x) islogical(x) || x == 1 || x == 0);
parser.addParamValue('needsNLP', false, @(x) islogical(x) || x == 1 || x == 0);
parser.addParamValue('needsQP', false, @(x) islogical(x) || x == 1 || x == 0);
parser.addParamValue('needsMIQP', false, @(x) islogical(x) || x == 1 || x == 0);
parser.addParamValue('needsEP', false, @(x) islogical(x) || x == 1 || x == 0);
parser.addParamValue('needsUnix', false, @(x) islogical(x) || x == 1 || x == 0);
parser.addParamValue('needsLinux', false, @(x) islogical(x) || x == 1 || x == 0);
parser.addParamValue('needsWindows', false, @(x) islogical(x) || x == 1 || x == 0);
parser.addParamValue('needsMac', false, @(x) islogical(x) || x == 1 || x == 0);
parser.addParamValue('needsWebAddress', '', @ischar);
parser.addParamValue('needsWebRead', false, @(x) islogical(x) || x == 1 || x == 0);

parser.parse(varargin{:});

useQP = parser.Results.needsQP;
useLP = parser.Results.needsLP;
useMIQP = parser.Results.needsMIQP;
useNLP = parser.Results.needsNLP;
useMILP = parser.Results.needsMILP;
useEP = parser.Results.needsEP;

macOnly = parser.Results.needsMac;
windowsOnly = parser.Results.needsWindows;
unixOnly = parser.Results.needsUnix;
linuxOnly = parser.Results.needsLinux;

toolboxes = union(parser.Results.toolboxes, parser.Results.requiredToolboxes);
requiredSolvers = parser.Results.requiredSolvers;
possibleSolvers = parser.Results.requireOneSolverOf;
excludedSolvers = parser.Results.excludeSolvers;
if ischar(excludedSolvers)
    excludedSolvers = {excludedSolvers};
end
preferredSolvers = parser.Results.useSolversIfAvailable;

needsWebAddress = parser.Results.needsWebAddress;
needsWebRead = parser.Results.needsWebRead;
useMinimalNumberOfSolvers = parser.Results.useMinimalNumberOfSolvers;
runtype = getenv('CI_RUNTYPE');

minimalMatlabSolverVersion = parser.Results.minimalMatlabSolverVersion;

errorMessage = {};
infoMessage = {};

% first, check whether the OS is applicable
if macOnly
    if ~ismac
        errorMessage{end + 1} = 'This test only works on macOS';
    end
end

if windowsOnly
    if ~ispc
        errorMessage{end + 1} = 'This test only works on Windows';
    end
end

if linuxOnly
    if ~isunix
        errorMessage{end + 1} = 'This test only works on Linux Systems';
    else
        if ~strcmp(computer('arch'), 'glnx64')
            errorMessage{end + 1} = 'This test only works on Linux Systems';
        end
    end
end

if ~isempty(needsWebAddress)
    [status_curl, result_curl] = system(['curl -s -k ' needsWebAddress]);
    if status_curl ~= 0 || isempty(result_curl)
        errorMessage{end + 1} = sprintf('This function needs to connect to %s and was unable to do so.',needsWebAddress);
    end
    if needsWebRead
        if verLessThan('MATLAB','9.3') && isunix && strncmp(needsWebAddress,'https',5)
            errorString = sprintf(['This function needs to connect to a ''https'' address using webread.\n', ...
                                   'Your MATLAB version is shipped with an invalid libssl.so.1.0.0 \n',...
                                   'which will cause MATLAB to crash if webread is called with an \n',...
                                   '''https'' website.\n',...
                                   'To fix this, you can replace your MATLAB library with the system library \n',...
                                   'by running the following commands in the console:\n',...
                                   '$ sudo mv %s/bin/glnxa64/libssl.so.1.0.0 %s/bin/glnxa64/libssl.so.1.0.0.old\n',...
                                   '$ sudo cp /lib/x86_64-linux-gnu/libssl.so.1.0.0 %s/bin/glnxa64/libssl.so.1.0.0\n',...
                                   'Please note that this test will not be able to run on your system,\n',...
                                   'regardless on whether you fixed the library or not. If you want to run it,',...
                                   'you will have to remove the ''needsWebRead'' flag from the ''prepareTest''',...
                                   'statement in the test and run it again.'],...
                                   matlabroot,matlabroot,matlabroot);
            errorMessage{end + 1} = errorString;
        end
    end
end

if unixOnly
    if ~isunix
        errorMessage{end + 1} = 'This test only works on Unix Systems (Mac and Linux)';
    end
end

% restrict the solvers available for this test
solversForTest = availableSolvers;

if any(ismember(solversForTest.LP,'matlab'))
    boxes = ver();
    optBox = find(ismember({boxes.Name},'Optimization Toolbox'));
    if ~isempty(optBox)
        optVer = boxes(optBox).Version;
        if str2double(optVer) < minimalMatlabSolverVersion
            excludedSolvers = [columnVector(excludedSolvers);'matlab'];
        end
    end
end

if ~isempty(excludedSolvers)
    solverTypes = fieldnames(availableSolvers);
    for i = 1:numel(solverTypes)
        excludedPos = ismember(solversForTest.(solverTypes{i}),excludedSolvers);
        solversForTest.(solverTypes{i}) = solversForTest.(solverTypes{i})(~excludedPos);
    end
    if numel(excludedSolvers) == 1
        infoMessage{end+1} = sprintf('%s is not compatible with the tested function and thus excluded.',excludedSolvers{1});
    else
        infoMessage{end+1} = sprintf('The following solvers are not compatible with this test and therefore excluded:\n%s and %s', strjoin(excludedSolvers(1:end-1),' and '),excludedSolvers{end});
    end
end

% then, check the required Solvers
if ~isempty(requiredSolvers) && ~all(ismember(requiredSolvers, solversForTest.ALL))
    % we have required solvers and some are missing
    missing = ~ismember(requiredSolvers, solversForTest.ALL);
    if sum(missing) == 1
        misssolver = requiredSolvers{missing};
            errorMessage{end + 1} = sprintf('%s is a required solver for the test and not available on your system.', misssolver);
    else
        errorMessage{end + 1} = sprintf('%s are missing solvers required for the test but not available on your system.', strjoin(requiredSolvers(missing), ' and '));
    end
else
    % otherwise add the required Solvers to the preferred solvers.
    preferredSolvers = union(preferredSolvers, requiredSolvers);
end

if ~isempty(possibleSolvers) && ~any(ismember(possibleSolvers,solversForTest.ALL))
    if numel(possibleSolvers) == 1
        errorMessage{end + 1} = sprintf('The test requires that the following solver is installed:\n%s', strjoin(possibleSolvers, ' or '));
    else
        errorMessage{end + 1} = sprintf('The test requires that at least one of the following solvers is installed:\n%s or %s', strjoin(possibleSolvers(1:end-1), ', '),possibleSolvers{end});
    end
else
    if ~isempty(possibleSolvers)
        %We have a set of possible solvers.
        %So we restrict the preferredSolvers to those
        % if there are preferred solvers.
        if ~isempty(preferredSolvers)
            preferredSolvers = intersect(preferredSolvers,possibleSolvers);
        else
            solverOptions = intersect(possibleSolvers,solversForTest.ALL);
            preferredSolvers = solversForTest.ALL(find(ismember(solversForTest.ALL,possibleSolvers),1));
        end

    end
end

% check the Toolboxes
res = ver;
missingTBs = struct('License', {{}}, 'Installation', {{}});
for i = 1:numel(toolboxes)
    tbstring = lower(toolboxes{i});
    licpres = license('test', tbstring);
    if any(ismember(tbstring, fieldnames(toolboxInfo)))
        tbpres = any(ismember(toolboxInfo.(lower(toolboxes{i})), {res.Name}));
    else
        % rely on the license
        tbpres = licpres;
    end
    if ~tbpres
        missingTBs.Installation{end + 1} = tbstring;
    end
    if ~licpres
        missingTBs.License{end + 1} = tbstring;
    end
end

% append the error message
if ~isempty(missingTBs.License)
    errorMessage{end + 1} = sprintf('The test requires licenses for the following Toolboxes: %s', strjoin(missingTBs.License, ' and '));
end
if ~isempty(missingTBs.Installation)
    errorMessage{end + 1} = sprintf('The test requires the following Toolboxes to be installed: %s', strjoin(missingTBs.Installation, ' and '));
end

% set up default solvers and test whether the test is useable
if isempty(solversForTest.LP)
    if useLP
        errorMessage{end + 1} = 'The test requires at least one LP solver but no solver is installed';
    end
else
    if ~isempty(solversForTest.LP)
        defaultLPSolver = solversForTest.LP{1};
    else
        defaultLPSolver = '';
    end
end

if isempty(solversForTest.QP)
    if useQP
        errorMessage{end + 1} = 'The test requires at least one QP solver but no solver is installed';
    end
else
    if ~isempty(solversForTest.QP)
        defaultQPSolver = solversForTest.QP{1};
    else
        defaultQPSolver = '';
    end
end

if isempty(solversForTest.MILP)
    if useMILP
        errorMessage{end + 1} = 'The test requires at least one MILP solver but no solver is installed';
    end
else
    if ~isempty(solversForTest.MILP)
        defaultMILPSolver = solversForTest.MILP{1};
    else
        defaultMILPSolver = '';
    end

end

if isempty(solversForTest.MIQP)
    if useMIQP
        errorMessage{end + 1} = 'The test requires at least one MIQP solver but no solver is installed';
    end
else
    if ~isempty(solversForTest.MIQP)
        defaultMIQPSolver = solversForTest.MIQP{1};
    else
        defaultMIQPSolver = '';
    end

end

if isempty(solversForTest.NLP)
    if useNLP
        errorMessage{end + 1} = 'The test requires at least one NLP solver but no solver is installed';
    end
else
    if ~isempty(solversForTest.NLP)
        defaultNLPSolver = solversForTest.NLP{1};
    else
        defaultNLPSolver = '';
    end
end

if isempty(solversForTest.EP)
    if useEP
        errorMessage{end + 1} = 'The test requires at least one EP solver but no solver is installed';
    end
else
    if ~isempty(solversForTest.EP)
        defaultEPSolver = solversForTest.EP{1};
    else
        defaultEPSolver = '';
    end
end

if ~isempty(errorMessage)
    errorString = strjoin(errorMessage, '\n');
    infoString = strjoin(infoMessage, '\n');
    error(CBT_MISSING_REQUIREMENTS_ERROR_ID, strjoin({errorString,infoString}, '\n'));
end

% collect the Used Solvers.
solversToUse = struct();
problemTypes = OPT_PROB_TYPES;
% if this is the extensive test suite, and the solver use not just about
% testing whether the actual work succeeded.
if strcmpi(runtype, 'extensive') && ~useMinimalNumberOfSolvers
    solversToUse = solversForTest;
    if 0
        % exclude pdco if not explicitly requested and available, as it has issues at the moment.
        if ~any(ismember('pdco',preferredSolvers)) && any(ismember('pdco',solversToUse.LP))
            solversToUse.LP(ismember(solversToUse.LP,'pdco')) = [];
            solversToUse.QP(ismember(solversToUse.LP,'pdco')) = [];
        end
    end
    if ~isempty(possibleSolvers)
        %Restrict to the possibleSolvers
        for i = 1:numel(problemTypes)
            solversToUse.(problemTypes{i}) = intersect(solversToUse.(problemTypes{i}),possibleSolvers);
        end
    end
else
    for i = 1:numel(problemTypes)
        solversToUse.(problemTypes{i}) = intersect(preferredSolvers, solversForTest.(problemTypes{i}));
        if isempty(solversToUse.(problemTypes{i})) && ~isempty(solversForTest.(problemTypes{i}))
            if isempty(preferredSolvers)
                eval(['solversToUse.' problemTypes{i} ' = {default' problemTypes{i} 'Solver};']);
            else
                if isempty(solversForTest.(problemTypes{i}))
                    % no solver exists, the cell array is empty.
                    solversToUse.(problemTypes{i}) = {};
                else
                    % a solver exists, provide it.
                    eval(['solversToUse.' problemTypes{i} ' = {default' problemTypes{i} 'Solver};']);
                end
            end
        end
    end
end


function oldSettings = fillPage(h, varargin)
%FILLPAGE set figure h to fill a page when printed/exported
%   FILLPAGE will adjust printing/exporting related properties so the
%   figure (h) will take up a full page when printed/exported. Optional
%   arguments (varargin) allow you to adjust the margins and page size used.
%
%	OLDSETTINGS = FILLPAGE(fig) returns a structure containing the names of
%	page-related properties that **may** have been affected by FILLPAGE, and
%	the original values of those properties (before any FILLPAGE changes)
%   The figure settings can be restored by
%      set(fig, oldsettings);
%
%   FILLPAGE also accepts up to 2 optional parameter-value pairs:
%       parameter      value/meaning
%       ----------     --------------------------------------
%        'margins'     1x4 numeric array specifying the
%                      margins to use on the left, right, top,
%                      and bottom, respectively. Units used are the
%                      figure's current PaperUnits.
%
%                      If not specified, a margin of [.25 .25 .5 .5]
%                      is used.
%
%        'papersize'   a 1x2 numeric array specifying the
%                      width and height of the page, respectively.
%                      Units used are the figure's current PaperUnits.
%                                  OR
%                      a string specifying the paper type to use
%                        (see the figure's PaperType property for
%                        valid values)
%
%                      If not specified, the figure's current PaperSize
%                      is used.
%
%   Example usage:
%     % fills page based on current settings
%        figure;
%        surf(peaks);
%        oldSettings = fillpage(gcf);
%     % fills page leaving a margin of .5 around all sides
%        figure;
%        surf(peaks);
%        oldSettings = fillpage(gcf, 'margins', [.5 .5 .5 .5]);
%     % fills page using A4 paper size
%        figure;
%        surf(peaks);
%        oldSettings = fillpage(gcf, 'papersize', 'A4');
%     % fills page using a paper size of 4x6
%        figure;
%        surf(peaks);
%        oldSettings = fillpage(gcf, 'papersize', [4 6]);
%     % fills page using USLetter paper size with margin of 1 all around
%        figure;
%        surf(peaks);
%        oldSettings = fillpage(gcf, 'papersize', 'usletter', 'margins', [1 1 1 1]);
%
% See also PRINT

%   Copyright 2007 The MathWorks, Inc.

% set up some meaningful aliases for index values
IDX_PAPERTYPE = 1;
IDX_PAPERSIZE = 2;
IDX_PAPERPOSITION = 3;
IDX_PAPERPOSITIONMODE = 4;

if ishandle(h)
    setprops = {'PaperType', 'PaperSize', 'PaperPosition', 'PaperPositionMode'};
    try
        settings = get(h, setprops);
    catch
        error('fillPage unable to get figure properties');
    end

    oldSettings = cell2struct(settings, setprops, 2); % to return to caller
    paramSettings = processArgs(varargin{:});
    if isstruct(paramSettings)
        % process papersize/type
        if isfield(paramSettings, 'papertype')
            if ~isempty(paramSettings.papertype)
                settings{IDX_PAPERTYPE} = paramSettings.papertype;
                % surround with try/catch in case setting is invalid
                try
                   set(h, 'PaperType', paramSettings.papertype);
                catch
                    error('fillPage: invalid PaperType ''%s'' requested ', ...
                        paramSettings.papertype );
                end
                if isfield(paramSettings, 'papersize') && ...
                    ~isempty(paramSettings.papersize)
                    settings{IDX_PAPERSIZE} = paramSettings.papersize;
                else
                    % since changing papertype might change papersize...
                    % re-read value
                    settings{IDX_PAPERSIZE} = get(h, 'PaperSize');
                end
            end
        end

        % process margins
        if isfield(paramSettings, 'margins')
            margins = paramSettings.margins;
            papersize = settings{IDX_PAPERSIZE};
            settings{IDX_PAPERPOSITIONMODE} = 'manual';
            settings{IDX_PAPERPOSITION} = [ ...
                 margins.left ... % X = leftMargin
                 margins.bottom ... % Y = bottomMargin
                 papersize(1) - (margins.right + margins.left) ... % W =  paperwidth - rightMargin - leftMargin
                 papersize(2) - (margins.top + margins.bottom) ... % H = paperheight - topMargin - bottomMargin
                 ];
        end
    end
    set(h, setprops, settings);
else
    error('fillPage requires a handle to a figure');
end
end

% helper function to deal with parsing command line arguments
function param_settings = processArgs(varargin)
    margins.left   = .25;
    margins.right  = .25;
    margins.top    = .5;
    margins.bottom = .5;
    papertype = [];
    papersize = [];

    for i = 1 : 2 : length(varargin)-1
        param_arg = varargin{i};

        % if caller specified margins to use
        if ischar(param_arg) && strcmpi(param_arg, 'margins')
           val_arg = varargin{i+1};
           if isnumeric(val_arg) && length(val_arg) == 4
               margins.left   = val_arg(1);
               margins.right  = val_arg(2);
               margins.top    = val_arg(3);
               margins.bottom = val_arg(4);
           else
               warning('fillpage:InvalidMargin', ...
                   'fillpage ignoring invalid margin setting; using default');
           end
        end

        % if caller specified papersize to use
        if ischar(param_arg) && strcmpi(param_arg, 'papersize')
           val_arg = varargin{i+1};
           if ischar(val_arg)
              papertype = val_arg;
            elseif isnumeric(val_arg) && length(val_arg) == 2
              papertype = '<custom>';
              papersize = val_arg;
           else
               warning('fillpage:InvalidPapersize', ...
                   'fillpage ignoring invalid papersize setting; using figure''s current papersize');
           end
        end
    end

    param_settings.margins = margins;
    param_settings.papertype = papertype;
    param_settings.papersize = papersize;
end


function [ loadFiles, loadDirs ] = findFilesDirs( imagePath)
% recursive search
%
% (c) Marc Fischer, Thomas Kuestner
% ---------------------------------------------------------------------

[filesInPath, dirsInPath] = rdir(imagePath);
% filter files (just use *.mat and *.dat)
allFiles = cell(1,length(filesInPath));
allDirs = cell(1,length(dirsInPath));
foundFile = false(1,length(filesInPath));
if ~isempty(dirsInPath)
    nDirsInPath = length(dirsInPath);
    for k = 1:nDirsInPath
        allDirs{k} = dirsInPath.fullpath;
    end;
else
    nDirsInPath = 1;
end;
foundDir = false(1,length(nDirsInPath));

for i=1:length(filesInPath)
    allFiles{i} = filesInPath(i).fullpath;
        tmp = regexp(allFiles{i},'\w+x\d*\w+\.[md]at', 'once');
        tmp2 = regexp(allFiles{i},'\w+_rec\w+', 'once');
        if (~isempty(tmp) && isempty(tmp2))
            foundFile(i) = true;
        end;
end;
for k=1:nDirsInPath; % for DICOM only check for dirs, since fReadDICOM searches a whole folder -> if folder contains *.IMA-file, set found(k) true
    for i=1:length(filesInPath)
        if ~isempty(allDirs)
            tmp = regexp(allFiles{i},'\w+.IMA', 'once');
            if(~isempty(tmp))
                dirString = regexptranslate('escape', allDirs{k});
                tmp_dir = regexp(allFiles{i},[dirString '\w*'],'once');
                if(~isempty(tmp_dir))
                    foundDir(k) = true;
                end;
            end;
        else
            allDirs{k} = imagePath;
            allFiles{i} = filesInPath(i).fullpath;
            tmp = regexp(allFiles{i},'\w+.IMA', 'once');
            if(~isempty(tmp))
                dirString = regexptranslate('escape', allDirs{k});
                regexp(allFiles{i},[dirString '\w*']);
                foundDir(k) = true;
            end;
        end;
    end;
end

loadFiles = allFiles(foundFile);
loadDirs = allDirs(foundDir);

% remove same file names (only needed for mat/dat)
helper = cellfun(@(x) x(1:end-4), loadFiles, 'UniformOutput', false); % removes file extension in string
[~, idxloadFiles, ~] = unique(helper); % sorts out double entries
loadFiles = loadFiles(idxloadFiles);

end


function test_suite = test_regression_additive2

%   Run specific demo, save values and compare the results to the expected.
%   Works for both xUnit Test Framework package by Steve Eddins and for
%   the built-in Unit Testing Framework (as of Matlab version 2013b).
%
%   See also
%     TEST_ALL, DEMO_REGRESSION_ADDITIVE2
%
% Copyright (c) 2011-2012 Ville Tolvanen
% Copyright (c) 2014 Tuomas Sivula

% This software is distributed under the GNU General Public
% License (version 3 or later); please refer to the file
% License.txt, included with the software, for details.

  % Check which package to use
  if exist('initTestSuite', 'file')
    initTestSuite_path = which('initTestSuite');
  else
    initTestSuite_path = '';
  end
  if ~isempty(initTestSuite_path) && ...
     exist([initTestSuite_path(1:end-15) 'runtests'], 'file')
    % xUnit package
    initTestSuite;
  else
    % Built-in package
    % Use all functions except the @setup
    tests = localfunctions;
    tests = tests(~cellfun(@(x)strcmp(func2str(x),'setup'),tests));
    test_suite = functiontests(tests);
  end
end

% -------------
%     Tests
% -------------

function testRunDemo(testCase)
  % Run the correspondin demo and save the values. Note this test has to
  % be run at lest once before the other test may succeed.
  rundemo(getName())
end

function testNeuralNetworkCFPrediction(testCase)
  verifyVarsEqual(testCase, getName(), {'Eft_map'}, ...
    'RelTolElement', 0.05, 'RelTolRange', 0.01)
end

% ------------------------
%     Helper functions
% ------------------------

function testCase = setup
  % Helper function to suply empty array into variable testCase as an
  % argument for each test function, if using xUnit package. Not to be
  % used with built-in test framework.
  testCase = [];
end

function name = getName
  % Helperfunction that returns the name of the demo, e.g. 'binomial1'.
  name = mfilename;
  name = name(6:end);
end


function [models, info] = slproglearn(source, getter, learnfunctor, varargin)
%SLPROGLEARN Performs Progressive Learning from sample source
%
% $ Syntax $
%   - models = slproglearn(source, getter, learnfunctor, ...)
%   - [models, info] = slproglearn(source, getter, learnfunctor, ...)
%
% $ Arguments $
%   - source:       the source from which the data are fetched
%   - getter:       the functor to fetch data from source, in the form:
%                   data= f(source, ...)
%   - learnfunctor: the functor to construct/update models from data,
%                   it is given in the following form:
%                   models = f(models, data, ...)
%                   If the learning is recorded, it is like:
%                   [models, record] = f(models, data, ...)
%                   On initial construction, the input models is [].
%   - models:       The constructed models
%
% $ Description $
%   - models = slproglearn(source, getter, learnfunctor, ...)
%     construct models based on source, from which the samples are
%     fetched. It is assumed that the source can continuously offer
%     infinite number of samples. The construction is controlled by
%     the following properties.
%     \*
%     \t   Table. Properties of Progressive Learning
%     \h       name        &            description             \\
%          'isrecorded'    &  Whether each iteration is recorded
%                             (default = false)                 \\
%          'gtuner'        &  The functor to tune the getter, in the form:
%                             getter = f(getter, models, ...)
%                             (default = {})                      \\
%          'cmpfunctor'    &  The functor to compare two set of models
%                             and judge whether discrepancies meet the
%                             criteria of convergence.
%                             It is given in the following form:
%                             isconverged = f(models1, models2, ...)
%                             This properties must be specified.     \\
%          'iter'          &  The iteration control properties for
%                             sliterproc, default = {}.
%          'verbose'       &  whether to show progress information
%                             (default = true)                       \\
%          'initmodels'    &  The initial models, (default = [])
%     \*
%
%   - [models, info] = slproglearn(source, getter, learnfunctor, ...) also
%     returns the information of iterative process.
%
% $ History $
%   - Created by Dahua Lin, on Aug 31, 2006
%

%% Parse and verify input arguments

if nargin < 3
    raise_lackinput('slproglearn', 3);
end

opts.isrecorded = false;
opts.gtuner = [];
opts.cmpfunctor = [];
opts.iter = {};
opts.verbose = true;
opts.initmodels = [];
opts = slparseprops(opts, varargin{:});

if isempty(opts.cmpfunctor)
    error('sltoolbox:invalidarg', ...
        'You should specify a models comparison functor');
end

%% Main Skeleton

slsharedisp_attach('slproglearn', 'show', opts.verbose);

slsharedisp(opts, 'Progressive Learning from source');

objects = {source, opts.initmodels, getter};
iterfunctor = {@proglearn_iter, learnfunctor, opts};
cmpfunctor = {@proglearn_cmp, opts};
if nargout < 2
    objects = ...
        sliterproc(objects, iterfunctor, cmpfunctor, opts.isrecorded, opts.iter{:});
else
    [objects, info] = ...
        sliterproc(objects, iterfunctor, cmpfunctor, opts.isrecorded, opts.iter{:});
end

models = objects{2};

slsharedisp_detach();

%% Core Iteration function

function varargout = proglearn_iter(objects, learnfunctor, opts)
% objects = {source, models, getter}

% take input
source = objects{1};
models = objects{2};
getter = objects{3};

% fetch data
data = slevalfunctor(getter, source);

% learn models
if ~opts.isrecorded
    models = slevalfunctor(learnfunctor, models, data);
else
    [models, rec] = slevalfunctor(learnfunctor, models, data);
end

% tune getter
if ~isempty(opts.gtuner)
    getter = slevalfunctor(opts.gtuner, getter, models);
end

% make output
objects = {source, models, getter};
if ~opts.isrecorded
    varargout = {objects};
else
    varargout = {objects, rec};
end

function isconverged = proglearn_cmp(objects_prev, objects, opts)

models_prev = objects_prev{2};
models = objects{2};

isconverged = slevalfunctor(opts.cmpfunctor, models_prev, models);


function hdr = read_yokogawa_header_new(filename)

% READ_YOKOGAWA_HEADER_NEW reads the header information from continuous,
% epoched or averaged MEG data that has been generated by the Yokogawa
% MEG system and software and allows that data to be used in combination
% with FieldTrip.
%
% Use as
%  [hdr] = read_yokogawa_header_new(filename)
%
% This is a wrapper function around the functions
% getYkgwHdrSystem
% getYkgwHdrChannel
% getYkgwHdrAcqCond
% getYkgwHdrCoregist
% getYkgwHdrDigitize
% getYkgwHdrSource
%
% See also READ_YOKOGAWA_DATA_NEW, READ_YOKOGAWA_EVENT

% **
% Copyright (C) 2005, Robert Oostenveld and 2010, Tilmann Sander-Thoemmes
%
% 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$

% FIXED
%  txt -> m
%  fopen iee-le

if ~ft_hastoolbox('yokogawa_meg_reader')
    ft_error('cannot determine whether Yokogawa toolbox is present');
end

handles = definehandles;

sys_info = getYkgwHdrSystem(filename);
id = sys_info.system_id;
ver = sys_info.version;
rev = sys_info.revision;
sys_name = sys_info.system_name;
model_name = sys_info.model_name;
clear('sys_info'); % remove structure as local variables are collected in the end

channel_info = getYkgwHdrChannel(filename);
channel_count = channel_info.channel_count;

acq_cond = getYkgwHdrAcqCond(filename);
acq_type = acq_cond.acq_type;

% these depend on the data type
sample_rate        = [];
sample_count       = [];
pretrigger_length  = [];
averaged_count     = [];
actual_epoch_count = [];

switch acq_type
  case handles.AcqTypeContinuousRaw
    sample_rate = acq_cond.sample_rate;
    sample_count = acq_cond.sample_count;
    if isempty(sample_rate) || isempty(sample_count)
      ft_error('invalid sample rate or sample count in ', filename);
      return;
    end
    pretrigger_length = 0;
    averaged_count = 1;

  case handles.AcqTypeEvokedAve
    sample_rate = acq_cond.sample_rate;
    sample_count = acq_cond.frame_length;
    pretrigger_length = acq_cond.pretrigger_length;
    averaged_count = acq_cond.average_count;
    if isempty(sample_rate) || isempty(sample_count) || isempty(pretrigger_length) || isempty(averaged_count)
      ft_error('invalid sample rate or sample count or pretrigger length or average count in ', filename);
      return;
    end
    if acq_cond.multi_trigger.enable
      ft_error('multi trigger mode not supported for ', filename);
      return;
    end
  case handles.AcqTypeEvokedRaw
    sample_rate = acq_cond.sample_rate;
    sample_count = acq_cond.frame_length;
    pretrigger_length = acq_cond.pretrigger_length;
    actual_epoch_count = acq_cond.average_count;
    if isempty(sample_rate) || isempty(sample_count) || isempty(pretrigger_length) || isempty(actual_epoch_count)
      ft_error('invalid sample rate or sample count or pretrigger length or epoch count in ', filename);
      return;
    end
    if acq_cond.multi_trigger.enable
      ft_error('multi trigger mode not supported for ', filename);
      return;
    end

  otherwise
    ft_error('unknown data type');
end
clear('acq_cond'); % remove structure as local variables are collected in the end

coregist = getYkgwHdrCoregist(filename);
digitize = getYkgwHdrDigitize(filename);
source = getYkgwHdrSource(filename);

% put all local variables into a structure, this is a bit unusual matlab programming style
tmp = whos;
orig = [];
for i=1:length(tmp)
  if isempty(strmatch(tmp(i).name, {'tmp', 'ans', 'handles'}))
    orig = setfield(orig, tmp(i).name, eval(tmp(i).name));
  end
end

% convert the original header information into something that FieldTrip understands
hdr = [];
hdr.orig         = orig;                % also store the original full header information
hdr.Fs           = orig.sample_rate;    % sampling frequency
hdr.nChans       = orig.channel_count;  % number of channels
hdr.nSamples     = [];                  % number of samples per trial
hdr.nSamplesPre  = [];                  % number of pre-trigger samples in each trial
hdr.nTrials      = [];                  % number of trials

switch orig.acq_type
  case handles.AcqTypeEvokedAve
    hdr.nSamples    = orig.sample_count;
    hdr.nSamplesPre = orig.pretrigger_length;
    hdr.nTrials     = 1;                % only the average, which can be considered as a single trial
  case handles.AcqTypeContinuousRaw
    hdr.nSamples    = orig.sample_count;
    hdr.nSamplesPre = 0;                % there is no fixed relation between triggers and data
    hdr.nTrials     = 1;                % the continuous data can be considered as a single very long trial
  case handles.AcqTypeEvokedRaw
    hdr.nSamples    = orig.sample_count;
    hdr.nSamplesPre = orig.pretrigger_length;
    hdr.nTrials     = orig.actual_epoch_count;
  otherwise
    ft_error('unknown acquisition type');
end

% construct a cell-array with labels of each channel
for i=1:hdr.nChans
% this should be consistent with the predefined list in ft_senslabel,
% with yokogawa2grad_new and with ft_channelselection
  if     hdr.orig.channel_info.channel(i).type == handles.NullChannel
    prefix = '';
  elseif hdr.orig.channel_info.channel(i).type == handles.MagnetoMeter
    prefix = 'M';
  elseif hdr.orig.channel_info.channel(i).type == handles.AxialGradioMeter
    prefix = 'AG';
  elseif hdr.orig.channel_info.channel(i).type == handles.PlannerGradioMeter
    prefix = 'PG';
  elseif hdr.orig.channel_info.channel(i).type == handles.RefferenceMagnetoMeter
    prefix = 'RM';
  elseif hdr.orig.channel_info.channel(i).type == handles.RefferenceAxialGradioMeter
    prefix = 'RAG';
  elseif hdr.orig.channel_info.channel(i).type == handles.RefferencePlannerGradioMeter
    prefix = 'RPG';
  elseif hdr.orig.channel_info.channel(i).type == handles.TriggerChannel
    prefix = 'TRIG';
  elseif hdr.orig.channel_info.channel(i).type == handles.EegChannel
    prefix = 'EEG';
  elseif hdr.orig.channel_info.channel(i).type == handles.EcgChannel
    prefix = 'ECG';
  elseif hdr.orig.channel_info.channel(i).type == handles.EtcChannel
    prefix = 'ETC';
  end
  hdr.label{i} = sprintf('%s%03d', prefix, i);

  % overwrite EEG-channel labels
  if hdr.orig.channel_info.channel(i).type == handles.EegChannel
    if ~isempty(hdr.orig.channel_info.channel(i).data.name)
      hdr.label{i} = hdr.orig.channel_info.channel(i).data.name;
    end
  end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% this defines some usefull constants
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function handles = definehandles
handles.output = [];
handles.sqd_load_flag = false;
handles.mri_load_flag = false;
handles.NullChannel         = 0;
handles.MagnetoMeter        = 1;
handles.AxialGradioMeter    = 2;
handles.PlannerGradioMeter  = 3;
handles.RefferenceChannelMark = hex2dec('0100');
handles.RefferenceMagnetoMeter       = bitor( handles.RefferenceChannelMark, handles.MagnetoMeter );
handles.RefferenceAxialGradioMeter   = bitor( handles.RefferenceChannelMark, handles.AxialGradioMeter );
handles.RefferencePlannerGradioMeter = bitor( handles.RefferenceChannelMark, handles.PlannerGradioMeter );
handles.TriggerChannel      = -1;
handles.EegChannel          = -2;
handles.EcgChannel          = -3;
handles.EtcChannel          = -4;
handles.NonMegChannelNameLength = 32;
handles.DefaultMagnetometerSize       = (4.0/1000.0);       % Square of 4.0mm in length
handles.DefaultAxialGradioMeterSize   = (15.5/1000.0);      % Circle of 15.5mm in diameter
handles.DefaultPlannerGradioMeterSize = (12.0/1000.0);      % Square of 12.0mm in length
handles.AcqTypeContinuousRaw = 1;
handles.AcqTypeEvokedAve     = 2;
handles.AcqTypeEvokedRaw     = 3;
handles.sqd = [];
handles.sqd.selected_start  = [];
handles.sqd.selected_end    = [];
handles.sqd.axialgradiometer_ch_no      = [];
handles.sqd.axialgradiometer_ch_info    = [];
handles.sqd.axialgradiometer_data       = [];
handles.sqd.plannergradiometer_ch_no    = [];
handles.sqd.plannergradiometer_ch_info  = [];
handles.sqd.plannergradiometer_data     = [];
handles.sqd.eegchannel_ch_no   = [];
handles.sqd.eegchannel_data    = [];
handles.sqd.nullchannel_ch_no   = [];
handles.sqd.nullchannel_data    = [];
handles.sqd.selected_time       = [];
handles.sqd.sample_rate         = [];
handles.sqd.sample_count        = [];
handles.sqd.pretrigger_length   = [];
handles.sqd.matching_info   = [];
handles.sqd.source_info     = [];
handles.sqd.mri_info        = [];
handles.mri                 = [];


function oM  = PatalaOrientationMapping(varargin)

warning('Starting with MTEX 5.1 "PatalaOrientationMapping" has been replaced by "PatalaColorKey".')
oM = PatalaColorKey(varargin{:});

end


function [atlasView, atlasTypeNum] = getAtlasView()
%
% [atlasView, atlasTypeNum] = getAtlasView()
%
% Author:  Brewer, Wandell
% Purpose:
%
% We check which of the currently open FLAT windows have dataTYPE set to
% Atlases-???'. If there is only one, then that FLAT view is returned. If
% there are none, an empty array is returned. If there is more than one,
% the user is prompted to select the figure showing the desired Atlas.
%
mrGlobals;
atlasViewList = {};

% Changed -- if createAtlas fails this could be the cause.
atlasTypeNum = existDataType('Atlases',[],0);

for(ii=1:length(FLAT))
    % strmatch will match if only the first part matches
    if(~isempty(FLAT{ii}) & strmatch('Atlases',getDataTypeName(FLAT{ii})))
        % These are the FLAT{} data structures with an Atlases type
        % selected.
        atlasViewList{end+1} = ii;
    end
end

if(isempty(atlasViewList))
    atlasView = [];
elseif(length(atlasViewList)==1)
    atlasView = FLAT{atlasViewList{1}};
else
    % More than one of the FLAT{} structures has an Atlases type selected.
    % We ask the user which of the FLAT{} structures they have in mind.
    % We figure this out by asking them to identify the figure number with
    % the selected atlas.  Then, we convert the figure number into the
    % index into the FLAT{} cell array.
    prompt={'Enter the figure number of the FLAT view showing the atlas'};
    def={'1'}; dlgTitle='Figure Showing Atlas'; lineNo=1;
    answer=inputdlg(prompt,dlgTitle,lineNo,def);
    atlasFig = str2num(answer{1});
    idx = fignum2FLATindex(atlasFig);
    if ~isempty(idx),  atlasView = FLAT{idx};
    else
        errordlg('Selected figure number does not have an Atlases data type.');
        atlasView = [];
    end
end

return;


% This demo script runs the SRDCF tracker on the included "Couple" video.

% Load video information
video_path = 'sequences/Couple';
% video_path = 'D:/Users/sliay/research/drone_benchmark/car2';
[seq, ~] = load_video_info(video_path);

% Run SRDCF
results = run_SRDCF(seq);


function f = getfigurepos(fig,units)

% function f = getfigurepos(fig,units)
%
% <fig> (optional) is the figure handle.  default: gcf.
% <units> (optional) is 'normalized' (default) | 'points'
%
% return the position of <fig> in units specified by <units>.
%
% example:
% figure; getfigurepos(gcf,'points')

% input
if ~exist('fig','var') || isempty(fig)
  fig = gcf;
end
if ~exist('units','var') || isempty(units)
  units = 'normalized';
end

% do it
  prev = get(fig,'Units');
  set(fig,'Units',units);
f = get(fig,'Position');
  set(fig,'Units',prev);


%DISP Display dataset
%
%	DISP(A)
%
% Display dataset A and its content


classdef testPrintingComparator < handle

    properties (Access = protected, Abstract)
        fileOutputName
        iter
    end

    methods (Access = protected)

        function hasPassed = hasPassed(obj)
            hasMshChanged = obj.compareFile('.msh');
            hasResChanged = obj.compareFile('.res');
            filesHaveChanged = hasMshChanged || hasResChanged;
            hasPassed = ~filesHaveChanged;
        end

        function selectComputedVar(obj)
        end

    end

    methods (Access = private)

       function sF = obtainSavedPrintedFile(obj,ext)
           out   = obj.fileOutputName;
           fullOutSavedName = [out,'.flavia',ext];
           sF = fullfile('tests','PrintingTests',out,fullOutSavedName);
        end

        function oF = obtainOutPutFile(obj,ext)
           out   = obj.fileOutputName;
           fullOutName = [out,num2str(obj.iter),'.flavia',ext];
           oF = fullfile('Output',out,fullOutName);
        end

        function hasChanged = compareFile(obj,ext)
            sF = obj.obtainSavedPrintedFile(ext);
            oF = obj.obtainOutPutFile(ext);
            hasChanged = FileComparator().areFilesDifferent(sF,oF);
        end

    end

end


% mff_fileio_write - export Fieldtrip structures to MFF file
%
% Usage:
%   mff_fileio_write(mffFile, header, data, event);
%
% Inputs:
%   mffFile - [string] MFF file name
%   header   - fieldtrip data header
%   data     - fieldtrip raw data
%   event    - fieldtrip event structure (optional)

% This file is part of mffmatlabio.
%
% mffmatlabio 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.
%
% mffmatlabio 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 mffmatlabio.  If not, see <https://www.gnu.org/licenses/>.

function mff_fileio_write(filename, hdr, data, evt)

if exist('pop_fileio')
    a = dir(which('pop_fileio.m'));
    b = dir(which('pop_fileio2.m'));
    if isempty(a) || isempty(b) || a.bytes ~= b.bytes
        fprintf([ '-----------------------------------------------------------------------------\n' ...
                  'WARNING: pop_fileio.m and pop_fileio2.m differ; likely you are using\n' ...
                  '         an old version of EEGLAB; The importer will try to import data using\n' ...
                  '         the pop_fileio.m function, and revert to pop_fileio2.m if it crashes\n' ...
                  '-----------------------------------------------------------------------------\n' ]);
    end
    try
        EEG = pop_fileio(hdr, data, evt); % maybe the wrong version?
    catch
        EEG = pop_fileio2(hdr, data, evt); % backup function included here
    end
else
    EEG = pop_fileio2(hdr, data, evt); % backup function included here
end

if isfield(hdr, 'orig')
    if isfield(hdr.orig, 'etc')
        EEG.etc = hdr.orig.etc;
    end
end

mff_export(EEG, filename);

% add code for eeg_emptyset
% add code for pop_fileio
% add code for finputcheck


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


classdef (Abstract) AbstractTrajectoryViewType < matlab.mixin.SetGet & matlab.mixin.Heterogeneous
    %AbstractTrajectoryViewType Summary of this class goes here
    %   Detailed explanation goes here

    methods
        [hCBodySurf, childrenHGs] = plotStateLog(obj, orbitNumToPlot, lvdData, handles)
    end
end


function eeg_write_scan4_avg(f,filename)

% eeg_write_scan4_avg - Write a Neuroscan 'scan4.x' average file
%
% Useage: eeg_write_scan4_avg(f,filename)
%
% where:    filename is a complete 'path\fileprefix.ext' string;
%           the file will be a neuroscan 4.x avg file.
%
%           f is a structure containing:
%
%               f.header
%               f.electloc
%               f.data
%               f.variance
%               f.tag
%
%           See companion function: eeg_load_scan4_avg.m
%

% $Revision: 1.1 $ $Date: 2009-04-28 22:13:54 $

% Licence:  GNU GPL, no implied or express warranties
% Created:  08/2000, Sean.Fitzgibbon_at_flinders.edu.au
% Modified: 08/2001, Darren.Weber_at_radiology.ucsf.edu
%                    distribute under GPL, with Sean's permission
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

ver = '$Revision: 1.1 $';
fprintf('EEG_WRITE_SCAN4_AVG [v %s]\n',ver(11:15)); tic;

fid = fopen(filename,'w');

fwrite(fid,f.header.rev,'char');
fwrite(fid,f.header.nextfile,'long');
fwrite(fid,f.header.prevfile,'long');
fwrite(fid,f.header.type,'char');
fwrite(fid,f.header.id,'char');
fwrite(fid,f.header.oper,'char');
fwrite(fid,f.header.doctor,'char');
fwrite(fid,f.header.referral,'char');
fwrite(fid,f.header.hospital,'char');
fwrite(fid,f.header.patient,'char');
fwrite(fid,f.header.age,'short');
fwrite(fid,f.header.sex,'char');
fwrite(fid,f.header.hand,'char');
fwrite(fid,f.header.med,'char');
fwrite(fid,f.header.category,'char');
fwrite(fid,f.header.state,'char');
fwrite(fid,f.header.label,'char');
fwrite(fid,f.header.date,'char');
fwrite(fid,f.header.time,'char');
fwrite(fid,f.header.mean_age,'float');
fwrite(fid,f.header.stdev,'float');
fwrite(fid,f.header.n,'short');
fwrite(fid,f.header.compfile,'char');
fwrite(fid,f.header.spectwincomp,'float');
fwrite(fid,f.header.meanaccuracy,'float');
fwrite(fid,f.header.meanlatency,'float');
fwrite(fid,f.header.sortfile,'char');
fwrite(fid,f.header.numevents,'int');
fwrite(fid,f.header.compoper,'char');
fwrite(fid,f.header.avgmode,'char');
fwrite(fid,f.header.review,'char');
fwrite(fid,f.header.nsweeps,'ushort');
fwrite(fid,f.header.compsweeps,'ushort');
fwrite(fid,f.header.acceptcnt,'ushort');
fwrite(fid,f.header.rejectcnt,'ushort');
fwrite(fid,f.header.pnts,'ushort');
fwrite(fid,f.header.nchannels,'ushort');
fwrite(fid,f.header.avgupdate,'ushort');
fwrite(fid,f.header.domain,'char');
fwrite(fid,f.header.variance,'char');
fwrite(fid,f.header.rate,'ushort');
fwrite(fid,f.header.scale,'double');
fwrite(fid,f.header.veogcorrect,'char');
fwrite(fid,f.header.heogcorrect,'char');
fwrite(fid,f.header.aux1correct,'char');
fwrite(fid,f.header.aux2correct,'char');
fwrite(fid,f.header.veogtrig,'float');
fwrite(fid,f.header.heogtrig,'float');
fwrite(fid,f.header.aux1trig,'float');
fwrite(fid,f.header.aux2trig,'float');
fwrite(fid,f.header.heogchnl,'short');
fwrite(fid,f.header.veogchnl,'short');
fwrite(fid,f.header.aux1chnl,'short');
fwrite(fid,f.header.aux2chnl,'short');
fwrite(fid,f.header.veogdir,'char');
fwrite(fid,f.header.heogdir,'char');
fwrite(fid,f.header.aux1dir,'char');
fwrite(fid,f.header.aux2dir,'char');
fwrite(fid,f.header.veog_n,'short');
fwrite(fid,f.header.heog_n,'short');
fwrite(fid,f.header.aux1_n,'short');
fwrite(fid,f.header.aux2_n,'short');
fwrite(fid,f.header.veogmaxcnt,'short');
fwrite(fid,f.header.heogmaxcnt,'short');
fwrite(fid,f.header.aux1maxcnt,'short');
fwrite(fid,f.header.aux2maxcnt,'short');
fwrite(fid,f.header.veogmethod,'char');
fwrite(fid,f.header.heogmethod,'char');
fwrite(fid,f.header.aux1method,'char');
fwrite(fid,f.header.aux2method,'char');
fwrite(fid,f.header.ampsensitivity,'float');
fwrite(fid,f.header.lowpass,'char');
fwrite(fid,f.header.highpass,'char');
fwrite(fid,f.header.notch,'char');
fwrite(fid,f.header.autoclipadd,'char');
fwrite(fid,f.header.baseline,'char');
fwrite(fid,f.header.offstart,'float');
fwrite(fid,f.header.offstop,'float');
fwrite(fid,f.header.reject,'char');
fwrite(fid,f.header.rejstart,'float');
fwrite(fid,f.header.rejstop,'float');
fwrite(fid,f.header.rejmin,'float');
fwrite(fid,f.header.rejmax,'float');
fwrite(fid,f.header.trigtype,'char');
fwrite(fid,f.header.trigval,'float');
fwrite(fid,f.header.trigchnl,'char');
fwrite(fid,f.header.trigmask,'short');
fwrite(fid,f.header.trigisi,'float');
fwrite(fid,f.header.trigmin,'float');
fwrite(fid,f.header.trigmax,'float');
fwrite(fid,f.header.trigdir,'char');
fwrite(fid,f.header.autoscale,'char');
fwrite(fid,f.header.n2,'short');
fwrite(fid,f.header.dir,'char');
fwrite(fid,f.header.dispmin,'float');
fwrite(fid,f.header.dispmax,'float');
fwrite(fid,f.header.xmin,'float');
fwrite(fid,f.header.xmax,'float');
fwrite(fid,f.header.automin,'float');
fwrite(fid,f.header.automax,'float');
fwrite(fid,f.header.zmin,'float');
fwrite(fid,f.header.zmax,'float');
fwrite(fid,f.header.lowcut,'float');
fwrite(fid,f.header.highcut,'float');
fwrite(fid,f.header.common,'char');
fwrite(fid,f.header.savemode,'char');
fwrite(fid,f.header.manmode,'char');
fwrite(fid,f.header.ref,'char');
fwrite(fid,f.header.rectify,'char');
fwrite(fid,f.header.displayxmin,'float');
fwrite(fid,f.header.displayxmax,'float');
fwrite(fid,f.header.phase,'char');
fwrite(fid,f.header.screen,'char');
fwrite(fid,f.header.calmode,'short');
fwrite(fid,f.header.calmethod,'short');
fwrite(fid,f.header.calupdate,'short');
fwrite(fid,f.header.calbaseline,'short');
fwrite(fid,f.header.calsweeps,'short');
fwrite(fid,f.header.calattenuator,'float');
fwrite(fid,f.header.calpulsevolt,'float');
fwrite(fid,f.header.calpulsestart,'float');
fwrite(fid,f.header.calpulsestop,'float');
fwrite(fid,f.header.calfreq,'float');
fwrite(fid,f.header.taskfile,'char');
fwrite(fid,f.header.seqfile,'char');
fwrite(fid,f.header.spectmethod,'char');
fwrite(fid,f.header.spectscaling,'char');
fwrite(fid,f.header.spectwindow,'char');
fwrite(fid,f.header.spectwinlength,'float');
fwrite(fid,f.header.spectorder,'char');
fwrite(fid,f.header.notchfilter,'char');
fwrite(fid,f.header.headgain,'short');
fwrite(fid,f.header.additionalfiles,'int');
fwrite(fid,f.header.unused,'char');
fwrite(fid,f.header.fspstopmethod,'short');
fwrite(fid,f.header.fspstopmode,'short');
fwrite(fid,f.header.fspfvalue,'float');
fwrite(fid,f.header.fsppoint,'short');
fwrite(fid,f.header.fspblocksize,'short');
fwrite(fid,f.header.fspp1,'ushort');
fwrite(fid,f.header.fspp2,'ushort');
fwrite(fid,f.header.fspalpha,'float');
fwrite(fid,f.header.fspnoise,'float');
fwrite(fid,f.header.fspv1,'short');
fwrite(fid,f.header.montage,'char');
fwrite(fid,f.header.eventfile,'char');
fwrite(fid,f.header.fratio,'float');
fwrite(fid,f.header.minor_rev,'char');
fwrite(fid,f.header.eegupdate,'short');
fwrite(fid,f.header.compressed,'char');
fwrite(fid,f.header.xscale,'float');
fwrite(fid,f.header.yscale,'float');
fwrite(fid,f.header.xsize,'float');
fwrite(fid,f.header.ysize,'float');
fwrite(fid,f.header.acmode,'char');
fwrite(fid,f.header.commonchnl,'uchar');
fwrite(fid,f.header.xtics,'char');
fwrite(fid,f.header.xrange,'char');
fwrite(fid,f.header.ytics,'char');
fwrite(fid,f.header.yrange,'char');
fwrite(fid,f.header.xscalevalue,'float');
fwrite(fid,f.header.xscaleinterval,'float');
fwrite(fid,f.header.yscalevalue,'float');
fwrite(fid,f.header.yscaleinterval,'float');
fwrite(fid,f.header.scaletoolx1,'float');
fwrite(fid,f.header.scaletooly1,'float');
fwrite(fid,f.header.scaletoolx2,'float');
fwrite(fid,f.header.scaletooly2,'float');
fwrite(fid,f.header.port,'short');
fwrite(fid,f.header.numsamples,'long');
fwrite(fid,f.header.filterflag,'char');
fwrite(fid,f.header.lowcutoff,'float');
fwrite(fid,f.header.lowpoles,'short');
fwrite(fid,f.header.highcutoff,'float');
fwrite(fid,f.header.highpoles,'short');
fwrite(fid,f.header.filtertype,'char');
fwrite(fid,f.header.filterdomain,'char');
fwrite(fid,f.header.snrflag,'char');
fwrite(fid,f.header.coherenceflag,'char');
fwrite(fid,f.header.continuoustype,'char');
fwrite(fid,f.header.eventtablepos,'long');
fwrite(fid,f.header.continuousseconds,'float');
fwrite(fid,f.header.channeloffset,'long');
fwrite(fid,f.header.autocorrectflag,'char');
fwrite(fid,f.header.dcthreshold,'uchar');

for n = 1:f.header.nchannels
fwrite(fid,f.electloc(n).lab,'char');
fwrite(fid,f.electloc(n).reference,'char');
fwrite(fid,f.electloc(n).skip,'char');
fwrite(fid,f.electloc(n).reject,'char');
fwrite(fid,f.electloc(n).display,'char');
fwrite(fid,f.electloc(n).bad,'char');
fwrite(fid,f.electloc(n).n,'ushort');
fwrite(fid,f.electloc(n).avg_reference,'char');
fwrite(fid,f.electloc(n).clipadd,'char');
fwrite(fid,f.electloc(n).x_coord,'float');
fwrite(fid,f.electloc(n).y_coord,'float');
fwrite(fid,f.electloc(n).veog_wt,'float');
fwrite(fid,f.electloc(n).veog_std,'float');
fwrite(fid,f.electloc(n).snr,'float');
fwrite(fid,f.electloc(n).heog_wt,'float');
fwrite(fid,f.electloc(n).heog_std,'float');
fwrite(fid,f.electloc(n).baseline,'short');
fwrite(fid,f.electloc(n).filtered,'char');
fwrite(fid,f.electloc(n).fsp,'char');
fwrite(fid,f.electloc(n).aux1_wt,'float');
fwrite(fid,f.electloc(n).aux1_std,'float');
fwrite(fid,f.electloc(n).senstivity,'float');
fwrite(fid,f.electloc(n).gain,'char');
fwrite(fid,f.electloc(n).hipass,'char');
fwrite(fid,f.electloc(n).lopass,'char');
fwrite(fid,f.electloc(n).page,'uchar');
fwrite(fid,f.electloc(n).size,'uchar');
fwrite(fid,f.electloc(n).impedance,'uchar');
fwrite(fid,f.electloc(n).physicalchnl,'uchar');
fwrite(fid,f.electloc(n).rectify,'char');
fwrite(fid,f.electloc(n).calib,'float');
end

for i = 1:f.header.nchannels
   fwrite(fid,f.data(i).header,'char');
   fwrite(fid,f.data(i).samples,'float');
end

for j = 1:f.header.nchannels
   fwrite(fid,f.variance(j).samples,'float');
end

fwrite(fid,f.tag,'char');

frewind(fid);
fclose(fid);

t = toc; fprintf('...done (%6.2f sec).\n\n',t);

return


function [orbitRow] = getSingularOrbitFromKSPTOTConnect(guid)
    orbitRow = {};

    if(~isempty(guid))
        name = readStringFromKSPTOTConnect('GetVesselNameByGUID', guid, true);
        status = readStringFromKSPTOTConnect('GetVesselStatusByGUID', guid, true);
        orbitDbl = readDoublesFromKSPTOTConnect('GetVesselOrbitByGUID', guid, true);
    else
        name = readStringFromKSPTOTConnect('GetActiveVesselName', '', true);
        status = '';
        orbitDbl = readDoublesFromKSPTOTConnect('GetActiveVesselOrbit', '', true);
    end

    orbitRow{1} = name;
    orbitRow{2} = status;
    orbitRow{3} = orbitDbl(1);
    orbitRow{4} = orbitDbl(2);
    orbitRow{5} = orbitDbl(3);
    orbitRow{6} = orbitDbl(4);
    orbitRow{7} = orbitDbl(5);

    if(orbitDbl(2) > 1.0)
        orbitRow{8} = orbitDbl(8);
    else
        orbitRow{8} = AngleZero2Pi(orbitDbl(8));
    end

    orbitRow{9} = orbitDbl(9);
    orbitRow{10} = orbitDbl(13);

    if(orbitRow{6} < 0)
        orbitRow{6} = orbitRow{6} + 360;
    end

    if(orbitRow{7} < 0)
        orbitRow{7} = orbitRow{7} + 360;
    end
end


function  AIMIDA  = readAIMIDA(fid)
%
% <<<<<<<<<< CLASSIFICATION: UNCLASSIFIED >>>>>>>>>>
%
% READAIMIDA Create structure for metadata fields.
%   AIMIDA = READAIMIDA(FID) returns a structure of fields and their
%   associated values.

% Written by Matt Donath, NGA, matthew.b.donath@nga.ic.gov
% References:
%  > MIL-STD-2500A, NATIONAL IMAGERY TRANSMISSION FORMAT VERSION 2.0
%  > MIL-STD-2500C, NATIONAL IMAGERY TRANSMISSION FORMAT VERSION 2.1
%  > STDI-0001,     NATIONAL SUPPORT DATA EXTENSIONS (SDE)(VERSION 1.3/CN2)
%                   FOR THE NATIONAL IMAGERY TRANSMISSION FORMAT (NITF)
%  > STDI-0002,     THE COMPENDIUM OF CONTROLLED EXTENSIONS (CE) FOR THE
%                   NATIONAL IMAGERY TRANSMISSION FORMAT (NITF) VERSION 2.1
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

%% Create the metadata structure for AIMIDA.

AIMIDA.CETAG = fread(fid,6,'uint8=>char')';
AIMIDA.CEL = str2double(fread(fid,5,'uint8=>char')');

AIMIDA.MISSION_DATE = fread(fid,7,'uint8=>char')';
AIMIDA.MISSION_NO = fread(fid,4,'uint8=>char')';
AIMIDA.FLIGHT_NO = fread(fid,2,'uint8=>char')';
AIMIDA.OP_NUM = fread(fid,3,'uint8=>char')';
AIMIDA.START_SEGMENT = fread(fid,2,'uint8=>char')';
AIMIDA.REPRO_NUM = str2double(fread(fid,2,'uint8=>char')');
AIMIDA.REPLAY = fread(fid,3,'uint8=>char')';
AIMIDA.Reserved1 = fread(fid,1,'uint8=>char')';
AIMIDA.START_COLUMN = str2double(fread(fid,2,'uint8=>char')');
AIMIDA.START_ROW = str2double(fread(fid,5,'uint8=>char')');
AIMIDA.END_SEGMENT = fread(fid,2,'uint8=>char')';
AIMIDA.END_COLUMN = str2double(fread(fid,2,'uint8=>char')');
AIMIDA.END_ROW = str2double(fread(fid,5,'uint8=>char')');
AIMIDA.COUNTRY = fread(fid,2,'uint8=>char')';
AIMIDA.Reserved2 = fread(fid,4,'uint8=>char')';
AIMIDA.LOCATION = fread(fid,11,'uint8=>char')';
AIMIDA.TIME = fread(fid,5,'uint8=>char')';
AIMIDA.CREATION_DATE = fread(fid,7,'uint8=>char')';

% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////


classdef Tx < adi.AD9371.Base & adi.common.Tx
    % adi.AD9371.Tx Transmit data from the AD9371 transceiver
    %   The adi.AD9371.Tx System object is a signal sink that can tranmsit
    %   complex data from the AD9371.
    %
    %   tx = adi.AD9371.Tx;
    %   tx = adi.AD9371.Tx('uri','192.168.2.1');
    %
    %   AD9371 Datasheet

    properties
        %AttenuationChannel0 Attenuation Channel 0
        %   Attentuation specified as a scalar from -89.75 to 0 dB with a
        %   resolution of 0.25 dB.
        AttenuationChannel0 = -30;
        %AttenuationChannel1 Attenuation Channel 1
        %   Attentuation specified as a scalar from -89.75 to 0 dB with a
        %   resolution of 0.25 dB.
        AttenuationChannel1 = -30;
    end

    properties (Hidden, Nontunable, Access = protected)
        isOutput = true;
    end

    properties(Nontunable, Hidden, Constant)
        Type = 'Tx';
        channel_names = {'voltage0','voltage1','voltage2','voltage3'};
    end

    properties (Nontunable, Hidden)
        devName = 'axi-ad9371-tx-hpc';
    end

    methods
        %% Constructor
        function obj = Tx(varargin)
            coder.allowpcode('plain');
            obj = obj@adi.AD9371.Base(varargin{:});
        end
        % Check Attentuation
        function set.AttenuationChannel0(obj, value)
            validateattributes( value, { 'double','single' }, ...
                { 'real', 'scalar', 'finite', 'nonnan', 'nonempty', '>=', -89.75,'<=', 0}, ...
                '', 'Attenuation');
            assert(mod(value,1/4)==0, 'Attentuation must be a multiple of 0.25');
            obj.AttenuationChannel0 = value;
            if obj.ConnectedToDevice
                id = 'voltage0';
                obj.setAttributeLongLong(id,'hardwaregain',value,true);
            end
        end
        % Check Attentuation
        function set.AttenuationChannel1(obj, value)
            validateattributes( value, { 'double','single' }, ...
                { 'real', 'scalar', 'finite', 'nonnan', 'nonempty', '>=', -89.75,'<=', 0}, ...
                '', 'Attenuation');
            assert(mod(value,1/4)==0, 'Attentuation must be a multiple of 0.25');
            obj.AttenuationChannel1 = value;
            if obj.ConnectedToDevice
                id = 'voltage1';
                obj.setAttributeLongLong(id,'hardwaregain',value,true);
            end
        end

    end

    %% API Functions
    methods (Hidden, Access = protected)

        function setupInit(obj)
            % Write all attributes to device once connected through set
            % methods
            % Do writes directly to hardware without using set methods.
            % This is required sine Simulink support doesn't support
            % modification to nontunable variables at SetupImpl

            if obj.EnableCustomProfile
                writeProfileFile(obj);
            end

            id = sprintf('altvoltage%d',strcmp(obj.Type,'Tx'));
            obj.setAttributeLongLong(id,'TX_LO_frequency',obj.CenterFrequency ,true);
            obj.setAttributeLongLong('voltage0','hardwaregain',obj.AttenuationChannel0,true);
            obj.setAttributeLongLong('voltage1','hardwaregain',obj.AttenuationChannel1,true);

            obj.ToggleDDS(strcmp(obj.DataSource,'DDS'));
            if strcmp(obj.DataSource,'DDS')
                obj.DDSUpdate();
            end
        end

    end

end


function moverotateobj(action)
%moverotateobj(action)
%
%Called when an object is clicked on
%whos ButtonDownFcn = moverotateobj('BtnDown')
%
%This is can be done by using
%   set(h,'ButtonDownFcn','moverotateobj(''BtnDown'')')
%where h is handle vector or typing
%moverotateobj('On') does this automatically
%moverotateobj('Off') takes it off
%
%moverotateobj by its self turns the property 'On'
%if it is 'Off' or turns it 'Off' if it is 'On'
%
%Copy-Left, Alejandro Sanchez-Barba, 2005

if nargin==0
    hFig = gcf;
    ud = get(hFig,'UserData');
    if isfield(ud,'manual')
        if strcmp(ud.manual,'On')
            action = 'Off';
        else %off
            action = 'On';
        end
    else
        action = 'On';
    end
end
eval(action)
return

%-----------------------------------------------------------
function BtnDown
hFig = gcf;
Button = get(hFig,'SelectionType');
ud = get(hFig,'UserData');
ud.Button = Button;
ud.hAx = get(hFig,'CurrentAxes');
ud.CurrentPoint = get(ud.hAx,'CurrentPoint');
ud.hObj = get(hFig,'CurrentObject');
set(ud.hObj,'Selected','On')
ud.ObjType = get(ud.hObj,'Type');
switch ud.Button
    case 'normal' %Move
        setptr(hFig,'closedhand');
    case 'alt' %Rotate
        setptr(hFig,'rotate');
        ud.hLine = line('XData',[],'YData',[], ...
            'Parent',ud.hAx,'Color','k');
        ud.Orig = ud.CurrentPoint;
    otherwise
        return
end %switch
ud.xmode = get(ud.hAx,'XLimMode');
ud.ymode = get(ud.hAx,'YLimMode');
set(ud.hAx,'XLimMode','manual')
set(ud.hAx,'YLimMode','manual')
set(hFig,'UserData',ud)
set(hFig,'WindowButtonMotionFcn','moverotateobj(''BtnMotion'')',...
   'WindowButtonUpFcn', 'moverotateobj(''BtnUp'')');
return

%-----------------------------------------------------------
function BtnMotion
hFig = gcf;
ud = get(hFig,'UserData');
hObj = ud.hObj;
ObjType = ud.ObjType;
switch ObjType
    case 'line'
        x = get(hObj,'XData');
        y = get(hObj,'YData');
    case 'text'
        pos = get(hObj,'Position');
        x = pos(1);
        y = pos(2);
    otherwise
        error('Unknown Object');
end %switch
hAx = ud.hAx;
LastPoint = ud.CurrentPoint;
CurrentPoint = get(hAx,'CurrentPoint');
Button = ud.Button;
switch Button
    case 'normal' %Move
        %Calculate Difference
        dx = CurrentPoint(1,1) - LastPoint(1,1);
        dy = CurrentPoint(1,2) - LastPoint(1,2);
        x = x + dx;
        y = y + dy;
        %Update position on Plot
        switch ObjType
            case 'line'
                set(hObj,'XData',x,'YData',y)
            case 'text'
                set(hObj,'Position',[x,y])
            otherwise
                error('Unknown Object')
        end %switch
    case 'alt' %Rotate
        xline = [ud.Orig(1,1),CurrentPoint(1,1)];
        yline = [ud.Orig(1,2),CurrentPoint(1,2)];
        set(ud.hLine,'XData',xline,'YData',yline)
        u1 = CurrentPoint(1,1) - ud.Orig(1,1);
        v1 = CurrentPoint(1,2) - ud.Orig(1,2);
        th1 = atan2(v1,u1);
        u2 = LastPoint(1,1) - ud.Orig(1,1);
        v2 = LastPoint(1,2) - ud.Orig(1,2);
        th2 = atan2(v2,u2);
        theta = th1 - th2;
%         disp([th1,th2,theta]*180/pi)
        switch ObjType
            case 'line'
                rot = [cos(theta) -sin(theta); ...
                    sin(theta) cos(theta)];
                vec = [x(:)-ud.Orig(1,1),y(:)-ud.Orig(1,2)];
                newvec = (rot*vec')';
                x = newvec(:,1) + ud.Orig(1,1);
                y = newvec(:,2) + ud.Orig(1,2);
                set(hObj,'XData',x,'YData',y)
            case 'text'
                thetaold = get(hObj,'Rotation');
                thetanew = thetaold + theta*180/pi;
                set(hObj,'Rotation',thetanew)
            otherwise
                error('Unknown Object')
        end %switch
end %switch
ud.CurrentPoint = CurrentPoint;
set(hFig,'UserData',ud)
return

%-----------------------------------------------------------
function BtnUp
hFig = gcf;
setptr(hFig,'arrow');
set(hFig,'WindowButtonMotionFcn','');
ud = get(hFig,'UserData');
ud.xmode = get(ud.hAx,'XLimMode');
ud.ymode = get(ud.hAx,'YLimMode');
set(ud.hObj,'Selected','Off')
if strcmp(ud.xmode,'auto')
    set(ud.hAx,'XLimMode','auto')
end
if strcmp(ud.ymode,'auto')
    set(ud.hAx,'YLimMode','auto')
end
if strcmp(ud.Button,'alt')
    set(ud.hLine,'XData',[],'YData',[])
end
return

%-----------------------------------------------------------
function On
hFig = gcf;
ud = get(hFig,'UserData');
ud.hAx = get(hFig,'CurrentAxes');
ud.manual = 'On';
set(hFig,'UserData',ud)
h = get(ud.hAx,'Children');
set(h,'ButtonDownFcn','moverotateobj(''BtnDown'')')
return

%-----------------------------------------------------------
function Off
hFig = gcf;
ud = get(hFig,'UserData');
ud.hAx = get(hFig,'CurrentAxes');
ud.manual = 'Off';
set(hFig,'UserData',ud)
h = get(ud.hAx,'Children');
set(h,'ButtonDownFcn','')
set(hFig,'WindowButtonMotionFcn','',...
            'WindowButtonUpFcn','');
return


function [handles,msg,lattice,msize,dim,normalization,comps]=vis_som_show_data(p,f)

% VIS_SOM_SHOW_DATA Checks and returns UserData and subplot handles stored by SOM_SHOW
%
% [handles,msg,lattice,msize,dim,normalization,comps] = vis_som_show_data(p, f)
%
%  Input and output arguments ([]'s are optional):
%   [p]           (vector) subplot numbers
%                 (string) 'all' to process all subplots, this is default
%                          'comp' to process only subplots which have
%                          component planes
%   [f]           (double) figure handle, default is current figure
%
%   handles       (vector) handles of requested subplots
%   msg           (string) error message or empty string (no error)
%   lattice       (string) map lattice: 'hexa' or 'rect'
%   msize         (vector) map grid size in figure
%   dim           (scalar) map data dimension in figure
%   normalization (struct) normalization struct used in the map in figure
%   comps         (vector) the component indexes in figure
%
% This function gets the handles of component planes and u-matrices in
% subplots p from figure f. SOM_SHOW writes the handles into the
% UserData field of the figure where their order won't be mixed
% up. This function reads the data according to the vector p. If the
% figure has been manipulated (original planes are missing) the function
% warns user or returns error string.
%
% The main purpose for this is to be a subfuncion for SOM_SHOW_ADD,
% SOM_SHOW_CLEAR and SOM_RECOLORBAR functions, but it may be used on
% command line in the followong manner:
%
%  % plots text on the fifth plane
%  axes(vis_som_show_data(5)); hold on; text(1,3,'I am here');
%
% See also SOM_SHOW, SOM_SHOW_ADD.

% Copyright (c) 1997-2000 by the SOM toolbox programming team.
% http://www.cis.hut.fi/projects/somtoolbox/

% Version 2.0beta Johan 201099 juuso 160600

%% Check input args %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

error(nargchk(0, 2, nargin))  % check no. of input args

%% Init %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

handles=[];                                     % initialize output
normalize=[];
comps=[];
dim=[];
msize=[];
lattice=[];
msg=[];

cr=sprintf('\n');                               % carriage return

if nargin < 2 || isempty(f)
  f=gcf;                                        % default figure
end

if nargin < 1 || isempty(p)                      % default p
  p= 'all';
end

% Find component planes and u-matrices from the figure and get the
% UserData field where the handles for the components are
% in the original order.
% If the fields are corrupted, return an error message.

h_real = [findobj(f, 'Tag', 'Cplane'); ...
    findobj(f, 'Tag', 'Uplane'); ...
    findobj(f,'Tag','CplaneI'); ...
    findobj(f,'Tag','UplaneI')];
eval( 'h_stored=getfield(get(f,''UserData''),''subplotorder'');' , ...
    'msg=[ msg cr '' Missing SOM_SHOW.subplotorder''];');
eval( 'normalization=getfield(get(f,''UserData''),''comp_norm'');' , ...
    'msg=[msg cr '' Missing SOM_SHOW.comp_norm''];');
eval( 'comps=getfield(get(f,''UserData''),''comps'');' , ...
    'msg=[msg cr '' Missing SOM_SHOW.comps''];');
eval( 'msize=getfield(get(f,''UserData''),''msize'');' , ...
    'msg=[msg cr '' Missing SOM_SHOW.msize''];');
eval( 'dim=getfield(get(f,''UserData''),''dim'');' , ...
    'msg=[msg cr '' Missing SOM_SHOW.dim''];');
eval( 'lattice=getfield(get(f,''UserData''),''lattice'');' , ...
    'msg=[msg cr '' Missing SOM_SHOW.lattice''];');
if ~isempty(msg),
  msg=['The figure does not contain SOM_SHOW visualization or is corrupted.'...
	cr msg cr cr ...
	'This command may be applied only to a SOM_SHOW visualization.'];
  return;
end

%% Check arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

index=ismember(h_stored, h_real);  % the original order for plot axes

if ~prod(double(index))                    % missing planes?!
                                           % double added by kr 1.10.02
  l1= 'Some of the original planes seems to be missing.';
  l2= 'Subplot numbers now refer to the existing ones.';
  warning([l1 cr l2]);
end

if ~prod(double(ismember(h_real, h_stored))) % extra planes?!
                                             % double added by kr 5.9.02
  warning('There seems to be new planes. Subplot numbers refer to the old ones.');
end

h_stored=h_stored(index);          % existing original plots in original order

if ischar(p)                       % check if p is 'all'
  switch(p)
   case 'all'
    p=1:size(h_stored,1);          % all original subplots
   case 'comp'
    p=find(comps>0);
   otherwise
    msg= 'String value for subplot number vector has to be ''all''!';
    return;
  end
end

if ~vis_valuetype(p,{ '1xn','nx1'}) % check the size
  msg= 'Subplot numbers (argument p in help text) have to be in a vector!';
  return
end

if min(p) < 1                      % check for invalid values
  msg= 'Subplot numbers (argument p in help text) must be at least 1!';
  return
end

%% p is too large

if max(p) > size(h_stored,1)
  l1= 'There are not so many existing subplots created by SOM_SHOW in the';
  l2= 'figure as you are trying to refer with subplot numbers.';
  l3= 'This is probably caused by having a too large subplot number.';
  l4= 'However, the reason may be invalid manipulation of';
  l5= 'this figure object or a program failure, too.';
  msg=([l1 cr l2 cr l3 cr cr l4 cr l5]);
  return;
end

%% Action and building output %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

handles=h_stored(p);
comps=comps(p);


function v = sparse(i,j,v,varargin)

v.x = sparse(i,j,v.x,varargin{:});
v.y = sparse(i,j,v.y,varargin{:});
v.z = sparse(i,j,v.z,varargin{:});


function x = cvx_accept_concave( x )
global cvx___
if isa( x, 'cvx' ),
    t = cvx_vexity( x ) < 0;
    if any( t( : ) ),
        prob = cvx___.problems(end).self;
        if all( t ),
            src = x;
            dst = newtemp( prob, size( src ) );
            x = dst;
        else
            src = x( t );
            dst = newtemp( prob, size( src ) );
            x( t ) = dst;
        end
        newcnstr( prob, src(:), dst(:), '>=' );
    end
end

% Copyright 2005-2016 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function slComplete(searchlight, removeFiles)
% slComplete(searchlight, removeFiles)
% SEARCHLIGHT - COMPLETE
% ---------------------------------------------------------
% Verifies presence of all necessary portions of searchlight, finishing by
% inserting all of them into a parameter map for loading into mrVista.
%
% INPUTS
%   searchlight - Structure generated by slInit.
%   removeFiles - Off by default, when set to true it will clean up files
%       as it reads them in.
%
% OUTPUTS
%   N/A
%
% USAGE
%   After running a searchlight, passing it to slComplete to construct a
%   parameter map.  In this case, we choose to remove the files.
%       searchlight = slInit(...);
%       slRun(searchlight, ...);
%       slComplete(searchlight, true);
%
% See also SLINIT, SLRUN, SLSPAWN, SVMINIT.
%
% renobowen@gmail.com [2010]
%

if notDefined('removeFiles'), removeFiles = false; end

totalProcesses = searchlight.processes * searchlight.partitions;
if (isSearchlightComplete(searchlight, totalProcesses))
    processSearchlight(searchlight, totalProcesses, removeFiles);
end

end

function bool = isSearchlightComplete(searchlight, totalProcesses)
for i = 1:totalProcesses
    if (~exist(sprintf('%s/%s/searchlight%04d.mat', searchlight.path, searchlight.tmpDir, i), 'file'))
        bool = false;
        return;
    end
end
bool = true;
end

function processSearchlight(searchlight, processes, removeFiles)
svm = searchlight.svm;
svm = rmfield(svm, 'data'); % this is to save space

for i = 1:processes
    filename = sprintf('%s/%s/searchlight%04d.mat', searchlight.path, searchlight.tmpDir, i);
    tmp = load(filename);
    nCenters = size(tmp.centers, 2);
    for j = 1:nCenters
        if (~isempty(tmp.meanAccs(j)))
            if (strcmpi(searchlight.searchView, 'gray'))
                map{1}(tmp.centers(1, j)) = tmp.meanAccs(j);
            else
                map{1}(tmp.centers(1, j), tmp.centers(2, j), tmp.centers(3, j)) = tmp.meanAccs(j);
            end
        end
    end
    if (removeFiles), delete(filename); end
end
growBy = tmp.growBy;
fprintf('done.\n');

if (removeFiles), rmdir(sprintf('%s/%s', searchlight.path, searchlight.tmpDir)); end

filename = sprintf('%s/%s.mat', searchlight.path, searchlight.tmpDir);
mapName = 'searchlight';
if exist('mapBootstrap','var')
    save(filename, 'map', 'mapName', 'growBy', 'svm', 'mapBootstrap', '-v7.3');
else
    save(filename, 'map', 'mapName', 'growBy', 'svm', '-v7.3');
end
fprintf('Saved to: %s\n', filename);

end


function compile_mex( cudaRoot )
%compile_mex compiles all the MEX-functions included in this package

rootDir = fileparts( mfilename( 'fullpath' ) );

% image cropping on a GPU
cd( fullfile(rootDir, 'utils', 'cropRectanglesMex') );
if exist('cudaRoot', 'var')
	build_cropRectanglesMex( cudaRoot );
else
	build_cropRectanglesMex;
end
cd(rootDir);

% computation of the min-marginals
cd( fullfile(rootDir, 'pairwiseModel', 'computeMinMarginalsBinaryMex') );
build_computeMinMarginalsBinaryMex;
cd(rootDir);

% brute force energy minimization
cd( fullfile(rootDir, 'pairwiseModel', 'energyMinimization', 'bruteForceBinaryPairwiseMex') );
build_bruteForceBinaryPairwiseMex;
cd( rootDir );

% QPBO
cd( fullfile(rootDir, 'pairwiseModel', 'energyMinimization', 'qpboMex') );
build_qpboMex;
cd( rootDir );

% TRW-S
cd( fullfile(rootDir, 'pairwiseModel', 'energyMinimization', 'trwsMex') );
build_trwsMex;
cd( rootDir );

end


function [pfdata,pfunits,update] = readPFData(pfname,flies,params)

ss = fopen(pfname,'r');
qq = fread(ss,10,'*char')';
fclose(ss);
if nargin < 3
    params = struct;
    do_check = false;
else
    do_check = true;
end

% Doing matfile is slower for more than 4 flies
saved_params = struct;
update = false;
if strcmp(qq(8:10),'7.3') && numel(flies)<4
  m = matfile(pfname);
  pfdata = cell(1,numel(flies));
  for ndx = 1:numel(flies);
    pfdata(ndx) = m.data(1,flies(ndx));
  end
  pfunits = m.units;
  if isprop(m,'params')
      saved_params = m.params;
  else
      do_check = false;
  end
else
  m = load(pfname);
  pfdata = m.data(flies);
  pfunits = m.units;
  if isfield(m,'params')
      saved_params = m.params;
  else
      do_check = false;
  end
end

if ~isequal(saved_params,params) && do_check ...
    && ~isempty(saved_params) && ~isempty(params)
    update = true;
end


function [obj_subset, to_extract] = select_atlas_subset(obj, varargin)
% Select a subset of regions in an atlas by name or integer code, with or without collapsing regions together
%
% Select a subset of regions in an atlas using:
% - a cell array of one or more strings to search for in labels
% - a vector of one or more integers indexing regions
%
% Output:
%       a new object, obj_subset
%       to_extract, a logical vector indicating which regions were selected
%
% obj_subset = select_atlas_subset(obj, varargin)
%
% Options:
% 'flatten' : Flatten integer vector in .dat to a single 1/0 mask. Good for
% creating masks from combinations of regions, or adding a set to another
% atlas as a single atlas region. .probability_maps reduced to single max
% map
%
% 'labels_2' : If you enter any field name in the object, e.g., labels_2,
% the function will search for keyword matches here instead of in obj.labels.
%
% Examples:
%
% atlasfile = which('Morel_thalamus_atlas_object.mat');
% load(atlasfile)
% [obj_subset, to_extract] = select_atlas_subset(atlas_obj, [1 3]);
% [obj_subset, to_extract] = select_atlas_subset(atlas_obj, [1 3], {'VPL'});
% [obj_subset, to_extract] = select_atlas_subset(atlas_obj, {'VPL'});             % Sensory VPL thalamus, when using morel atlas
% [obj_subset, to_extract] = select_atlas_subset(atlas_obj, {'VPL' 'VPM' 'VPI'}); % Sensory thalamus, both lat and medial
%
% [obj_subset, to_extract] = select_atlas_subset(atlas_obj, {'Hb'});              % Habenula
%
% [obj_subset, to_extract] = select_atlas_subset(atlas_obj, {'CL' 'CeM' 'CM' 'Pf'});  % Intralaminar
% [obj_subset, to_extract] = select_atlas_subset(atlas_obj, {'Pv' 'SPf'});           % Midline group
% [obj_subset, to_extract] = select_atlas_subset(atlas_obj, {'CL' 'CeM' 'CM' 'Pf' 'Pv' 'SPf'}); % Intralaminar and Midline group
% [obj_subset, to_extract] = select_atlas_subset(atlas_obj, {'MD'});              % Mediodorsal nuc.
%
% [obj_subset, to_extract] = select_atlas_subset(atlas_obj, {'Pu'});              % Pulvinar
% [obj_subset, to_extract] = select_atlas_subset(atlas_obj, {'LGN'});             % LGN
% [obj_subset, to_extract] = select_atlas_subset(atlas_obj, {'MGN'});             % MGN
%
% Create a mask from a set of regions:
% obj_subset = select_atlas_subset(atlas_obj, {'CL' 'CeM' 'CM' 'Pf'}, 'flatten');  % Intralaminar
% r = atlas2region(obj_subset);
% orthviews(r)
%
% Load a canonical atlas and select only the default mode, limbic, and brainstem regions
% based on the .labels_2 property
% -------------------------------------------------------
% atlas_obj = load_atlas('canlab2018_2mm');
% [obj_subset, to_extract] = select_atlas_subset(atlas_obj, {'Cerebellum', 'Def'}, 'labels_2');
% montage(obj_subset);
%
% see also: image_vector.select_voxels_by_value

% Programmers' notes:
% Created by tor wager
% Edited by tor, 12/2019, to use any field to select labels; and update
% auxiliary label fields too.
%

% -------------------------------------------------------------------------
% DEFAULTS AND INPUTS
% -------------------------------------------------------------------------

strings_to_find = [];
integers_to_find = [];
doflatten = false;

% for entry of optional field to search for keywords
myfields = fieldnames(obj);
mylabelsfield = 'labels';

% optional inputs with default values
for i = 1:length(varargin)

    if iscell(varargin{i})
        strings_to_find = varargin{i};

    elseif isnumeric(varargin{i})
        integers_to_find = varargin{i};

    elseif ischar(varargin{i})
        switch varargin{i}

             case 'flatten', doflatten = true;

                 %             case 'xxx', xxx = varargin{i+1}; varargin{i+1} = [];

            otherwise

                if any(strcmp(varargin{i}, myfields))
                    mylabelsfield = varargin{i};

                else

                    warning(['Unknown input string option:' varargin{i} '. Assuming it might be an atlas label. Place atlas labels in a cell array']);
                    strings_to_find{1} = varargin{i};

                end
        end
    end
end

% -------------------------------------------------------------------------
% INIT
% -------------------------------------------------------------------------

k = num_regions(obj);
to_extract = false(1, k);

% -------------------------------------------------------------------------
% FIND BY STRING
% -------------------------------------------------------------------------

for i = 1:length(strings_to_find)

    % Find which names match
    wh = ~cellfun(@isempty, strfind(obj.(mylabelsfield), strings_to_find{i}));
    if strmatch(mylabelsfield, 'label_descriptions')
        wh=wh';
    end

    to_extract = to_extract | wh;

end

% -------------------------------------------------------------------------
% FIND BY NUMBERS
% -------------------------------------------------------------------------

to_extract(integers_to_find) = true;

if ~any(to_extract)
    error('No regions identified to extract.');
end

% -------------------------------------------------------------------------
% Extract
% -------------------------------------------------------------------------

obj_subset = obj;

% labels and names

obj_subset.labels = obj_subset.labels(to_extract);

% obj_subset.label_descriptions = obj_subset.label_descriptions(to_extract);

% if ~isempty(obj_subset.image_names) && size(obj_subset.image_names, 1) == k
%     obj_subset.image_names = obj_subset.image_names(to_extract, :);
% end

my_strings = {'image_names' 'fullpath'};

for i = 1:length(my_strings)

    if  ~isempty(obj_subset.(my_strings{i})) && size(obj_subset.(my_strings{i}), 1) == k
        obj_subset.(my_strings{i}) = obj_subset.(my_strings{i})(to_extract, :);
    end

end

my_strings = {'label_descriptions' 'image_names' 'fullpath' 'labels_2' 'labels_3' 'labels_4' 'labels_5'};

for i = 1:length(my_strings)
    if  ~isempty(obj_subset.(my_strings{i})) && length(obj_subset.(my_strings{i})) == k
        obj_subset.(my_strings{i}) = obj_subset.(my_strings{i})(to_extract);
    end

end

if ~isempty(obj.probability_maps) && size(obj.probability_maps, 2) == k  % valid p maps

    obj_subset.probability_maps(:, ~to_extract) = [];

    obj_subset = probability_maps_to_region_index(obj_subset);

else % must use .dat vector with integers

    % rebuild integer index

    dat = zeros(size(obj_subset.dat));
    wh_cols = find(to_extract);

    for i = 1:length(wh_cols)

        wh_vals = obj_subset.dat == wh_cols(i);

        dat(wh_vals) = i;

    end

    obj_subset.dat = dat;

end

if doflatten
    % Flatten into mask
    % -------------------------------------------------------------------
    obj_subset.dat = single(obj_subset.dat > 0);

    obj_subset.probability_maps = max(obj_subset.probability_maps, [], 2);

    % Add labels for combined mask

    mylabels = [];
    if iscell(strings_to_find)
        mylabels = cat(2, strings_to_find{:});
    end

    if ~isempty(integers_to_find)
        morelabels = cat(2, obj.labels{integers_to_find});
        mylabels = [mylabels morelabels];
    end

    obj_subset.labels = {mylabels};

    obj_subset.label_descriptions = {sprintf('Combined subset: %s', mylabels)};

        % Make sure they are length of prob maps, to conform to standard atlas
    % object
%     np = size(obj_subset.probability_maps, 2);
%     if np
%         obj_subset.labels = repmat(obj_subset.labels, 1, np);
%         obj_subset.label_descriptions = repmat(obj_subset.label_descriptions, np, 1);
%     end

end % flatten

end % function


function cl = hlp_bm_updateLights(BMopts,hlights)
% update lighting for a brainmovie
% returns handles to camlight objects

if nargin<2
    hlights = []; end

if isempty(hlights) || ~ishandle(hlights(1))
    lighting(BMopts.vars.hbrainax,BMopts.facelighting);

    % delete existing lights
    hlights = findobj(BMopts.vars.hbrainax,'type','light');
    delete(hlights)
    hlights = [];
end

if ~isempty(BMopts.theme)
    cl=feval(BMopts.theme.lightingfcn,BMopts.vars.hbrainax,BMopts.theme.name,hlights);
    set(cl,'tag','brain_camlight','parent',BMopts.vars.hbrainax);
else
    cl(1) = camlight(BMopts.vars.hbrainax,'left');
    cl(2) = camlight(BMopts.vars.hbrainax,'right');
    set(cl,'tag','brain_camlight','parent',BMopts.vars.hbrainax);
end


%% SO3FunComposition


function calSave7 (~, ~, xt, cumu2, as)
    % Save cum #  and z value to an interactively chosen file

    %msg.infodisp('  ','Save Data');

    [file1,path1] = uiputfile(fullfile(ZmapGlobal.Data.Directories.output, '*.dat'), 'Earthquake Datafile');
    if file1 && path1
        data = [xt', cumu2', as']';
        fid = fopen([path1 file1],'w') ;
        fprintf(fid, '%6.2f  %6.2f %6.2f\n' , data);
        fclose(fid) ;
    else
        %msg.dbdisp('  ','cancelled save');
    end

end


%kkthreshbelow 'Threshold Data Values that are Below Specified Cutoff'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros kthreshbelow.pane file
%
% Parameters:
% InputFile: i 'Input ', required: 'Input file'
% OutputFile: o ' Output ', required: 'output file'
%
% Example: o = kkthreshbelow(i, {'i','';'o',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% kthreshbelow - Threshold Data Values that are Below Specified Cutoff
%
%  DESCRIPTION
% The "Threshold Below" operator generates a two-level output by
% thresholding the "Input" data object (i).  Data values less than
% the "Cutoff Value" (lc) are set to the "LESS THAN" output value
% (fval), and values greater than or equal to the "Cutoff Value" are set
% to the "GREATER THAN or EQUAL" Output value (tval).
%
% The following histogram defines the results of the thresholding operation.
%
%
% \f(CW
%                                 |<-F->|<----T---->|
%                                 |     | :     .   |
%                                 |    .:.:.  .:::  |
%                                 |:. .::::::.::::: |
%                                 |::::::::::::::::.|
%                                 ------|------------
%                                       Cutoff
%
%         F:  if value <= Cutoff,  Output = fval
%         T:  if value >  Cutoff,  Output = tval
% "
%
%
%  "Data Type" 5
% .cI $DATAMANIP/repos/shared/man/sections/value_type_1input
%
%  "Map Data" 5
% .cI $DATAMANIP/repos/shared/man/sections/map_1input
%
%  "Validity Mask" 5
% .cI $DATAMANIP/repos/shared/man/sections/mask_1input
%
%  "Explicit Location and Time Data" 5
% .cI $DATAMANIP/repos/shared/man/sections/loc_and_time_1input
%
%  "Failure Modes"
% .cI $DATAMANIP/repos/shared/man/sections/fail_1input
%
% Executing "Threshold Above" runs the program \fIkclip\fP with the -thresh
% option set to TRUE (-thresh 1).
%
%
%
%  EXAMPLES
%
%  "SEE ALSO"
% DATAMANIP::kthreshabove, DATAMANIP::kthreshin, DATAMANIP::kthreshout,
% DATAMANIP::kmegathresh, DATAMANIP::kclip
%
%  RESTRICTIONS
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993 - 1997, Khoral Research, Inc. ("KRI")  All rights reserved.
%

function varargout = kkthreshbelow(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,..] = kkthreshbelow(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 'kclip"  -thresh'],Inputs,narglist);


function s1= struct_sloppycat(s1, s2, varargin)
% STRUCT_SLOPPYCAT - Copy fields
%
% Synopsis:
%   s1= file_loadMatlab(s1,s2,<OPT>)
%
%Arguments:
%   S1:     STRUCT - target struct in which fields from s2 are copied
%   S2:     STRUCT
%   OPT: PROPLIST - Structure or property/value list of optional properties:
%     'Dim' - INT (default 2): ?
%     'Keepfields' -
%     'Matchsize' -
%
% See also: struct_copyFields

props = {'Dim',         2           '!INT[1]';
         'Keepfields'   3           '!INT[1]|!CHAR(none first last all)';
         'Matchsize'    0           '!BOOL';
         };

if nargin==0
    s1=props;return
end

if isempty(s1),
  s1= s2;
  return;
elseif isempty(s2),
  return;
end

opt= opt_proplistToStruct(varargin{:});
[opt, isdefault]= opt_setDefaults(opt, props);
opt_checkProplist(opt, props);
misc_checkType(s1,'STRUCT');
misc_checkType(s2,'STRUCT');

flds1= fieldnames(s1);
flds2= fieldnames(s2);

switch(opt.Keepfields),
 case {0,'none'},
  flds= intersect(flds1, flds2,'legacy');
  s1= rmfield(s1, setdiff(flds1, flds,'legacy'));
  s2= rmfield(s2, setdiff(flds2, flds,'legacy'));
 case {1,'first'},
  flds= flds1;
  if opt.Matchsize,
    s2= struct_createfields(s2, setdiff(flds, flds2,'legacy'), 'matchsize',s1(1));
  else
    s2= struct_createfields(s2, setdiff(flds, flds2,'legacy'));
  end
 case {2,'last'},
  flds= flds2;
  if opt.Matchsize,
    s1= struct_createfields(s1, setdiff(flds, flds1,'legacy'), 'matchsize',s2(1));
  else
    s1= struct_createfields(s1, setdiff(flds, flds1,'legacy'));
  end
 case {3,'all'},
  flds= union(flds1, flds2,'legacy');
  if opt.Matchsize,
    s1= struct_createfields(s1, setdiff(flds, flds1,'legacy'), 'matchsize',s2(1));
    s2= struct_createfields(s2, setdiff(flds, flds2,'legacy'), 'matchsize',s1(1));
  else
    s1= struct_createfields(s1, setdiff(flds, flds1,'legacy'));
    s2= struct_createfields(s2, setdiff(flds, flds2,'legacy'));
  end
 otherwise
  error('unknown value for OPT.Keepfields');
end

s1= cat(opt.Dim, s1, s2);


function excelrecord5fcn(stringdates2, endo, plotdata, n, pref)
% script excelrecord5
% records the information contained in the worksheet 'forecasts' of the excel spreadsheet 'results.xls'

% create the cell that will be saved on excel
forecastcell={};

% build preliminary elements: space between the tables
vertspace=repmat({''},size(stringdates2,1)+3,1);

% loop over variables (horizontal dimension)
for ii=1:n
    % create cell of forecast record for variable ii
    temp=['forecasts: ' endo{ii,1}];
    forecast_i=[temp {''} {''} {''} {''};{''} {''} {''} {''} {''};{''} {'sample'} {'lw. bound'} {'median'} {'up. bound'};stringdates2 num2cell((plotdata{ii,1})')];

    % switch NaN entries to empty
    forecast_i(~cellfun(@any,forecast_i))={[]};
    forecastcell=[forecastcell forecast_i vertspace];
end

% trim
forecastcell=forecastcell(:,1:end-1);

% write in excel
if pref.results==1
    bear.xlswritegeneral(fullfile(pref.results_path, [pref.results_sub '.xlsx']),forecastcell,'forecasts','B2');
end