function [opts,rem_opts] = vgg_argparse(opts,varargin)

%VGG_ARGPARSE  Parse variable arguments into a structure
%  opts = vgg_argparse(inopts,varargin)
%    inopts: structure (cells array) listing valid members and default values
%    varargin: variable arguments of form '<name>',<value>,...
%    opts: opts modified by varargin
%
%  Example:
%    function f = foo(varargin)
%    opts = vgg_argparse(struct('maxiters',10,'verbose',0), varargin)
%    ...
%
%  An unknown option (ie, present in varargin but absent in inopts)
%  causes an error. Calling the function as
%  [opts,rem_opts] = vgg_argparse(inopts,varargin) returns the unknown
%  option(s) in rem_opts for later use rather than causes an error.
%
%  May also use OPTS = VGG_ARGPARSE(OPTS, ASTRUCT) where ASTRUCT is a struct
%  of options.

% Author: Mark Everingham <me@robots.ox.ac.uk>
% modified by werner, Jan 03
% Date: 16 Jan 02

if iscell(opts)
  opts=struct(opts{:});
end

if length(varargin) & iscell(varargin{1})
    if isempty(varargin{1})
        inopts = struct([]);
    else
        inopts=struct(varargin{1}{:});
    end
else
    if isempty(varargin)
        inopts = struct([]);
    elseif isstruct(varargin{1})
        inopts = varargin{1};
    else
        inopts=struct(varargin{:});
    end
end

rem_opts = [];
fn = fieldnames(inopts);
for i=1:length(fn)
    if isfield(opts,fn{i})
        %opts.(fn{i})=inopts.(fn{i});
        opts = setfield(opts,fn{i},getfield(inopts,fn{i}));
    else
        if nargout < 2
            error(sprintf('bad argument: ''%s''', fn{i}));
        else
            %rem_opts.(fn{i}) = inopts.(fn{i});
            rem_opts = setfield(rem_opts,fn{i},getfield(inopts,fn{i}));
        end
    end
end


function ADMINrenamefilenames(HOMEANNOTATIONS, Folder)
%
% Writes in the filename field of the xml file the nane of the filename.
%
% This script is useful when changing image and annotation file names. This function guaratees consistency.

% Create list of folders
if nargin == 1
    Folder = folderlist(HOMEANNOTATIONS);
    Folder = [{''} Folder];
end

Nfolders = length(Folder);

for n = 1:Nfolders
    f = Folder{n};

    if ~isempty(fullfile(HOMEANNOTATIONS, f))
        files = dir(fullfile(HOMEANNOTATIONS, f, '*.xml'));

        Nfiles = length(files);
        for i = 1:Nfiles
            newname = files(i).name;
            newname = strrep(newname, '.xml', '.jpg');

            % load annotation
            dest = fullfile(HOMEANNOTATIONS, f, files(i).name);
            xml = loadxml(dest);

            % change inside annotation file
            ii = strfind(xml, '<filename>');
            jj = strfind(xml, '</filename>');
            oldname = strtrim(xml(ii+10:jj-1));

            if ~strcmp(oldname, newname)
                disp('rename filename field inside xml')

                xml = [xml(1:ii+9) newname xml(jj:end)];

                % save annotation
                fid = fopen(dest, 'w');
                fprintf(fid, xml');
                fclose(fid);
            end
        end
    end

end

function xml = loadxml(filename)
[fid, message] = fopen(filename,'r');
if fid == -1; error(message); end
xml = fread(fid, 'uint8=>char');
fclose(fid);
xml = xml';


function [ObjHandle, varargout] = guipanel(varargin)

%% Parse Child -----------------------------------------------------------%
child = inputParser;
child.StructExpand = true;
child.KeepUnmatched = true;

%Interuptible: Defaults to off
child.addParamValue('Interruptible','off')

%BusyAction: Defaults to cancel
child.addParamValue('BusyAction','queue')

%Child's Parent: Defaults to new fig if Param/Value pair is missing
if (nargin >= 1) && ~ischar(varargin{1})
    assert(ishandle(varargin{1}),'guipanel:badHandle',...
        ['When creating a guipanel inside an existing figure/panel, ',...
        'the first argument must be a currently existing/valid graphics handle'])
    child.addOptional('Parent',varargin{1})
else
    %-% NOTICE %-%
    % The figure handle is generated by evaluating a figure command at the
    % time the addParamValue method is called.
    child.addParamValue('Parent',figure);
end

%% Finish Parsing and Instantiate ----------------------------------------%
%   We have only slightly differed from the calling syntax of uipanel.
%   Specifically, guipanel may be called with a single argument, the handle
%   of a pre-existing figure or pre-exisiting panel (this allows easy
%   nesting of panels).

child.parse(varargin{:});

if ~any(strcmp('BusyAction',child.UsingDefaults));
    warning('guipanel:defaultOverWrite',...
        'Setting ''BusyAction'' to ''cancel'' may cause unexpected gui behavior')
end

if ~any(strcmp('Interruptible',child.UsingDefaults));
    warning('guipanel:defaultOverWrite',...
        'Setting ''Interruptible'' to ''on'' may cause unexpected gui behavior')
end

assert(ishandle(child.Results.Parent),'guipanel:badHandle',...
    '%s is not a valid graphics handle',num2str(child.Results.Parent))
    %Create a panel in the specified container (Figure or Panel)
    if isempty(fieldnames(child.Unmatched))
        ObjHandle = uipanel(child.Results,...
            'ButtonDownFcn',@PanelButtonDownFcn);
    else
        ObjHandle = uipanel(child.Results,...
            child.Unmatched,...
            'ButtonDownFcn',@PanelButtonDownFcn);
    end
   %inputParser class is poorly behaved, manually free mem
    clear child

    %Create togglebutton in the panel.  Togglebutton will lock panel in
    %place when activated, and release the panel when deactivated.
    uicontrol(ObjHandle,...
        'Style','togglebutton',...
        'Units','pixels',...
        'BackgroundColor','red',...
        'Position',[4 2 9 9],...
        'ToolTipString','Lock',...
        'Tag','Lock',...
        'Callback',@LockPanelCallback);

    %% Begin callbacks and guipanel subfcns

    function PanelButtonDownFcn(src,event)

        uistack(src,'top') %just in case
        if ~get(findobj('Parent',src,...
                'Type','uicontrol',...
                'Style','togglebutton',...
                'Tag','Lock'),'Value')

            %Get parent container of src
            parent = get(src,'Parent');

            %Get parent figure of src
            fig = ancestor(src,'figure');

            %Sync units
            old_units = SyncUnits([0,src,parent,fig],'pixels');

            %Position of src relative to parent figure
            pos_r2fig = getpixelposition(src,true);

            %Position of src relative to parent container
            pos_r2par = getpixelposition(src);

            %Position of pointer relative to parent figure
            point_r2fig = Root2Fig(get(0,'PointerLocation'),fig);

            [epsX,epsY] = MakeEpsilon(point_r2fig,pos_r2fig);
            if any(abs(epsX) <= 10) || any(abs(epsY) <= 10)
                %RESIZE
                set(fig,'Pointer','fleur')
                if fig == parent
                    position = rbbox(pos_r2par);
                    setpixelposition(src,position)
                else
                    position = rbbox(pos_r2fig);
                    setpixelposition(src,position,true)
                end
            else
                %MOVE
                set(fig,'Pointer','fleur')
                if fig == parent
                    position = dragrect(pos_r2fig);
                    setpixelposition(src,position)
                else
                    position = dragrect(pos_r2fig);
                    setpixelposition(src,position,true)
                end
            end
            set(fig,'Pointer','arrow')
            UnSyncUnits(old_units)
            refresh(fig)
        end
    end

    function LockPanelCallback(src,event)
        if get(src,'Value')
            set(src,'BackgroundColor','white')
        else
            set(src,'BackgroundColor','red')
        end
    end

    varargout{1} = struct(...
        'Root2Fig',@Root2Fig,...
        'Parent2Child',@Parent2Child,...
        'MakeEpsilon',@MakeEpsilon,...
        'MakeRect',@MakeRect,...
        'SyncUnits',@SyncUnits,...
        'UnSyncUnits',@UnSyncUnits,...
        'OverlapingAt',@OverlappingAt);
end

%% Utility Functions -----------------------------------------------------%
%

function coords = Root2Fig(point, fig)
% Transforms point from root-centric to child-centric coordinates.
% Point is measured in the parent's reference frame

if fig == 0
    coords = point;
    return
end

oldUnits = SyncUnits([0,fig],'Pixels');

%Get position of user specified point relative to the Root
PxRoot = point(1); PyRoot = point(2);

%Get position of Figure relative to the Root
figloc = get(fig,'Position');
FigOriginX = figloc(1); FigOriginY = figloc(2);

%Send cursor coordinates from Root to Figure reference frame:
PxRoot2Fig = (PxRoot - FigOriginX); PyRoot2Fig = (PyRoot - FigOriginY);

%Clean up and return result
coords = [PxRoot2Fig,PyRoot2Fig];
UnSyncUnits(oldUnits)

end
function coords = Parent2Child(point, child)
% Transforms point from parent-centric to child-centric coordinates.
% Point is measured in the parent's reference frame
parent = ancestor(child,{'figure','uipanel'});
fig = ancestor(child,'figure');
oldUnits = SyncUnits([0,fig,parent,child],'pixels');

%Root->Figure
r2f = Root2Fig(point, fig);

%Parent's position in Figure frame
if (parent ~= 0) && (parent ~= fig)
    parent_position = getpixelposition(parent,true);
    x = r2f(1) - parent_position(1);
    y = r2f(2) - parent_position(2);
    coords = [x,y];
else
    coords = r2f;
end

UnSyncUnits(oldUnits)

end
function varargout = MakeEpsilon(point, position_vector)
%Determine a position vector's left/right & top/bottom distances from a point
%
%   Calling syntax:
%       [epsX,epsY] = MakeEpsilon(point, vector)
%       [X_right,X_left,Y_bottom,Y_top] = MakeEpsilon(point,vector)
%       Where point is 1x2
%       or
%
%       [X_right,X_left,Y_bottom,Y_top] = MakeEpsilon(vector1,vector2)
%       Where vector1 is 1x4xN, and vector2 is 1x4.  In the case that
%       N > 1, each of X_right, X_left, Y_bottom, and Y_top will be
%       1x1xN.
%
%   If epsX(1) <= 0 &&  epsX(2) >= 0 then px is inside the
%   horizontal boundaries.
%
%   If epsY(1) <= 0 &&  epsY(2) >= 0 then py is inside the vertical
%   boundaries.
%
    assert(nargin == 2,'Too few/Too many inputs, MakeEpsilon requires two input args')
    if nargout
        %assert((nargout == 2) || (nargout == 4), 'MakeEpsilon takes either two or four output args')
    end

    sz = size(point);

    switch mat2str(sz)
        case '[1 2]'
            [epsX,epsY] = epsilonPointSubFcn(point, position_vector);
            varargout{1} = epsX; varargout{2} = epsY;
            return
        case '[1 4]'
            [X_right,X_left,Y_bottom,Y_top] = epsilonVectorSubFcn(point,position_vector);
        otherwise
            try
                [X_right,X_left,Y_bottom,Y_top] = epsilonVectorSubFcn(point,position_vector);
            catch ME
                ME.message
                error('guiSubFcn:MakeEpsilon','Cannot reconcile input')
            end
    end

    varargout{1} = X_right; varargout{2} = X_left;
    varargout{3} = Y_bottom; varargout{4} = Y_top;

    function varargout = epsilonPointSubFcn(pnt, pos)
        %Do horz
        leftXlim = pos(1)-pnt(:,1);
        rightXlim = pos(1)+pos(3)-pnt(:,1);
        epsX = [leftXlim, rightXlim];
        %Do vert
        bottomYlim = pos(2)-pnt(:,2);
        topYlim = pos(2)+pos(4)-pnt(:,2);
        epsY = [bottomYlim, topYlim];
        %Parse outputs
        if nargout ==2
            varargout{1} = epsX; varargout{2} = epsY;
        else
            varargout{1} = epsX(:,1); varargout{2} = epsX(:,2);
            varargout{3} = epsY(:,1); varargout{4} = epsY(:,2);
        end
    end
    function varargout = epsilonVectorSubFcn(pos1,pos2)
       [rectX,rectY] = MakeRect(pos1); %todo, overload MakeRect to accept pos vecs
       %rectX, rectY will each be 4x1
       pnt_array = [rectX,rectY];
       [X_right,X_left,Y_bottom,Y_top] = epsilonPointSubFcn(pnt_array, pos2);
       varargout{1} = X_right; varargout{2} = X_left;
       varargout{3} = Y_bottom; varargout{4} = Y_top;
    end

end
function [rectX,rectY] = MakeRect(position_vector)
%MakeRect takes a position vector and creates X,Y vertices for the
%corresponding rectangle. The position vector can be a (1,4,N)
%multidimensional array.
bottomLeft = [position_vector(:,1,:),position_vector(:,2,:)];
bottomRight = [position_vector(:,1,:)+position_vector(:,3,:),position_vector(:,2,:)];
topRight = [position_vector(:,1,:)+position_vector(:,3,:),position_vector(:,2,:)+position_vector(:,4,:)];
topLeft = [position_vector(:,1,:),position_vector(:,2,:)+position_vector(:,4,:)];
coords = [bottomLeft; bottomRight; topRight; topLeft];
rectX = coords(:,1,:); rectY = coords(:,2,:);
end
function oldHandleUnits = SyncUnits(handles, trgt_units)
% oldUnits is a n x 2 cell array where oldUnits{:,1} == handles
% and oldUnits{:,2} == "Units"
if nargout < 1
    warning('utilityFcns:reconcileUnits',...
        'old units not recorded, new units still set')
elseif nargout > 1
    error('Too many output arguments')
elseif nargin < 2 || ~ischar(trgt_units)
    error('Target units not specified')
end
[m,n] = size(handles);
handles = reshape(handles,m*n,1); % Turn handles into column vector
oldUnits = get(handles,'Units');

handles_cell = mat2cell(handles, ones(1,m*n), 1); % Turn handles into cell
oldHandleUnits = [handles_cell, oldUnits];

%Set new units last as a precautionary -- if exception arises at
%least we might recover the old units.
try
    set(handles, 'Units', trgt_units)
catch ME
    ME.message
    error('Unable to set units')
end

end
function UnSyncUnits(old_handle_units)
    arrayfun(@(k)set(old_handle_units{k,1},'Units',old_handle_units{k,2}),...
        1:1:size(old_handle_units,1))
end
function [adjacencyMatrix,varargout] = OverlappingAt(position_vector)
%Returns the adjacency matrix indicating the overlap of any of N rectangles
%as specified by the Nx4 array of position vectors, position_vector.  If
%called with two outputs, the second output is matrix where the (i,j)th
%element is the area of overlap between position_vector(i,:) and position_vector(j,:).
%

area = rectint(position_vector,position_vector);
density = nnz(area) / numel(area);
if density <= 0.4
    area = sparse(area);
end
area = area - diag(diag(area)); %removes self-reference
if nargout == 2
    varargout{1} = area;
end
adjacencyMatrix = (area ~= 0);
end


function varargout=cosmo_warning(message, varargin)
% show a warning message; by default just once for each message
%
% cosmo_warning(message, ...)
% cosmo_warning(state)
% state=cosmo_warning()
%
% Inputs:
%   message      warning message to be shown, or one of:
%                'on'   : show all warning messages
%                'off'  : show no warning messages
%                'once' : show each warning message once [default]
%                'reset':
%   ...          if a warning message is provided according with
%                placeholders as used in sprintf, then the subsequent
%                arguments should contain their values
%   state        if a struct, then this queries or sets the state of
%                cosmo_warning.
%
% Notes:
%   - this function works more or less like matlab's warning function,
%     except that by default each warning is just shown once.
%
% #   For CoSMoMVPA's copyright information and license terms,   #
% #   see the COPYING file distributed with CoSMoMVPA.           #

    if isempty(get_from_state('when'))
        set_default_state();
    end

    if nargin==0
        varargout={get_state()};
        return
    end

    if isstruct(message)
        set_state(message);
        return
    end

    lmessage=lower(message);

    switch lmessage
        case {'on','off','once'}
            update_state('when',lmessage);
            return;

        case 'reset'
            set_default_state();
            return;

        otherwise
            show_warning(message,varargin{:});
    end

function show_warning(message,varargin)
    [identifier,full_message]=get_identifier_and_message(...
                                    message,varargin{:});

    shown_warnings=get_from_state('shown_warnings');
    has_warning=cosmo_match({full_message},shown_warnings);
    if ~has_warning
        shown_warnings{end+1}=full_message;
        update_state('shown_warnings',shown_warnings);
    end

    when=get_from_state('when');
    switch when
        case 'once'
            do_show_warning=~has_warning;

            me=mfilename();
            postfix=sprintf(['\n\nThis warning is shown only once, '...
                           'but the underlying issue may occur '...
                           'multiple times. To show each warning:\n'...
                           ' - every time:   %s(''on'')\n'...
                           ' - once:         %s(''once'')\n'...
                           ' - never:        %s(''off'')\n'],me,me,me);
            full_message=[full_message postfix];

        case 'off'
            do_show_warning=false;
        case 'on'
            do_show_warning=true;
        otherwise
            assert(false);
    end

    if do_show_warning
        state=warning(); % store state
        state_resetter=onCleanup(@()warning(state));

        warning('on','all');
        % avoid extra entry on the stack
        has_identifier=~isempty(identifier);

        if has_identifier
            warning(identifier,'%s',full_message);
        else
            warning('%s',full_message);
        end
    end

function [identifier,full_message]=get_identifier_and_message(...
                                            message,varargin)
    args=varargin;
    has_identifier=numel(args)>0 && has_warning_identifier(message);
    if has_identifier
        identifier=message;
        message=args{1};
        args=args(2:end);
    else
        identifier='';
    end

    if numel(args)>0
        full_message=sprintf(message, args{:});
    else
        full_message=message;
    end

function tf=has_warning_identifier(s)
    alpha_num='([a-z_A-Z0-9]+)';
    pat=sprintf('^%s(:%s)?:%s$',alpha_num,alpha_num,alpha_num);
    tf=~isempty(regexp(s,pat,'once'));

function s=get_state()
    s=get_or_set_state();

function set_state(s)
    get_or_set_state(s);

function set_default_state()
    s=struct();
    s.when='once';
    s.shown_warnings=cell(0);
    set_state(s);

function value=get_from_state(key)
    s=get_state();
    value=s.(key);

function update_state(key, value)
    s=get_state();
    s.(key)=value;
    set_state(s);

function varargout=get_or_set_state(s)
    persistent state;
    switch nargin
        case 0
            % get state
            if isempty(state)
                set_default_state();
            end

            varargout={state};

        case 1
            % set state
            state=s;
            varargout={};

        otherwise
            assert(false);
    end


function [output] = viewTableOnFigure(inputTable,varargin)
	% Adds a table to a figure.
	% Biafra Ahanonu
	% started: 2014.01.03 [19:13:01]
	% inputs
		%
	% outputs
		%

	% changelog
		% 2021.08.08 [19:30:20] - Updated to handle CIAtah v4.0 switch to all functions inside ciapkg package.
	% TODO
		%

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

	%========================
	options.newFig = 1;
	% handle to previous table
	options.tableHandle = [];
	% row, column, value
	options.updateTable = {};
	% get options
	options = getOptions(options,varargin);
	% display(options)
	% unpack options into current workspace
	% fn=fieldnames(options);
	% for i=1:length(fn)
	% 	eval([fn{i} '=options.' fn{i} ';']);
	% end
	%========================

	try
		output = 1;
		if ~isempty(options.tableHandle)
			% set(t,'Data',data);
			t = options.tableHandle;

			% t.Data{[options.updateTable{1}],[options.updateTable{2}]} = {options.updateTable{3}};
			t.Data([options.updateTable{1}],[options.updateTable{2}]) = options.updateTable{3};

			% jscroll = findjobj(t);
			% jtable = jscroll.getViewport.getComponent(0);
			% jtable.setValueAt(java.lang.String(options.updateTable{3}),options.updateTable{1},options.updateTable{2}); % to insert this value in cell (1,1)

			output = t;
		else
			% uitable('Data',T{:,:},'ColumnName',T.Properties.VariableNames,...
			    % 'RowName',T.Properties.RowNames,'Units', 'Normalized', 'Position',[0, 0, 1, 1]);

			if options.newFig==1
		    	f = figure;
		    	% pause(0.05)
		    	pause(2)
		    else
		    	clf
		    	f = gcf;
		    end
	        fp = get(f, 'Position');
		    t = uitable(f);
		    output = t;
		    % for i = 1:size(T,1)
		    % 	for j = 1:size(T,2)
		    % 			T(i,j) = {num2str(T{i,j})};
		    % 		try
			   %  	catch
			   %  	end
		    % 	end
		    % end
		    % class(T{1,1})
		    T2 = table2cell(inputTable);
		    t.Data = T2;
		    t.RowName = inputTable.Properties.RowNames;
		    t.ColumnName = inputTable.Properties.VariableNames;
		    % Figure-Size
		    t.Position = [0 0 fp(3:4)];
		    % t.Data = char(T{:,:});
		    % set(f, 'ResizeFcn', {@resizeCallback, gcf, t, T2});

			% % Get the table in string form.
			% TString = evalc('disp(T)');
			% % Use TeX Markup for bold formatting and underscores.
			% TString = strrep(TString,'<strong>','\bf');
			% TString = strrep(TString,'</strong>','\rm');
			% TString = strrep(TString,'_','\_');
			% % Get a fixed-width font.
			% FixedWidth = get(0,'FixedWidthFontName');
			% % Output the table using the annotation command.
			% annotation(gcf,'Textbox','String',TString,'Interpreter','Tex',...
			%     'FontName',FixedWidth,'FontSize',7,'Units','Normalized','Position',[0 0 1 1]);
		end
	catch err
		display(repmat('@',1,7))
		disp(getReport(err,'extended','hyperlinks','on'));
		display(repmat('@',1,7))
	end
end
% function resizeCallback(hFig, ~, hAx, t, T2)
% 	pause(0.05)
%     fp = get(hFig, 'Position');
%     t.Position = [0 0 fp(3:4)];
% 	    t.Data = T2;
% end


function s = structrmfield(s,flds)
% s = structrmfield(s,flds)
% rmfield with removal of nested fields allowed
%
% Elements of flds which are not present in s are silently ignored.
%
% Example:
% flds = {'fld1','fld2.subfld'};
% s = structrmfield(s,flds);

assert(isstruct(s) && isscalar(s));
if ischar(flds)
  flds = cellstr(flds);
end
assert(iscellstr(flds));

for f = flds(:)',f=f{1}; %#ok<FXSET>
  fsplit = regexp(f,'\.','split');
  if isscalar(fsplit)
    fldRm = fsplit{1};
    if isfield(s,fldRm)
      s = rmfield(s,fldRm);
    else
      %warning('structrmfield:noField','No field ''%s''.',fldRm);
    end
  else
    fldTop = fsplit{1};
    fldRemainder = f(numel(fldTop)+2:end);
    valTop = s.(fldTop);
    if ~isstruct(valTop)
      %warning('structrmfield:badField','Expected field ''%s'' to be a struct.',fldTop);
    else
      s.(fldTop) = structrmfield(valTop,fldRemainder);
    end
  end
end


 function h = sgtitlef(varargin)
%function h = sgtitlef(varargin)
%|
%| version of sgtitle with built-in sprintf
%| and defaults to latex interpreter
%| also supports default font size from ir_fontsize()
%|
%| Jeff Fessler, University of Michigan

if nargin < 1, ir_usage, end

opt = {'fontsize', ir_fontsize('title')};
%opt = {opt{:}, 'fontname', 'times'};

if ir_is_octave
	opt = {opt{:}, 'fontname', 'Helvetica'};
end

varargin{1} = ir_strrep_tex(varargin{1}); % trick

if ir_is_octave
	tex = {};
	str = varargin{1};
	str = strrep(str, '$', ''); % remove $ needed for latex
	varargin{1} = str;
else
	tex = {'interpreter', 'latex'};
	str = varargin{1};
	str = strrep(str, '\', '\\'); % because of sprintf below
	% trick to replace "|" with "$|$" in strings
	if ~isempty(strfind(str, '|')) && isempty(strfind(str, '$'))
		str = strrep(str, '|', '$|$');
	end
	varargin{1} = str;
end

if isfreemat
	for ii=1:length(varargin)
		if streq(varargin{ii}, 'interpreter') % not supported by freemat
			varargin{ii} = {};
			varargin{ii+1} = {};
		end
	end
end

if im
	tmp = sprintf(varargin{:});
	tmp = strrep(tmp, '%', '\%'); % else latex will ignore %
	hh = sgtitle(tmp, tex{:}, opt{:});
else
	hh = [];
end

if nargout
	h = hh;
end


function article=indefiniteArticle(phrase)
% A simple function that returns the indefinite articles "a" or "an" based on a given word or phrase.
% based on the javascript implementation: https://github.com/rigoneri/indefinite-article.js/blob/master/indefinite-article.js
% indefiniteArticle('')
% indefiniteArticle('apple pie')
% indefiniteArticle('vision group')
% indefiniteArticle('Priceton local restaurant')

   % Getting the first word
    [~,match] = regexp(phrase,'\w+');

    if ~isempty(match)
        word = phrase(1:match(1));
    else
        article=''; return;
    end

    l_word = lower(word);
    % Specific start of words that should be preceeded by 'an'
    alt_cases = {'honest', 'hour', 'hono'};
    for i=1:length(alt_cases)
        t = strfind(l_word, alt_cases{i});
        if (~isempty(t) && t(1) == 1)
            article='an'; return;
        end
    end

    % Single letter word which should be preceeded by 'an'
    if length(l_word) == 1
        if ~isempty(strfind('aedhilmnorsx',l_word))
            article='an'; return;
        else
            article='a'; return;
        end
    end

    % Capital words which should likely be preceeded by 'an'

    match = regexp(word,'(?!FJO|[HLMNS]Y.|RY[EO]|SQU|(F[LR]?|[HL]|MN?|N|RH?|S[CHKLMNPTVW]?|X(YL)?)[AEIOU])[FHLMNRSX][A-Z]', 'once');
    if ~isempty(match)
        article='an'; return;
    end

    % Special cases where a word that begins with a vowel should be preceeded by 'a'
    regexes = {'^e[uw]', '^onc?e\b', '^uni([^nmd]|mo)', '^u[bcfhjkqrst][aeiou]'};
    for i=1:length(regexes)
        match = regexp(l_word,regexes{i}, 'once');
        if ~isempty(match)
            article='a'; return;
        end
    end

    % Special capital words (UK, UN)
    match = regexp(word,'^U[NK][AIEO]', 'once');
    if ~isempty(match)
        article='a'; return;
    else
        if strcmp(word, upper(word))
            if ~isempty(strfind('aedhilmnorsx',l_word(1)))
                article='an'; return;
            else
                article='a'; return;
            end
        end
    end

    % Basic method of words that begin with a vowel being preceeded by 'an'
    if ~isempty(strfind('aeiou',l_word(1)))
        article='an'; return;
    end

    % Instances where y follwed by specific letters is preceeded by 'an'
    match = regexp(l_word,'^y(b[lor]|cl[ea]|fere|gg|p[ios]|rou|tt)', 'once');
    if ~isempty(match)
        article='an'; return;
    end

    article='a'; return;


function address = getaddress(hostname)

% GETADDRESS returns the IP address
%
% Use as
%   address = getaddress();
% or
%   address = getaddress(hostname);
%
% See also GETUSERNAME, GETHOSTNAME

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

% this is to speed up subsequent calls
persistent previous_argin previous_argout

if nargin==0
  hostname = [];
end

if ~isempty(previous_argout) && isequal(hostname, previous_argin)
  address = previous_argout;
  return
end

if usejava('jvm')
  if ~isempty(hostname)
    address = java.net.InetAddress.getByName(hostname);
  else
    address = java.net.InetAddress.getLocalHost;
  end
  address = char(address.getHostAddress);
else
  % FIXME it would be possible to do a system call, but it would be different for linux, osx and windows
  address = '127.0.0.1';
end

% remember for subsequent calls
previous_argin  = hostname;
previous_argout = address;


function enforceFields(structure, field_names)
%ENFORCEFIELDS   Checks structure field names for existance.
%
% DESCRIPTION:
%       enforceFields checks a MATLAB structure for the existance of a set
%       of required field name defined by a cell array. If a field name
%       within the cell array is not found within the structure, an error
%       is thrown with the name of the missing field given in the error
%       message. The function is useful for enforcing a set of required
%       fields within a structure.
%
% USAGE:
%       enforceFields(structure, field_names)
%
% INPUTS:
%       structure   - MATLAB structure
%       field_names - cell array of allowable field names
%
% ABOUT:
%       author      - Bradley Treeby
%       date        - 13th October 2009
%       last update - 13th October 2009
%
% This function is part of the k-Wave Toolbox (http://www.k-wave.org)
% Copyright (C) 2009-2014 Bradley Treeby and Ben Cox
%
% See also fieldnames

% This file is part of k-Wave. k-Wave is free software: you can
% redistribute it and/or modify it under the terms of the GNU Lesser
% General Public License as published by the Free Software Foundation,
% either version 3 of the License, or (at your option) any later version.
%
% k-Wave 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 Lesser General Public License for
% more details.
%
% You should have received a copy of the GNU Lesser General Public License
% along with k-Wave. If not, see <http://www.gnu.org/licenses/>.

names = fieldnames(structure);
for field_index = 1:length(field_names)
    field_found = false;
    for names_index = 1:length(names)
        if strcmp(field_names{field_index}, names{names_index})
            field_found = true;
        end
    end
    if ~field_found
    	error(['The field ' inputname(1) '.' field_names{field_index} ' must be defined']);
    end
end


function v = isabspath(filename)

if isempty(filename),
  v = false;
  return;
end

if isunix,
  v = filename(1) == '/';
else
  v = numel(filename) > 1 && filename(2) == ':';
end


function test_suite = test_TestSuiteInDir
%test_TestSuiteInDir Unit test for TestSuiteInDir class.

%   Steven L. Eddins
%   Copyright 2009 The MathWorks, Inc.

initTestSuite;

function test_constructor
this_test_path = fileparts(which(mfilename));
cwd_test_dir = fullfile(this_test_path, 'cwd_test');
suite = TestSuiteInDir(cwd_test_dir);

assertEqual(suite.Name, 'cwd_test');
assertEqual(suite.Location, cwd_test_dir);

function test_gatherTestCases
this_test_path = fileparts(which(mfilename));
cwd_test_dir = fullfile(this_test_path, 'cwd_test');
suite = TestSuiteInDir(cwd_test_dir);
suite.gatherTestCases();

assertEqual(numel(suite.TestComponents), 3);


function datapt = lvd_EngineTasks(stateLogEntry, subTask, engine)
%lvd_EngineTasks Summary of this function goes here
%   Detailed explanation goes here

    switch subTask
        case 'active'
            engineStates = stateLogEntry.getAllEngineStates();
            engineState = engineStates([engineStates.engine] == engine);

            if(not(isempty(engineState)))
                engineState = engineState(1);
                datapt = double(engineState.active);
            else
                datapt = -1;
            end
    end
end


% The COBRAToolbox: testMets2str.m
%
% Purpose:
%     - testMets2str tests the functionality of mets2str in the
%     rBioNet extension
%
% Authors:
%     - Stefania Magnusdottir April 2017
%

% save the current path
currentDir = pwd;

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

% load rBioNet reaction database
load([fileDir, filesep 'rxn.mat'])

% concatenate cell array of strings into one string
outstr = mets2str(rxn(1:3, 1));

% test that output is a string
assert(ischar(outstr))

% change the directory
cd(currentDir)


function succ = install_matpower(modify, save_it, verbose, rm_oldpaths)
%INSTALL_MATPOWER  Assist user in setting path to install MATPOWER.
%   INSTALL_MATPOWER
%   INSTALL_MATPOWER(MODIFY)
%   INSTALL_MATPOWER(MODIFY, SAVE_IT)
%   INSTALL_MATPOWER(MODIFY, SAVE_IT, VERBOSE)
%   INSTALL_MATPOWER(MODIFY, SAVE_IT, VERBOSE, RM_OLDPATHS)
%   SUCCESS = INSTALL_MATPOWER(...)
%
%   Assists the user in setting up the proper MATLAB/Octave path to
%   be able to use MATPOWER and run its tests. With no input arguments
%   it prompts interactively to determine how to handle the paths.
%
%   Inputs (all are optional):
%       MODIFY : select how to set path
%           0 (default) - generate relevant ADDPATH() commands, but
%               don't execute them
%           1 - modify the path directly executing the relevant
%               ADDPATH() commands
%       SAVE_IT : indicates whether or not to save the results
%           0 or [] (default) - don't save any results
%           if MODIFY is 0
%               SAVE_IT = <string> : the relevant ADDPATH() commands
%                   are saved to a file whose name is provided in SAVE_IT
%               SAVE_IT = <other true value> : the relevant ADDPATH() commands
%                   are saved to a file named 'startup.m' in the current
%                   directory
%               otherwise : the commands are displayed, but not saved
%           if MODIFY is 1
%               SAVE_IT = <any true value> : the path will be modified
%                   and saved with SAVEPATH
%               otherwise : the path will be modified but not saved
%       VERBOSE : prints the relevant ADDPATH commands if true (default),
%               silent otherwise
%       RM_OLDPATHS : remove existing installation
%           0 (default) - do NOT remove existing MATPOWER from path
%           1 - remove existing MATPOWER paths first
%
%   Outputs (all are optional):
%       SUCCESS : 1 if all commands succeeded, 0 otherwise
%
%   Examples:
%       install_matpower;           %% print the required ADDPATH() commands
%       install_matpower(0, 1);     %% save the commands to startup.m
%       install_matpower(1, 1);     %% modify my path and save
%       install_matpower(1, 0, 0);  %% modify my path temporarily and silently
%       install_matpower(0, 'matpower6');   %% save the commands to matpower6.m
%       install_matpower(0, 0, 1, 1);   %% uninstall MATPOWER from path
%                                   %% (must call SAVEPATH separately
%                                   %%  to make permanent)
%
%   See also ADDPATH, SAVEPATH.

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

%% installation data for each component
min_ver.Octave = '4.0.0';
min_ver.MATLAB = '7.5.0';
install = struct( ...
    'name', { ...       %% (not currently used)
        'matpower', ...
        'most', ...
        'mp-opt-model', ...
        'mips', ...
        'mptest', ...
        'maxloadlim', ...
        'misc', ...
        'reduction', ...
        'sdp_pf', ...
        'se', ...
        'simulink_matpower', ...
        'smartmarket', ...
        'state_estimator', ...
        'syngrid' }, ...
    'dirs', { ...       %% directories to add to path
        {{'lib'}, {'lib', 't'}, {'data'}}, ...
        {{'most', 'lib'}, {'most', 'lib', 't'}}, ...
        {{'mp-opt-model', 'lib'}, {'mp-opt-model', 'lib', 't'}}, ...
        {{'mips', 'lib'}, {'mips', 'lib', 't'}}, ...
        {{'mptest', 'lib'}, {'mptest', 'lib', 't'}}, ...
        {{'extras', 'maxloadlim'}, {'extras', 'maxloadlim', 'tests'}, ...
            {'extras', 'maxloadlim', 'examples'}}, ...
        {{'extras', 'misc'}}, ...
        {{'extras', 'reduction'}}, ...
        {{'extras', 'sdp_pf'}}, ...
        {{'extras', 'se'}}, ...
        {{'extras', 'simulink_matpower'}, ...
            {'extras', 'simulink_matpower', 'helper_functions'}, ...
            {'extras', 'simulink_matpower', 'helper_functions', 'getter_setter_functions'}}, ...
        {{'extras', 'smartmarket'}}, ...
        {{'extras', 'state_estimator'}}, ...
        {{'extras', 'syngrid', 'lib'}, {'extras', 'syngrid', 'lib', 't'}} }, ...
    'fcns', { ...       %% functions to search for to find old paths to remove
        {'mpver', 'test_matpower', 'case9'}, ...
        {'mostver', 'test_most'}, ...
        {'mpomver', 'test_mp_opt_model'}, ...
        {'mipsver', 'test_mips'}, ...
        {'t_begin', 'test_mptest'}, ...
        {'maxloadlim', 'test_mll_main', 'example_ieee9.m'}, ...
        {'checklimits'}, ...
        {'MPReduction'}, ...
        {'sdp_pf_ver'}, ...
        {'run_se'}, ...
        {'SimulinkMATPOWERbase.slx', 'ac_testbed_setup', 'get_losses_from_matpower'}, ...
        {'runmarket'}, ...
        {'runse'}, ...
        {'syngrid', 'test_syngrid'} } ...
);
ni = length(install);   %% number of components

%% default arguments
interactive = 0;
if nargin < 4
    rm_oldpaths = 0;
    if nargin < 3
        verbose = 1;
        if nargin < 2
            save_it = 0;
            if nargin < 1
                modify = [];
                interactive = 1;
            end
        end
    end
end

%% get path to new MATPOWER installation root
[root, n, e] = fileparts(which('install_matpower'));

%% MATLAB or Octave
if exist('OCTAVE_VERSION', 'builtin') == 5
    sw = 'Octave';
else
    sw = 'MATLAB';
end

%% check for required version of MATLAB or Octave
vstr = '';
switch sw
    case 'Octave'
        v = ver('octave');
    case 'MATLAB'
        v = ver('matlab');
        if length(v) > 1
            warning('The built-in VER command is behaving strangely, probably as a result of installing a 3rd party toolbox in a directory named ''matlab'' on your path. Check each element of the output of ver(''matlab'') to find the offending toolbox, then move the toolbox to a more appropriately named directory.');
            v = v(1);
        end
end
if ~isempty(v) && isfield(v, 'Version') && ~isempty(v.Version)
    vstr = v.Version;
    if vstr2num(vstr) < vstr2num(min_ver.(sw))
        error('\n\n%s\n  MATPOWER requires %s %s or later.\n      You are using %s %s.\n%s\n\n', repmat('!',1,45), sw, min_ver.(sw), sw, vstr, repmat('!',1,45));
    end
else
    warning('\n\n%s\n  Unable to determine your %s version. This indicates\n  a likely problem with your %s installation.\n%s\n', repmat('!',1,60), sw, sw, repmat('!',1,60));
end

%% get installation options interactively, if necessary
div_line = sprintf('\n-------------------------------------------------------------------\n\n');
if interactive
    fprintf(div_line);
    fprintf('MATPOWER Installation Options:\n\n');
    fprintf('   1. Do NOT modify the %s path\n', sw);
    fprintf('          (just generate the required ADDPATH commands)\n');
    fprintf('   2. DO modify the %s path, but only temporarily\n', sw);
    fprintf('          (you will have to do it again next time you run %s)\n', sw);
    fprintf('   3. DO modify the %s path, and SAVE the updated path\n', sw);
    fprintf('          (so you will not have to do it again next time you run %s)\n\n', sw);
    s = 0;
    while ~isempty(s) && (s < 1 || s > 3 || rem(s, 1))
        s = str2num(input('Please enter your selection [1, 2, 3] (default = 1) : ', 's'));
    end
    if isempty(s)
        s = 1;              %% default to option 1
    end
    switch s
        case 1              %% don't modify
            modify = 0;
        case 2              %% modify, don't save
            modify = 1;
            save_it = 0;
        case 3              %% modify and save
            modify = 1;
            save_it = 1;
        otherwise
    end
end

%% find available new components
available = zeros(ni, 1);
for i = 1:ni
    if exist(fullfile(root, install(i).dirs{1}{:}), 'dir')
        available(i) = 1;
    end
    % fprintf('%d %s\n', available(i), fullfile(root, install(i).dirs{:}));
end

%% find paths for currently installed components
oldpaths = {};
for i = 1:ni
    if available(i)     %% only if we have a new replacement
        for k = 1:length(install(i).fcns)
            [p, n, e] = fileparts(which(install(i).fcns{k}));
            if ~isempty(p) && ~ismember(p, oldpaths)
                oldpaths{end+1} = p;
            end
        end
    end
end

if ~isempty(oldpaths)
    if exist('mpver', 'file')
        v = mpver;
    else
        v = '';
    end
    str = sprintf('It appears you already have MATPOWER %s or some of its\n', v);
    str = sprintf('%scomponents installed in the following directories:\n\n', str);
    rm_path_str = '';
    for k = 1:length(oldpaths)
        rm_path_str = sprintf('%s    %s\n', rm_path_str, oldpaths{k});
    end
    if interactive
        fprintf(div_line);
        fprintf('%s%s\n', str, rm_path_str);
        fprintf('Unless you are sure you know what you are doing, we recommend\n');
        fprintf('removing these directories from your %s path before proceeding.\n\n', sw);
        s = '?';
        while ~isempty(s) && (s(1) ~= 'Y' && s(1) ~= 'N')
            s = upper(input('Would you like me to do it for you? [Y or N] (default = N) : ', 's'));
        end
        if isempty(s)
            s = 'N';                %% default to N
        end
        if s(1) == 'Y'
            rm_oldpaths = 1;
        end
    elseif ~rm_oldpaths
        error('install_matpower: %s%s\nPlease remove the old installation first, or re-run\nINSTALL_MATPOWER in interactive mode (no arguments).', str, rm_path_str);
    end

    %% remove old paths
    if rm_oldpaths
        rmpath(oldpaths{:});
        if verbose
            fprintf(div_line);
            fprintf('The following directories were removed from your %s path:\n\n%s\n', sw, rm_path_str);
            if ~modify
                fprintf('You will need to manually use SAVEPATH to make the changes permanent.\n');
                if interactive
                    s = input('Hit any key to continue ...', 's');
                end
            end
        end
    end
end

%% generate paths to add
newpaths = {};
for i = 1:ni
    if available(i)     %% only available components
        for k = 1:length(install(i).dirs)
            p = fullfile(root, install(i).dirs{k}{:});
            if ~isempty(p) && ~ismember(p, newpaths)
                newpaths{end+1} = p;
            end
        end
    end
end

%% build addpath string
cmd = sprintf('addpath( ...\n');
for k = 1:length(newpaths)
    cmd = sprintf('%s    ''%s'', ...\n', cmd, newpaths{k});
end
cmd = sprintf('%s    ''%s'' );\n', cmd, '-end');

%% print addpath
if verbose
    fprintf(div_line);
    if modify
        fprintf('Your %s path will be updated using the following command:\n\n%s', sw, cmd);
        if interactive
            s = input(sprintf('\nHit any key to continue ...'), 's');
        end
    else
        fprintf('Use the following command to add MATPOWER to your %s path:\n\n%s\n', sw, cmd);
    end
end

%% add the new paths
if modify
    addpath(newpaths{:}, '-end');
    if verbose
        fprintf('Your %s path has been updated.\n', sw);
    end
end

%% prompt about saving the command to a file
if interactive && ~modify
    s = '?';
    while ~isempty(s) && (s(1) ~= 'Y' && s(1) ~= 'N')
        s = upper(input('Would you like to save this command to a file? [Y or N] (default = N) : ', 's'));
    end
    if isempty(s)
        s = 'N';                %% default to N
    end
    if s(1) == 'Y'
        %% prompt for file name
        s = '?';
        while ~isempty(s) && s(1) == '?'
            s = input('Please enter the name of file? (default = ''startup.m'') : ', 's');
        end
        if isempty(s)
            s = 'startup.m';    %% default to 'startup.m'
        end
        save_it = s;
    else
        save_it = 0;
    end
end

%% save path
success = 1;
if save_it
    if modify                   %% modify the path directly
        savepath;                   %% save the updated path
        if verbose
            fprintf(div_line);
            fprintf('Your updated %s path has been saved using SAVEPATH.\n', sw);
        end
    else                        %% don't modify the path directly
        %% set up file name
        if ~ischar(save_it)
            save_it = 'startup.m';
        end
        [p, n, e] = fileparts(save_it);
        if isempty(e)
            e = '.m';
        end
        fn = fullfile(p, [n e]);

        %% write file
        if exist(fn, 'file')        %% file exists, print a warning
            if verbose
                fprintf(div_line);
                fprintf('The file ''%s'' was not written. A file with that name already exists.', fn);
            else
                error('install_matpower: file ''%s'' not written, a file with that name already exists', fn);
            end
        else                        %% create the file
            fid = fopen(fn, 'a');
            if fid == -1
                success = 0;
            else
                fprintf(fid, '%%%s\n\n', upper(n));
                fprintf(fid, '%%%% add MATPOWER paths\n');
                fprintf(fid, '%s', cmd);
                fclose(fid);
            end
            if verbose
                fprintf(div_line);
                fprintf('The file ''%s'' containing the commands to\nadd MATPOWER to your %s path has been created.\n', fn, sw);
            end
        end
    end
end

if verbose
    fprintf(div_line);
    if modify
        fprintf('Now that you have added the required directories to your %s path\n', sw);
        fprintf('MATPOWER is installed and ready to use.\n\n');
    else
        fprintf('Once you have added the required directories to your %s path\n', sw);
        fprintf('MATPOWER will be installed and ready to use.\n\n');
    end
    fprintf('You may want to begin by typing: mpver\n');
    fprintf('to see the list of installed MATPOWER related software versions.\n\n');
    fprintf('Or to run the MATPOWER test suite to ensure everything is\n');
    fprintf('working correctly, type: test_matpower\n\n');

    if interactive && modify
        s = '?';
        while ~isempty(s) && (s(1) ~= 'Y' && s(1) ~= 'N')
            s = upper(input('Would you like to run the MATPOWER tests now? [Y or N] (default = N) : ', 's'));
        end
        if isempty(s)
            s = 'N';                %% default to N
        end
        if s(1) == 'Y'
            test_matpower;
        end
    end
end

if nargout
    succ = success;
end

function num = vstr2num(vstr)
% Converts version string to numerical value suitable for < or > comparisons
% E.g. '3.11.4' -->  3.011004
pat = '\.?(\d+)';
[s,e,tE,m,t] = regexp(vstr, pat);
b = 1;
num = 0;
for k = 1:length(t)
    num = num + b * str2num(t{k}{1});
    b = b / 1000;
end


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

    properties
        groundObjs(1,:) LaunchVehicleGroundObject = LaunchVehicleGroundObject.empty(1,0);

        lvdData LvdData
    end

    methods
        function obj = LaunchVehicleGroundObjectSet(lvdData)
            obj.lvdData = lvdData;
        end

        function addGroundObj(obj, groundObj)
            obj.groundObjs(end+1) = groundObj;
            groundObj.groundObjs = obj;
        end

        function removeGroundObj(obj, groundObj)
            obj.groundObjs([obj.groundObjs] == groundObj) = [];
        end

        function [listBoxStr, groundObjs] = getListboxStr(obj)
            listBoxStr = {};

            for(i=1:length(obj.groundObjs))
                listBoxStr{end+1} = obj.groundObjs(i).name; %#ok<AGROW>
            end

            groundObjs = obj.groundObjs;
        end

        function groundObjects = getGroundObjsForInds(obj, inds)
            groundObjects = obj.groundObjs(inds);
        end

        function inds = getIndsForGroundObjs(obj, grdObjs)
            inds = find(ismember(obj.groundObjs, grdObjs));
        end

        function grndObj = getGroundObjAtInd(obj, ind)
            if(ind > 0 && ind <= length(obj.groundObjs))
                grndObj = obj.groundObjs(ind);
            else
                grndObj = LaunchVehicleGroundObject.empty(1,0);
            end
        end

        function numGrndObjs = getNumGroundObj(obj)
            numGrndObjs = length(obj.groundObjs);
        end

        function [grdObjAzGAStr, grdObjs] = getGrdObjAzGraphAnalysisTaskStrs(obj)
            grdObjs = obj.groundObjs;

            grdObjAzGAStr = cell(1,length(grdObjs));
            A = length(grdObjs);
            formSpec = sprintf('%%0%uu',floor(log10(abs(A)+1)) + 1);
            for(i=1:length(grdObjs))
                grdObjAzGAStr{i} = sprintf(sprintf('Ground Object %s Azimuth to S/C - "%s"',formSpec, grdObjs(i).name), i);
            end
        end

        function [grdObjElevGAStr, grdObjs] = getGrdObjElevGraphAnalysisTaskStrs(obj)
            grdObjs = obj.groundObjs;

            grdObjElevGAStr = cell(1,length(grdObjs));
            A = length(grdObjs);
            formSpec = sprintf('%%0%uu',floor(log10(abs(A)+1)) + 1);
            for(i=1:length(grdObjs))
                grdObjElevGAStr{i} = sprintf(sprintf('Ground Object %s Elevation to S/C - "%s"',formSpec, grdObjs(i).name), i);
            end
        end

        function [grdObjRngGAStr, grdObjs] = getGrdObjRangeGraphAnalysisTaskStrs(obj)
            grdObjs = obj.groundObjs;

            grdObjRngGAStr = cell(1,length(grdObjs));
            A = length(grdObjs);
            formSpec = sprintf('%%0%uu',floor(log10(abs(A)+1)) + 1);
            for(i=1:length(grdObjs))
                grdObjRngGAStr{i} = sprintf(sprintf('Ground Object %s Range to S/C - "%s"',formSpec, grdObjs(i).name), i);
            end
        end

        function [grdObjLoSGAStr, grdObjs] = getGrdObjLoSGraphAnalysisTaskStrs(obj)
            grdObjs = obj.groundObjs;

            grdObjLoSGAStr = cell(1,length(grdObjs));
            A = length(grdObjs);
            formSpec = sprintf('%%0%uu',floor(log10(abs(A)+1)) + 1);
            for(i=1:length(grdObjs))
                grdObjLoSGAStr{i} = sprintf(sprintf('Ground Object %s Line of Sight to S/C - "%s"',formSpec, grdObjs(i).name), i);
            end
        end
    end

    methods(Static)
        function obj = loadobj(obj)
            for(i=1:length(obj.groundObjs))
                grdObj = obj.groundObjs(i);

                if(isempty(grdObj.groundObjs))
                    grdObj.groundObjs = obj;
                end
            end
        end
    end
end