function varargout = GINavPlot(varargin)
% GINAVPLOT MATLAB code for GINavPlot.fig
%      GINAVPLOT, by itself, creates a new GINAVPLOT or raises the existing
%      singleton*.
%
%      H = GINAVPLOT returns the handle to a new GINAVPLOT or the handle to
%      the existing singleton*.
%
%      GINAVPLOT('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in GINAVPLOT.M with the given input arguments.
%
%      GINAVPLOT('Property','Value',...) creates a new GINAVPLOT or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before GINavPlot_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to GINavPlot_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help GINavPlot

% Last Modified by GUIDE v2.5 23-Dec-2020 21:34:33
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Copyright (C) 2020-2025, by Kai Chen, All rights reserved.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @GINavPlot_OpeningFcn, ...
                   'gui_OutputFcn',  @GINavPlot_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before GINavPlot is made visible.
function GINavPlot_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to GINavPlot (see VARARGIN)

H=get(0,'ScreenSize'); h=get(gcf,'Position');
x=H(3)/2-h(3)/2; y=H(4)/2-h(4)/2; h(1)=x; h(2)=y;
set(gcf,'Position',h);

% Choose default command line output for GINavPlot
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes GINavPlot wait for user response (see UIRESUME)
% uiwait(handles.figure1);

% --- Outputs from this function are returned to the command line.
function varargout = GINavPlot_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;

% --- Executes on button press in solfile.
function solfile_Callback(hObject, eventdata, handles)
% hObject    handle to solfile (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global glc
fullpath=which('GINavExe.m');
[path,~,~]=fileparts(fullpath);
result_path=[path,glc.sep,'result',glc.sep];
[filename,pathname] = uigetfile('*.pos','Select solution file',result_path);
if any(filename)
    fullname = [pathname filename];
    if ~exist(fullname,'file')
        error('The solution file does not exist!!!');
    end
    idx=find(filename=='.');
    if any(idx)
        suffix=filename(idx+1:end);
    else
        error('Incorrect file suffix name!!!');
    end
    switch suffix
        case 'mat'
            load(fullname);
        case 'pos'
            solution=readGINavsol(fullname);
        case 'pva'
            solution=readGINavsol(fullname);
    end
    handles.solution=solution;
    guidata(hObject,handles)
else
    fprintf('Please reselect solution file!!!\n');
end

% --- Executes on selection change in plot_any.
function plot_any_Callback(hObject, eventdata, handles)
% hObject    handle to plot_any (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns plot_any contents as cell array
%        contents{get(hObject,'Value')} returns selected item from plot_any
solution=handles.solution;
str = get(handles.plot_any,'String');
val = get(handles.plot_any,'Value');
switch str{val}
    case 'Trajectory'
        plot_trajectory(solution);
    case 'Position'
        plot_position(solution);
    case 'Velocity'
        plot_velocity(solution);
    case 'Number of satellite'
        plot_nsat(solution);
    case 'AR ratio factor'
        plot_ARratio(solution);
end

% --- Executes during object creation, after setting all properties.
function plot_any_CreateFcn(hObject, eventdata, handles)
% hObject    handle to plot_any (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function staname_Callback(hObject, eventdata, handles)
% hObject    handle to staname (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of staname as text
%        str2double(get(hObject,'String')) returns contents of staname as a double
station_name=get(handles.staname,'String');
if any(station_name)
    handles.station_name=station_name;
    guidata(hObject,handles);
else
    fprintf('Please re-enter the station name!!!\n');
end

% --- Executes during object creation, after setting all properties.
function staname_CreateFcn(hObject, eventdata, handles)
% hObject    handle to staname (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in SNX.
function SNX_Callback(hObject, eventdata, handles)
% hObject    handle to SNX (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
[filename,pathname] = uigetfile({'*.snx';'*.SNX'},'Select SNX file');
if any(filename)
    snxfilename = [pathname filename];
    if ~exist(snxfilename,'file')
        error('The SNX file does not exist!!!');
    end
    handles.snxfilename=snxfilename;
    guidata(hObject,handles);
else
   fprintf('Please reselect SNX file!!!\n');
end

% --- Executes on button press in plotPPP.
function plotPPP_Callback(hObject, eventdata, handles)
% hObject    handle to plotPPP (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
station_name=handles.station_name;
snxfilename=handles.snxfilename;
solution=handles.solution;
plot_ppp_err(solution,station_name,snxfilename);

% --- Executes on button press in ref.
function ref_Callback(hObject, eventdata, handles)
% hObject    handle to ref (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
[filename,pathname] = uigetfile('*.mat','Select pos reference data');
if any(filename)
    fullname = [pathname filename];
    if ~exist(fullname,'file')
        error('The pos reference file does not exist!!!');
    end
    load(fullname);
    handles.reference=reference;
    guidata(hObject,handles)
else
    fprintf('Please reselect pos ref file!!!\n');
end

% --- Executes on selection change in plot_err.
function plot_err_Callback(hObject, eventdata, handles)
% hObject    handle to plot_err (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns plot_err contents as cell array
%        contents{get(hObject,'Value')} returns selected item from plot_err
solution  = handles.solution;
reference = handles.reference;
str = get(handles.plot_err,'String');
val = get(handles.plot_err,'Value');
switch str{val}
    case 'Position error'
        plot_pva_err(solution,reference,1)
    case 'Velocity error'
        plot_pva_err(solution,reference,2)
    case 'Attitude error'
        plot_pva_err(solution,reference,3)
end

% --- Executes during object creation, after setting all properties.
function plot_err_CreateFcn(hObject, eventdata, handles)
% hObject    handle to plot_err (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


classdef MimModelCallback  < CoreBaseClass

    properties (Access = private)
        ModelId
        ModelMap
        Mim
    end

    methods
        function obj = MimModelCallback(modelId, modelMap, mim)
            obj.ModelId = modelId;
            obj.ModelMap = modelMap;
            obj.Mim = mim;
        end

        function value = getModelValue(obj, modelId)
            % Returns the current value of the specified model

           value = obj.ModelMap.getDependentValue(modelId, obj.ModelId);
        end

        function setModelValue(obj, modelId, value)
            % Sets the current value of the specified model

           obj.ModelMap.setValue(modelId, value);
        end

        function addModelItem(obj, modelId, itemId)
           obj.ModelMap.addItem(modelId, itemId);
        end

        function removeModelItem(obj, modelId, itemId)
           obj.ModelMap.removeItem(modelId, itemId);
        end

        function modelId = buildModelId(obj, modelClassName, parameters)
            modelId = obj.ModelMap.buildModelId(modelClassName, parameters);
        end

        function mim = getMim(obj)
            mim = obj.Mim;
        end
    end
end


function pBar = bst_progress(varargin)
% bst_progress: Manage the Brainstorm progress bar
%
% USAGE : pBar = bst_progress('start', title, msg, valStart, valStop) : Create a progress bar with start and stop bounds
%         pBar = bst_progress('start', title, msg)                    : Create a progress bar (unlimited)
%         pBar = bst_progress('stop')        : stop and hide progress bar
%         pBar = bst_progress('inc', valInc) : increment of 'valInc' the position of the progress bar
%         pBar = bst_progress('set', pos)    : set the position
%          pos = bst_progress('get')         : get the position
%         pBar = bst_progress('text', txt)   : set the text
%    isVisible = bst_progress('isvisible')   : return 1 if progress bar is visible, 0 else
%         pBar = bst_progress('show')        : display previously defined progress bar
%         pBar = bst_progress('hide')        : hide progress bar
%         pBar = bst_progress('setimage', imagefile) : display an image in the wait bar
%         pBar = bst_progress('setlink', url)        : clicking on the image opens a browser to display the url
%         pBar = bst_progress('removeimage')         : Remove the image from the wait bar

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

% JAVA imports
import org.brainstorm.icon.*;
import java.awt.Dimension;

global GlobalData;

%% ===== PARSE INPUTS =====
if ((nargin >= 1) && ischar(varargin{1}))
    commandName = varargin{1};
else
    error('Usage : bst_progress(commandName, parameters)');
end

%% ===== GET OR CREATE PROGRESS BAR =====
% Do nothing in case of server mode
if ~isempty(GlobalData) && ~isempty(GlobalData.Program) && isfield(GlobalData.Program, 'GuiLevel') && (GlobalData.Program.GuiLevel == -1)
    if ismember(lower(commandName), {'pos','isvisible'})
        pBar = 0;
    else
        pBar = [];
    end
    return;
end
% If running in NOGUI mode: just display the message in the command window
if ~bst_get('isGUI')
    switch lower(commandName)
        case 'start',     disp(['PROGRESS> ' varargin{2} ': ' varargin{3}]); pBar = [];
        case 'text',      disp(['PROGRESS> ' varargin{2}]); pBar = [];
        case 'get',       pBar = 1;
        case 'isvisible', pBar = 0;
    end
    return;
end
% Get progress bar
if ~isempty(GlobalData) && ~isempty(GlobalData.Program) && isfield(GlobalData.Program, 'ProgressBar') && ~isempty(GlobalData.Program.ProgressBar)
    pBar = GlobalData.Program.ProgressBar;
else
    pBar = [];
end
% Get Brainstorm GUI context
jBstFrame = bst_get('BstFrame');
if isempty(jBstFrame)
    return
end

% Default window size
if isempty(pBar) || strcmpi(commandName, 'removeimage') || (strcmpi(commandName, 'stop') && pBar.isImage)
    DefaultSize = java_scaled('dimension', 350, 130);
end

% If progress bar was not created yet : create it
if isempty(pBar)
    % If action=isvisible: no need to create the progress bar
    if strcmpi(commandName, 'isvisible')
        pBar = 0;
        return
    end
    % Create a JDialog, if possible dependent of the main Brainstorm JFrame
    pBar.jWindow = java_create('javax.swing.JDialog');
    % Set icon
    try
        pBar.jWindow.setIconImage(IconLoader.ICON_APP.getImage());
    catch
        % Old matlab... just ignore...
    end
    % Set as always-on-top / non-focusable
    pBar.jWindow.setAlwaysOnTop(1);
    pBar.jWindow.setFocusable(0);
    pBar.jWindow.setFocusableWindowState(0);
    % Non-modal
    pBar.jWindow.setModal(0);

    % Closing callback
%     if bst_iscompiled()
        pBar.jWindow.setDefaultCloseOperation(pBar.jWindow.HIDE_ON_CLOSE);
%     else
%         pBar.jWindow.setDefaultCloseOperation(pBar.jWindow.DO_NOTHING_ON_CLOSE);
%         java_setcb(pBar.jWindow, 'WindowClosingCallback', @(h,ev)CloseCallback);
%     end

    % Configure window
    pBar.jWindow.setPreferredSize(DefaultSize);
    % Main panel
    pBar.jPanel = java_create('javax.swing.JPanel');
    pBar.jPanel.setLayout(java_create('java.awt.GridBagLayout'));

    % Create objects
    pBar.isImage = 0;
    pBar.jImage = java_create('javax.swing.JLabel');
    pBar.jLabel = java_create('javax.swing.JLabel', 'Ljava.lang.String;', '...');
    pBar.jLabel.setFont(bst_get('Font'));
    pBar.jProgressBar = java_create('javax.swing.JProgressBar', 'II', 0, 99);
    % Update constraints
    UpdateConstraints(0);

    % Add the main Panel
    pBar.jWindow.getContentPane.add(pBar.jPanel);
    pBar.jWindow.pack();
    % Set window size and location
    %pBar.jWindow.setLocationRelativeTo(pBar.jWindow.getParent());
    jLoc = jBstFrame.getLocation();
    jSize = jBstFrame.getSize();
    pos = [jLoc.getX() + ((jSize.getWidth() - DefaultSize.getWidth()) / 2), ...
           jLoc.getY() + ((jSize.getHeight() - DefaultSize.getHeight()) / 2)];
    pBar.jWindow.setLocation(pos(1), pos(2));
    % Save progress bar
    GlobalData.Program.ProgressBar = pBar;
end

% Linux: need to print something on the command window (don't know why...)
if strcmpi(commandName, 'stop') && ismember(computer('arch'), {'glnx86', 'glnxa64'})
    drawnow();
    fprintf(' ');
    fprintf('\b');
    drawnow();
    % The dialog needs to be displayed for a short period before being hidden
    pause(0.05);
end

%% ===== SWITCH BETWEEN COMMANDS =====
switch (lower(commandName))
    % ==== START ====
    case 'start'
        % Set as "always on top"
        java_call(pBar.jWindow, 'setAlwaysOnTop', 'Z', 1);
        java_call(pBar.jWindow, 'setFocusable',   'Z', 0);
        java_call(pBar.jWindow, 'setFocusableWindowState', 'Z', 0);
        % Call: bst_progress(''start'', title, msg)
        if (nargin == 3) && ischar(varargin{3}) && ischar(varargin{2})
            % Get window title and comment
            wndTitle    = varargin{2};
            msg = varargin{3};
            % Set Progress bar in inderminate mode
            pBar.jProgressBar.setIndeterminate(1);
            pBar.jProgressBar.setStringPainted(0);
            % Set progress bar bounds
            pBar.jProgressBar.setMinimum(0);
            pBar.jProgressBar.setMaximum(100);
            % Set initial value to start
            pBar.jProgressBar.setValue(0);

        % Call: bst_progress(''start'', title, msg, start, stop)
        elseif ((nargin == 5) && ischar(varargin{2}) && ischar(varargin{3}) && isnumeric(varargin{4}) && isnumeric(varargin{5}))
            % Get window title and comment
            wndTitle = varargin{2};
            msg = varargin{3};
            % Set Progress bar in derminate mode
            pBar.jProgressBar.setIndeterminate(0);
            pBar.jProgressBar.setStringPainted(1);
            % Get progress bar bounds
            valStart = varargin{4};
            valStop  = varargin{5};
            % Test bounds
            if ( (valStart >= valStop) || (valStop <= 0) )
                % Set indeterminate bounds
                pBar.jProgressBar.setIndeterminate(1);
                pBar.jProgressBar.setStringPainted(0);
                valStart = 0;
                valStop  = 100;
            end
            % Set progress bar bounds
            pBar.jProgressBar.setMinimum(valStart);
            pBar.jProgressBar.setMaximum(valStop);
            % Set initial value to start
            pBar.jProgressBar.setValue(valStart);

        else
            error(['Usage : bst_progress(''start'', title, comment) ' 10 '        bst_progress(''start'', title, comment, valStart, valStop)']);
        end
        % Set window title
        pBar.jWindow.setTitle(wndTitle);
        % Set window comment (central label)
        pBar.jLabel.setText(msg);
        % Show window
        java_call(pBar.jWindow, 'setVisible', 'Z', 1);
        % Set watch cursor
        jBstFrame.setCursor(java_create('java.awt.Cursor', 'I', java.awt.Cursor.WAIT_CURSOR));

    % ==== STOP ====
    case 'stop'
        % Remove the "always on top" status
        java_call(pBar.jWindow, 'setAlwaysOnTop', 'Z', 0);
        java_call(pBar.jWindow, 'setFocusable',   'Z', 1);
        java_call(pBar.jWindow, 'setFocusableWindowState', 'Z', 1);
        % Hide window
        java_call(pBar.jWindow, 'setVisible', 'Z', 0);
        % Restore cursor
        jBstFrame.setCursor([]);
        % Remove image
        if pBar.isImage
            GlobalData.Program.ProgressBar.isImage = 0;
            pBar.jImage.setIcon([]);
            java_setcb(pBar.jImage, 'MouseClickedCallback', []);
            UpdateConstraints(0);
            pBar.jWindow.setPreferredSize(DefaultSize);
            pBar.jWindow.pack();
        end

    % ==== INCREMENT ====
    case 'inc'
        % Parse arguments
        if ((nargin == 2) && isnumeric(varargin{2}))
            valInc = varargin{2};
        else
            error('Usage : bst_progress(''inc'', valInc)');
        end
        % Get current value
        curValue = pBar.jProgressBar.getValue();
        % Get the incremented progress bar position
        newVal = min(curValue + valInc, pBar.jProgressBar.getMaximum());
        pBar.jProgressBar.setValue(newVal);

    % ==== SET POSITION ====
    case 'set'
        % Parse arguments
        if ((nargin == 2) && isnumeric(varargin{2}))
            newVal = varargin{2};
        else
            error('Usage : bst_progress(''set'', pos)');
        end
        % Get current value
        curValue = pBar.jProgressBar.getValue();
        % Get the incremented progress bar position
        if (curValue ~= newVal)
            newVal = min(newVal, pBar.jProgressBar.getMaximum());
            pBar.jProgressBar.setValue(newVal);
        end

    % ==== GET POSITION ====
    case 'get'
        % Get the incremented progress bar position
        pBar = pBar.jProgressBar.getValue();

    % ==== SET TEXT ====
    case 'text'
        % Parse arguments
        if ((nargin == 2) && ischar(varargin{2}))
            % Set new label
            pBar.jLabel.setText(varargin{2});
        else
            % Get label
            pBar.jLabel.getText();
        end

    % ==== IS VISIBLE ====
    case 'isvisible'
        pBar = pBar.jWindow.isVisible();

    % ==== SHOW ====
    case 'show'
        % Set as "always on top"
        java_call(pBar.jWindow, 'setAlwaysOnTop', 'Z', 1);
        java_call(pBar.jWindow, 'setFocusable',   'Z', 0);
        java_call(pBar.jWindow, 'setFocusableWindowState', 'Z', 0);
        % Show window
        java_call(pBar.jWindow, 'setVisible', 'Z', 1);
        % Set watch cursor
        jBstFrame.setCursor(java_create('java.awt.Cursor', 'I', java.awt.Cursor.WAIT_CURSOR));

    % ==== HIDE ====
    case 'hide'
        % Remove the "always on top" status
        java_call(pBar.jWindow, 'setAlwaysOnTop', 'Z', 0);
        java_call(pBar.jWindow, 'setFocusable',   'Z', 1);
        java_call(pBar.jWindow, 'setFocusableWindowState', 'Z', 1);
        % Hide window
        java_call(pBar.jWindow, 'setVisible', 'Z', 0);
        % Restore cursor
        jBstFrame.setCursor([]);

    % ==== SET IMAGE ====
    case 'setimage'
        % Get image path
        imagefile = varargin{2};
        if ~file_exist(imagefile)
            imagefile = bst_fullfile(bst_get('BrainstormDocDir'), imagefile);
        end
        if ~file_exist(imagefile)
            warning(['Image not found: ' imagefile]);
            return
        end
        % Image in label
        pBar.jImage.setIcon(javax.swing.ImageIcon(imagefile));
        GlobalData.Program.ProgressBar.isImage = 1;
        % Extend size of the frame
        UpdateConstraints(1);
        pBar.jWindow.setPreferredSize([]);
        pBar.jWindow.pack();

    % ==== SET LINK ====
    case 'setlink'
        url = varargin{2};
        java_setcb(pBar.jImage, 'MouseClickedCallback', @(h,ev)web(url, '-browser'));

    % ==== REMOVE IMAGE ====
    case 'removeimage'
        % Remove image
        GlobalData.Program.ProgressBar.isImage = 0;
        pBar.jImage.setIcon([]);
        java_setcb(pBar.jImage, 'MouseClickedCallback', []);
        UpdateConstraints(0);
        pBar.jWindow.setPreferredSize(DefaultSize);
        pBar.jWindow.pack();
end

%% ===== ADD COMPONENTS =====
    function UpdateConstraints(isImage)
        import java.awt.GridBagConstraints;
        import java.awt.Insets;
        % Remove all components
        pBar.jPanel.removeAll();
        % Generic constraints
        c = GridBagConstraints();
        c.fill = GridBagConstraints.BOTH;
        c.gridx = 1;
        c.weightx = 1;
        % IMAGE
        c.gridy = 1;
        c.weighty = isImage;
        c.insets = Insets(0,0,0,0);
        pBar.jPanel.add(pBar.jImage, c);
        % TEXT
        c.gridy = 2;
        c.weighty = ~isImage;
        c.insets = Insets(5,12,5,12);
        pBar.jPanel.add(pBar.jLabel, c);
        % PROGRESS BAR
        c.gridy = 3;
        c.weighty = 0;
        c.insets = Insets(0,12,9,12);
        pBar.jPanel.add(pBar.jProgressBar, c);
%         % CANCEL BUTTON
%         c.gridy = 4;
%         c.weighty = 0;
%         c.insets = Insets(0,12,9,12);
%         c.weightx = 0;
%         pBar.jPanel.add(pBar.jButtonCancel, c);
    end

%     %% ===== CLOSE CALLBACK =====
%     function CloseCallback()
%         % Hide progress bar
%         %java_call(pBar.jWindow, 'setVisible', 'Z', 0);
%         bst_progress('stop');
%
%         if bst_iscompiled()
%             try
%                 % Get command window
%                 cmdWindow = com.mathworks.mde.cmdwin.CmdWin.getInstance();
%                 cmdWindow.grabFocus();
%                 %2) Wait for focus transfer to complete (up to 2 seconds)
%                 focustransferTimer = tic;
%                 while ~cmdWindow.isFocusOwner
%                     pause(0.1);  %Pause some small interval
%                     if (toc(focustransferTimer) > 2)
%                         error('Error transferring focus for CTRL+C press.')
%                     end
%                 end
%
%                 %3) Use Java robot to execute a CTRL+C in the (now focused) command window.
%
%                 %3.1)  Setup a timer to relase CTRL + C in 0.3 second
%                 %  Try to reuse an existing timer if possible (this would be a holdover
%                 %  from a previous execution)
%                 t_all = timerfindall;
%                 releaseTimer = [];
%                 ix_timer = 1;
%                 while isempty(releaseTimer) && (ix_timer<= length(t_all))
%                     if isequal(t_all(ix_timer).TimerFcn, @releaseCtrl_C)
%                         releaseTimer = t_all(ix_timer);
%                     end
%                     ix_timer = ix_timer+1;
%                 end
%                 if isempty(releaseTimer)
%                     releaseTimer = timer;
%                     releaseTimer.TimerFcn = @(h,ev)releaseCtrl_C;
%                 end
%                 releaseTimer.StartDelay = 0.3;
%                 start(releaseTimer);
%
%                 %3.2)  Press press CTRL+C
%                 pressCtrl_C();
%             catch
%                 disp('BST> Could not post a CTRL+C signal in the command window.');
%             end
%         end
%     end
%
%     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%     function pressCtrl_C()
%         SimKey = java.awt.Robot;
%         SimKey.keyPress(java.awt.event.KeyEvent.VK_CONTROL);
%         SimKey.keyPress(java.awt.event.KeyEvent.VK_C);
%     end
%
%     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%     function releaseCtrl_C()
%         SimKey = java.awt.Robot;
%         SimKey.keyRelease(java.awt.event.KeyEvent.VK_CONTROL);
%         SimKey.keyRelease(java.awt.event.KeyEvent.VK_C);
%         jBstFrame.setVisible(1);
%     end

end


function newFormat = openBabelConverter(origFormat, outputFormat, saveFileDir)
% This function converts chemoformatic formats using OpenBabel. It requires
% to have openbabel installed. The formats that can be converted are used
% MDL MOL, SMILES, InChI, InChIKey, MDL RXN, reaction SMILES and rInChI.
%
% USAGE:
%
%    newStructure = openBabelConverter(origFormat, outputFormat, saveFile)
%
% INPUT:
%    origFormat:    Original chemoinformatic format. Chemical tables such
%                   as MDL MOL or MDL RXN must be provided as files
%    outputFormat:  The format to be converted. Formats supported: smiles,
%                   mol, inchi, inchikey, rxn and rinchi.
%
% OPTIONAL INPUTS:
%    saveFileDir:	String with the directory where the new format will be
%                   saved. If is empty, the format is not saved.
%
% EXAMPLE:
%
%    Example 1 (MDL MOL to InChI):
%    origFormat = [pwd filesep 'alanine.mol'];
%    outputFormat = 'inchi';
%    newFormat = openBabelConverter(origFormat, outputFormat);
%
%    Example 2 (InChI to SMILES):
%    origFormat = 'InChI=1S/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m0/s1';
%    outputFormat = 'smiles';
%    newFormat = openBabelConverter(origFormat, outputFormat);
%
%    Example 3 (SMILES to mol):
%    origFormat = 'C[C@@H](C(=O)O)N';
%    outputFormat = 'mol';
%    newFormat = openBabelConverter(origFormat, outputFormat);

if nargin < 3 || isempty(saveFileDir)
    toSave = false;
else
    toSave = true;
end

% Check openbabel installation
if isunix || ispc
    obabelCommand = 'obabel';
else
    obabelCommand = 'openbabel.obabel';
end
[oBabelInstalled, cmdout] = system(obabelCommand);
if oBabelInstalled == 127
    error('To use this function, Open Babel must be installed; follow the installation instructions in https://openbabel.org/wiki/Category:Installation')
end

% Identify the chemoinformatic format of the input
if contains(origFormat, '.mol')
    if isfile(origFormat)
        inputType = 'mol';
    else
        error(['The file ' origFormat ' is missing'])
    end
elseif contains(origFormat, '.rxn')
    if isfile(origFormat)
        inputType = 'rxn';
    else
        error(['The file ' origFormat ' is missing'])
    end
elseif contains(origFormat, 'InChI=')
    inputType = 'inchi';
else
    inputType = 'smiles';
end

% Convert
if ismember(inputType, {'inchi'; 'smiles'})

    fid2 = fopen('tmp', 'w');
    fprintf(fid2, '%s\n', origFormat);
    fclose(fid2);
    [~, cmdout] = system([obabelCommand ' -i' inputType ' tmp -o' outputFormat]);

else
    switch inputType
        case 'mol'
            [~, cmdout] = system([obabelCommand ' -imol ' origFormat ' -o' outputFormat]);
        case 'rxn'
            [~, cmdout] = system([obabelCommand ' -irxn ' origFormat ' -o' outputFormat]);
    end
end

% Prepare the output
cmdout = splitlines(cmdout);
newFormat = [];
switch outputFormat
    case 'mol'
        startIdx = find(cellfun(@isempty, cmdout));
        endIdx = find(ismember(cmdout, 'M  END'));
        newFormat = cmdout(startIdx(1):endIdx);

    case 'inchikey'
        cmdout = split(cmdout{end - 2});
        newFormat = cmdout{1};

    case 'inchi'
        if any(contains(cmdout,'InChI=1S'))
            newFormat = cmdout{contains(cmdout,'InChI=1S')};
        else
            error('')
        end

    case 'smiles'
        cmdout = split(cmdout{end - 2});
        newFormat = cmdout{1};

    case 'rinchi'
        newFormat = cmdout{contains(cmdout,'RInChI=')};
end

% Save the file
if toSave && ~isempty(newFormat)
    fid2 = fopen(saveFileDir, 'w');
    fprintf(fid2, '%s\n', newFormat{:});
    fclose(fid2);
% elseif isempty(newFormat)
%     error(['The format ' origFormat ' couldn''t be converted'])
end


function drgui
%DRGUI Runs the graphical user interface of the DR toolbox
%
%   drgui
%
% Runs the graphical user interface of the dimensionality reduction toolbox.

% This file is part of the Matlab Toolbox for Dimensionality Reduction.
% The toolbox can be obtained from http://homepage.tudelft.nl/19j49
% You are free to use, change, or redistribute this code in any way you
% want for non-commercial purposes. However, it is appreciated if you
% maintain the name of the original author.
%
% (C) Laurens van der Maaten, Delft University of Technology

    drtool;


function cells2file(inputC,fnameS)
%function cells2file.  Write out cell contents to a file.
%JOD.
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR 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.
%
% CERR 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 CERR.  If not, see <http://www.gnu.org/licenses/>.

fid=fopen(fnameS,'wt+');
i=1;
for i=1:length(inputC)
  lineS=inputC{i};
  fwrite(fid,lineS,'char');
  fprintf(fid,'\n',[]);
end

fclose(fid);


function newmodel = addGenes(model,geneIDs,varargin)
% Add Genes (or a single gene) to the model
%
% USAGE:
%    model = addGenes(model,geneIDs,varargin)
%
% INPUT:
%    model:             The model to add the Metabolite batch to.
%    geneIDs:           The IDs of the genes that shall be added.
%    varargin:          fieldName, Value pairs. The given fields will be set
%                       according to the values. Only defined COBRA fields may be
%                       used. The following fields will be ignored (as they
%                       are dependent on the existing model structure):
%
%                        * rxnGeneMat - The size will be extended, but no associations will be set.
% OUTPUT:
%    newmodel:     The model structure with the additional reactions.
%
% EXAMPLE:
%    %To add genes with specific fields use:
%    `model = addGenes(model, {'G1', 'Gene2', 'InterestingGene'}, 'proteins', {'Protein1','Protein B','Protein Alpha'}, 'geneField2', {'D','E','F'})`
%
% NOTE:
%    All fields (geneField1/geneField2) have to be present in
%    the model, or defined in the field definitions, otherwise they are
%    ignored.
%

if (isfield(model,'genes') && ~isempty(model.genes) && any(ismember(model.genes,geneIDs))) || numel(unique(geneIDs)) < numel(geneIDs)
    error('Duplicate Reaction ID detected.');
end

if ~isfield(model,'genes') % Should not happen but if, lets add it.
    model.genes = cell(0,1);
end

nGenes = numel(model.genes);

%We have make sure, that the new fields are in sync, so we create those
%first.
fieldDefs = getDefinedFieldProperties();
fieldDefs = fieldDefs(cellfun(@(x) strcmp(x,'genes'), fieldDefs(:,2)) | cellfun(@(x) strcmp(x,'genes'), fieldDefs(:,3)));
modelGeneFields = getModelFieldsForType(model,'genes');
model.genes = [model.genes;columnVector(geneIDs)];

for field = 1:2:numel(varargin)
    %If the field does not exist and is not defined, we will not add that
    %information, as we don't know how the field should look.
    cfield = varargin{field};
    if strcmp('rxnGeneMat',cfield) || (~any(ismember(fieldDefs(:,1),cfield)) && ~any(ismember(modelGeneFields,cfield)))
        warning('Field %s is excluded.',cfield);
        continue;
    end

    if ~any(size(varargin{field+1}) == numel(geneIDs)) %something must fit
        error('Size of field %s does not fit to the rxnList size', varargin{field});
    end
    %Now add the field data.
    if ~isfield(model,cfield)
        %If its not yet in the model, create it
        %according to its defaults and replace the final elements.
        model = createEmptyFields(model,cfield);
        model.(cfield)((end-numel(varargin{field+1})+1):end) = columnVector(varargin{field+1});
    else
        %Or just extend it with the supplied data.
        model.(cfield) = [model.(cfield);columnVector(varargin{field+1})];
    end

end
%Extend the remaining fields, to keep the fields in sync
newmodel = extendModelFieldsForType(model,'genes','originalSize',nGenes);


%% Upload templates and subject data from AFQ to Archiva
%

rd = RdtClient('vistasoft');
rd.credentialsDialog;

%% Templates
cd(vistaRootPath);
cd(fullfile('..','AFQ'))
baseDir = pwd;
fullDir = fullfile(baseDir,'templates');

rd.crp('/AFQ/templates');

a = rd.publishArtifacts(fullDir);

%% List the artifacts it thinks it sent up
for ii=1:length(a)
    disp(a(ii).artifactId)
end

%% List, but this time ask the repository for the list
rd.crp('/AFQ/templates/');
a = rd.listArtifacts;

%% Now the AFQ data sets

% These are in AFQ/data
% So the base directory starts at AFQ
% We will then move into AFQ/data and the subdirectories
cd(vistaRootPath);
cd(fullfile('..','AFQ'))
baseDir = pwd;

% First the afq.mat file
rd.crp('/AFQ/data');
fullDir = fullfile(baseDir,'data');
rd.publishArtifacts(fullDir);

% rd.openBrowser('fancy',true)

%%  Find the directory tree under AFQ/data
cd(vistaRootPath);
cd(fullfile('..','AFQ','data'))
baseDir = pwd;

pNames = dirwalk(baseDir);

nDirs = length(pNames);
for ii=1:nDirs
    fullDir = pNames{ii};
    remotePath = strrep(pNames{ii},'/Users/wandell/Github','');
    rd.crp(remotePath);
    rd.publishArtifacts(fullDir);
end

%%


function [] = Test_D_Gen_S(block,signal)

% Callback processing function for mask parameter
% - number of <Requirement name> used in the System
set_param(block, 'LinkStatus', 'none');
load_system('Simulink'); % Load Simulink library (background)
load_system('MIL_Test');
if signal < 0
No = str2double(get_param(block,'So')); % Get # of VF-s
else
    No = signal;
end

T1 = strcat(block, '/<Requirement name>/<Preconditions name>');
T2 = strcat(block, '/<Requirement name>');
OldNo = length(find_system(T1, 'regexp', 'on','LookUnderMasks','all','Name','Feature generation'));
OldNoReq = length(find_system(block, 'regexp', 'on','LookUnderMasks','all','Name','<Requirement name>'));
for i = 1:max(No,OldNo)
    if OldNo > No && i > No && i <= OldNo % Remove
        % delete lines

        % block

        SigAtTLines2 = get_param([block '/switch <signal' num2str(i) '>'],'LineHandles');
        delete_line(SigAtTLines2.Outport(1));
        for j = 1:(OldNoReq+1)
         delete_line(SigAtTLines2.Inport(j));
        end
        delete_block([block '/<signal' num2str(i) '>']);
        delete_block([block '/switch <signal' num2str(i) '>']);
        %T2
        for k = 1:OldNoReq
            if k == 1
           T1 = strcat(block, '/<Requirement name>/<Preconditions name>');
           T2 = strcat(block, '/<Requirement name>');
        SigAtTLines1 = get_param([T2 '/switch <signal' num2str(i) '>'],'LineHandles');
        delete_line(SigAtTLines1.Outport(1));
        delete_line(SigAtTLines1.Inport(1));
        delete_line(SigAtTLines1.Inport(2));
        delete_line(SigAtTLines1.Inport(3));

        % T1
        SigAtTLines = get_param([T1 '/Feature generation' num2str(i)],'LineHandles');
        %delete_line(SigAtTLines.Inport(1));
        delete_line(SigAtTLines.Outport(1));
        % delete block
        delete_block([T2 '/<signal' num2str(i) '>']);
        delete_block([T2 '/switch <signal' num2str(i) '>']);
        delete_block([T1 '/Feature generation' num2str(i)]);
        delete_block([T1 '/<signal' num2str(i) '>']);
            else
                 T1 = strcat(block, '/<Requirement name>', num2str(k), '/<Preconditions name>');
                 T2 = strcat(block, '/<Requirement name>', num2str(k));
                 SigAtTLines1 = get_param([T2 '/switch <signal' num2str(i) '>'],'LineHandles');
        delete_line(SigAtTLines1.Outport(1));
        delete_line(SigAtTLines1.Inport(1));
        delete_line(SigAtTLines1.Inport(2));
        delete_line(SigAtTLines1.Inport(3));

        % T1
        SigAtTLines = get_param([T1 '/Feature generation' num2str(i)],'LineHandles');
        %delete_line(SigAtTLines.Inport(1));
        delete_line(SigAtTLines.Outport(1));
        % delete block
        delete_block([T2 '/<signal' num2str(i) '>']);
        delete_block([T2 '/switch <signal' num2str(i) '>']);
        delete_block([T1 '/Feature generation' num2str(i)]);
        delete_block([T1 '/<signal' num2str(i) '>']);
            end
        end

    elseif No > OldNo && i > OldNo && i <= No % Add
         % Block
                add_block('Simulink/Sinks/Out1',[block '/<signal' num2str(i) '>']);
                fix_pos([block '/<signal' num2str(i-1) '>'],[block '/<signal' num2str(i) '>'],0,145);
                add_block([block '/switch <signal1>'],[block '/switch <signal' num2str(i) '>']);
                fix_pos([block '/switch <signal' num2str(i-1) '>'],[block '/switch <signal' num2str(i) '>'],0,60);
                add_line(block,['switch <signal' num2str(i) '>' '/1'],['<signal' num2str(i) '>/' num2str(1)],'autorouting','on');
                add_line(block,['Bus Selector/1'],['switch <signal' num2str(i) '>/' num2str(1)],'autorouting','on');
        % Add blocks
        % <Test data generator>/<Requirement name>/<Preconditions name>
        for j = 1:OldNoReq
           if j == 1
               T1 = strcat(block, '/<Requirement name>/<Preconditions name>');
               T2 = strcat(block, '/<Requirement name>');
               add_block('Simulink/Sinks/Out1',[block '/<Requirement name>/<Preconditions name>/<signal' num2str(i) '>']);
               fix_pos([block '/<Requirement name>/<Preconditions name>/<signal' num2str(i-1) '>'],[block '/<Requirement name>/<Preconditions name>/<signal' num2str(i) '>'],0,-70);
               add_block([block '/<Requirement name>/<Preconditions name>/Feature generation'],[block '/<Requirement name>/<Preconditions name>/Feature generation' num2str(i)]);
               fix_pos([block '/<Requirement name>/<Preconditions name>/Feature generation'],[block '/<Requirement name>/<Preconditions name>/Feature generation' num2str(i)],0,-i*50);
               add_line(T1,['Feature generation' num2str(i) '/1'],['<signal' num2str(i) '>/' num2str(1)],'autorouting','on');
               % T2
               add_block('Simulink/Sinks/Out1',[T2 '/<signal' num2str(i) '>']);
               fix_pos([T2 '/<signal' num2str(i-1) '>'],[T2 '/<signal' num2str(i) '>'],0,145);
               add_block([T2 '/switch <signal1>'],[T2 '/switch <signal' num2str(i) '>']);
               fix_pos([T2 '/switch <signal' num2str(i-1) '>'],[T2 '/switch <signal' num2str(i) '>'],0,60);
               add_line(T2,['switch <signal' num2str(i) '>' '/1'],['<signal' num2str(i) '>/' num2str(1)],'autorouting','on');
               add_line(T2,['Sequencing of test data in time due to Preconditions/1'],['switch <signal' num2str(i) '>/' num2str(1)],'autorouting','on');
               add_line(T2,['Initialisation & Stabilisation/1'],['switch <signal' num2str(i) '>/' num2str(3)],'autorouting','on');
               add_line(T2,['<Preconditions name>/' num2str(i+1)],['switch <signal' num2str(i) '>/' num2str(2)],'autorouting','on');
               % Block
               add_line(block,['<Requirement name>/' num2str(i)],['switch <signal' num2str(i) '>/' num2str(2)],'autorouting','on');
           else

                T1 = strcat(block, '/<Requirement name>', num2str(j), '/<Preconditions name>');
                T2 = strcat(block, '/<Requirement name>', num2str(j));

                add_block('Simulink/Sinks/Out1',[T1 '/<signal' num2str(i) '>']);
                fix_pos([T1 '/<signal' num2str(i-1) '>'],[T1 '/<signal' num2str(i) '>'],0,-70);
                add_block([T1 '/Feature generation'],[T1 '/Feature generation' num2str(i)]);
                fix_pos([T1 '/Feature generation'],[T1 '/Feature generation' num2str(i)],0,-i*50);
                add_line(T1,['Feature generation' num2str(i) '/1'],['<signal' num2str(i) '>/' num2str(1)],'autorouting','on');
                % T2
                add_block('Simulink/Sinks/Out1',[T2 '/<signal' num2str(i) '>']);
                fix_pos([T2 '/<signal' num2str(i-1) '>'],[T2 '/<signal' num2str(i) '>'],0,145);
                add_block([T2 '/switch <signal1>'],[T2 '/switch <signal' num2str(i) '>']);
                fix_pos([T2 '/switch <signal' num2str(i-1) '>'],[T2 '/switch <signal' num2str(i) '>'],0,60);
                add_line(T2,['switch <signal' num2str(i) '>' '/1'],['<signal' num2str(i) '>/' num2str(1)],'autorouting','on');
                add_line(T2,['Sequencing of test data in time due to Preconditions/1'],['switch <signal' num2str(i) '>/' num2str(1)],'autorouting','on');
                add_line(T2,['Initialisation & Stabilisation/1'],['switch <signal' num2str(i) '>/' num2str(3)],'autorouting','on');
                add_line(T2,['<Preconditions name>/' num2str(i+1)],['switch <signal' num2str(i) '>/' num2str(2)],'autorouting','on');
                add_line(block,['<Requirement name>' num2str(j) '/' num2str(i)],['switch <signal' num2str(i) '>/' num2str(j+1)],'autorouting','on');
           end
        end

    end
end


%UI Controller class to create an EventDetection algorithm from a UI
classdef EventDetectionConfigurator < handle
    properties (Access = public)
        uiElements EventDetectionConfiguratorUIElements;
        algorithmConfigurator;
        preprocessingConfigurator;
        delegate;
    end

    properties (Access = private)
        eventDetectionAlgorithms;
    end

    methods (Access = public)
        function obj = EventDetectionConfigurator(signals, preprocessingSignalAlgorithms,...
                eventDetectionAlgorithms, uiElements,delegate)

            obj.uiElements = uiElements;
            obj.eventDetectionAlgorithms = eventDetectionAlgorithms;

            if nargin > 4
                obj.delegate = delegate;
            end

            obj.preprocessingConfigurator = PreprocessingConfigurator(...
                signals,...
                preprocessingSignalAlgorithms,...
                uiElements.preprocessingSignalsList,...
                uiElements.preprocessingAlgorithmsList,...
                uiElements.preprocessingAlgorithmsVariablesTable,...
                obj);

            obj.algorithmConfigurator = AlgorithmConfigurator(...
                eventDetectionAlgorithms,...
                uiElements.eventDetectionList,...
                uiElements.eventDetectionVariablesTable,...
                obj);
        end

        function algorithm = createEventDetectorWithUIParameters(obj)
            preprocessingAlgorithm = obj.createPreprocessingAlgorithmWithUIParameters();
            if isempty(preprocessingAlgorithm)
                algorithm = [];
            else
                eventDetector = obj.algorithmConfigurator.createAlgorithmWithUIParameters();
                if isa(eventDetector,'NoOp')
                    algorithm = [];
                else
                    preprocessingAlgorithm.lastAlgorithms{1}.addNextAlgorithm(eventDetector);
                    algorithm = preprocessingAlgorithm;
                end
            end
        end

        function algorithm = createPreprocessingAlgorithmWithUIParameters(obj)
            algorithm = obj.preprocessingConfigurator.createPreprocessingAlgorithmWithUIParameters();
        end

        function setSignals(obj,signals)
            obj.preprocessingConfigurator.setSignals(signals);
        end

        %% handles
        function handlePreprocessingAlgorithmChanged(obj,preprocessingAlgorithm,~)
            outputType = preprocessingAlgorithm.outputPort;
            obj.algorithmConfigurator.algorithms = ...
                Palette.FilterAlgorithmsToInputType(obj.eventDetectionAlgorithms,outputType);

            obj.algorithmConfigurator.reloadUI();
        end

        function handleAlgorithmChanged(obj,algorithm,~)
            if ~isempty(obj.delegate)
                obj.delegate.handleAlgorithmChanged(algorithm,obj);
            end
        end

    end
end


function createBasePanel(handles)
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR 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.
%
% CERR 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 CERR.  If not, see <http://www.gnu.org/licenses/>.

global planC stateS;
indexS = planC{end};

    %create a tree view and initialize filter parameters;
    w = 0.3; h = 0.6;
    createTreeView(handles, w, h);
    handles = guidata(handles.mainframe);

    fsize = 9;

    %create output list panel
    handles.outputPanel = uipanel('Parent',handles.mainframe,'Units','characters','FontSize',fsize,'Title','Output','Tag','OutputPanel',...
                    'Clipping','on','Units','normalized','Position',[0 0 w 1-h]);

    handles.OutputList = uicontrol('Parent',handles.outputPanel,'Units','normalized',...
                    'FontSize',fsize,'Position',[0 0 1 1],'Style','listbox', 'Tag','OutputList');

    %add generalPanel,toolPanel and optionPanel
    w = 0.3; h1 = 0.30; h2 = 0.6; h3 = 1-h1-h2;
    handles.generalPanel = uipanel('parent', handles.mainframe, 'units', 'normalize', 'FontSize',fsize, 'position', [w h2+h3 1-w h1]);

    handles.toolPanel = uipanel('parent', handles.mainframe, 'FontSize',fsize, 'units', 'normalize', 'position', [w h3 1-w h2]);

    handles.optionPanel = uipanel('parent', handles.mainframe, 'FontSize',fsize, 'Title','Options', 'units', 'normalize', ...
                                  'position', [w 0 1-w h3]);

    %do button
    handles.doButton = uicontrol(handles.optionPanel, 'style', 'pushbutton', 'units', 'pixel', ...
                            'position', [310 10 100 28], 'string', 'Continue', ...
                            'tag', 'continueButton', 'callback', 'CERRRegistrationRigidSetup(''auto_registration'')');

% Options
    %downsample option
    dy = 20;
    handles.dsampleCheck = uicontrol(handles.optionPanel, 'style', 'checkbox', 'units', 'pixel', 'value', 0, ...
                                'position', [2 24 136 20], 'string', 'downSample(2x2x2)', 'tag', 'dsamplecheckbox');
    handles.saveCheck = uicontrol(handles.optionPanel, 'style', 'checkbox', 'units', 'pixel', 'Value', 0, ...
                                'position', [2 2 136 20], 'string', 'save resampled data', 'tag', 'savecheckbox');

    InitTranstext = uicontrol(handles.optionPanel, 'style', 'text', 'units', 'pixel', ...
                                'position', [138 1 50 16], 'string', 'InitTrans:');
    handles.InitTrans = uicontrol(handles.optionPanel, 'style', 'popup', 'units', 'pixel', 'value', 1, ...
                                'position', [188 4 86 18], 'string', 'MomentsOn|GeometryOn|InitTransMOn','tag', 'InitTrans');
%
    handles.flipX = uicontrol(handles.optionPanel, 'style', 'checkbox', 'units', 'pixel', 'Value', 0, ...
                                'position', [138 24 50 20], 'string', 'flipX', 'tag', 'flipX', 'enable', 'off');
    handles.flipY = uicontrol(handles.optionPanel, 'style', 'checkbox', 'units', 'pixel', 'Value', 0, ...
                                'position', [188 24 50 20], 'string', 'flipY', 'tag', 'flipY', 'enable', 'off');
    handles.flipZ = uicontrol(handles.optionPanel, 'style', 'checkbox', 'units', 'pixel', 'Value', 0, ...
                                'position', [238 24 50 20], 'string', 'flipZ', 'tag', 'flipZ', 'enable', 'off');

%     2D Match
%     handles.match2DCheck = uicontrol(handles.optionPanel, 'style', 'checkbox', 'units', 'pixel', 'Value', 0, ...
%                                 'position', [138 15 80 28], 'string', '2D
%                                 Match', 'tag', 'match2Dcheckbox');

%registration method panel
    handles.registrationMethodPanel = uipanel('Parent',handles.generalPanel,'Units','normalize', 'FontSize',fsize,...
                                'Title','Image Registration Method','Tag','regMethodPanel','Clipping','off',...
                                'Position',[0 0 1 1], 'Visible','on');

    dy = -1; dx = -5;
    h21 = uicontrol(...
    'Parent',handles.registrationMethodPanel,...
    'Units','characters',...
    'FontSize',10,...
    'HorizontalAlignment','left',...
    'Position',[6+dx 10.2307692307692+dy 20.6 2],...
    'String','Transform:',...
    'Style','text',...
    'Tag','text6');

    handles.transform = uicontrol(...
    'Parent',handles.registrationMethodPanel,...
    'Units','characters',...
    'FontSize',10,...
    'Position',[28.2+dx 10.1538461538462+dy 51 2.07692307692308],...
    'String',{ 'Similarity Transform'; 'Versor3D Transform'; 'Euler Transform';  },... %'Affine Transform'
    'Style','popupmenu',...
    'CallBack', 'createParaPanel(guidata(gcbf), ''transform_advance'')', ...
    'Value',1);

%     try
%         [x, map] = imread('help-book-open.gif', 'GIF');
%         a = ind2rgb(x, map);
%     catch
%         a = [];
%     end
%     handles.helpButton = uicontrol(handles.registrationMethodPanel, 'style', 'pushbutton', 'units', 'characters', ...
%                             'cdata', a, 'position', [80+dx 10.1538461538462+dy 6 2.07692307692308], 'string', '', ...
%                             'tag', 'continueButton', 'callback', 'winopen(''irqat.chm'')');

    h23 = uicontrol(...
    'Parent',handles.registrationMethodPanel,...
    'Units','characters',...
    'FontSize',10,...
    'HorizontalAlignment','left',...
    'Position',[6+dx 7.38461538461539+dy 20.6 2],...
    'String','Interpolator:',...
    'Style','text',...
    'Tag','text7');

    handles.interpolater = uicontrol(...
    'Parent',handles.registrationMethodPanel,...
    'Units','characters',...
    'FontSize',10,...
    'Position',[28.2+dx 7.30769230769231+dy 51 2.07692307692308],...
    'String',{  'Linear Interpolate'; 'Nearest Interpolate'},...
    'Style','popupmenu',...
    'Value',1);

    h25 = uicontrol(...
    'Parent',handles.registrationMethodPanel,...
    'Units','characters',...
    'FontSize',10,...
    'HorizontalAlignment','left',...
    'Position',[6+dx 4.61538461538462+dy 20.6 2],...
    'String','Similarity Metric:',...
    'Style','text',...
    'Tag','text8');

    handles.metric = uicontrol(...
    'Parent',handles.registrationMethodPanel,...
    'Units','characters',...
    'FontSize',10,...
    'Position',[28.2+dx 4.53846153846154+dy 51 2.07692307692308],...
    'String',{  'Mean Squares'; 'Normalized Correlation' },...
    'Style','popupmenu',...
    'Value',1);

    h27 = uicontrol(...
    'Parent',handles.registrationMethodPanel,...
    'Units','characters',...
    'FontSize',10,...
    'HorizontalAlignment','left',...
    'Position',[6+dx 1.92307692307692+dy 20.6 2],...
    'String','Optimizer:',...
    'Style','text',...
    'Tag','text9');

    handles.optimizer = uicontrol(...
    'Parent',handles.registrationMethodPanel,...
    'Units','characters',...
    'FontSize',10,...
    'Position',[28.2+dx 1.84615384615385+dy 51 2.07692307692308],...
    'String','RegularStepGradientDescent',...
    'Style','popupmenu',...
    'Value',1);

    %save handles
    guidata(handles.mainframe, handles);
end


function svgTile(s, source, result)
% Adds a feTile SVG filter
% PRELIMINARY IMPLEMENTATION (Parameters may change)
%
% svgTile(s, source, result)
% Parameters:
%   s : Array of plot object handles
%   source : Any previous defined filter result string, 'SourceGraphic',
%            or 'SourceAlpha'.
%   result : String that identifies the filter result for following filter
%            stages.
for i = 1:length(s)
    userdata = get(s(i),'UserData');
    if isfield(userdata, 'svg') && isfield(userdata.svg, 'Filter')
        next = length(userdata.svg.Filter) + 1;
    else
        next = 1;
    end
    userdata.svg.Filter(next).Subfilter.Type = 'feTile';
    userdata.svg.Filter(next).Subfilter.Source = source;
    userdata.svg.Filter(next).Subfilter.Result = result;
    set(s(i),'UserData', userdata);
end


function values = generic_wizard(varargin)

api.Data     = get_option(varargin,'data',rand(1000,7));
api.Header   = get_option(varargin,'header','i am a header');
api.Columns  = get_option(varargin,'columns','');

if size(api.Columns,2) ~= size(api.Data,2)
  api.Columns = cellfun(@(x) ['Column' num2str(x)], ...
    num2cell(1:size(api.Data,2)),'UniformOutput',false);
end

api.Type     = get_option(varargin,'type','EBSD');

api.isPublishMode       = getMTEXpref('generatingHelpMode');

p = get(0,'MonitorPositions');
api = WizardEmptyGUIApi(api,'PageHeight',min(2/3*p(1,4),600));
api = GenericApi(api);

waitfor(api.hFigure);

values = api.getOptions();

end


function handles = dtiDeleteROI(roiNum,handles)
%
%   handles = dtiDeleteROI(roiNum,handles)
%
%Author: Wandell
%Purpose:
%
% Example:
%    handles = dtiDeleteROI(handles.curRoi,handles)

if ieNotDefined('roiNum'), error('roi number required.'); end
if isempty(handles.rois), warning('No ROIS to delete'); return;  end

nRois = length(handles.rois);
if (roiNum < 1) | (roiNum > nRois), error('Bad roi number.'); end

handles.rois(roiNum) = [];
if (roiNum <= handles.curRoi), handles.curRoi = handles.curRoi - 1; end

if isempty(handles.rois), handles.curRoi = 0;
elseif handles.curRoi < 1, handles.curRoi = 1; end

return;


%% patch2tri
% Below is a demonstration of the features of the |patch2tri| function

%%
clear; close all; clc;

%% Syntax
% |[varargout]=patch2tri(varargin);|

%% Description
% UNDOCUMENTED
%% Examples
%
%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>
%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


function hRD = plugin_rd(board, design)
% Reference design definition

%   Copyright 2014-2015 The MathWorks, Inc.

% Construct reference design object
hRD = hdlcoder.ReferenceDesign('SynthesisTool', 'Xilinx Vivado');

% Create the reference design for the SOM-only
% This is the base reference design that other RDs can build upon
hRD.ReferenceDesignName = sprintf('%s (%s)', upper(board), design);

% Determine the board name based on the design
hRD.BoardName = sprintf('AnalogDevices ADRV9361-Z7035 AGC');

% Tool information
hRD.SupportedToolVersion = {'2018.2'};

% Add AGC control
hRD.addParameter( ...
    'ParameterID',   'en_agc', ...
    'DisplayName',   'Control AGC', ...
    'DefaultValue',  'Rx', ...
    'ParameterType',  hdlcoder.ParameterType.Dropdown, ...
    'Choice',       {'Rx', 'Tx'});

% Get the root directory
rootDir = fileparts(strtok(mfilename('fullpath'), '+'));
tmp = strsplit(rootDir,'/');
rootDir = fullfile('/',tmp{1:end-2});
rootDirBSP = fullfile('hdl_wa_bsp','vendor','AnalogDevices','vivado');

% Design files are shared
hRD.SharedRD = true;
hRD.SharedRDFolder = rootDir;

board = 'ccfmc_lvds_agc';

hRD.addCustomVivadoDesign( ...
    'CustomBlockDesignTcl', fullfile('targeting_models', 'tuneAGC-ad9361',  'ccfmc_lvds_agc', 'system_project_rx.tcl'), ...
    'CustomTopLevelHDL',    fullfile('targeting_models', 'tuneAGC-ad9361',  'ccfmc_lvds_agc', 'system_top.v'));

hRD.BlockDesignName = 'system';

% custom constraint files
board_type = strsplit(board,'_');
hRD.CustomConstraints = {...
    fullfile(rootDirBSP, 'projects', 'adrv9361z7035', 'common', strcat(board_type{1}, '_constr.xdc')), ...
	fullfile(rootDirBSP, 'projects', 'adrv9361z7035', 'common', 'adrv9361z7035_constr.xdc'), ...
	fullfile(rootDirBSP, 'projects', 'adrv9361z7035', 'common', strcat('adrv9361z7035_constr_', board_type{2}, '.xdc')), ...
    };

% custom source files
hRD.CustomFiles = {...
	fullfile(rootDirBSP, 'library')...,
	fullfile(rootDirBSP, 'library','xilinx')...,
	fullfile(rootDirBSP, 'projects','common')...,
	fullfile(rootDirBSP, 'projects','scripts')...,
	fullfile(rootDirBSP, 'projects','fmcomms2')...,
	fullfile(rootDirBSP, 'projects','adrv9361z7035', 'common')...,
    fullfile('targeting_models', 'tuneAGC-ad9361', 'ccfmc_lvds_agc')...,
    };

%% Add interfaces
% add clock interface
hRD.addClockInterface( ...
    'ClockConnection',   'util_ad9361_divclk/clk_out', ...
    'ResetConnection',   'util_ad9361_divclk_reset/peripheral_aresetn');


function [ images_array ] = readImages( image_dir, max )
%readImages Summary
% Reads images in the give directory and returns a cell array.

% Read images
file_names = fullfile(image_dir, '*.jpg');
image_files = dir(file_names);

% Number of frames for testing
n = min([length(image_files) max]);

% Preallocation
images_array = cell(n, 1);

for k = 1:n
    base_name = image_files(k).name;
    full_name = fullfile(image_dir, base_name);
    fprintf(1, 'Now reading %s\n', full_name);
    im = imread(full_name);
    im = imresize(im, [360 640]);
    images_array{k} = im;
end

end


classdef FigureRendererEnum < matlab.mixin.SetGet
    %FigureRendererEnum Summary of this class goes here
    %   Detailed explanation goes here

    enumeration
        OpenGL('OpenGL','opengl');
        Painters('Painters','painters');
    end

    properties
        name char = '';
        renderer char = '';
    end

    methods
        function obj = FigureRendererEnum(name,renderer)
            obj.name = name;
            obj.renderer = renderer;
        end
    end

    methods(Static)
        function listBoxStr = getListboxStr()
            m = enumeration('FigureRendererEnum');
            listBoxStr = {m.name};
        end

        function [enum, ind] = getEnumForListboxStr(nameStr)
            m = enumeration('FigureRendererEnum');
            ind = find(ismember({m.name},nameStr),1,'first');
            enum = m(ind);
        end

        function [ind, enum] = getIndForName(name)
            m = enumeration('FigureRendererEnum');
            ind = find(ismember({m.name},name),1,'first');
            enum = m(ind);
        end
    end
end


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

function test_type_basics()
    fn=cosmo_make_temp_filename();
    cleaner=onCleanup(@()delete(fn));

    data=write_data(fn);

    s=cosmo_type(fn);
    assertEqual(s,data);

function test_dim_type_fprintf()
    if cosmo_skip_test_if_no_external('!evalc')
        return;
    end

    fn=cosmo_make_temp_filename();
    cleaner=onCleanup(@()delete(fn));

    data=write_data(fn);

    expr=sprintf('cosmo_type(''%s'')',fn);

    s=evalc(expr);
    s_fixed=regexprep(s,'ans\s*=\s*','');
    s_fixed=regexprep(s_fixed,'\s*$','');

    assertEqual(s_fixed,data);

function data=write_data(fn)
    fid=fopen(fn,'w');
    data=sprintf('foo\nbar%s',cosmo_make_temp_filename());
    fprintf(fid,data);
    fclose(fid);


function devInfo = FindImaqDevices(desiredFormat)
%FINDIMAQDEVICES returns list of available image acquisition devices.
%   DEVINFO = FINDIMAQDEVICES returns a structure array with named fields.
%     .NAME is good for populating a GUI for user selection.
%     .CONSTRUCTOR aids programmatic connection to each device.
%     .ADAPTOR and .DEVICE help with nondefault object constructors.
%   The length of DEVINFO indicates how many devices detected.
%   If no devices detected, DEVINFO is empty.
%
%   DEVINFO = FINDIMAQDEVICES(DESIREDFORMAT) allows specification of the
%   desired video format. This string is inserted into the constructor
%   field for each device. DESIREDFORMAT is not checked, so if you specify
%   an invalid format then evaluating the constructor(s) will error.
%
%   NOTE: This function calls IMAQRESET, which closes and deletes any
%   previously active videoinput objects.
%
%   See also FINDCAM, IMAQHWINFO, IMAQRESET.

% Copyright 2003-2010 The MathWorks, Inc.

error(nargchk(0,1,nargin))
error(nargoutchk(1,1,nargout))

%make sure recently added plug-n-play devices also detectable
imaqreset

%installed adaptors
hwInfo = imaqhwinfo;
adaptors = hwInfo.InstalledAdaptors;

%available devices
numDevices = 0;  %start with empty list
for i=1:length(adaptors)  %check each adaptor
  adaptorInfo = imaqhwinfo(adaptors{i});
  devices = adaptorInfo.DeviceIDs;
  %add each device to list
  for j=1:length(devices)
    numDevices = numDevices+1;
    deviceInfo = imaqhwinfo(adaptors{i},devices{j});
    devInfo(numDevices).name = deviceInfo.DeviceName;
    constructor = deviceInfo.ObjectConstructor;
    if nargin>0  %add format to object constructor
      constructor = [constructor(1:end-1) ', ''' desiredFormat ''')'];
    end
    devInfo(numDevices).constructor = constructor;
    devInfo(numDevices).adaptor = adaptors{i};
    devInfo(numDevices).device = devices{j};
  end  %for j = devices
end  %for i = adaptors

%return empty idicator if no devices detected
if numDevices==0
  devInfo=[];
end


function par_accept_results(tag, payload)
% Accept a result from the scheduler and store it in a result table.
% par_accept_result(Tag, Payload)
%
% This function stores the results produced by the scheduler in a global result table for later
% pickup by par_endschedule. The reason is that the scheduler, being a Java class, cannot hold very
% large (or very many) results since the MATLAB Java memory is limited to a maximum of 64GB.
% Therefore we need to ferry the results out of Java as they are being produced.
%
% The function also attempts to check if the results contain errors, and prints them as they are
% being received.
%
% In:
%   Tag: tag string that uniquely identifies the result; should begin with 'tag__'.
%
%   Payload: payload uint8 array of the same format as returned by the Scheduler

global tracking;
% atomically store payload in global results table
tracking.parallel.results.(tag) = payload;

if length(payload) < 16384
    try
        % for short results we check if we got an error, and if so, we print it out
        decoded = hlp_deserialize(typecast(payload,'uint8'));
        if all(isfield(decoded{2},{'message','identifier','stack'}))
            fprintf('Got an error during parallel execution: %s\n',hlp_handleerror(decoded{2})); end
    catch e %#ok<NASGU>
    end
end


function [data] = fiff_read_evoked(fname,setno)
%
% [data] = fiff_read_evoked(fname,setno)
%
% Read one evoked data set
%

%
%   Author : Matti Hamalainen, MGH Martinos Center
%   License : BSD 3-clause
%
%
%   Revision 1.11  2009/03/30 11:37:37  msh
%   Added copying of measurement info blocks from the original like in mne_browse_raw
%
%   Revision 1.10  2008/03/28 13:42:01  msh
%   Accommodate evoked files from xplotter, which may have channel information
%   local to the evoked block
%
%   Revision 1.9  2007/11/13 10:55:32  msh
%   Specify the second argument to all calls to the exist function
%
%   Revision 1.8  2006/10/14 11:47:32  msh
%   Omitted listing of nepoch from the diagnostic output
%
%   Revision 1.7  2006/09/21 19:27:16  msh
%   fiff_read_evoked did not tolerate missing comment
%
%   Revision 1.6  2006/05/03 19:03:19  msh
%   Eliminated the use of cast function for Matlab 6.5 compatibility
%
%   Revision 1.5  2006/04/23 15:29:40  msh
%   Added MGH to the copyright
%
%   Revision 1.4  2006/04/18 20:44:46  msh
%   Added reading of forward solution.
%   Use length instead of size when appropriate
%
%   Revision 1.3  2006/04/12 13:13:51  msh
%   Added fiff_find_evoked.m
%   Use aspect_kind field name instead of aspect_type
%
%   Revision 1.2  2006/04/12 10:29:02  msh
%   Made evoked data writing compatible with the structures returned in reading.
%
%   Revision 1.1  2006/04/10 23:26:54  msh
%   Added fiff reading routines
%
%

global FIFF;
if isempty(FIFF)
    FIFF = fiff_define_constants();
end

me='MNE:fiff_read_evoked';

if nargin == 1
    setno = 1;
elseif nargin ~= 2
    error(me,'Incorrect number of arguments');
end
if setno <= 0
    error(me,'Data set selector must be positive');
end
%
%   Open the file
%
fprintf(1,'Reading %s ...\n',fname);
[ fid, tree ] = fiff_open(fname);
%
%   Read the measurement info
%
[ info, meas ] = fiff_read_meas_info(fid,tree);
info.filename = fname;
%
%   Locate the data of interest
%
processed = fiff_dir_tree_find(meas,FIFF.FIFFB_PROCESSED_DATA);
if length(processed) == 0
    fclose(fid);
    error(me,'Could not find processed data');
end
%
evoked = fiff_dir_tree_find(meas,FIFF.FIFFB_EVOKED);
if length(evoked) == 0
    fclose(fid);
    error(me,'Could not find evoked data');
end
%
%   Identify the aspects
%
naspect = 0;
is_smsh = [];
for k = 1:length(evoked)
    sets(k).aspects = fiff_dir_tree_find(evoked(k),FIFF.FIFFB_ASPECT);
    sets(k).naspect = length(sets(k).aspects);
    if sets(k).naspect > 0
        is_smsh = [ is_smsh zeros(1,sets(k).naspect) ];
        naspect = naspect + sets(k).naspect;
    end
    saspects  = fiff_dir_tree_find(evoked(k), FIFF.FIFFB_SMSH_ASPECT);
    nsaspects = length(saspects);
    if nsaspects > 0
        sets(k).naspect = sets(k).naspect + nsaspects;
        sets(k).aspects = [ sets(k).aspects saspects ];
        is_smsh = [ is_smsh ones(1,sets(k).naspect) ];
        naspect = naspect + nsaspects;
    end
end
fprintf(1,'\t%d evoked data sets containing a total of %d data aspects in %s\n',length(evoked),naspect,fname);
if setno > naspect || setno < 1
    fclose(fid);
    error(me,'Data set selector out of range');
end
%
%   Next locate the evoked data set
%
p = 0;
goon = true;
for k = 1:length(evoked)
    for a = 1:sets(k).naspect
        p = p + 1;
        if p == setno
            my_evoked = evoked(k);
            my_aspect = sets(k).aspects(a);
            goon = false;
            break;
        end
    end
    if ~goon
        break;
    end
end
%
%   The desired data should have been found but better to check
%
if ~exist('my_evoked','var') || ~exist('my_aspect','var')
    fclose(fid);
    error(me,'Desired data set not found');
end
%
%   Now find the data in the evoked block
%
nchan = 0;
sfreq = -1;
q = 0;
for k = 1:my_evoked.nent
    kind = my_evoked.dir(k).kind;
    pos  = my_evoked.dir(k).pos;
    switch kind
        case FIFF.FIFF_COMMENT
            tag = fiff_read_tag(fid,pos);
            comment = tag.data;
        case FIFF.FIFF_FIRST_SAMPLE
            tag = fiff_read_tag(fid,pos);
            first = tag.data;
        case FIFF.FIFF_LAST_SAMPLE
            tag = fiff_read_tag(fid,pos);
            last = tag.data;
        case FIFF.FIFF_NCHAN
            tag = fiff_read_tag(fid,pos);
            nchan = tag.data;
        case FIFF.FIFF_SFREQ
            tag = fiff_read_tag(fid,pos);
            sfreq = tag.data;
        case FIFF.FIFF_CH_INFO
            q = q+1;
            tag = fiff_read_tag(fid,pos);
            chs(q) = tag.data;
    end
end
if ~exist('comment','var')
    comment = 'No comment';
end
%
%   Local channel information?
%
if nchan > 0
    if ~exist('chs','var')
        fclose(fid);
        error(me, ...
            'Local channel information was not found when it was expected.');
    end
    if length(chs) ~= nchan
        fclose(fid);
        error(me, ...
            'Number of channels and number of channel definitions are different');
    end
    info.chs   = chs;
    info.nchan = nchan;
    fprintf(1, ...
        '\tFound channel information in evoked data. nchan = %d\n',nchan);
    if sfreq > 0
        info.sfreq = sfreq;
    end
end
nsamp = last-first+1;
fprintf(1,'\tFound the data of interest:\n');
fprintf(1,'\t\tt = %10.2f ... %10.2f ms (%s)\n',...
    1000*double(first)/info.sfreq,1000*double(last)/info.sfreq,comment);
if ~isempty(info.comps)
    fprintf(1,'\t\t%d CTF compensation matrices available\n',length(info.comps));
end
%
% Read the data in the aspect block
%
nepoch = 0;
for k = 1:my_aspect.nent
    kind = my_aspect.dir(k).kind;
    pos  = my_aspect.dir(k).pos;
    switch kind
        case FIFF.FIFF_COMMENT
            tag = fiff_read_tag(fid,pos);
            comment = tag.data;
        case FIFF.FIFF_ASPECT_KIND
            tag = fiff_read_tag(fid,pos);
            aspect_kind = tag.data;
        case FIFF.FIFF_NAVE
            tag = fiff_read_tag(fid,pos);
            nave = tag.data;
        case FIFF.FIFF_EPOCH
            nepoch = nepoch + 1;
            tag = fiff_read_tag(fid,pos);
            epoch(nepoch) = tag;
    end
end
if ~exist('nave','var')
    nave = 1;
end
fprintf(1,'\t\tnave = %d aspect type = %d\n',...
    nave,aspect_kind);
if nepoch ~= 1 && nepoch ~= info.nchan
    fclose(fid);
    error(me,'Number of epoch tags is unreasonable (nepoch = %d nchan = %d)',nepoch,info.nchan);
end
%
if nepoch == 1
    %
    %   Only one epoch
    %
    all = epoch(1).data;
    %
    %   May need a transpose if the number of channels is one
    %
    if size(all,2) == 1 && info.nchan == 1
        all = all';
    end
else
    %
    %   Put the old style epochs together
    %
    all = epoch(1).data';
    for k = 2:nepoch
        all = [ all ; epoch(k).data' ];
    end
end
if size(all,2) ~= nsamp
    fclose(fid);
    error(me,'Incorrect number of samples (%d instead of %d)',...
        size(all,2),nsamp);
end
%
%   Calibrate
%
for k = 1:info.nchan
    cals(k) = info.chs(k).cal;
end
all = diag(cals)*all;
%
%   Put it all together
%
data.info = info;
data.evoked.aspect_kind = aspect_kind;
data.evoked.is_smsh     = is_smsh(setno);
if exist('nave','var')
    data.evoked.nave = nave;
else
    data.evoked.nave  = 1;
end
data.evoked.first = first;
data.evoked.last  = last;
if exist('comment','var')
    data.evoked.comment = comment;
end
%
%   Times for convenience and the actual epoch data
%
data.evoked.times = double(data.evoked.first:1:data.evoked.last)/data.info.sfreq;
data.evoked.epochs = all;

fclose(fid);

return;

    function [tag] = find_tag(node,findkind)

        for p = 1:node.nent
            kind = node.dir(p).kind;
            pos  = node.dir(p).pos;
            if kind == findkind
                tag = fiff_read_tag(fid,pos);
                return;
            end
        end
        tag = [];
        return
    end

end


function [success] = downsampleHdf5Movie(inputFilePath, varargin)
	% [success] = downsampleHdf5Movie(inputFilePath, varargin)
	%
	% Downsamples a movie (HDF5, SLD, etc.) in inputFilePath piece by piece and appends it to already created hdf5 file. Useful for large files that otherwise would not fit into RAM.
	%
	% Biafra Ahanonu
	% started: 2013.12.19
	%
	% Part of append code based on work by Dinesh Iyer (http://www.mathworks.com/matlabcentral/newsreader/author/130530)
	% note: checked between this implementation and imageJ's scale, they are nearly identical (subtracted histogram mean is 1 vs each image mean of ~1860, so assuming precision error).
	%
	% inputs
	%	inputFilePath - Str: path to movie to downsample into HDF5.
	% outputs
	% 	success - Binary: 1 = completed successfully, 0 = did not complete successfully.
	% options
	%	inputDatasetName = hierarchy where data is stored in HDF5 file

	% changelog
		% 2014.01.18 - improved method of obtaining the newFilename
		% 2014.06.16 - updated output notifications to user
		% 2021.08.08 [19:30:20] - Updated to handle CIAtah v4.0 switch to all functions inside ciapkg package.
		% 2022.07.10 [19:24:29] - Added Bio-Formats support.
		% 2022.07.15 [13:34:28] - Switch chunking to automatic by default, generally improved reading from data later than small chunks.
	% TODO
		% Use handles to reduce memory load when doing computations.

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

	%========================
	% Str: name of the input hierarchy in the HDF5 files
	options.inputDatasetName = '/1';
	% Str: name of the output hierarchy in the HDF5 files
	options.outputDatasetName = '/1';
	% Vector: frames to use.
	options.frameList = 1;
	% Int: amount to downsample movie. Value of 1 = no downsample (e.g. just file conversion).
	options.downsampleFactor = 4;
	% Int: max size of a chunk in Mbytes. For HDF5 files.
	options.maxChunkSize = 20000;
	% Int: bytes to MB conversion. DO NOT CHANGE.
	options.bytesToMB = 1024^2;
	% Int: number of frames to use when loading file in chunks. For Bio-Formats files!
	options.numFramesSubset = 1000;
	% interval over which to show waitbar
	options.waitbarInterval = 1000;
	% Str: new filename to save to for the downsampled movie.
	options.newFilename = '';
	% Str: downsample to different folder. Leave blank to use same folder as input file.
	options.saveFolder = [];
	% second if want to do another downsample without loading another file
	options.saveFolderTwo = [];
	% Int: amount to downsample movie to 2nd folder. Value of 1 = no downsample (e.g. just file conversion).
	options.downsampleFactorTwo = 2;
	% Str: new filename to save to for the downsampled movie in 2nd folder.
	options.newFilenameTwo = '';
	% Int: Defines gzip compression level (0-9). 0 = no compression, 9 = most compression.
	options.deflateLevel = 1;
	% Int: chunk size in [x y z] of the dataset, leave empty for auto chunking
	options.dataDimsChunkCopy = []; % [128 128 1]
	% Str: movie type: hdf5, bioformats. Leave blank for automatic determination.
	options.movieType = '';
	% Int: Bio-Formats series number to load.
	options.bfSeriesNo = 1;
	% Int: Bio-Formats channel number to load.
	options.bfChannelNo = 1;
	% Int: Bio-Formats z dimension to load.
	options.bfZdimNo = 1;
	% Str: Bio-Formats series name. Function will search via regexp for this series within a Bio-Formats file.
	options.bfSeriesName = '';
	% Binary: 1 = whether to display info on command line.
	options.displayInfo = 1;
	% Binary: 1 = waitbar/progress bar is shown, 0 = no progress shown.
	options.waitbarOn = 1;
	% get options
	options = getOptions(options,varargin);
	% unpack options into current workspace
	% fn=fieldnames(options);
	% for i=1:length(fn)
	%     eval([fn{i} '=options.' fn{i} ';']);
	% end
	%========================

	[pathstr,name,ext] = fileparts(inputFilePath);
	inputFileEmpty = 0;
	if isempty(options.newFilename)
		inputFileEmpty = 1;
		options.newFilename = [pathstr filesep 'concat_' name '.h5'];
	end
	if isempty(options.newFilenameTwo)
		options.newFilenameTwo = [pathstr filesep 'concat_' name '.h5'];
	end

	% Check that options.dataDimsChunkCopy

	% Check type of movie being read in.
	if isempty(options.movieType)
		[options.movieType] = ciapkg.io.getMovieFileType(inputFilePath);
	end

	startTime = tic;

	fileIdOpen = [];

	switch options.movieType
		case 'hdf5'
			% movie dimensions and subsets to analyze
			[subsets, dataDim] = getSubsetOfDataToAnalyze(inputFilePath, options, varargin);
		case 'bioformats'
			disp(['Opening connection to Bio-Formats file:' inputFilePath])
			startReadTime = tic;
			fileIdOpen = bfGetReader(inputFilePath);
			toc(startReadTime)

			% If user inputs a series name, find within the file and overwrite default series name.
			if ~isempty(options.bfSeriesName)
				[bfSeriesNo] = ciapkg.bf.getSeriesNoFromName(inputFilePath,options.bfSeriesName,'fileIdOpen',fileIdOpen);
				if isnan(bfSeriesNo)
					disp(['Series "' options.bfSeriesName '" not found in ' inputFilePath])
					disp('Returning...')
					return;
				else
					options.bfSeriesNo = bfSeriesNo;
				end
			end

			% Convert for 0-base indexing.
			bfSeriesNoTrue = options.bfSeriesNo-1;

			fileIdOpen.setSeries(bfSeriesNoTrue);
			omeMeta = fileIdOpen.getMetadataStore();

			dim = struct;
			dataDim.x = omeMeta.getPixelsSizeX(bfSeriesNoTrue).getValue(); % image width, pixels
			dataDim.y = omeMeta.getPixelsSizeY(bfSeriesNoTrue).getValue(); % image height, pixels
			dataDim.z = fileIdOpen.getSizeT;

			thisStr = char(omeMeta.getImageName(bfSeriesNoTrue));

			disp(['Loading series: ' thisStr])
			display(dataDim)

			% If filename is empty
			if inputFileEmpty==1
				options.newFilename = [pathstr filesep 'concat_' thisStr '.h5'];
			end

			disp('===')
			disp(['Series in file: ' inputFilePath])
			nSeries = fileIdOpen.getSeriesCount();
			for seriesNo = 1:nSeries
				thisStr = char(omeMeta.getImageName(seriesNo-1));
				disp([num2str(seriesNo) ': "' thisStr '"'])
			end
			disp('===')

			% Get the subsets of the movie to analyze
			subsetSize = options.numFramesSubset;
			movieLength = dataDim.z;
			numSubsets = ceil(movieLength/subsetSize)+1;
			subsets = round(linspace(1,movieLength,numSubsets));
		otherwise
	end

	subsetsDiff = diff(subsets);
	% to compensate for flooring of linspace
	subsetsDiff(end) = subsetsDiff(end)+1;
	display(['subsets: ' num2str(subsets)]);
	display(['subsets diffs: ' num2str(subsetsDiff)]);

	% Change output filename if user request a different folder than where original file is.
	if ~isempty(options.saveFolder)
		[pathstr,name,ext] = fileparts(options.newFilename);
		options.newFilename = [options.saveFolder filesep name '.h5'];
	end
	if ~isempty(options.saveFolderTwo)
		[pathstr,name,ext] = fileparts(options.newFilename);
		options.newFilenameTwo = [options.saveFolderTwo filesep name '.h5'];
	end

	% Pre-establish connection to file to save time.
	switch options.movieType
		case 'hdf5'
			% hdf5FileWorkerConstant.Value = H5F.open(inputMovie);
		case 'bioformats'
			if isempty(fileIdOpen)
				disp(['Opening connection to Bio-Formats file:' inputFilePath])
				startReadTime = tic;
				fileIdOpen = bfGetReader(inputFilePath);
				toc(startReadTime)
			end
		otherwise
	end
	display(repmat('+',1,21))
	disp(['Saving to: ' options.newFilename])
	% display(['saving to: ' options.newFilename])

	try
		nSubsets = (length(subsets)-1);
		for currentSubset = 1:nSubsets
			loopStartTime = tic;
			% get current subset location and size
			currentSubsetLocation = subsets(currentSubset);
			lengthSubset = subsetsDiff(currentSubset);
			% convert offset to C-style offset for low-level HDF5 functions
			offset = [0 0 currentSubsetLocation-1];
			block = [dataDim.x dataDim.y lengthSubset];
			display('---')
			% display(sprintf(['current location: ' num2str(round(currentSubsetLocation/dataDim.z*100)) '% | ' num2str(currentSubsetLocation) '/' num2str(dataDim.z) '\noffset: ' num2str(offset) '\nblock: ' num2str(block)]));
			fprintf('current location: %d%% | %d/%d \noffset: %s \nblock: %s\n',round(currentSubsetLocation/dataDim.z*100),currentSubsetLocation,dataDim.z,mat2str(offset),mat2str(block));

			switch options.movieType
				case 'hdf5'
					% load subset of HDF5 file into memory
					inputMovie = readHDF5Subset(inputFilePath,offset,block,'datasetName',options.inputDatasetName);
				case 'bioformats'
					thisFrameList = currentSubsetLocation:(currentSubsetLocation+lengthSubset-1);
					disp(['Frames ' num2str(thisFrameList(1)) ' to ' num2str(thisFrameList(end))])
					[inputMovie] = local_readBioformats(inputFilePath,thisFrameList,fileIdOpen,options);
				otherwise
			end

			% split into second movie if need be
			if ~isempty(options.saveFolderTwo)
				inputMovieTwo = inputMovie;
			end

			% Downsample section of the movie, keep in memory
			if options.downsampleFactor==1
			else
				downsampleMovieNested('downsampleDimension', 'space','downsampleFactor',options.downsampleFactor,'waitbarInterval',options.waitbarInterval);
			end
			% thisMovie = uint16(thisMovie);
			display(['subset class: ' class(inputMovie)])

			% For snapshots with a single frame
			if size(inputMovie,3)==1
				inputMovie(:,:,2) = inputMovie;
			end

			% save the movie
			if currentSubset==1
				createHdf5File(options.newFilename, options.outputDatasetName, inputMovie,'deflateLevel',options.deflateLevel,'dataDimsChunkCopy',options.dataDimsChunkCopy);
			else
				appendDataToHdf5(options.newFilename, options.outputDatasetName, inputMovie);
			end
			toc(loopStartTime);
			display(sprintf(['downsample dims: ' num2str(size(inputMovie)) '\n-------']));

			if ~isempty(options.saveFolderTwo)
				display('secondary downsample in progress...')
				inputMovie = inputMovieTwo;
				% downsample section of the movie, keep in memory
				downsampleMovieNested('downsampleDimension', 'space','downsampleFactor',options.downsampleFactorTwo,'waitbarInterval',options.waitbarInterval);
				% save the movie
				if currentSubset==1
					createHdf5File(options.newFilenameTwo, options.outputDatasetName, inputMovie,'deflateLevel',options.deflateLevel,'dataDimsChunkCopy',options.dataDimsChunkCopy);
				else
					appendDataToHdf5(options.newFilenameTwo, options.outputDatasetName, inputMovie);
				end
			end
			% clear inputMovie;
		end
		success = 1;
		options.inputDatasetName = options.outputDatasetName;
		[subsets dataDim] = getSubsetOfDataToAnalyze(options.newFilename, options, varargin);
		display(repmat('+',1,7))
		display(['final HDF5 dims: ' num2str(cell2mat(struct2cell(dataDim))')]);
		display(repmat('+',1,7))
	catch err
		display(repmat('@',1,7))
		disp(getReport(err,'extended','hyperlinks','on'));
		display(repmat('@',1,7))
		success = 0;
	end
	toc(startTime);

	function downsampleMovieNested(varargin)
		% downsamples a movie in either space or time, uses floor to calculate downsampled dimensions.
		% biafra ahanonu
		% started 2013.11.09 [09:31:32]
		%
		% inputs
			% inputMovie: a NxMxP matrix
		% options
			% downsampleType
			% downsampleFactor - amount to downsample in time
		% changelog
			% 2013.12.19 added the spatial downsampling to the function.
		% TODO

		%========================
		% default options
		nestedoptions.downsampleDimension = 'time';
		nestedoptions.downsampleType = 'bilinear';
		nestedoptions.downsampleFactor = 4;
		% exact dimensions to downsample in Z
		nestedoptions.downsampleZ = [];
		nestedoptions.waitbarOn = 1;
		% number of frames in each movie to load, [] = all, 1:500 would be 1st to 500th frame.
		nestedoptions.frameList = [];
		% whether to convert movie to double on load, not recommended
		nestedoptions.convertToDouble = 0;
		% name of HDF5 dataset name to load
		nestedoptions.inputDatasetName = '/1';
		% interval over which to show waitbar
		nestedoptions.waitbarInterval = 1000;
		% get user options, else keeps the defaults
		nestedoptions = getOptions(nestedoptions,varargin);
		% unpack options into current workspace
		% fn=fieldnames(options);
		% for i=1:length(fn)
		%     eval([fn{i} '=options.' fn{i} ';']);
		% end
		%========================
		% load the movie within downsample function
		if strcmp(class(inputMovie),'char')|strcmp(class(inputMovie),'cell')
			inputMovie = loadMovieList(inputMovie,'convertToDouble',nestedoptions.convertToDouble,'frameList',nestedoptions.frameList,'inputDatasetName',nestedoptions.inputDatasetName);
		end

		switch nestedoptions.downsampleDimension
			case 'time'
				switch nestedoptions.downsampleType
					case 'bilinear'
						% we do a bit of trickery here: we can downsample the movie in time by downsampling the X*Z 'image' in the Z-plane then stacking these downsampled images in the Y-plane. Would work the same of did Y*Z and stacked in X-plane.
						downX = size(inputMovie,1);
						downY = size(inputMovie,2);
						if isempty(nestedoptions.downsampleZ)
							downZ = floor(size(inputMovie,3)/nestedoptions.downsampleFactor);
						else
							downZ = nestedoptions.downsampleZ;
						end
						% pre-allocate movie
						% inputMovieDownsampled = zeros([downX downY downZ]);
						% this is a normal for loop at the moment, if convert inputMovie to cell array, can force it to be parallel
						reverseStr = '';
						for frame=1:downY
						   downsampledFrame = imresize(squeeze(inputMovie(:,frame,:)),[downX downZ],'bilinear');
						   % to reduce memory footprint, place new frame in old movie and cut off the unneeded frames after
						   inputMovie(1:downX,frame,1:downZ) = downsampledFrame;
						   % inputMovie(:,frame,:) = downsampledFrame;
							if frame==1||mod(frame,nestedoptions.waitbarInterval)==0&nestedoptions.waitbarOn==1|frame==downY
								reverseStr = cmdWaitbar(frame,downY,reverseStr,'inputStr','temporally downsampling matrix');
							end
						end
						inputMovie = inputMovie(:,:,1:downZ);
						drawnow;
					otherwise
						return;
				end
			case 'space'
				switch nestedoptions.downsampleType
					case 'bilinear'
						% we do a bit of trickery here: we can downsample the movie in time by downsampling the X*Z 'image' in the Z-plane then stacking these downsampled images in the Y-plane. Would work the same of did Y*Z and stacked in X-plane.
						downX = floor(size(inputMovie,1)/nestedoptions.downsampleFactor);
						downY = floor(size(inputMovie,2)/nestedoptions.downsampleFactor);
						downZ = size(inputMovie,3);
						% pre-allocate movie
						% inputMovieDownsampled = zeros([downX downY downZ]);
						% this is a normal for loop at the moment, if convert inputMovie to cell array, can force it to be parallel
						reverseStr = '';
						for frame=1:downZ
						   downsampledFrame = imresize(squeeze(inputMovie(:,:,frame)),[downX downY],'bilinear');
						   % to reduce memory footprint, place new frame in old movie and cut off the unneeded frames after
						   inputMovie(1:downX,1:downY,frame) = downsampledFrame;
						   % inputMovieDownsampled(1:downX,1:downY,frame) = downsampledFrame;
							if frame==1||mod(frame,nestedoptions.waitbarInterval)==0&nestedoptions.waitbarOn==1|frame==downZ
								reverseStr = cmdWaitbar(frame,downZ,reverseStr,'inputStr','spatially downsampling matrix');
							end
						end
						inputMovie = inputMovie(1:downX,1:downY,:);
						drawnow;
					otherwise
						return;
				end
			otherwise
				display('incorrect dimension option, choose time or space');
		end
		% display(' ');
	end
end

function [outputMovie] = local_readBioformats(thisMoviePath,thisFrameList,bfreaderTmp,options)
	% Reads in Bio-Formats data in chunks, uses open ID to speed up read times.

	% Setup movie class
	numMovies = 1;

	% Account for 0-base indexing.
	bfSeriesNoTrue = options.bfSeriesNo-1;

	% bfreaderTmp = bfGetReader(thisMoviePath);
	bfreaderTmp.setSeries(bfSeriesNoTrue);

	omeMeta = bfreaderTmp.getMetadataStore();
	stackSizeX = omeMeta.getPixelsSizeX(bfSeriesNoTrue).getValue(); % image width, pixels
	stackSizeY = omeMeta.getPixelsSizeY(bfSeriesNoTrue).getValue(); % image height, pixels
	stackSizeZ = omeMeta.getPixelsSizeZ(bfSeriesNoTrue).getValue();
	nChannels = omeMeta.getChannelCount(bfSeriesNoTrue);

	% Get the number of time points (frames).
	nFramesHere = bfreaderTmp.getSizeT;

	xyDims = [stackSizeX stackSizeY];

	if isempty(thisFrameList)
		nFrames = nFramesHere;
		framesToGrab = 1:nFrames;
	else
		nFrames = length(thisFrameList);
		framesToGrab = thisFrameList;
	end
	vidHeight = xyDims(2);
	vidWidth = xyDims(1);

	iPlane = bfreaderTmp.getIndex(0, options.bfChannelNo-1, 0)+1;
	tmpFrame = bfGetPlane(bfreaderTmp, iPlane);
	imgClass = class(tmpFrame);

	% Preallocate movie structure.
	if numMovies==1
		outputMovie = zeros(vidHeight, vidWidth, nFrames, imgClass);
	else
		tmpMovie = zeros(vidHeight, vidWidth, nFrames, imgClass);
	end

	% Read one frame at a time.
	reverseStr = '';
	iframe = 1;
	nFrames = length(framesToGrab);

	zPlane = 1;
	iZ = 1;
	dispEvery = round(nFrames/20);
	% Adjust for zero-based indexing
	% framesToGrab = framesToGrab-1;

	% figure;
	reverseStr = '';
	for t = framesToGrab
		% Assume 1-based adjust to 0-based indexing
		iPlane = bfreaderTmp.getIndex(zPlane-1, options.bfChannelNo-1, t-1)+1;
		tmpFrame = bfGetPlane(bfreaderTmp, iPlane);
		% figure;
		% imagesc(tmpFrame);
		if numMovies==1
			outputMovie(:,:,iZ) = tmpFrame;
		else
			tmpMovie(:,:,iZ) = tmpFrame;
		end
		iZ = iZ+1;

		if options.displayInfo==1
			reverseStr = ciapkg.view.cmdWaitbar(iZ,nFrames,reverseStr,'inputStr','Loading bio-formats file: ','waitbarOn',options.waitbarOn,'displayEvery',dispEvery);
		end
		% pause(0.01)
	end
end

function [subsets dataDim] = getSubsetOfDataToAnalyze(inputFilePath, options, varargin)
	import ciapkg.api.* % import CIAtah functions in ciapkg package API.

	% get HDF5 info
	hinfo = hdf5info(inputFilePath);
	hinfo.GroupHierarchy.Datasets;
	% find dataset name location
	% datasetNames = {hinfo.GroupHierarchy.Datasets.Name};
	% thisDatasetName = strmatch(options.inputDatasetName,datasetNames);
	% hReadInfo = hinfo.GroupHierarchy.Datasets(thisDatasetName);
	hReadInfo = getHdf5Info(hinfo,options);
	dataDim.x = hReadInfo.Dims(1);
	dataDim.y = hReadInfo.Dims(2);
	dataDim.z = hReadInfo.Dims(3);
	% estimate size of movie in Mbytes
	testFrame = readHDF5Subset(inputFilePath,[0 0 0],[dataDim.x dataDim.y 1],'datasetName',options.inputDatasetName);
	testFrameInfo = whos('testFrame');
	estSizeMovie = (testFrameInfo.bytes/options.bytesToMB)*dataDim.z;
	numSubsets = ceil(estSizeMovie/options.maxChunkSize)+1;
	% get the subsets of the 3D matrix to analyze
	subsets = floor(linspace(1,dataDim.z,numSubsets));
end
function hReadInfo = getHdf5Info(hinfo,options)
	import ciapkg.api.* % import CIAtah functions in ciapkg package API.

	try
		datasetNames = {hinfo.GroupHierarchy.Datasets.Name};
		thisDatasetName = strmatch(options.inputDatasetName,datasetNames);
		hReadInfo = hinfo.GroupHierarchy.Datasets(thisDatasetName);
	catch
		try
			datasetNames = {hinfo.GroupHierarchy.Groups.Datasets.Name};
			thisDatasetName = strmatch(options.inputDatasetName,datasetNames);
			hReadInfo = hinfo.GroupHierarchy.Groups.Datasets(thisDatasetName);
		catch
			nGroups = length(hinfo.GroupHierarchy.Groups);
			datasetNames = {};
			for groupNo = 1:nGroups
				datasetNames{groupNo} = hinfo.GroupHierarchy.Groups(groupNo).Datasets.Name;
			end
			thisDatasetName = strmatch(options.inputDatasetName,datasetNames);
			hReadInfo = hinfo.GroupHierarchy.Groups(thisDatasetName).Datasets;
		end
	end
end