function errorMsg = import_anatomy_bs(iSubject, BsDir, nVertices, isInteractive, sFid, isVolumeAtlas, isKeepMri)
% IMPORT_ANATOMY_BS: Import a full BrainSuite folder as the subject's anatomy.
%
% USAGE:  errorMsg = import_anatomy_bs(iSubject, BsDir=[ask], nVertices=[ask], isInteractive=1, sFid=[], isVolumeAtlas=1, isKeepMri=0)
%
% INPUT:
%    - iSubject      : Indice of the subject where to import the MRI
%                      If iSubject=0 : import MRI in default subject
%    - BsDir         : Full filename of the BrainSuite folder to import
%    - nVertices     : Number of vertices in the file cortex surface
%    - isInteractive : If 0, no input or user interaction
%    - sFid          : Structure with the fiducials coordinates
%                      Or full MRI structure with fiducials defined in the SCS structure, to be registered with the FS MRI
%    - isVolumeAtlas : If 1, imports the svreg atlas as a set of surfaces
%    - isKeepMri     : 0=Delete all existing anatomy files
%                      1=Keep existing MRI volumes (when running segmentation from Brainstorm)
%                      2=Keep existing MRI and surfaces
% OUTPUT:
%    - errorMsg : String: error message if an error occurs

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

%% ===== PARSE INPUTS =====
% Keep MRI
if (nargin < 7) || isempty(isKeepMri)
    isKeepMri = 0;
end
% Import volume atlas
if (nargin < 6) || isempty(isVolumeAtlas)
    isVolumeAtlas = 1;
end
% Fiducials
if (nargin < 5) || isempty(sFid)
    sFid = [];
end
% Interactive / silent
if (nargin < 4) || isempty(isInteractive)
    isInteractive = 1;
end
% Ask number of vertices for the cortex surface
if (nargin < 3) || isempty(nVertices)
    nVertices = [];
end
% Initialize returned variables
errorMsg = [];
% Ask folder to the user
if (nargin < 2) || isempty(BsDir)
    % Get default import directory and formats
    LastUsedDirs = bst_get('LastUsedDirs');
    % Open file selection dialog
    BsDir = java_getfile( 'open', ...
        'Import BrainSuite folder...', ...     % Window title
        bst_fileparts(LastUsedDirs.ImportAnat, 1), ...           % Last used directory
        'single', 'dirs', ...                  % Selection mode
        {{'.folder'}, 'BrainSuite folder', 'BsDir'}, 0);
    % If no folder was selected: exit
    if isempty(BsDir)
        return
    end
    % Save default import directory
    LastUsedDirs.ImportAnat = BsDir;
    bst_set('LastUsedDirs', LastUsedDirs);
end
% Unload everything
bst_memory('UnloadAll', 'Forced');

%% ===== DELETE PREVIOUS ANATOMY =====
% Get subject definition
sSubject = bst_get('Subject', iSubject);
% Check for existing anatomy
if (~isempty(sSubject.Anatomy) && (isKeepMri == 0)) || (~isempty(sSubject.Surface) && (isKeepMri < 2))
    % Ask user whether the previous anatomy should be removed
    if isInteractive
        isDel = java_dialog('confirm', ['Warning: There is already an anatomy defined for this subject.' 10 10 ...
            'Are you sure you want to delete the previous MRI and surfaces ?' 10 10], 'Import BrainSuite folder');
    else
        isDel = 1;
    end
    % If user canceled process
    if ~isDel
        bst_progress('stop');
        return;
    end
    % Delete anatomy
    sSubject = db_delete_anatomy(iSubject, isKeepMri);
end

%% ===== ASK NB VERTICES =====
if isempty(nVertices)
    nVertices = java_dialog('input', 'Number of vertices on the cortex surface:', 'Import BrainSuite folder', [], '15000');
    if isempty(nVertices)
        return
    end
    nVertices = str2double(nVertices);
end
% Number for each hemisphere
nVertHemi = round(nVertices / 2);

%% ===== PARSE BRAINSUITE FOLDER =====
% Find MRI
FilePrefix = get_fileprefix(BsDir);
if isempty(FilePrefix)
    errorMsg = [errorMsg 'Could not determine file prefix from BFC file' 10 10 ...
        'Make sure SVREG was executed in BrainSuite before importing the data in Brainstorm.'];
    if isInteractive
        bst_error(['Could not import BrainSuite folder: ' 10 10 errorMsg], 'Import BrainSuite folder', 0);
    end
    return;
end
T1File = {file_find(BsDir, [FilePrefix '.nii.gz']), ...
           file_find(BsDir, [FilePrefix '.nii']), ...
           file_find(BsDir, [FilePrefix '.img.gz']),...
           file_find(BsDir, [FilePrefix '.img'])};
T1File = [T1File{find(~cellfun(@isempty, T1File))}];
if isempty(T1File)
    errorMsg = [errorMsg 'MRI file was not found: ' FilePrefix '.*' 10];
end

% Find volume segmentation file
BsDirMultiParc = fullfile(BsDir,'multiparc');

SvregFile = file_find(BsDir, [FilePrefix '.svreg.label.nii.gz']);
OtherSvregFiles = file_find(BsDirMultiParc, [FilePrefix '.svreg.*.label.nii.gz'], 2, 0);

% Find surfaces
HeadFile        = file_find(BsDir, [FilePrefix '.scalp.dfs']);
InnerSkullFile  = file_find(BsDir, [FilePrefix '.inner_skull.dfs']);
OuterSkullFile  = file_find(BsDir, [FilePrefix '.outer_skull.dfs']);
TessLhFile      = file_find(BsDir, [FilePrefix '.left.pial.cortex.svreg.dfs']);
TessRhFile      = file_find(BsDir, [FilePrefix '.right.pial.cortex.svreg.dfs']);
TessLwFile      = file_find(BsDir, [FilePrefix '.left.inner.cortex.svreg.dfs']);
TessRwFile      = file_find(BsDir, [FilePrefix '.right.inner.cortex.svreg.dfs']);
TessLsphFile    = file_find(BsDir, [FilePrefix '.left.mid.cortex.svreg.dfs']);
TessRsphFile    = file_find(BsDir, [FilePrefix '.right.mid.cortex.svreg.dfs']);
TessLAtlsphFile = file_find(BsDir, 'atlas.left.mid.cortex.svreg.dfs');
TessRAtlsphFile = file_find(BsDir, 'atlas.right.mid.cortex.svreg.dfs');

% Find labels
AnnotLhFiles = file_find(BsDirMultiParc, [FilePrefix '.left.mid.cortex.svreg.*.dfs'], 2, 0);
AnnotRhFiles = file_find(BsDirMultiParc, [FilePrefix '.right.mid.cortex.svreg.*.dfs'], 2, 0);

if isempty(AnnotLhFiles)
    AnnotLhFiles = TessLhFile;
end

if isempty(AnnotRhFiles)
    AnnotRhFiles = TessRhFile;
end

if isempty(HeadFile)
    %errorMsg = [errorMsg 'Scalp file was not found: ' FilePrefix '.scalp.dfs' 10];
    disp(['BST> Warning: Scalp file was not found: ' FilePrefix '.scalp.dfs']);
end
if isempty(InnerSkullFile) && isempty(OuterSkullFile)
    %errorMsg = [errorMsg 'Inner or Outer Skull File not found' 10];
    disp('BST> Warning: Inner or Outer Skull File not found.');
end
if isempty(TessLhFile)
    errorMsg = [errorMsg 'Surface file was not found: ' FilePrefix '.left.pial.cortex.svreg.dfs' 10];
end
if isempty(TessRhFile)
    errorMsg = [errorMsg 'Surface file was not found: ' FilePrefix '.right.pial.cortex.svreg.dfs' 10];
end

% Report errors
if ~isempty(errorMsg)
    if isInteractive
        bst_error(['Could not import BrainSuite folder: ' 10 10 errorMsg], 'Import BrainSuite folder', 0);
    end
    return;
end

%% ===== IMPORT MRI =====
if isKeepMri && ~isempty(sSubject.Anatomy)
    BstT1File = file_fullpath(sSubject.Anatomy(sSubject.iAnatomy).FileName);
else
    bst_progress('text', 'Loading MRI...');
    % Read MRI
    [BstT1File, sMri] = import_mri(iSubject, T1File);
    if isempty(BstT1File)
        errorMsg = 'Could not import BrainSuite folder: MRI was not imported properly';
        if isInteractive
            bst_error(errorMsg, 'Import BrainSuite folder', 0);
        end
        return;
    end
    % Enforce it as the permanent default MRI
    sSubject = db_surface_default(iSubject, 'Anatomy', 1, 0);
end

%% ===== DEFINE FIDUCIALS / MNI NORMALIZATION =====
% Set fiducials and/or compute linear MNI normalization
[isComputeMni, errCall] = process_import_anatomy('SetFiducials', iSubject, BsDir, BstT1File, sFid, isKeepMri, isInteractive);
% Error handling
if ~isempty(errCall)
    errorMsg = [errorMsg, errCall];
    if isempty(isComputeMni)
        if isInteractive
            bst_error(errorMsg, 'Import BrainSuite folder', 0);
        end
        return;
    end
end

%% ===== IMPORT SURFACES =====
% Left pial
if ~isempty(TessLhFile)
    % Import file
    [iLh, BstTessLhFile, nVertOrigL] = import_surfaces(iSubject, TessLhFile, 'DFS', 0);
    BstTessLhFile = BstTessLhFile{1};
    % Load atlas
    if ~isempty(AnnotLhFiles)
        bst_progress('start', 'Import BrainSuite folder', 'Loading atlas: left pial...');
        [sAllAtlas, err] = import_label(BstTessLhFile, AnnotLhFiles, 1);
        errorMsg = [errorMsg err];
    end
    % Load registration square
    if ~isempty(TessLsphFile)
        bst_progress('start', 'Import BrainSuite folder', 'Loading registered square: left pial...');
        [TessMat, err] = tess_addsquare(BstTessLhFile, TessLsphFile, TessLAtlsphFile);
        errorMsg = [errorMsg err];
    end
    % Downsample
    bst_progress('start', 'Import BrainSuite folder', 'Downsampling: left pial...');
    [BstTessLhLowFile, iLhLow, xLhLow] = tess_downsize(BstTessLhFile, nVertHemi, 'reducepatch');
end
% Right pial
if ~isempty(TessRhFile)
    % Import file
    [iRh, BstTessRhFile, nVertOrigR] = import_surfaces(iSubject, TessRhFile, 'DFS', 0);
    BstTessRhFile = BstTessRhFile{1};
    % Load atlas
    if ~isempty(AnnotRhFiles)
        bst_progress('start', 'Import BrainSuite folder', 'Loading atlas: right pial...');
        [sAllAtlas, err] = import_label(BstTessRhFile, AnnotRhFiles, 1);
        errorMsg = [errorMsg err];
    end
    % Load registration square
    if ~isempty(TessRsphFile)
        bst_progress('start', 'Import BrainSuite folder', 'Loading registered square: right pial...');
        [TessMat, err] = tess_addsquare(BstTessRhFile, TessRsphFile, TessRAtlsphFile);
        errorMsg = [errorMsg err];
    end
    % Downsample
    bst_progress('start', 'Import BrainSuite folder', 'Downsampling: right pial...');
    [BstTessRhLowFile, iRhLow, xRhLow] = tess_downsize(BstTessRhFile, nVertHemi, 'reducepatch');
end
% Left white matter
if ~isempty(TessLwFile)
    % Import file
    [iLw, BstTessLwFile] = import_surfaces(iSubject, TessLwFile, 'DFS', 0);
    BstTessLwFile = BstTessLwFile{1};
    % Load atlas
    if ~isempty(AnnotLhFiles)
        bst_progress('start', 'Import BrainSuite folder', 'Loading atlas: left white...');
        [sAllAtlas, err] = import_label(BstTessLwFile, AnnotLhFiles, 1);
        errorMsg = [errorMsg err];
    end
    % Load registration square
    if ~isempty(TessLsphFile)
        bst_progress('start', 'Import BrainSuite folder', 'Loading registered square: left white...');
        [TessMat, err] = tess_addsquare(BstTessLwFile, TessLsphFile, TessLAtlsphFile);
        errorMsg = [errorMsg err];
    end
    % Downsample
    bst_progress('start', 'Import BrainSuite folder', 'Downsampling: left white...');
    [BstTessLwLowFile, iLwLow] = tess_downsize(BstTessLwFile, nVertHemi, 'reducepatch');
end
% Right white matter
if ~isempty(TessRwFile)
    % Import file
    [iRw, BstTessRwFile] = import_surfaces(iSubject, TessRwFile, 'DFS', 0);
    BstTessRwFile = BstTessRwFile{1};
     % Load atlas
    if ~isempty(AnnotRhFiles)
        bst_progress('start', 'Import BrainSuite folder', 'Loading atlas: right inner...');
        [sAllAtlas, err] = import_label(BstTessRwFile, AnnotRhFiles, 1);
        errorMsg = [errorMsg err];
    end
    % Load registration square
    if ~isempty(TessRsphFile)
        bst_progress('start', 'Import BrainSuite folder', 'Loading registered square: right white...');
        [TessMat, err] = tess_addsquare(BstTessRwFile, TessRsphFile, TessRAtlsphFile);
        errorMsg = [errorMsg err];
    end
    % Downsample
    bst_progress('start', 'Import BrainSuite folder', 'Downsampling: right white...');
    [BstTessRwLowFile, iRwLow] = tess_downsize(BstTessRwFile, nVertHemi, 'reducepatch');
end
% Process error messages
if ~isempty(errorMsg)
    if isInteractive
        bst_error(errorMsg, 'Import BrainSuite folder', 0);
    end
    return;
end

%% ===== MERGE SURFACES =====
rmFiles = {};
rmInd   = [];
% Merge hemispheres: pial
if ~isempty(TessLhFile) && ~isempty(TessRhFile)
    % Hi-resolution surface
    CortexHiFile  = tess_concatenate({BstTessLhFile,    BstTessRhFile},    sprintf('cortex_%dV', nVertOrigL + nVertOrigR), 'Cortex');
    CortexLowFile = tess_concatenate({BstTessLhLowFile, BstTessRhLowFile}, sprintf('cortex_%dV', nVertices), 'Cortex');
    % Delete separate hemispheres
    rmFiles = cat(2, rmFiles, {BstTessLhFile, BstTessRhFile, BstTessLhLowFile, BstTessRhLowFile});
    rmInd   = [rmInd, iLh, iRh, iLhLow, iRhLow];
end
% Merge hemispheres: white
if ~isempty(TessLwFile) && ~isempty(TessRwFile)
    % Hi-resolution surface
    WhiteHiFile  = tess_concatenate({BstTessLwFile,    BstTessRwFile},    sprintf('white_%dV', nVertOrigL + nVertOrigR), 'Cortex');
    WhiteLowFile = tess_concatenate({BstTessLwLowFile, BstTessRwLowFile}, sprintf('white_%dV', nVertices), 'Cortex');
    % Delete separate hemispheres
    rmFiles = cat(2, rmFiles, {BstTessLwFile, BstTessRwFile, BstTessLwLowFile, BstTessRwLowFile});
    rmInd   = [rmInd, iLw, iRw, iLwLow, iRwLow];
end

%% ===== HEAD AND SKULL SURFACES =====
bst_progress('start', 'Import BrainSuite folder', 'Importing scalp and skull surfaces...');
% Head
if ~isempty(HeadFile)
    % Import file
    bst_progress('start', 'Import BrainSuite folder', 'Imported scalp surface...');
    [iHead, BstHeadHiFile] = import_surfaces(iSubject, HeadFile, 'DFS', 0);
    BstHeadHiFile = BstHeadHiFile{1};
    % Downsample
    bst_progress('start', 'Import BrainSuite folder', 'Downsampling: scalp...');
    BstHeadFile = tess_downsize( BstHeadHiFile, 1082, 'reducepatch' );
    % Load MRI
    bst_progress('start', 'Import BrainSuite folder', 'Filling holes in the head surface...');
    sMri = in_mri_bst(BstT1File);
    % Load head surface
    sHead = in_tess_bst(BstHeadFile);
    % Remove holes
    [sHead.Vertices, sHead.Faces] = tess_fillholes(sMri, sHead.Vertices, sHead.Faces, 2, 2);
    % Save back to file
    sHeadNew.Vertices = sHead.Vertices;
    sHeadNew.Faces = sHead.Faces;
    sHeadNew.Comment = sHead.Comment;
    bst_save(file_fullpath(BstHeadFile), sHeadNew, 'v7');
    % Delete initial file
    rmFiles = cat(2, rmFiles, BstHeadHiFile);
    rmInd   = [rmInd, iHead];
% Or generate one from Brainstorm
else
    % Generate head surface
    BstHeadFile = tess_isohead(iSubject, 10000, 0, 2);
end

% Inner Skull
if ~isempty(InnerSkullFile)
    % Import file
    [iIs, BstInnerSkullHiFile] = import_surfaces(iSubject, InnerSkullFile, 'DFS', 0);
    BstInnerSkullHiFile = BstInnerSkullHiFile{1};
    % Downsample
    bst_progress('start', 'Import BrainSuite folder', 'Downsampling: inner skull...');
    BstInnerSkullFile = tess_downsize(BstInnerSkullHiFile, 1000, 'reducepatch');
    % Delete initial file
    rmFiles = cat(2, rmFiles, BstInnerSkullHiFile);
    rmInd   = [rmInd, iIs];
end
if ~isempty(OuterSkullFile)
    % Import file
    [iOs, BstOuterSkullHiFile] = import_surfaces(iSubject, OuterSkullFile, 'DFS', 0);
    BstOuterSkullHiFile = BstOuterSkullHiFile{1};
    % Downsample
    bst_progress('start', 'Import BrainSuite folder', 'Downsampling: outer skull...');
    BstOuterSkullFile = tess_downsize(BstOuterSkullHiFile, 1000, 'reducepatch');
    % Delete initial file
    rmFiles = cat(2, rmFiles, BstOuterSkullHiFile);
    rmInd   = [rmInd, iOs];
end

% Delete intermediary files
if ~isempty(rmFiles)
    % Delete files
    file_delete(file_fullpath(rmFiles), 1);
    % Update subject definition
    sSubject = bst_get('Subject', iSubject);
    sSubject.Surface(rmInd) = [];
    bst_set('Subject', iSubject, sSubject);
    % Refresh tree
    panel_protocols('UpdateNode', 'Subject', iSubject);
    panel_protocols('SelectNode', [], 'subject', iSubject, -1 );
end

%% ===== IMPORT SVREG ATLAS =====
if isVolumeAtlas && ~isempty(SvregFile)
    % Import atlas as volume
    [BstSvregFile, sMriSvreg] = import_mri(iSubject, SvregFile, 'ALL-ATLAS', 0, 1, 'svreg');
    % Import other label volumes
    for iFile = 1:length(OtherSvregFiles)
        st=strfind(OtherSvregFiles{iFile},'.svreg.');
        ed=strfind(OtherSvregFiles{iFile},'.label.nii.gz');
        AtlasName = OtherSvregFiles{iFile}(st+7:ed-1);
        import_mri(iSubject, OtherSvregFiles{iFile}, 'ALL-ATLAS', 0, 1, AtlasName);
    end
    % Import atlas
    SelLabels = {...
        'Accumbens L', 'Hippocampus L', 'Pallidum L', 'Putamen L', 'Thalamus L', ...
        'Accumbens R', 'Hippocampus R', 'Pallidum R', 'Putamen R', 'Thalamus R', ...
        'Brainstem', 'Cerebellum'};
    [iSvreg, BstSvregFile] = import_surfaces(iSubject, SvregFile, 'MRI-MASK', 0, [], SelLabels, 'subcortical');
    % Extract cerebellum only
    try
        BstCerebFile = tess_extract_struct(BstSvregFile{1}, {'Cerebellum'}, 'svreg | cerebellum');
    catch
        BstCerebFile = [];
    end
    % If the cerebellum surface can be reconstructed
    if ~isempty(BstCerebFile)
        % Downsample cerebllum
        [BstCerebLowFile, iCerLow, xCerLow] = tess_downsize(BstCerebFile, 2000, 'reducepatch');
        % Merge with low-resolution pial
        BstMixedLowFile = tess_concatenate({CortexLowFile, BstCerebLowFile}, sprintf('cortex_cereb_%dV', length(xLhLow) + length(xRhLow) + length(xCerLow)), 'Cortex');
        % Rename mixed file
        oldBstMixedLowFile = file_fullpath(BstMixedLowFile);
        BstMixedLowFile    = bst_fullfile(bst_fileparts(oldBstMixedLowFile), 'tess_cortex_pialcereb_low.mat');
        file_move(oldBstMixedLowFile, BstMixedLowFile);
        % Delete intermediate files
        file_delete({file_fullpath(BstCerebFile), file_fullpath(BstCerebLowFile)}, 1);
        db_reload_subjects(iSubject);
    end
end

%% ===== UPDATE GUI =====
% Set default cortex
if ~isempty(TessLhFile) && ~isempty(TessRhFile)
    [sSubject, iSubject, iSurface] = bst_get('SurfaceFile', CortexLowFile);
    db_surface_default(iSubject, 'Cortex', iSurface);
end
% Set default scalp
db_surface_default(iSubject, 'Scalp');
% Set default skulls
db_surface_default(iSubject, 'OuterSkull');
db_surface_default(iSubject, 'InnerSkull');
% Update subject node
panel_protocols('UpdateNode', 'Subject', iSubject);
% Save database
db_save();
% Unload everything
bst_memory('UnloadAll', 'Forced');
% Give a graphical output for user validation
if isInteractive
    % Display the downsampled cortex and the head
    hFig = view_surface(BstHeadFile);
    view_surface(CortexLowFile);
    % Set orientation
    figure_3d('SetStandardView', hFig, 'left');
end
% Close progress bar
bst_progress('stop');

end

%% ======================================================================================
%  ===== HELPER FUNCTIONS ===============================================================
%  ======================================================================================
%% ===== GET PREFIX OF FILENAMES =====
function FilePrefix = get_fileprefix(BsDir)
    % Determine file prefix based on left cortex file
    TestFile = file_find(BsDir, '*.left.pial.cortex.svreg.dfs');
    if ~isempty(TestFile)
        [tmp, FilePrefix] = bst_fileparts(TestFile(1:end-27));
    else
        FilePrefix = [];
    end
end


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

    properties

    end

    methods
        sensor = getSensor(obj);

        activeTf = getSensorActiveState(obj);

        setSensorActiveState(obj, activeTf);

        steeringModel = getSensorSteeringMode(obj);

        setSteeringModel(obj, steeringModel);

        range = getSensorMaxRange(obj);

        setSensorMaxRange(obj, range);

        angle = getMaxAngle(obj);
    end
end


function [obj] = modelReadTable(obj,varargin)
	% Read in table, decides whether to do a single or multiple tables. If multiple tables, should have the same column names.
	% Biafra Ahanonu
	% branched from controllerAnalysis: 2014.08.01 [16:09:16]
	% inputs
		%
	% outputs
		%

	% changelog
		% 2021.08.10 [09:57:36] - Updated to handle CIAtah v4.0 switch to all functions inside ciapkg package.
	% TODO
		%

	import ciapkg.api.* % import CIAtah functions in ciapkg package API.

	%========================
	% which table to read in
	options.table = 'discreteStimulusTable';
	% whether to add file information to the table
	options.addFileInfoToTable = 0;
	% get options
	options = getOptions(options,varargin);
	% display(options)
	% unpack options into current workspace
	% fn=fieldnames(options);
	% for i=1:length(fn)
	% 	eval([fn{i} '=options.' fn{i} ';']);
	% end
	%========================

	if isempty(obj.delimiter)
		delimiter = 'tab';
	end
	pathClass = class(obj.(options.table));
	% pathClass
	switch pathClass
		case 'char'
			display(['loading: ' obj.(options.table)])
			outputTable = readtable(obj.(options.table),'Delimiter',obj.delimiter,'FileType','text');
		case 'cell'
			nPaths = length(obj.(options.table));
			for i=1:nPaths
				thisTablePath = obj.(options.table){i};
				if(exist(thisTablePath, 'file'))
					display(['loading: ' thisTablePath])
					if ~exist('outputTable')
						outputTable = readtable(char(obj.(options.table)(i)),'Delimiter',obj.delimiter,'FileType','text','TreatAsEmpty',{'NA','N/A'});
						if options.addFileInfoToTable==1
							[outputTable] = addFileInfoToTable(outputTable,thisTablePath);
						end
					else
						tmpTable = readtable(char(obj.(options.table)(i)),'Delimiter',obj.delimiter,'FileType','text','TreatAsEmpty',{'NA','N/A'});
						if options.addFileInfoToTable==1
							[tmpTable] = addFileInfoToTable(tmpTable,thisTablePath);
						end
						outputTable = [outputTable;tmpTable];
					end
				end
			end
		otherwise
	end

	obj.(options.table) = outputTable;

	function [inputTable] = addFileInfoToTable(inputTable,inputFileName)
		fileInfo = getFileInfo(inputFileName);
		repeatSize = [size(inputTable,1) 1];
		inputTable.subject = repmat(fileInfo.subjectNum,repeatSize);
		% inputTable.assay = repmat({fileInfo.assay},repeatSize);
		inputTable.trial = repmat({fileInfo.assay},repeatSize);
		inputTable.date = repmat({fileInfo.date},repeatSize);
	end
end


function data_out = model2data(model,fordb)
% Load complete reconstructions and output format for rBioNets ReconstructionCreator.
%
% USAGE:
%
%    data_out = model2data(model, fordb)
%
% INPUTS:
%    model:    model
%    fordb:    1 if metabolite table is wanted, default 0 if not
%
% OUTPUT:
%    data_out:
%
% .. Author: - Stefan G. Thorleifsson 2011
%
% .. rBioNet is published under GNU GENERAL PUBLIC LICENSE 3.0+
% .. Thorleifsson, S. G., Thiele, I., rBioNet: A COBRA toolbox extension for
% .. reconstructing high-quality biochemical networks, Bioinformatics, Accepted.
% .. rbionet@systemsbiology.is

if nargin < 2
    fordb = 0;
end
%   rxn table ->data
%   description
%   genes
%   model with setup change.

handles.model = model;

names = fieldnames(handles.model);

name = {'genes','data','description'};
match = zeros(size(names));
for i = 1:size(name,2)
    match(i) = strcmp(name{i},names{i});
end

if sum(match) == length(name)
    msgbox(['This file is not an complete reconstruction. Try opening'...
        ' it as a mat file.'], 'Incorrect file type','Help');
    return
end

%This field is necessary for the output.
if ~isfield(model,'grRules')
    model = creategrRulesField(model);
end

Mandatory = {'rxns','rxnNames','grRules', 'lb', 'ub','S','genes'};
%Opt numbers: CS = 1, subsystem = 2, citations = 3, comments = 4, ecNumbers = 5,
% rxnKEGGID = 6, description = 7

% reaction data lineup:
% 1.rxns
% 2.rxnNames
% 3.formula
% 4.reversible
% 5.grRules,
% 6.lb
% 7.ub
% 8.confidenceScores
% 9.subSystems
% 10.citations
% 11.comments
% 12.ecNumbers
% 13.KEGGID.

%enable is set infront afterwards.

%Check Mandatory

for i = 1:length(Mandatory)
    k = ismember(Mandatory(i),names);
    if k == 0
        msgbox(['Group ' Mandatory{i} ' is missing from structure of model.']...
            ,'Structure incorrect.','error');
        return
    end
end

S1 = size(handles.model.rxns); %Get size of model
data = cell(S1(1),13); %create cell matrix for data
data(:,1) = handles.model.rxns;
data(:,2) = handles.model.rxnNames;
data(:,3) = printRxnFormula(handles.model, handles.model.rxns,false);
data(:,4) = num2cell(double(model.lb < 0));
data(:,5) = handles.model.grRules;
data(:,6) = num2cell(handles.model.lb);
data(:,7) = num2cell(handles.model.ub);

Optional = {'confidenceScores', 'subSystems','citations', 'comments', 'ecNumbers',...
    'rxnKEGGID','description'};
%Check Optional
opt = [];
for i = 1:length(Optional)

    % Recon had different names of fields, this is a quick fix.
    if strcmp(Optional{i},'ecNumbers')
        if ismember('rxnECNumbers',names)
            Optional{i} = 'rxnECNumbers';
            continue;
        end

    elseif strcmp(Optional{i},'subSystems')
        if ismember('rxnSubSystems',names)
            Optional{i} = 'rxnSubSystems';
            continue;
        end
        if ismember('subSystems',names)
            Optional{i} = 'subSystems';
            if ~ischar([handles.model.subSystems{:}])
                handles.model.subSystems = cellfun(@(x) strjoin(x,';'),handles.model.subSystems,'UniformOutput',0);
            end
            continue;
        end
    elseif strcmp(Optional{i},'confidenceScores')
        if ismember('rxnConfidenceScores',names)
            Optional{i} = 'rxnConfidenceScores';
            continue;
        end

    elseif strcmp(Optional{i},'citations')
        if ismember('rxnReferences',names)
            Optional{i} = 'rxnReferences';
            continue;
        end

    elseif strcmp(Optional{i},'comments')
        if ismember('rxnNotes',names)
            Optional{i} = 'rxnNotes';
            continue;
        end
    end
    k = ismember(Optional(i),names);
    if k == 0
        opt = [opt,i]; %data missing
    end
end
%Opt numbers: CS = 1, subsystem = 2, citations = 3, comments = 4,
%ecNumbers = 5, rxnKEGGID = 6, description = 7
for i = 1:length(Optional)-1
    if isfield(model,Optional{i})
        if isnumeric(handles.model.(Optional{i}))
            %Confidence Scores are numeric values....
            data(:,i+7) = num2cell(handles.model.(Optional{i}));
        else
            data(:,i+7) = handles.model.(Optional{i});
        end
    else %data missing
        data(:,i+7) = cell(S1(1),1);
    end
end

%description
if ~any(ismember(opt,7)) %data exist
    if isa(handles.model.description,'char')

        s_b = [NaN NaN];
        description{1} = handles.model.description;
        description{2} = '';
        description{3} = '';
        description{4} = '';
        description{5} = '';
        description{6} = '';
        description{7} = '';
        handles.description = description;
    elseif isa(handles.model.description,'struct')
        b = fieldnames(handles.model.description);
        s_b = size(b);
    else
        s_b = [NaN NaN];
    end

    if s_b(1) == 7 %Date is not loaded into description.
        description{1} = handles.model.description.name;
        description{2} = handles.model.description.organism;
        description{3} = handles.model.description.author;
        description{4} = handles.model.description.geneindex;
        description{5} = handles.model.description.genedate;
        description{6} = handles.model.description.genesource;
        description{7} = handles.model.description.notes;
        handles.description = description;
    end

end

%This is a quick fix after adding the logical term in the front of the
%reaction table: 4. Mar. 2011
data(:,2:end+1) = data;
%Matlab does not allow data(:,1) = true;
for k=1:size(data,1)
    data{k,1} = true;
end
disabled = {};
if isfield(handles.model,'disabled')
    for i = 1:size(handles.model.disabled,1)
        disabled(i,:) = handles.model.disabled(i,:);
    end
else
    handles.model.disabled = {};
end

% Note disabled data does not carry metabolite data.

if fordb == 0
    data_out = {[data; disabled], description, handles.model.genes, handles.model};
elseif fordb == 1
    % From the metabolite database the only thing missing is the Neutral
    % formula.
     met_fields = {'mets','metNames','metFormulas','metCharges','metKEGGID',...
         'metPubChemID','metChEBIID','metInChIString','metSmiles','metHMDB',...
         'metHepatoNetID','metEHMNID'};

     names = fieldnames(model);
     %Fix incorrect cases compared to structure
     for i=1:length(met_fields)
         if isempty(find(strcmp(names,met_fields{i}),1)) %Fannst ekki
             match = find(strcmpi(names,met_fields{i}),1);
             if isempty(match) % Field not here
                 continue;
             else % Field named incorrectly regarding case.
                 met_fields{i} = names{match};
             end
         end
     end

     metabolites={};
     for i = 1:length(met_fields)
         if isfield(model,met_fields{i})
             if isempty(model.(met_fields{i})) %fields can exist but be empty.
                 metabolites(:,i) = cell(size(model.mets,1),1);
             elseif strcmp(met_fields{i}, 'metCharges') %numeric fix
                 metabolites(:,i) = num2cell(model.(met_fields{i}));
             else
                 metabolites(:,i) = model.(met_fields{i});
             end
         else %no data
             metabolites(:,i) = cell(size(model.mets,1),1);
         end
     end
     data_out = {[data; disabled], description, handles.model.genes, handles.model, metabolites};

else %input incorrect
    error('fordb is supposed to be 0 or 1.');
end


function z = bsxfun( func, x, y, varargin )

global cvx___
oflag = cvx___.broadcast;
try
    cvx___.broadcast = true;
    z = func( x, y, varargin{:} );
    cvx___.broadcast = oflag;
catch exc
    cvx___.broadcast = oflag;
    cvx_throw( exc );
end


function T56=T56(h)

T56=270.5;


 function [opt, extra] = vararg_pair(opt, varargs, varargin)
%function [opt, extra] = vararg_pair(opt, varargs, [options])
%|
%| Process name / value pairs, replacing the "default" field values
%| of the opt structure with the user-specified values.
%| This allows flexible argument order and "named arguments" somewhat like IDL.
%| This newer version allows option names to differ from the field names.
%| If two output arguments are given, then any "extra" name value pairs
%| that are not associated with the fields in structure opt will be
%| returned as name/value pairs in the "extra" output.
%|
%| in
%|	opt	struct	opt.name1 opt.name2 etc., containing default values
%|	varargs	{'name1', 'value1', ... } as a cell array
%|
%| options
%|	'subs'	Nx2 cell	{'arg_name1', 'struct_name1'; ...}
%|		short argument name followed by longer structure name
%|	'allow_new'	0|1	allow new structure elements? (default: 0)
%|
%| out
%|	opt		opt.(name) = value
%|	extra		{'name_i', 'value_i', ...} all "unused" pairs
%|
%| Copyright 2005-6-18, Jeff Fessler, University of Michigan

if nargin < 1, ir_usage, end
if nargin == 1 && streq(opt, 'test'), vararg_pair_test, clear, return, end

if isempty(varargs) && numel(varargin) == 0
	extra = {};
	return
end

base = [caller_name ' arg: ']; % for printing

local.subs = {};
local.allow_new = 0;
local = vararg_pair_do(local, varargin, {}, 0, 0);

allow_extra = nargout > 1;
[opt extra] = vararg_pair_do(opt, varargs, local.subs, local.allow_new, ...
	allow_extra, base);

% Structure elements of opt with value "NaN" are checked as being required.
% NO, this just adds overhead.  Removed 2007-2-9.
% vararg_pair_check(opt);

%
% vararg_pair_do()
%
function [opt, extra] = ...
	vararg_pair_do(opt, varargs, subs, allow_new, allow_extra, base)

if allow_extra && allow_new
	error 'only one of "new" or "extra" is sensible for vararg_pair'
end

npair = floor(length(varargs) / 2);
if 2*npair ~= length(varargs), fail('need names and values in pairs'), end
args = varargs(1:2:end);
vals = varargs(2:2:end);

if ~isempty(subs)
	if size(subs,2) ~= 2, fail('subs must be Nx2'), end
%	subs1 = strvcat(subs(:,1));
	subs1 = char(subs(:,1)); % strmatch doc says fastest for char array!
	subs2 = subs(:,2);
	% todo: apply 'subs' all at once here?
end

extra = {};
for ii=1:npair
	arg = args{ii};
	val = vals{ii};

	if ~ischar(arg)
		fail('unknown option of class %s', class(arg))
	end

	if ~isempty(subs)
		arg = vararg_pair_sub(arg, subs1, subs2);
	end

	[opt ex] = vararg_pair_put(opt, arg, val, allow_new, allow_extra);
	if allow_extra && ~isempty(ex)
		extra = [extra(:); ex(:)]'; % faster than {extra{:}, ex{:}};
	end

	if isfield(opt, 'chat') && opt.chat && isempty(ex)
		show_pair(arg, val, base)
	end
end

%
% vararg_pair_sub()
% substitute option name for field name, if a Nx2 cell array is provided.
%
function arg = vararg_pair_sub(arg, subs1, subs2)
ii = strmatch(arg, subs1, 'exact');
if isempty(ii)
	return
elseif length(ii) == 1
	arg = subs2{ii};
else
	printm([subs1(ii) ' ' subs2{ii}])
	error 'double match?  only one substitution allowed'
end

%
% vararg_pair_put()
% opt.(arg) = value
% with extra effort to handle opt.(arg1.arg2) = value
% because matlab does not handle that case by itself, except via subsagn
%
function [opt, extra] = vararg_pair_put(opt, arg, value, allow_new, allow_extra)

extra = {};
if isfield(opt, arg) % simple case of name / value pair
	opt.(arg) = value;
	return
end

idot = strfind(arg, '.');
if isempty(idot)
	if allow_new
		opt.(arg) = value;
		return
	elseif allow_extra
		extra = {arg, value};
		return
	else
		fail('unknown option name "%s"', arg)
	end
end

% tricky case of a.b.c
if length(idot) > 1, error 'a.b.c.d not done', end

arg1 = arg([1:(idot-1)]);
arg2 = arg([(idot+1):end]);
if ~isfield(opt, arg1)
	fail('unknown option1 name "%s"', arg1)
end
if ~isfield(opt.(arg1), arg2)
	fail('unknown option2 name %s', arg2)
end
s = struct('type', {'.', '.'}, 'subs', ...
	{ arg([1:(idot-1)]), arg([(idot+1):end]) });
try
	opt = subsasgn(opt, s, value);
catch
	printf(lasterr)
	fail('subsasgn? unknown option name %s', arg)
end

%
% vararg_pair_check()
% check that the user supplied the required arguments,
% which are signified by 'nan' values.
%
function vararg_pair_check(opt)
names = fieldnames(opt);
ok = 1;
for ii=1:length(names)
	t = opt.(names{ii});
	if isnumeric(t) && any(isnan(t(:)))
		printf('Required option "%s" missing', names{ii});
		ok = 0;
	end
end
if ~ok, error 'missing required "option(s)"', end

%
% show_pair()
%
function show_pair(name, value, base)

pri = @(varargin) printf([base varargin{1}], varargin{2:end});

if isnumeric(value) || islogical(value)
	if max(size(value)) == 1	% only print scalars
		if ~streq(name, 'chat')
			pri('%s = %g', name, value)
		end
	else	% otherwise print sum (e.g., for mask)
		pri('sum(%s) = %g', name, sum(value(:)))
	end

elseif ischar(value)
	pri('%s = %s', name, value)

elseif isa(value, 'cell')
	pri('%s {cell}', name)

elseif isa(value, 'function_handle')
	pri('%s = @%s', name, func2str(value))

elseif isstruct(value)	% show first structure element, if string
	fields = fieldnames(value);
%	name = getfield(arg, fields{1});
	name1 = value.(fields{1});
	if ischar(name1)
		pri('%s.%s = %s', name, fields{1}, name1)
	end

else
	warn('display type "%s" not implemented', class(value))
end

%
% test routine
%
function vararg_pair_test
args = {'a', 1, 'b', 2, 'c.d', 3, 'g', 9, 'l', 5, 'll', 6};%, 'c.f', 4};
opt.a = 0;
opt.b = 0;
opt.f = 0;
opt.long1 = 0;
opt.long2 = 0;
%opt.g = nan;
opt.c.d = 0;
opt.c.e = 0;
sub = {'g', 'f'; 'l', 'long1'; 'll', 'long2'};
opt = vararg_pair(opt, args, 'subs', sub);
jf_equal(opt.a, 1)
jf_equal(opt.b, 2)
jf_equal(opt.c.d, 3)
jf_equal(opt.c.e, 0)
jf_equal(opt.f, 9)
jf_equal(opt.long1, 5)
jf_equal(opt.long2, 6)

opt = vararg_pair(opt, {'z', 'new'}, 'allow_new', 1);
if ~isequal(opt.z, 'new'), fail('bug'), end
try % typo in name should yield error
	opt = vararg_pair(opt, {'verify_bad_test!', 'new'}, 'allow_new', 0)
catch
	return
end
error 'should not get here'


classdef PropertyChangedData < event.EventData & dynamicprops
    % Event data for widget property value changes
    %
    % Syntax:
    %           obj = wt.eventdata.PropertyChangedData(propName,newValue,oldValue)
    %           obj = wt.eventdata.PropertyChangedData(propName,valueChangedEvent)
    %           obj = wt.eventdata.PropertyChangedData(...,'p1',v1,...)
    %

    % Copyright 2020-2021 The MathWorks, Inc.

    %% Properties
    properties (SetAccess = protected)
        Value
        PreviousValue
        Property char
    end %properties

    %% Constructor / destructor
    methods
        function obj = PropertyChangedData(propName,newValue,varargin)

            % Set the changed property name
            obj.Property = propName;

            % Is input a MATLAB eventdata?
            if isa(newValue,'matlab.ui.eventdata.ValueChangedData')
                obj.Value = newValue.Value;
                obj.PreviousValue = newValue.PreviousValue;
            elseif isa(newValue,'matlab.ui.eventdata.ValueChangingData')
                obj.Value = newValue.Value;
            else
                % No - use the value directly
                obj.Value = newValue;
            end

            % Was a previous value provided?
            if mod(numel(varargin),2)
                obj.PreviousValue = varargin{1};
                varargin(1) = [];
            end

            % Any remaining varargin are dynamic property-value pairs
            for idx=1:numel(varargin)
                thisProp = varargin{idx};
                thisValue = remArgs.(thisProp);
                obj.addprop(thisProp);
                obj.(thisProp) = thisValue;
            end

        end %constructor
    end %methods

end % classdef


function batchImport(source,destn,zipFlag,mergeScansFlag)
%---------------------------------------------
%INPUTS
%source = 'path/to/source';
%destn = 'path/to/destn';
%zipFlag = 'No';
%mergeScansFlag = 'No';

%NOTE:
%1. To import selected list of folders:
%source: dirsToImportC (cell array of paths to directories to be imported)
%2.To open a pool of parallel processors:
%pool = parpool(4);

if iscell(source)

    dirsToImportC = source;

else

    % Define file and directory filter patterns
    fileFilterC = {'dose','scout','cor','sag','report','_nac','mip',...
        'coronal','sagittal','screen_save'};
    fileFilterC = {};
    dirFilterC = {'ot'};

    % Get all directories and files
    tic,
    [filesInCurDir,dirsInCurDir] = rdir(source);
    toc

    % Convert to lower case
    dirNameC = {dirsInCurDir.name};
    dirFullPathC = {dirsInCurDir.fullpath};

    % determine back or forward slash
    if ispc
        slashType = '\';
    else
        slashType = '/';
    end

    % Filter out files
    indV = zeros(1,length(dirNameC));
    for i = 1:length(fileFilterC)
        indC = strfind(dirNameC,fileFilterC{i});
        indV1 = ~cellfun(@isempty, indC);
        indV = indV | indV1;
        sum(indV)
    end

    % Filter out directories
    for i = 1:length(dirFilterC)
        indC = strfind(dirFullPathC,[slashType,dirFilterC{i},slashType]);
        indV1 = ~cellfun(@isempty, indC);
        indV = indV | indV1;
    end

    % list of directories after filtering NAC's, etc.
    dirsToImportC = dirFullPathC(~indV);

    % filter directories containing no files
    indV1 = false(length(dirsToImportC),1);
    tic,
    for dirNum = 1:length(dirsToImportC)
        dirS = dir(dirFullPathC{dirNum});
        if ~all([dirS.isdir])
            indV1(dirNum) = 1;
        end
    end
    toc
    dirsToImportC = dirsToImportC(indV1);
end

%% Import DICOM to CERR
tic
hWaitbar = NaN;
% Import all the dirs
for dirNum = 1:length(dirsToImportC)
    try
        init_ML_DICOM
        %hWaitbar = waitbar(0,'Scanning Directory Please wait...');
        sourceDir = dirsToImportC{dirNum};
        selected = 'all';
        if strcmpi(selected,'all')
            combinedDcmdirS = getCombinedDir(sourceDir);
            % Pass the java dicom structures to function to create CERR plan
            try
                optName = fullfile(getCERRPath,'CERROptions.json');
                optS    = opts4Exe(optName);
                planC = dcmdir2planC(combinedDcmdirS,mergeScansFlag,optS);
            end
        else
            patient = scandir_mldcm(sourceDir, hWaitbar, 1);
            %close(hWaitbar);
            dcmdirS = struct(['patient_' num2str(1)],patient.PATIENT(1));
            for j = 2:length(patient.PATIENT)
                dcmdirS.(['patient_' num2str(j)]) = patient.PATIENT(j);
            end
            patNameC = fieldnames(dcmdirS);
            planC = dcmdir2planC(patient.PATIENT,mergeScansFlag);
        end

        indexS = planC{end};

%         % build the filename for storing planC
%         mrn = planC{indexS.scan}(1).scanInfo(1).DICOMHeaders.PatientID;
%         studyDscr = planC{indexS.scan}(1).scanInfo(1).DICOMHeaders.StudyDescription;
%         seriesDscr = planC{indexS.scan}(1).scanInfo(1).DICOMHeaders.SeriesDescription;
%         modality = planC{indexS.scan}(1).scanInfo(1).DICOMHeaders.Modality;

%         outFileName = [mrn,'~',studyDscr,'~','_FSPost_',seriesDscr,'~',modality];
%         outFileName = strrep(outFileName,'\','-');
%         outFileName = strrep(outFileName,'/','-');
%         outFileName = strrep(outFileName,':','-');
        %outFileName = mrn;   % store file names as MRNs
        %------------TMEP FIX FOR FILES WITH dots in name-------------
        [~,outFileName,endbit] = fileparts(sourceDir);  % store file names as DICOM directory names
        outFileName = [outFileName,endbit];
        %-----------------------------------------------------
        fullOutFileName = fullfile(destn,outFileName);

        %Check for duplicate name of fullOutFileName
        dirOut = dir(destn);
        allOutNames = {dirOut.name};
        if any(strcmpi([outFileName,'.mat'],allOutNames))
            fullOutFileName = [outFileName,'_duplicate_',num2str(rand(1))];
        end
        if strcmpi(zipFlag,'Yes')
            saved_fullFileName = fullfile(destn,[outFileName,'.mat.bz2']);
        else
            saved_fullFileName = fullfile(destn,[outFileName,'.mat']);
        end
        if ~exist(fileparts(saved_fullFileName),'dir')
            mkdir(fileparts(saved_fullFileName))
        end
        save_planC(planC,[], 'passed', saved_fullFileName);

    catch

        disp(['Cannot convert ',sourceDir])

    end
end

toc
end


function create(obj,wrt)
% Create a NIFTI-1 file
% FORMAT create(obj)
% Write out the header information for the nifti object
%
% FORMAT create(obj,wrt)
% Also write out an empty image volume if wrt==1
%__________________________________________________________________________
% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging

%
% $Id: create.m 7147 2017-08-03 14:07:01Z spm $

for i=1:numel(obj)

    o = obj(i);

    if ~isa(o.dat,'file_array'), error('Data must be a file_array.'); end

    fname = o.dat.fname;
    if isempty(fname), error('No filename to write to.'); end

    %-Write NIFTI header
    sts = write_hdr_raw(fname, o.hdr, o.dat.dtype(end-1)=='B');
    if ~sts, error('Unable to write header for "%s".',fname); end

    %-Write extra information
    write_extras(fname,o.extras);

    %-Create an empty image file if necessary
    if nargin>1 && any(wrt==1)
        [pth,nam] = fileparts(fname);
        if any(strcmp(o.hdr.magic(1:3),{'n+1','n+2'}))
            ext = '.nii';
        else
            ext = '.img';
        end
        o.dat.fname = fullfile(pth,[nam ext]);

        initialise(o.dat);
    end

end


function [manifest] = write_manifest(tracker, directory)
% write_manifest Write a manifest file for the tracker
%
% Write a manifest file for the tracker. The manifest file contains some system
% statistics that can be used for debugging and analysis.
%
% Input:
% - tracker: Tracker structure.
% - tracker: Optional directory (default is tracker result root).
%
% Output:
% - manifest: Full path to the manifest file that is located in tracker result directory.

if nargin < 2
    directory = tracker.directory;
end;

mkpath(directory);
manifest = fullfile(directory, 'manifest.txt');

[platform_str, platform_maxsize, platform_endian] = computer();

if is_octave()
    environment = 'octave';
else
    environment = 'matlab';
end;

environment_version = version();

fid = fopen(manifest, 'w');

votversion = toolkit_version();

fprintf(fid, 'toolkit.version=%d.%d.%d\n', votversion.major, votversion.minor, votversion.patch);
if isfield(votversion, 'build')
fprintf(fid, 'toolkit.build=%d\n', votversion.build);
end;
fprintf(fid, 'tracker.identifier=%s\n', tracker.identifier);
fprintf(fid, 'tracker.interpreter=%s\n', tracker.interpreter);
fprintf(fid, 'timestamp=%s\n', datestr(now, 31));
fprintf(fid, 'platform=%s\n', platform_str);
fprintf(fid, 'platform.maxsize=%f\n', platform_maxsize);
fprintf(fid, 'platform.endian=%s\n', platform_endian);
fprintf(fid, 'environment=%s\n', environment);
fprintf(fid, 'environment.version=%s\n', environment_version);

fclose(fid);


function varargout=corr(varargin)
% INTERNAL FUNCTION
%

[varargout{1:nargout}]=corr(varargin{:});
end


function success=testJabCreationWithScoreFeatureInAlternateOrder()

testDataDirName='/groups/branson/bransonlab/projects/JAABA/test_data';
%testDataDirName='/Users/taylora/jaaba/test_data';
nameOfExpToAdd='GMR_71G01_AE_01_TrpA_Rig2Plate14BowlD_20110707T154929';

% % Copy the fooing scores into the exp dir
% cmd=sprintf('cp "%s/scores_fooing_GMR_71G01_AE_01_TrpA_Rig1Plate15BowlA_20120316T144027.mat" "%s/%s/scores_fooing.mat"', ...
%             testDataDirName, ...
%             testDataDirName, ...
%             nameOfExpToAdd);
% system(cmd);

% Make sure the fooing score are _not_ already in the perframe dir
scorePerframeFileNameAbs= ...
  sprintf('%s/%s/perframe/scores_fooing.mat', ...
          testDataDirName, ...
          nameOfExpToAdd);
if exist(scorePerframeFileNameAbs,'file') ,
  cmd=sprintf('rm -f "%s"',scorePerframeFileNameAbs);
  system(cmd);
end

% Make a Macguffin, from which we'll open a new file in JLabelData
macguffin=Macguffin('flies');
macguffin.setMainBehaviorName('metafooing');
macguffin.setScoreFileName('scores_metafooing.mat');
macguffin.setTrxFileName('registered_trx.mat');
macguffin.setMovieFileName('movie.ufmf');

% Create the JLabelData object
data=JLabelData('setstatusfn',@(str)(fprintf('%s\n',str)), ...
                'clearstatusfn',@()(nop()), ...
                'isInteractive',false);

% Create a new file in the JLabelData object
data.newJabFile(macguffin);

% Add a new exp dir
nameOfExpDirToAdd='/groups/branson/bransonlab/projects/JAABA/test_data/GMR_71G01_AE_01_TrpA_Rig2Plate14BowlD_20110707T154929';
%nameOfExpDirToAdd='/Users/taylora/jaaba/test_data/GMR_71G01_AE_01_TrpA_Rig2Plate14BowlD_20110707T154929';
data.SetGenerateMissingFiles();  % tell JLabelData to generate any missing perframe files
[success,msg]=data.AddExpDir(nameOfExpDirToAdd);
if ~success ,
  error(msg);
end

% Add the fooing score feature
scoreFeatureJabFileNameAbs=fullfile(testDataDirName,'fooing_labels_and_classifier.jab');
fooingJLabelData=JLabelData('setstatusfn',@(~)(nop()), ...
                            'clearstatusfn',@()(nop()));
fooingJLabelData.openJabFile(scoreFeatureJabFileNameAbs,false);
timeStamp=fooingJLabelData.classifierTS;
scoreFeatureName=baseNameFromFileName(fooingJLabelData.scorefilename);
fooingJLabelData.closeJabFile();
fooingJLabelData=[];  %#ok
data.setScoreFeatures({scoreFeatureJabFileNameAbs},timeStamp,{scoreFeatureName});

% Check the status table
perframeDirExists=data.FileExists('perframedir');
if perframeDirExists ,
  fprintf('The JLabelData object says that the perframe directory exists, as it should.\n');
else
  error('The JLabelData object says that the perframe directory does not exist, which is not as it should be.');
end

% Add the score feature to the current vocabulary
featureLexicon = data.featureLexicon;
scoreFeatures = data.scoreFeatures;
toBeCalculatedPFNames=data.allperframefns;
windowFeatureParams = data.GetPerframeParams();
fv= ...
  FeatureVocabularyForSelectFeatures(featureLexicon, ...
                                     scoreFeatures, ...
                                     toBeCalculatedPFNames, ...
                                     windowFeatureParams);
fv.setPFToWFAmount('scores_fooing','normal');
fv.setPFEnablement('scores_fooing',true);
windowFeaturesParams=fv.getInJLabelDataFormat();
data.setWindowFeaturesParams(windowFeaturesParams);

% Change the current target to the first fly of the new experiment
iExp=whichstr(nameOfExpDirToAdd,data.expdirs);
if isempty(iExp)
  error('Added experiment seems to be missing.');
elseif length(iExp)>1
  error('Added experiment seems to be present more than once in the JLabelData object.');
end
iFly=1;
data.setCurrentTarget(iExp,iFly);

% Add a label
ts1=5000+(0:50);  % frame indices to set
iBehavior1=whichstri('metafooing',data.labelnames);
isImportant1=true;
data.SetLabel(iExp,iFly,ts1,iBehavior1,isImportant1);

% Add a label
ts2=5100+(0:50);  % frame indices to set
iBehavior2=whichstri('none',data.labelnames);
isImportant2=true;
data.SetLabel(iExp,iFly,ts2,iBehavior2,isImportant2);

% Train
data.Train();

% The predictions should be correct for the labeled bouts
data.Predict(iExp,iFly,ts1(1),ts1(end));  % Make sure the prediction has been done
pred1=data.GetPredictedIdx(iExp,iFly,ts1(1),ts1(end));
if all(pred1.predictedidx==iBehavior1)
  fprintf('Predictions are correct for first labeled bout!\n');
else
  error('Predictions are wrong for first label');
end
data.Predict(iExp,iFly,ts2(1),ts2(end));  % Make sure the prediction has been done
pred2=data.GetPredictedIdx(iExp,iFly,ts2(1),ts2(end));
if all(pred2.predictedidx==iBehavior2)
  fprintf('Predictions are correct for second labeled bout!\n');
else
  error('Predictions are wrong for second label');
end

% Clean up
data.closeJabFile();
data=[];  %#ok
success=true;

end


function [weight] = bcrp_kernel(data, weight_o)
% BCRP for ps, kernel file
% Input
%     data    -- market historical prices
%     weight_o -- portfolio weight for last trading day
%
% Output
%     weight  -- weight column vector
%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This file is part of OLPS: http://OLPS.stevenhoi.org/
% Original authors: Bin LI, Steven C.H. Hoi
% Contributors:
% Change log:
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

return;
end


function matirc()
% MATLAB_IRC - A small proof of concept IRC client written in MATLAB
%
% DESCRIPTION.  This is a pretty minimal proof-of-concept client.  There
% is not much error checking, or robustness.
%
% Supported commands:
% /msg  - send private message:  /msg <user> <message>
%         example: /msg nickserv identify hunter123
%
% /quit - disconnect and quit the client
%
%
% REQUIREMENTS:
%  * TCP/UDP/IP Toolbox from:
%  https://www.mathworks.com/matlabcentral/fileexchange/345-tcpudpip-toolbox-2-0-6
%
% xixor
% Feb. 13, 2012
%
% MATIRC 0.1
%
% website: http://matirc.xixor.net
% email: xixor@xixor.net

%% OPTIONS
host = 'irc.freenode.net';
port = 6667;
opt.nick       = ['matirc_user_' num2str(randi(1000,1))];  % Doesn't handle it if someone already has your nick
opt.channel    = '##matlab';
opt.username   = 'matirc';
opt.hostname   = 'www.xixor.net';
opt.servername = 'matirc';
opt.realname   = 'im too lame to edit matirc.m';
timer_period   = 0.1;

%% CONNECT
con=pnet('tcpconnect',host,port);
pnet(con,'setwritetimeout',5);
pnet(con,'setreadtimeout',5);

if con==-1
	error 'Bad url or server down.....';
end

disp(['MATLAB IRC Client connected to: ' host]);

%% setup the data buffer callback event to check if messages have arrived
t = timer('StartDelay', 0, 'Period', timer_period,  ...
        	'ExecutionMode', 'fixedRate');
t.TimerFcn = {@tcpip_data_callback, con};

start(t);

c = onCleanup(@()on_exit_event(t,con));

%% Connection Things

pause(2);  % TODO: need a better way to wait for the connection to be initialized
register(con,opt);
pause(2);
register(con,opt);

msg_text = opt.channel;
while 1
	user_msg = input([msg_text ' >> '],'s');
	if isempty(user_msg), continue, end;
	user_msg = strtrim(user_msg);

	if numel(user_msg) >=4 && strcmp(user_msg(1:4),'/msg')
		send_priv_msg(user_msg,con);
		continue;
	end

	switch user_msg
		case '/quit'
			break;
		case '/help'
			display_help();
		otherwise
			send_msg = ['PRIVMSG ' opt.channel ' : ' user_msg '\r\n'];
			pnet(con,'printf',send_msg);
	end
	end

function send_priv_msg(msg,con)

[~,msg] = strtok(msg,' ');
[nick,msg] = strtok(msg,' ');
msg = strtrim(deblank(msg));
nick = strtrim(deblank(nick));

send_msg = ['PRIVMSG ' nick ' : ' msg '\r\n'];
pnet(con,'printf',send_msg);
fprintf('\n    --> %s : %s\n', nick, msg);

function display_help()
fprintf('------------------------------------------\r\n');
fprintf('MATLAB IRC Client version 0.0.69-pre-alpha\r\n');
fprintf('Just type your message and it will be sent to the channel\r\n');
fprintf('To send a private message: /msg <user> <msg>\r\n');
fprintf('To quit type: /quit\r\n');
fprintf('------------------------------------------\r\n');

function on_exit_event(t,con)
% ON_EXIT_EVENT - callback for onCleanup
% This function deletes the timer and closes the TCP/IP connection object
%

fprintf('\r\n Quit(): cleaning timer and TCP/IP connection.\r\n');

if isvalid(t)
	stop(t);
	delete(t);
end
pnet(con,'close');

function tcpip_data_callback(~, ~, con)
% TCPIP CALLBACK - callback to check the TCP/IP data queue
% This function is executed by a timerand is called automatically
% INPUTS:
% con - connection object
% OUTPUTS:
% none
% no error checking or printable output.
%

data = pnet(con,'read',4096,'noblock');
if isempty(data), return, end

d = regexp(data,'\n','split');   % break the message into a cell array

for i=1:size(d,1)
	process_message(con,d{i});
end

function process_message(con,msg)
% PROCESS_MESSAGE - process irc messages received from the server
%
% INPUTS:
% con: connection object
% msg: the messgae to parse
%
% OUTPUTS: none.  This function calls other functions based on the message.
%
% TODO: need to parse irc messages in a general way

if ~isempty(strfind(msg,'PRIVMSG'))
	parse_privmsg(msg)
	return;
end

prefix = find(msg ==':',1,'first');
msg_name = strtrim(msg(1:prefix-1));
msg_body = strtrim(msg(prefix+1:end));

switch msg_name
	case 'NOTICE AUTH'
		% server messages
		fprintf('%s\n',msg_body);
	case 'PING'
		% ping requests from the server
		pnet(con,'printf',['PONG ' msg_body '\r\n']);
		fprintf('PING? PONG!\n');
	otherwise
		% TODO: parse other messages
end

function register(con,opt)
%REGISTER - set nick, user info
% INPUTS:
% con - connection object
% opt - options struct, members: username, hostname, servername, realname,
%       nick, channel
%
% OUTPUTS:
% no outputs or error checking
%

pnet(con,'printf',['NICK ' opt.nick '\r\n']);
pnet(con,'printf',['USER ' opt.username ' ' opt.hostname ' ' opt.servername ' :' opt.realname '\r\n']);
pnet(con,'printf',['JOIN ' opt.channel '\r\n']);

function parse_privmsg(msg,con,opt)
% PARSE_PRIVMSG - parse a PRIVMSG, print to screen
%
% INPUTS
% msg : a privmsg string from the irc server
% con : connection object
% opt : options structure
% (con and opt unused, left for future implementation)
%
% OUTPUT:
% prints the <nick> msg to the command window
%
% No error checking or confirmation
%

% TODO: need a much more general and robust way of parsing irc messages
% fprintf('\n MSG: %s\n',msg); // debug statement
sent_nick = msg(find(msg==':',1,'first')+1:find(msg=='!',1,'first')-1);

fprintf('<%s> %s\n',sent_nick,strtrim(msg(find(msg ==':',1,'last')+1:end)));


%% script for making plots used to demonstrate accuracy of detectors

%% set up path

addpath ../perframe;
addpath ../perframe/compute_perframe_features;
addpath ../misc;
addpath ../filehandling;
addpath C:\Code\Ctrax\trunk\matlab\netlab;
outfigdir = 'C:/Code/Jdetect/figures/AccuracyOut';
if ~exist(outfigdir,'dir'),
  mkdir(outfigdir);
end

%% global parameters

% groundtruthing
ifpcolor = [0,0,.7];
fpcolor = [.3,.3,1];
ifncolor = [.7,0,0];
fncolor = [1,.3,.3];
ierrorcolor = [0,0,0];
errorcolor = [.3,.3,.3];
chancecolor = [.7,.7,.7];

TOUCH = 1;
CRABWALK = 2;
BACKUP = 3;
CHASE = 4;
WINGGROOMING = 5;
JUMP = 6;
STOP = 7;
RIGHTING = 8;
TAILPIVOTTURN = 9;
WALK = 10;

MOUSE_WALK = 11;
MOUSE_MALEFOLLOW = 12;

LARVA_HEADCAST = 13;
LARVA_CRAWL = 14;

%% TOUCH

behavior = 'Touch';
configfilename = '../perframe/params/JLabelParams_FlyBowl_Touch.xml';
roottraindir = 'C:/Data/JAABA/FlyBowl';
rootgroundtruthdir = 'C:/Data/JAABA/groundtruth_pBDPGAL4U_data';

train_experiment_names = {
  'GMR_71G01_AE_01_TrpA_Rig2Plate17BowlD_20110921T084818'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlB_20110922T145928'
  'pBDPGAL4U_TrpA_Rig2Plate14BowlD_20110615T164545'
  'pBDPGAL4U_TrpA_Rig2Plate14BowlD_20110707T085804'};

groundtruth_experiment_names = {
  'pBDPGAL4U_TrpA_Rig1Plate10BowlB_20110609T091905'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlD_20120210T152130'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlA_20120202T145723'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlC_20110811T133805'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlD_20111130T094443'};

train_expdirs = cellfun(@(x) fullfile(roottraindir,x),train_experiment_names,'UniformOutput',false);
groundtruth_expdirs = cellfun(@(x) fullfile(rootgroundtruthdir,x),groundtruth_experiment_names,'UniformOutput',false);

[hfigs,errordata,figfilenames,outmatfilename] = ...
  Compute_GroundTruthError_vs_TrainingSetSize(behavior,configfilename,train_expdirs,groundtruth_expdirs,...
  'hfigs',[3,4]+100*TOUCH,...
  'figpos',[95 550 1246 443],...
  'ifpcolor',ifpcolor,...
  'fpcolor',fpcolor,...
  'ifncolor',ifncolor,...
  'fncolor',fncolor,...
  'ierrorcolor',ierrorcolor,...
  'errorcolor',errorcolor,...
  'chancecolor',chancecolor,...
  'outfigdir',outfigdir);

%% CRABWALK

behavior = 'Crabwalk';
configfilename = '../perframe/params/JLabelParams_FlyBowl_Crabwalk.xml';

roottraindir = 'C:/Data/JAABA/FlyBowl';
rootgroundtruthdir = 'C:/Data/JAABA/groundtruth_pBDPGAL4U_data';

train_experiment_names = {
  'GMR_71G01_AE_01_TrpA_Rig2Plate17BowlD_20110921T084818'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlB_20110922T145928'
  'pBDPGAL4U_TrpA_Rig2Plate14BowlD_20110615T164545'
  'pBDPGAL4U_TrpA_Rig2Plate14BowlD_20110707T085804'};

groundtruth_experiment_names = {
  'pBDPGAL4U_TrpA_Rig1Plate10BowlB_20110609T091905'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlD_20120210T152130'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlA_20120202T145723'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlC_20110811T133805'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlD_20111130T094443'};

train_expdirs = cellfun(@(x) fullfile(roottraindir,x),train_experiment_names,'UniformOutput',false);
groundtruth_expdirs = cellfun(@(x) fullfile(rootgroundtruthdir,x),groundtruth_experiment_names,'UniformOutput',false);

try

[hfigs,errordata,figfilenames,outmatfilename] = ...
  Compute_GroundTruthError_vs_TrainingSetSize(behavior,configfilename,train_expdirs,groundtruth_expdirs,...
  'hfigs',[3,4]+100*CRABWALK,...
  'figpos',[95 550 1246 443],...
  'ifpcolor',ifpcolor,...
  'fpcolor',fpcolor,...
  'ifncolor',ifncolor,...
  'fncolor',fncolor,...
  'ierrorcolor',ierrorcolor,...
  'errorcolor',errorcolor,...
  'chancecolor',chancecolor,...
  'outfigdir',outfigdir);

catch ME
  warning('%s: %s',behavior,getReport(ME));
end

%% backup

behavior = 'Backup';
configfilename = '../perframe/params/JLabelParams_FlyBowl_Backup.xml';

roottraindir = 'C:/Data/JAABA/FlyBowl';
rootgroundtruthdir = 'C:/Data/JAABA/groundtruth_pBDPGAL4U_data';

train_experiment_names = {
  'GMR_71G01_AE_01_TrpA_Rig2Plate17BowlD_20110921T084818'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlB_20110922T145928'
  'pBDPGAL4U_TrpA_Rig2Plate14BowlD_20110615T164545'
  'pBDPGAL4U_TrpA_Rig2Plate14BowlD_20110707T085804'};

groundtruth_experiment_names = {
  'pBDPGAL4U_TrpA_Rig1Plate10BowlB_20110609T091905'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlD_20120210T152130'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlA_20120202T145723'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlC_20110811T133805'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlD_20111130T094443'};

train_expdirs = cellfun(@(x) fullfile(roottraindir,x),train_experiment_names,'UniformOutput',false);
groundtruth_expdirs = cellfun(@(x) fullfile(rootgroundtruthdir,x),groundtruth_experiment_names,'UniformOutput',false);

try
[hfigs,errordata,figfilenames,outmatfilename] = ...
  Compute_GroundTruthError_vs_TrainingSetSize(behavior,configfilename,train_expdirs,groundtruth_expdirs,...
  'hfigs',3:4+BACKUP*100,...
  'figpos',[95 550 1246 443],...
  'ifpcolor',ifpcolor,...
  'fpcolor',fpcolor,...
  'ifncolor',ifncolor,...
  'fncolor',fncolor,...
  'ierrorcolor',ierrorcolor,...
  'errorcolor',errorcolor,...
  'chancecolor',chancecolor,...
  'outfigdir',outfigdir);
catch ME
  warning('%s: %s',behavior,getReport(ME));
end

%% chase

behavior = 'Chase';
configfilename = '../perframe/params/JLabelParams_FlyBowl_Chase.xml';

roottraindir = 'C:/Data/JAABA/FlyBowl';
rootgroundtruthdir = 'C:/Data/JAABA/groundtruth_pBDPGAL4U_data';

train_experiment_names = {
  'GMR_14C07_AE_01_TrpA_Rig1Plate15BowlA_20120404T141155'
  'GMR_53B02_AE_01_TrpA_Rig1Plate15BowlC_20110930T140347'
  'GMR_71G01_AE_01_TrpA_Rig2Plate14BowlC_20110707T154934'
  'GMR_94B10_AE_01_TrpA_Rig1Plate15BowlC_20111007T155325'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlB_20110922T145928'
  'pBDPGAL4U_TrpA_Rig2Plate14BowlD_20110615T164545'};

groundtruth_experiment_names = {
  'pBDPGAL4U_TrpA_Rig1Plate10BowlB_20110609T091905'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlD_20120210T152130'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlA_20120202T145723'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlC_20110811T133805'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlD_20111130T094443'};

train_expdirs = cellfun(@(x) fullfile(roottraindir,x),train_experiment_names,'UniformOutput',false);
groundtruth_expdirs = cellfun(@(x) fullfile(rootgroundtruthdir,x),groundtruth_experiment_names,'UniformOutput',false);

try
  [hfigs,errordata,figfilenames,outmatfilename] = ...
  Compute_GroundTruthError_vs_TrainingSetSize(behavior,configfilename,train_expdirs,groundtruth_expdirs,...
  'hfigs',[3,4]+CHASE*100,...
  'figpos',[95 550 1246 443],...
  'ifpcolor',ifpcolor,...
  'fpcolor',fpcolor,...
  'ifncolor',ifncolor,...
  'fncolor',fncolor,...
  'ierrorcolor',ierrorcolor,...
  'errorcolor',errorcolor,...
  'chancecolor',chancecolor,...
  'outfigdir',outfigdir);
catch ME
  warning('%s: %s',behavior,getReport(ME));
end

%% wing grooming

behavior = 'WingGrooming';
configfilename = '../perframe/params/JLabelParams_FlyBowl_WingGrooming.xml';

roottraindir = 'C:/Data/JAABA/FlyBowl';
rootgroundtruthdir = 'C:/Data/JAABA/groundtruth_pBDPGAL4U_data';

train_experiment_names = {
  'GMR_71G01_AE_01_TrpA_Rig2Plate17BowlD_20110921T084818'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlB_20110922T145928'
  'pBDPGAL4U_TrpA_Rig2Plate14BowlD_20110615T164545'
  'pBDPGAL4U_TrpA_Rig2Plate14BowlD_20110707T085804'};

groundtruth_experiment_names = {
  'pBDPGAL4U_TrpA_Rig1Plate10BowlB_20110609T091905'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlD_20120210T152130'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlA_20120202T145723'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlC_20110811T133805'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlD_20111130T094443'};

train_expdirs = cellfun(@(x) fullfile(roottraindir,x),train_experiment_names,'UniformOutput',false);
groundtruth_expdirs = cellfun(@(x) fullfile(rootgroundtruthdir,x),groundtruth_experiment_names,'UniformOutput',false);

try
  [hfigs,errordata,figfilenames,outmatfilename] = ...
  Compute_GroundTruthError_vs_TrainingSetSize(behavior,configfilename,train_expdirs,groundtruth_expdirs,...
  'hfigs',[3,4]+WINGGROOMING*100,...
  'figpos',[95 550 1246 443],...
  'ifpcolor',ifpcolor,...
  'fpcolor',fpcolor,...
  'ifncolor',ifncolor,...
  'fncolor',fncolor,...
  'ierrorcolor',ierrorcolor,...
  'errorcolor',errorcolor,...
  'chancecolor',chancecolor,...
  'outfigdir',outfigdir);
catch ME
  warning('%s: %s',behavior,getReport(ME));
end

%% jump

behavior = 'Jump';
configfilename = '../perframe/params/JLabelParams_FlyBowl_Jump.xml';

roottraindir = 'C:/Data/JAABA/FlyBowl';
rootgroundtruthdir = 'C:/Data/JAABA/groundtruth_pBDPGAL4U_data';

train_experiment_names = {
'GMR_14C08_AE_01_TrpA_Rig1Plate15BowlB_20110914T113113'
'GMR_20B07_AE_01_TrpA_Rig2Plate17BowlC_20120216T143940'
'GMR_71G01_AE_01_TrpA_Rig2Plate14BowlC_20110707T154934'
'GMR_82D11_AE_01_TrpA_Rig1Plate15BowlB_20111028T093039'
'pBDPGAL4U_TrpA_Rig1Plate10BowlA_20110610T153218'
'pBDPGAL4U_TrpA_Rig2Plate17BowlA_20110929T143440'
};

groundtruth_experiment_names = {
  'pBDPGAL4U_TrpA_Rig1Plate10BowlB_20110609T091905'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlD_20120210T152130'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlA_20120202T145723'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlC_20110811T133805'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlD_20111130T094443'};

train_expdirs = cellfun(@(x) fullfile(roottraindir,x),train_experiment_names,'UniformOutput',false);
groundtruth_expdirs = cellfun(@(x) fullfile(rootgroundtruthdir,x),groundtruth_experiment_names,'UniformOutput',false);

try
  [hfigs,errordata,figfilenames,outmatfilename] = ...
  Compute_GroundTruthError_vs_TrainingSetSize(behavior,configfilename,train_expdirs,groundtruth_expdirs,...
  'hfigs',[3,4]+JUMP*100,...
  'figpos',[95 550 1246 443],...
  'ifpcolor',ifpcolor,...
  'fpcolor',fpcolor,...
  'ifncolor',ifncolor,...
  'fncolor',fncolor,...
  'ierrorcolor',ierrorcolor,...
  'errorcolor',errorcolor,...
  'chancecolor',chancecolor,...
  'outfigdir',outfigdir);
catch ME
  warning('%s: %s',behavior,getReport(ME));
end

%% stop

behavior = 'Stop';
configfilename = '../perframe/params/JLabelParams_FlyBowl_Stop.xml';

roottraindir = 'C:/Data/JAABA/FlyBowl';
rootgroundtruthdir = 'C:/Data/JAABA/groundtruth_pBDPGAL4U_data';

% find train directories by loading in the classifier
train_experiment_names = {
  'pBDPGAL4U_TrpA_Rig2Plate17BowlB_20110805T101647'
};

% always doing groundtruthing on these
groundtruth_experiment_names = {
  'pBDPGAL4U_TrpA_Rig1Plate10BowlB_20110609T091905'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlD_20120210T152130'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlA_20120202T145723'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlC_20110811T133805'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlD_20111130T094443'};

train_expdirs = cellfun(@(x) fullfile(roottraindir,x),train_experiment_names,'UniformOutput',false);
groundtruth_expdirs = cellfun(@(x) fullfile(rootgroundtruthdir,x),groundtruth_experiment_names,'UniformOutput',false);

try
  [hfigs,errordata,figfilenames,outmatfilename] = ...
  Compute_GroundTruthError_vs_TrainingSetSize(behavior,configfilename,train_expdirs,groundtruth_expdirs,...
  'hfigs',[3,4]+STOP*100,...
  'figpos',[95 550 1246 443],...
  'ifpcolor',ifpcolor,...
  'fpcolor',fpcolor,...
  'ifncolor',ifncolor,...
  'fncolor',fncolor,...
  'ierrorcolor',ierrorcolor,...
  'errorcolor',errorcolor,...
  'chancecolor',chancecolor,...
  'outfigdir',outfigdir);
catch ME
  warning('%s: %s',behavior,getReport(ME));
end

%% righting

behavior = 'Righting';
configfilename = '../perframe/params/JLabelParams_FlyBowl_Righting.xml';

roottraindir = 'C:/Data/JAABA/FlyBowl';
rootgroundtruthdir = 'C:/Data/JAABA/groundtruth_pBDPGAL4U_data';

% find train directories by loading in the classifier
train_experiment_names = {
  'pBDPGAL4U_TrpA_Rig1Plate10BowlA_20110610T153218'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlA_20110929T143440'
  'GMR_14C08_AE_01_TrpA_Rig1Plate15BowlB_20110914T113113'
  'GMR_71G01_AE_01_TrpA_Rig2Plate14BowlC_20110707T154934'
  'GMR_82D11_AE_01_TrpA_Rig1Plate15BowlB_20111028T093039'
};

% always doing groundtruthing on these
groundtruth_experiment_names = {
  'pBDPGAL4U_TrpA_Rig1Plate10BowlB_20110609T091905'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlD_20120210T152130'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlA_20120202T145723'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlC_20110811T133805'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlD_20111130T094443'};

train_expdirs = cellfun(@(x) fullfile(roottraindir,x),train_experiment_names,'UniformOutput',false);
groundtruth_expdirs = cellfun(@(x) fullfile(rootgroundtruthdir,x),groundtruth_experiment_names,'UniformOutput',false);

try
  [hfigs,errordata,figfilenames,outmatfilename] = ...
  Compute_GroundTruthError_vs_TrainingSetSize(behavior,configfilename,train_expdirs,groundtruth_expdirs,...
  'hfigs',[3,4]+RIGHTING*100,...
  'figpos',[95 550 1246 443],...
  'ifpcolor',ifpcolor,...
  'fpcolor',fpcolor,...
  'ifncolor',ifncolor,...
  'fncolor',fncolor,...
  'ierrorcolor',ierrorcolor,...
  'errorcolor',errorcolor,...
  'chancecolor',chancecolor,...
  'outfigdir',outfigdir);
catch ME
  warning('%s: %s',behavior,getReport(ME));
end

%% tail pivot turn

behavior = 'TailPivotTurn';
configfilename = '../perframe/params/JLabelParams_FlyBowl_TailPivotTurn.xml';

roottraindir = 'C:/Data/JAABA/FlyBowl';
rootgroundtruthdir = 'C:/Data/JAABA/groundtruth_pBDPGAL4U_data';

% find train directories by loading in the classifier
train_experiment_names = {
  'GMR_82D11_AE_01_TrpA_Rig1Plate15BowlB_20111028T093039'
  'GMR_80A01_AE_01_TrpA_Rig2Plate14BowlD_20110408T140618'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlB_20110922T145928'
  'pBDPGAL4U_TrpA_Rig2Plate14BowlD_20110615T164545'
  'FCF_attP2_1500062_None_Rig2Plate17BowlB_20120519T165213'
};

% always doing groundtruthing on these
groundtruth_experiment_names = {
  'pBDPGAL4U_TrpA_Rig1Plate10BowlB_20110609T091905'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlD_20120210T152130'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlA_20120202T145723'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlC_20110811T133805'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlD_20111130T094443'};

train_expdirs = cellfun(@(x) fullfile(roottraindir,x),train_experiment_names,'UniformOutput',false);
groundtruth_expdirs = cellfun(@(x) fullfile(rootgroundtruthdir,x),groundtruth_experiment_names,'UniformOutput',false);

try
  [hfigs,errordata,figfilenames,outmatfilename] = ...
  Compute_GroundTruthError_vs_TrainingSetSize(behavior,configfilename,train_expdirs,groundtruth_expdirs,...
  'hfigs',[3,4]+TAILPIVOTTURN*100,...
  'figpos',[95 550 1246 443],...
  'ifpcolor',ifpcolor,...
  'fpcolor',fpcolor,...
  'ifncolor',ifncolor,...
  'fncolor',fncolor,...
  'ierrorcolor',ierrorcolor,...
  'errorcolor',errorcolor,...
  'chancecolor',chancecolor,...
  'outfigdir',outfigdir);
catch ME
  warning('%s: %s',behavior,getReport(ME));
end

%% walk

behavior = 'Walk';
configfilename = '../perframe/params/JLabelParams_FlyBowl_Walk.xml';

roottraindir = 'C:/Data/JAABA/FlyBowl';
rootgroundtruthdir = 'C:/Data/JAABA/groundtruth_pBDPGAL4U_data';

% find train directories by loading in the classifier
train_experiment_names = {
 'pBDPGAL4U_TrpA_Rig2Plate17BowlB_20110805T101647'
 'pBDPGAL4U_TrpA_Rig2Plate14BowlD_20110707T085804'
 'pBDPGAL4U_TrpA_Rig2Plate14BowlD_20110615T164545'
 'pBDPGAL4U_TrpA_Rig1Plate15BowlB_20110922T145928'
 'GMR_80A01_AE_01_TrpA_Rig2Plate14BowlD_20110408T140618'
 'GMR_82D11_AE_01_TrpA_Rig1Plate15BowlB_20111028T093039'
};

% always doing groundtruthing on these
groundtruth_experiment_names = {
  'pBDPGAL4U_TrpA_Rig1Plate10BowlB_20110609T091905'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlD_20120210T152130'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlA_20120202T145723'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlC_20110811T133805'
  'pBDPGAL4U_TrpA_Rig2Plate17BowlD_20111130T094443'};

train_expdirs = cellfun(@(x) fullfile(roottraindir,x),train_experiment_names,'UniformOutput',false);
groundtruth_expdirs = cellfun(@(x) fullfile(rootgroundtruthdir,x),groundtruth_experiment_names,'UniformOutput',false);

try
  [hfigs,errordata,figfilenames,outmatfilename] = ...
  Compute_GroundTruthError_vs_TrainingSetSize(behavior,configfilename,train_expdirs,groundtruth_expdirs,...
  'hfigs',[3,4]+WALK*100,...
  'figpos',[95 550 1246 443],...
  'ifpcolor',ifpcolor,...
  'fpcolor',fpcolor,...
  'ifncolor',ifncolor,...
  'fncolor',fncolor,...
  'ierrorcolor',ierrorcolor,...
  'errorcolor',errorcolor,...
  'chancecolor',chancecolor,...
  'outfigdir',outfigdir);
catch ME
  warning('%s: %s',behavior,getReport(ME));
end


% *** This function is part of ERPLAB Toolbox ***
% Author: Javier Lopez-Calderon
% Center for Mind and Brain
% University of California, Davis,
% Davis, CA
% 2009

binArray       = plotset.pfrequ.binArray;
plotallbin     = plotset.pfrequ.plotallbin;
chanArray      = plotset.pfrequ.chanArray;
plotallch      = plotset.pfrequ.plotallch;
chanArray_MGFP = plotset.pfrequ.chanArray_MGFP;
blcorr         = plotset.pfrequ.blcorr;
xxscale        = plotset.pfrequ.xscale;
yyscale        = plotset.pfrequ.yscale;
linewidth      = plotset.pfrequ.linewidth;
isiy           = plotset.pfrequ.isiy;
fschan         = plotset.pfrequ.fschan;
fslege         = plotset.pfrequ.fslege;
fsaxtick       = plotset.pfrequ.fsaxtick;
pstyle         = plotset.pfrequ.pstyle;
errorstd       = plotset.pfrequ.errorstd;
stdalpha       = plotset.pfrequ.stdalpha;
isMGFP         = plotset.pfrequ.isMGFP;
%
% if plotallch
%         newnch = numel(chanArray);
%         if isMGFP
%                 newnch = newnch + 1;
%         end
%         dsqr   = round(sqrt(newnch));
%         sqrdif = dsqr^2 - newnch;
%         if sqrdif<0
%                 pbox(1) = dsqr + 1;
%         else
%                 pbox(1) = dsqr;
%         end
%         pbox(2) = dsqr;
% else
        pbox   = plotset.pfrequ.pbox;
% end
counterwin     = plotset.pfrequ.counterwin;
holdch         = plotset.pfrequ.holdch;
yauto          = plotset.pfrequ.yauto;
yautoticks     = plotset.pfrequ.yautoticks;
xautoticks     = plotset.pfrequ.xautoticks;
binleg         = plotset.pfrequ.binleg;
chanleg        = plotset.pfrequ.chanleg;

ismaxim        = plotset.pfrequ.ismaxim;
%istopo         = plotset.pfrequ.istopo;
axsize         = plotset.pfrequ.axsize;
minorticks     = plotset.pfrequ.minorticks;
linespeci      = plotset.pfrequ.linespec;
legepos        = plotset.pfrequ.legepos;
posgui         = plotset.pfrequ.posgui;
posminigui     = plotset.pfrequ.posminigui;
posfig         = plotset.pfrequ.posfig;
ibckground     = plotset.pfrequ.ibckground;


%% SO3FunHandle


classdef  VideoMaker_TopOpt_density3DXmirror < VideoMaker_TopOpt
  properties

  end

  methods (Access = public)

        function Make_video_design_variable(obj,output_video_name)
            post = Postprocess_TopOpt_density();
            field2print = post.density_name;
            componentfield = post.density_name_component;
            obj.Make_video_density_field(field2print,componentfield,output_video_name)
        end

        function Make_video_design_variable_reg(obj,output_video_name)
            post = Postprocess_TopOpt_density();
            field2print = post.density_name_reg;
            componentfield = post.density_name_component_reg;
            obj.Make_video_density_field(field2print,componentfield,output_video_name)
        end

  end

  methods (Access = private)
        function Make_video_density_field(obj,field2print,componentfield,output_video_name)
            file_tcl_name = 'tcl_gid.tcl';
            file_list = obj.create_file_list(obj.iterations_to_print,obj.file_name,obj.files_folder);
            [output_video_name] = obj.replace_special_character(output_video_name);
            [output_photo]=obj.replace_special_character(strcat(obj.files_folder,'\',obj.file_name,'.png'));
            [file_list] = obj.replace_special_character(file_list);

            file_tcl_name_with_path = fullfile(obj.files_folder,file_tcl_name);
            file_path_in = fullfile(pwd,'FEM','PostProcess','Make_Video_density3DXmirror.tcl');
            filepath = obj.replace_special_character(file_path_in);

            fid = fopen(file_tcl_name_with_path,'w+');

            fprintf(fid,'GiD_Process PostProcess \n');
            fprintf(fid,'%s\n',['set arg1 "',file_list,'"']);
            fprintf(fid,'%s\n',['set arg2 "',output_video_name,'"']);
            fprintf(fid,'%s\n',['set arg3 "',field2print,'"']);
            fprintf(fid,'%s\n',['set arg4 "',componentfield,'"']);
            fprintf(fid,'%s\n',['set arg5 "',output_photo,'"']);

            fprintf(fid,'%s\n',['source "',filepath,'"']);
            fprintf(fid,'%s\n',['Make_Video_density $arg1 $arg2 $arg3 $arg4 $arg5']);
            fprintf(fid,'%s\n',['GiD_Process Mescape Quit']);
            fclose(fid);
            obj.execute_tcl_files(obj.gidPath,file_tcl_name_with_path)
        end

    end
end


function plotmimac(mi,inde)

    % TODO maybe move into domisfit

    ZG=ZmapGlobal.Data; % used by get_zmap_globals

    report_this_filefun(mfilename('fullpath'));

    global mif2 mif1
    global oneOfHowManyPopupIdx

    %var1 = 4;
    sc = oneOfHowManyPopupIdx;
    figure(UNK) % FIXME: really? this figure? unsure
    delete(findobj(UNK,'Type','axes'));
    rect = [0.15,  0.20, 0.75, 0.65];
    axes('position',rect)
    watchon

    % check if cross-section exists
    figNumber=findobj('Type','Figure','-and','Name','Cross -Section');

    if isempty(figNumber)
        errordlg('Please create a cross-section first, then rerun the last selection');
        nlammap
        return
    end

    % check if cross-section is still current
    if max(mi(:,1)) > length(mi(:,1))
        errordlg('Please rerun the cross-section first, then rerun the last selection');
        nlammap
        return
    end

    mic = mi(inde,:);
    le = size(newa,2); %FIXME where does newa come from? ZG.newa? input parameter?  Needs to be treated like a ZmapCatalog

    if var1 == 1
        for i = 1:length(newa(:,6))
            pl =  plot(newa(i,le),-newa(i,7),'ro');
            hold on
            set(pl,'MarkerSize',mic(i,2)/sc)
        end

    elseif var1 == 2

        for i = 1:length(newa(:,6))
            pl =  plot(newa(i,le),-newa(i,7),'bx');
            hold on
            set(pl,'MarkerSize',mic(i,2)/sc,'LineWidth',mic(i,2)/sc)
        end

    elseif var1 == 3

        for i = 1:length(newa(:,6))
            pl =  plot(newa(i,le),-newa(i,7),'bx');
            hold on
            c = mic(i,2)/max(mic(:,2));
            %c = newa(i,15)*10;
            set(pl,'MarkerSize',mic(i,2)/sc+3,'LineWidth',mic(i,2)/sc+0.5,'Color',[ c c c ] )
        end

    elseif var1 == 4

        g = jet;
        for i = 1:length(newa(:,6))
            pl =  plot(newa(i,le),-newa(i,7),'bx');
            hold on
            c = floor(mic(i,2)/max(mic(:,2))*63+1);
            set(pl,'MarkerSize',4,'LineWidth',2,'Color',[ g(c,:) ] )
        end
        colorbar
        colormap(jet)
    end

    if exist('maex', 'var')
        hold on
        pl = plot(maex,-maey,'*m');
        set(pl,'MarkerSize',8,'LineWidth',2)
    end

    if exist('maex', 'var')
        hold on
        pl = plot(maex,-maey,'*m');
        set(pl,'MarkerSize',8,'LineWidth',2)
    end

    xlabel('Distance [km]','FontWeight','bold','FontSize',ZmapGlobal.Data.fontsz.m)
    ylabel('Depth [km]','FontWeight','bold','FontSize',ZmapGlobal.Data.fontsz.m)
    strib = [  'Misfit '];
    title(strib,'FontWeight','bold',...
        'FontSize',ZmapGlobal.Data.fontsz.m,'Color','k')

    set(gca,'Color',color_bg);
    set(gca,'box','on',...
        'SortMethod','childorder','TickDir','out','FontWeight',...
        'bold','FontSize',ZmapGlobal.Data.fontsz.m,'Linewidth',1.2)
    uicontrol(...
        'Style','pushbutton',...
        'Units','normalized',...
        'Position',[0.9 0.7 0.08 0.08],...
        'String','Grid',...
        'callback',@(~,~)mificrgr(mi,inde));

    uicontrol(...
        'Style','pushbutton',...
        'Units','normalized',...
        'Position',[0.9 0.6 0.08 0.08],...
        'String','Sel EQ',...
        'callback',@cb_pickinv);

    watchoff

    function cb_pickinv(~,~)
        newa2=crossel(newa);
        ZG.newt2=newa2;
        ZG.newcat=newa2;
        timeplot();
    end

end


function CPD = generic_CPD(clamped)
% GENERIC_CPD Virtual constructor for generic CPD
% CPD = discrete_CPD(clamped)

if nargin < 1, clamped = 0; end

CPD.clamped = clamped;
CPD = class(CPD, 'generic_CPD');


function cvx_expert_check( fname, varargin )

global cvx___
if cvx___.expert, return; end
if ~isempty( varargin ) && ~any(cellfun('isclass',varargin,'cvx')), return; end

url = [ 'file:///', cvx___.where, cvx___.fs, 'doc', cvx___.fs, 'advanced.html#the-successive-approximation-method' ];
fprintf( 1, [ 'CVX Warning:\n', ...
'   Models involving "%s" or other functions in the log, exp, and entropy\n', ...
'   family are solved using an experimental successive approximation method.\n', ...
'   This method is slower and less reliable than the method CVX employs for\n', ...
'   other models. Please see the section of the user''s guide entitled\n', ...
'       The successive approximation method\n', ...
'   for more details about the approach, and for instructions on how to\n', ...
'   suppress this warning message in the future.\n' ], fname, url );

cvx___.expert = true;

% Note that we do *not* call cvx_save_prefs here. We only save the
% preferences if an explicit setting of "cvx_expert true" is made.

% 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.


classdef dme_load3p_opf < mp.dme_load3p & mp.dme_shared_opf

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

%     properties
%     end     %% properties

%     methods
%     end     %% methods
end         %% classdef


function writestruct(filename, s)
% writestruct Store a structure to file
%
% Saves a structure object to a text file in an INI-like format.
%
% Input:
% - filename (string): Path to the file.
% - s (structure): A structure.
%

fid = fopen(filename, 'w');

writeimpl(fid, s, '');

fclose(fid);

end

function writeimpl(fid, s, prefix)

    % Extract field data
    fields = repmat(fieldnames(s), numel(s), 1);
    values = struct2cell(s);

    % Convert all numerical values to strings
    idx = cellfun(@isnumeric, values);
    values(idx) = cellfun(@num2str, values(idx), 'UniformOutput', 0);

    for i = 1:numel(fields)
        if isstruct(values{i})
            writeimpl(fid, values{i}, [prefix, fields{i}, '.']);
        else
            fprintf(fid, '%s%s=%s\n', prefix, fields{i}, values{i});
        end
    end;

end


function opts = mergeOptions(opts1, opts2)
% Merges two options structures with one having precedence over the other.
%
% function opts = mergeOptions(opts1, opts2)
%
% input: opts1 and opts2 are two structures.
% output: opts is a structure containing all fields of opts1 and opts2.
% Whenever a field is present in both opts1 and opts2, it is the value in
% opts2 that is kept.
%
% The typical usage is to have opts1 contain default options and opts2
% contain user-specified options that overwrite the defaults.
%
% See also: getGlobalDefaults

% This file is part of Manopt: www.manopt.org.
% Original author: Nicolas Boumal, Dec. 30, 2012.
% Contributors:
% Change log:

    if isempty(opts1)
        opts1 = struct();
    end
    if isempty(opts2)
        opts2 = struct();
    end

    opts = opts1;
    fields = fieldnames(opts2);
%     for i = 1 : length(fields)
%         opts.(fields{i}) = opts2.(fields{i});
%     end

    for i = 1 : length(fields)
        if strcmp(fields{i}, 'max_epoch') || strcmp(fields{i}, 'verbose')
            if ischar(opts2.(fields{i}))
                opts.(fields{i}) = str2double(opts2.(fields{i}));
            else
                opts.(fields{i}) = opts2.(fields{i});
            end
        else
            opts.(fields{i}) = opts2.(fields{i});
        end

    end

end