function [model,secretionRxnsAdded] = secretionProductGapfill(model,microbeID,database,inputDataFolder)
% This function adds exchange, transport and biosynthesis reactions for
% experimentally shown secreted metabolites according to data collected for
% the DEMETER pipeline.
%
% USAGE:
%
%   [model,secretionRxnsAdded] = secretionProductGapfill(model,microbeID,database,inputDataFolder)
%
% INPUTS
% model:                COBRA model structure
% microbeID:            ID of the reconstructed microbe that serves as the
%                       reconstruction name and to identify it in input tables
% database:             rBioNet reaction database containing min. 3 columns:
%                       Column 1: reaction abbreviation, Column 2: reaction
%                       name, Column 3: reaction formula.
% inputDataFolder:      Folder with input tables with experimental data
%                       and databases that inform the refinement process
%
% OUTPUTS
% model:                COBRA model structure with added pathways if applies
% secretionRxnsAdded:   Reactions added based on experimental data
%
% .. Author:
%       - Almut Heinken, 2019-2020
%       - Bronson R. Weston, 2022, introduced global additional secretion
%       reactions
global additionalSecretionRxns

% structure of lists of reactions to add per secretion product
% non-alphanumeric characters are removed from secretion product names in
% the structure; the script accounts for this when matching with the
% experimental data input
secretionRxns = struct();
% secretionRxns.Folate = {'EX_fol(e)','FOLte','EX_5mthf(e)','MTHFTe','EX_thf(e)','THFte'};
secretionRxns.Folate = {'EX_fol(e)','FOLte','EX_5mthf(e)','MTHFTe','EX_thf(e)','THFte','EX_4abz(e)','4ABZt2','DM_GCALD','DHPS','DHNPA','AKP1','GTPCI'};
secretionRxns.Thiamin = {'EX_thm(e)','THMte'};
% secretionRxns.Riboflavin = {'EX_ribflv(e)','RIBFLVt2r'};
secretionRxns.Riboflavin = {'EX_ribflv(e)','RIBFLVt2r','PMDPHT'};
secretionRxns.Niacin = {'EX_nac(e)','EX_ncam(e)','NACt2r','EX_ncam(e)','NCAMt2r'};
secretionRxns.Pyridoxine = {'EX_pydx(e)','EX_pydxn(e)','EX_pydam(e)','PYDXtr','PYDXNtr','PYDAMtr'};
% secretionRxns.Cobalamin = {'EX_cbl1(e)','CBl1te','EX_adocbl(e)','CBLTDe'};
secretionRxns.Cobalamin = {'EX_cbl1(e)','CBl1te','EX_adocbl(e)','CBLTDe','sink_dmbzid','CPC4MT','CPC5MT','LTHRK','SHCHD2','CYRDAR'};
% secretionRxns.Menaquinone = {'EX_mqn7(e)','MQN7te','EX_mqn8(e)','MK8t'};
secretionRxns.Menaquinone = {'EX_mqn7(e)','MQN7te','EX_mqn8(e)','MK8t','AMMQT8r','AMMQT72','DHNAOT7','DHNAOT4','DHNAOT','NCOAH','DHNAS','NPHS','SUCBZL','SUCBZS','2S6HCC','ICHORS','HETT','PREN','EX_2obut(e)','2OBUTt2r','EX_adn(e)','ADNCNT3tc','DHQTi'};
% secretionRxns.GABA = {'EX_4abut(e)','ABUTt2r'};
secretionRxns.GABA = {'EX_4abut(e)','ABUTt2r','GLUDC'};
secretionRxns.Biotin ={'EX_btn(e)','BTNT5r'};
secretionRxns.Cholate = {'EX_cholate(e)','BIACt1'};
secretionRxns.Chenodeoxycholate = {'EX_C02528(e)','BIACt2'};
secretionRxns.Deoxycholate = {'EX_dchac(e)','DCAT'};
% secretionRxns.Tyramine = {'EX_tym(e)','TYMt2r'};
% secretionRxns.Tryptamine = {'EX_trypta(e)', 'TRYPTAte'};
secretionRxns.Tyramine = {'EX_tym(e)','TYMt2r','TYRCBOX'};
secretionRxns.Tryptamine = {'EX_trypta(e)','TRYPTAte','LTDCL'};
secretionRxns.Dimethylamine = {'EX_dma(e)', 'DMAt2r'};
secretionRxns.TrimethylamineNoxide = {'EX_tmao(e)'};
secretionRxns.Trimethylamine = {'EX_tmao(e)', 'EX_tma(e)'};
secretionRxns.Spermine = {'EX_sprm(e)','SPRMTDe'};
secretionRxns.Spermidine = {'EX_spmd(e)','SPMDtex2'};
secretionRxns.Putrescine = {'EX_ptrc(e)','PTRCtex2'};
% secretionRxns.pCresol = {'EX_pcresol(e)','PCRESOLt2r'};
secretionRxns.pCresol = {'EX_pcresol(e)','PCRESOLt2r','4HPHACDC'};
secretionRxns.Ammonia = {'EX_nh4(e)','NH4tb'};
secretionRxns.Nitrogen = {'EX_n2(e)','N2t','N2OFO','EX_n2o(e)','N2Ot'};
secretionRxns.Methylamine = {'EX_mma(e)','MMAt2e'};
secretionRxns.Methanol = {'EX_meoh(e)','MEOHt2'};
secretionRxns.Lthreonine = {'EX_thr_L(e)','THRt2r'};
secretionRxns.Linoleicacid = {'EX_lnlc(e)','LNLCt'};
secretionRxns.Lithocholate = {'EX_HC02191(e)','LCAT'};
secretionRxns.Lglutamate = {'EX_glu_L(e)','GLUt2r'};
secretionRxns.Lglutamine = {'EX_gln_L(e)','GLNt2r'};
secretionRxns.Lalanine = {'EX_ala_L(e)','ALAt2r'};
secretionRxns.Indole3acetate = {'EX_ind3ac(e)','IND3ACt2r'};
% secretionRxns.Histamine = {'EX_hista(e)','HISTAt2'};
secretionRxns.Histamine = {'EX_hista(e)','HISTAt2','HISDC'};
secretionRxns.Peroxide = {'EX_h2o2(e)','H2O2t'};
secretionRxns.x_5Aminovalerate = {'EX_5aptn(e)','5APTNt2r'};
secretionRxns.x_2Oxobutyrate = {'EX_2obut(e)','2OBUTt2r'};
% secretionRxns.x_12Ethanediol = {'EX_12ethd(e)','12ETHDt'};
secretionRxns.x_12Ethanediol = {'EX_12ethd(e)','12ETHDt','LCAR2'};
% secretionRxns.Hydrogen = {'EX_h2(e)','H2td'};
secretionRxns.Hydrogen = {'EX_h2(e)','H2td','HYD4'};
% secretionRxns.Propionate = {'EX_ppa(e)','PPAtr'};
% secretionRxns.x_2Aminobutyrate = {'EX_C02356(e)','C02356t2r'};
secretionRxns.x_2Aminobutyrate = {'EX_C02356(e)','C02356t2r','RE2034C'};
% secretionRxns.x_13Propanediol = {'EX_13ppd(e)','13PPDt'};
secretionRxns.x_13Propanediol = {'EX_13ppd(e)','13PPDt','13PPDH','GLYCDH'};
% secretionRxns.x_12propanediol = {'EX_12ppd_S(e)','12PPDt'};
secretionRxns.x_12propanediol = {'EX_12ppd_S(e)','12PPDt','LCARS'};
% secretionRxns.Acetone = {'EX_acetone(e)','ACETONEt2'};
secretionRxns.Acetone = {'EX_acetone(e)','ACETONEt2','ADCi'};
% secretionRxns.Butylamine = {'EX_butam(e)','BUTAMt2r','EX_norval_L(e)','NORVALt2r','EX_M03134(e)','M03134t2r'};
secretionRxns.Butylamine = {'EX_butam(e)','BUTAMt2r','EX_norval_L(e)','NORVALt2r','EX_M03134(e)','M03134t2r','AKVALS','NORVALS','NORVALDC'};
% secretionRxns.Cadaverine = {'EX_15dap(e)','15DAPt'};
secretionRxns.Cadaverine = {'EX_15dap(e)','15DAPt','LYSDC'};
secretionRxns.Formaldehyde = {'EX_fald(e)','r1421'};
% secretionRxns.Urea = {'EX_urea(e)','UREAt'};
secretionRxns.Urea = {'EX_urea(e)','UREAt','ARGN'};
% secretionRxns.Propanol = {'EX_ppoh(e)','PPOHt2r','PPALt2r','EX_ppal(e)'};
secretionRxns.Propanol = {'EX_ppoh(e)','PPOHt2r','PPALt2r','EX_ppal(e)','ALCD3ir'};
% secretionRxns.Propanal = {'EX_ppal(e)','PPALt2r','EX_12ppd_S(e)','12PPDt'};
secretionRxns.Propanal = {'EX_ppal(e)','PPALt2r','EX_12ppd_S(e)','12PPDt','12PPDSDH'};
% secretionRxns.Phenylethylamine = {'EX_peamn(e)','PEAMNt2r'};
secretionRxns.Phenylethylamine = {'EX_peamn(e)','PEAMNt2r','PHYCBOXL'};
% secretionRxns.Isopropanol = {'EX_2ppoh(e)','2PPOHt2r','EX_acetone(e)','ACETONEt2'};
secretionRxns.Isopropanol = {'EX_2ppoh(e)','2PPOHt2r','EX_acetone(e)','ACETONEt2','ALCD20y'};
secretionRxns.Lmalate = {'EX_mal_L(e)','MALt2r'};
secretionRxns.Sulfide = {'EX_h2s(e)','H2St'};

%Add any additional secretion rxns if specified
if ~isempty(additionalSecretionRxns)
    addFields=fields(additionalSecretionRxns);
    for f=1:length(addFields)
        secretionRxns.(addFields{f})=additionalSecretionRxns.(addFields{f});
    end
end

% read in the secretion product data
secretionTable = readInputTableForPipeline([inputDataFolder filesep 'secretionProductTable.txt']);
secretionTable(:,find(strncmp(secretionTable(1,:),'Ref',3)))=[];

secretionGapfillAddConditional = {
    % secretion products, condition, add reaction(s)
    'Sulfide', '~any(ismember(model.rxns, {''CYSDS'',''CYSTS_H2S''}))', {'CYSDS'}
    'Trimethylamine', '~any(ismember(model.rxns, {''TMAOR1e'',''TMAOR2e''}))', {'TMAOt2r','TMAt2r','TMAOR1','TMAOR2'}
    };

% secretion product list from input table
% modify names to agree with structure
% can only contain alphabetic, numeric, or underscore characters and cannot
% start with a number or underscore.
% Any non-alphabetic, numeric, or underscore characters removed. Any names
% starting with a number changed to x_number.
products = secretionTable(1, 2:end);
numStart = find(~cellfun(@isempty, regexp(products, '^\d+')));% find names that start with numbers
products(numStart) = strcat('x_', products(numStart));
products = regexprep(products, '\W', '');% remove special characters

% microbe index in file
orgRow = find(strcmp(microbeID, secretionTable(:, 1)));

% find the secretion products for this microbe
if contains(version,'(R202') % for Matlab R2020a and newer
spCols = find(cell2mat(secretionTable(orgRow, 2:end)) == 1);
else
    spCols = find(str2double(secretionTable(orgRow, 2:end)) == 1);
end

% added rxns list
secretionRxnsAdded = {};

if ~isempty(spCols)
    secProds = products(spCols);
    for i = 1:length(secProds)
        % add rxns that are not already in model
        rxns2Add = setdiff(secretionRxns.(secProds{i}), model.rxns)
        if ~isempty(rxns2Add)
            for j = 1:length(rxns2Add)
                RxnForm = database.reactions(find(ismember(database.reactions(:, 1), rxns2Add{j})), 3);
                model = addReaction(model, rxns2Add{j}, 'reactionFormula', RxnForm{1, 1}, 'geneRule','secretionProductGapfill');
            end
            secretionRxnsAdded = union(secretionRxnsAdded, rxns2Add);
        end
        % add conditional reactions
        if any(ismember(secretionGapfillAddConditional(:, 1), secProds{i}))
            conditions = find(ismember(secretionGapfillAddConditional(:, 1), secProds{i}));
            for k = 1:length(conditions)
                if eval(secretionGapfillAddConditional{conditions(k), 2})
                    addRxns = secretionGapfillAddConditional{conditions(k), 3};
                    for j = 1:length(addRxns)
                        if ~any(ismember(model.rxns, addRxns{j}))
                            formula = database.reactions{ismember(database.reactions(:, 1), addRxns{j}), 3};
                            model = addReaction(model, addRxns{j}, 'reactionFormula', formula, 'geneRule', 'secretionProductGapfill');
                            secretionRxnsAdded = union(secretionRxnsAdded, addRxns{j});
                        end
                    end
                end
            end
        end
    end
end

end


function my_net_run_batch(net_config, work_info_batch)

    gen_data_info_groups_cache(net_config, work_info_batch);
    group_idx=net_config.ref.root_group_idx;

    data_info=init_one_data_info_from_cache(group_idx, work_info_batch);
    input_info=work_info_batch.ref.ds_info.net_input_info;
    data_info.ref.output_info_layers{1}=input_info;
    work_info_batch.ref.ds_info.net_input_info=[];

    do_run_one_pass(net_config, work_info_batch, group_idx);

    work_info_batch.ref.data_info_groups=[];

end

function do_run_one_pass(net_config, work_info_batch, group_idx)

    if work_info_batch.ref.net_run_verbose
        fprintf('---- runing one pass, root_group_idx:%d\n', group_idx);
    end

    do_run_one_group(net_config, work_info_batch, group_idx, 'forward');

    data_info=work_info_batch.ref.data_info_groups{group_idx};
    last_layer_output_info=data_info.ref.output_info_layers{end};
    assert(check_valid_net_output(last_layer_output_info));

    if work_info_batch.ref.run_backward

        init_dzdx=single(1);

        last_layer_output_info.dzdx=init_dzdx;
        last_layer_output_info.bp_finished=true;
        data_info.ref.output_info_layers{end}=last_layer_output_info;

        do_run_one_group(net_config, work_info_batch, group_idx, 'backward');
    end

end

function do_run_one_group(net_config, work_info_batch, group_idx, group_run_type)

group_info=net_config.ref.group_infos{group_idx};
work_info_batch.ref.net_run_current_group_idx=group_idx;

net_run_current_group_idx_linked=[];
if ~isempty(group_info.net_info)
    if isfield(group_info.net_info.ref, 'linked_group_idx')
        net_run_current_group_idx_linked=group_info.net_info.ref.linked_group_idx;
    end
end
work_info_batch.ref.net_run_current_group_idx_linked=net_run_current_group_idx_linked;

if work_info_batch.ref.net_run_verbose
    fprintf('----start group_idx:%d, name:%s, run_type:%s\n', ...
        group_info.group_idx, group_info.name, group_run_type);
end

if strcmp(group_run_type, 'forward')
    do_forward_one_group( net_config, work_info_batch, group_idx);
end

if strcmp(group_run_type, 'backward')
    do_backward_one_group( net_config, work_info_batch, group_idx);
end

if work_info_batch.ref.net_run_verbose
    fprintf('----finish group_idx:%d, name:%s, run_type:%s\n', ...
        group_info.group_idx, group_info.name, group_run_type);
end

end

function do_forward_group_child_chain( work_info_batch, data_info, group_info)

        net_config=work_info_batch.ref.net_config;

        child_group_idxes=group_info.child_group_idxes;

        child_num=length(child_group_idxes);
        child_valid_flags=data_info.ref.child_valid_flags;
        assert(any(child_valid_flags));

        input_info=data_info.ref.output_info_layers{1};
        assert(check_valid_net_output(input_info));
        need_bp=false;

        for g_idx=1:child_num

            child_valid=child_valid_flags(g_idx);
            if ~child_valid
                break;
            end

            child_group_idx=child_group_idxes(g_idx);

            [input_info, need_bp]=do_forward_one_child( net_config, ...
                work_info_batch, child_group_idx, input_info);

            if ~check_valid_net_output(input_info)
                break;
            end
        end

        data_info.ref.output_info_layers{2}=input_info;
        data_info.ref.need_bp=need_bp;

end

function do_forward_group_child_parallel( work_info_batch, data_info, group_info)

    net_config=work_info_batch.ref.net_config;

    child_group_idxes=group_info.child_group_idxes;
    child_num=length(child_group_idxes);
    child_valid_flags=data_info.ref.child_valid_flags;
    assert(any(child_valid_flags));

    group_input_info=data_info.ref.output_info_layers{1};

    assert(check_valid_net_output(group_input_info));

    assert(group_input_info.is_group_data);

    input_info_child_groups=group_input_info.data_child_groups;
    input_child_valid_flags=group_input_info.child_valid_flags;
    assert(length(input_info_child_groups)==child_num);
    assert(length(input_child_valid_flags)==child_num);

    output_child_groups=cell(child_num, 1);
    output_valid_flags=false(child_num,1);
    need_bp_flags=false(child_num,1);

    for g_idx=1:child_num

        child_valid=child_valid_flags(g_idx);
        if ~child_valid
            continue;
        end

        input_valid=input_child_valid_flags(g_idx);
        if ~input_valid
            continue;
        end
        child_input_info=input_info_child_groups{g_idx};

        child_group_idx=child_group_idxes(g_idx);

        [child_output_info, child_need_bp]=do_forward_one_child(net_config, ...
            work_info_batch, child_group_idx, child_input_info);
        output_child_groups{g_idx}=child_output_info;

        need_bp_flags(g_idx)=child_need_bp;

        output_valid_flags(g_idx)=check_valid_net_output(child_output_info);
    end

    assert(any(output_valid_flags));

    group_output_info=[];
    group_output_info.data_child_groups=output_child_groups;
    group_output_info.child_valid_flags=output_valid_flags;
    group_output_info.is_group_data=true;
    group_output_info.forward_finished=any(output_valid_flags);

    data_info.ref.output_info_layers{2}=group_output_info;
    data_info.ref.need_bp=any(need_bp_flags);
    data_info.ref.need_bp_child_groups=need_bp_flags;

end

function do_forward_one_group( net_config, work_info_batch, group_idx)

group_info=net_config.ref.group_infos{group_idx};
prediction_layer_idxes=group_info.prediction_layer_idxes;

if ~isempty(group_info.forward_begin_fn)
    group_info=group_info.forward_begin_fn(work_info_batch, group_info);
end

if ~group_info.skip_forward

    child_group_idxes=group_info.child_group_idxes;
    data_info=work_info_batch.ref.data_info_groups{group_idx};

    if isempty(child_group_idxes)

        net_run_config=work_info_batch.ref.net_run_config;

        extra_output_layer_idxes=[];
        if ~isempty(prediction_layer_idxes)
            extra_output_layer_idxes=cat(1, extra_output_layer_idxes, prediction_layer_idxes);
            extra_output_layer_idxes=unique(extra_output_layer_idxes);
        end

        work_info_batch.ref.current_group_data_info=data_info;

        forward_time=tic;
        extra_data_info=my_net_forward(retrieve_net_info(group_info, net_config), ...
            work_info_batch, data_info, net_run_config, extra_output_layer_idxes);
        forward_time=toc(forward_time);
        work_info_batch.ref.forward_time=work_info_batch.ref.forward_time+forward_time;

        data_info.ref.extra_input_infos=[];

        work_info_batch.ref.current_group_data_info=[];

    else

        switch group_info.child_relation
            case 'chain'
                do_forward_group_child_chain( work_info_batch, data_info, group_info);
            case 'parallel'
                do_forward_group_child_parallel( work_info_batch, data_info, group_info);
            otherwise
                error('not support!');
        end

    end
end

if ~isempty(prediction_layer_idxes)

    assert(isempty(child_group_idxes));

    prediction_info=work_info_batch.ref.prediction_info_groups{group_idx};
    keep_output_infos=extra_data_info.output_layers(group_info.prediction_layer_idxes);

    prediction_info.output_infos=keep_output_infos;
    work_info_batch.ref.prediction_info_groups{group_idx}=prediction_info;
end

if ~isempty(group_info.forward_finish_fn)
    group_info=group_info.forward_finish_fn(work_info_batch, group_info);
end

if ~isempty(group_info.forward_evaluate_fn)
    forward_eva_time=tic;
    group_info.forward_evaluate_fn( work_info_batch, group_idx);
    forward_eva_time=toc(forward_eva_time);
    work_info_batch.ref.eva_time=work_info_batch.ref.eva_time+forward_eva_time;
end

end

function [output_info, child_need_bp]=do_forward_one_child(net_config,...
    work_info_batch, child_group_idx, input_info)

    child_data_info=init_one_data_info_from_cache(child_group_idx, work_info_batch);
    child_data_info.ref.output_info_layers{1}=input_info;

    do_run_one_group(net_config, work_info_batch, child_group_idx, 'forward');
    output_info=child_data_info.ref.output_info_layers{end};

    child_data_info.ref.output_info_layers{end}=[];
    child_need_bp=child_data_info.ref.need_bp;

    if ~child_need_bp
        child_data_info.ref.output_info_layers=[];
    end

end

function output_info_layers=gen_net_output_info_basic(net_info)

if isempty(net_info)
    n=1;
else
    n = numel(net_info.ref.layers) ;
end

sample_output_info=[];
sample_output_info.x=[];
sample_output_info.aux=[];
sample_output_info.dzdx=[];
sample_output_info.dzdw=[];
sample_output_info.is_group_data=false;
sample_output_info.bp_finished=false;
sample_output_info.forward_finished=false;

output_info_layers=repmat({sample_output_info}, n+1, 1);

end

function data_info=init_one_data_info_from_cache(group_idx, work_info_batch)

data_info=work_info_batch.ref.data_info_groups{group_idx};
data_info.ref=work_info_batch.ref.sample_data_info_groups{group_idx};

tmp_data_info=work_info_batch.ref.data_info_groups_extra{group_idx};
data_info.ref.extra_input_infos=tmp_data_info.extra_input_infos;

end

function data_info=init_one_data_info(group_info, net_config)

    data_info=[];
    data_info.output_info_layers=[];
    data_info.forward_time=0;
    data_info.backward_time=0;
    data_info.need_bp=false;
    data_info.extra_input_infos=cell(0);

    child_num=length(group_info.child_group_idxes);
    data_info.child_valid_flags=true(child_num, 1);

    data_info.output_info_layers=gen_net_output_info_basic(...
        retrieve_net_info(group_info, net_config));

end

function gen_data_info_groups_cache(net_config, work_info_batch)

    group_num=length(net_config.ref.group_infos);
    work_info=work_info_batch.ref.work_info;
    if ~isfield(work_info.ref.tmp_cache, 'sample_data_info_groups')
        data_info_groups=cell(group_num, 1);
        data_info_groups_ref=cell(group_num, 1);
        for g_idx=1:group_num
            tmp_data_info=[];
            make_ref_obj(tmp_data_info);
            data_info_groups_ref{g_idx}=tmp_data_info;
            data_info=init_one_data_info(net_config.ref.group_infos{g_idx}, net_config);
            data_info_groups{g_idx}=data_info;
        end
        work_info.ref.tmp_cache.sample_data_info_groups=data_info_groups;
        work_info.ref.tmp_cache.sample_data_info_groups_ref=data_info_groups_ref;

        data_info_groups_extra=cell(group_num, 1);
        for g_idx=1:group_num
            tmp_data_info_extra=[];
            tmp_data_info_extra.extra_input_infos=cell(0);
            data_info_groups_extra{g_idx}=tmp_data_info_extra;
        end
        work_info.ref.tmp_cache.sample_data_info_groups_extra=data_info_groups_extra;

    end

    work_info_batch.ref.sample_data_info_groups=work_info.ref.tmp_cache.sample_data_info_groups;
    work_info_batch.ref.data_info_groups=work_info.ref.tmp_cache.sample_data_info_groups_ref;
    work_info_batch.ref.prediction_info_groups=cell(group_num, 1);

    work_info_batch.ref.data_info_groups_extra=work_info.ref.tmp_cache.sample_data_info_groups_extra;

end

function do_backward_group_child_chain(net_config,work_info_batch, data_info, group_info)

    child_group_idxes=group_info.child_group_idxes;
    child_num=length(child_group_idxes);
    child_valid_flags=data_info.ref.child_valid_flags;
    assert(any(child_valid_flags));

        start_g_idx=find(~child_valid_flags, 1);
        if isempty(start_g_idx)
            start_g_idx=child_num;
        end

        init_output_info=data_info.ref.output_info_layers{end};

        for g_idx=start_g_idx:-1:1

            child_group_idx=child_group_idxes(g_idx);
            init_output_info=do_backward_child_group( net_config,...
                work_info_batch, child_group_idx, init_output_info);

            if ~init_output_info.bp_finished
                break;
            end
        end

        data_info.ref.output_info_layers{1}=init_output_info;

end

function do_backward_group_child_parallel(net_config,work_info_batch,data_info, group_info)

    child_group_idxes=group_info.child_group_idxes;
    child_num=length(child_group_idxes);
    child_valid_flags=data_info.ref.child_valid_flags;
    assert(any(child_valid_flags));

        init_group_output_info=data_info.ref.output_info_layers{end};

        assert(init_group_output_info.is_group_data);
        output_info_child_groups=init_group_output_info.data_child_groups;
        output_child_valid_flags=init_group_output_info.child_valid_flags;
        init_bp_child_valid_flags=init_group_output_info.bp_child_valid_flags;

        assert(length(output_info_child_groups)==child_num);
        assert(length(output_child_valid_flags)==child_num);

        first_output_info=data_info.ref.output_info_layers{1};
        assert(first_output_info.is_group_data);

        bp_child_valid_flags=false(child_num, 1);
        for g_idx=1:child_num

            child_valid=output_child_valid_flags(g_idx);
            if ~child_valid
                continue;
            end

            init_bp_finished=init_bp_child_valid_flags(g_idx);
            if ~init_bp_finished
                continue;
            end

            child_group_idx=child_group_idxes(g_idx);
            child_init_output_info=output_info_child_groups{g_idx};

            if ~check_valid_net_output(child_init_output_info)
                continue;
            end

            child_first_output_info=do_backward_child_group( net_config,...
                work_info_batch, child_group_idx, child_init_output_info);

            first_output_info.data_child_groups{g_idx}=child_first_output_info;

            bp_child_valid_flags(g_idx)=child_first_output_info.bp_finished;

        end

        first_output_info.bp_child_valid_flags=bp_child_valid_flags;
        first_output_info.bp_finished=any(bp_child_valid_flags);

        data_info.ref.output_info_layers{1}=first_output_info;
end

function do_backward_one_group( net_config, work_info_batch, group_idx)

data_info=work_info_batch.ref.data_info_groups{group_idx};
if ~data_info.ref.need_bp
    return;
end

group_info=net_config.ref.group_infos{group_idx};

if ~group_info.skip_backward

    child_group_idxes=group_info.child_group_idxes;

    if isempty(child_group_idxes)

        net_run_config=work_info_batch.ref.net_run_config;

        backward_time=tic;
        do_bp_current_net=check_do_bp_current_net(work_info_batch, net_run_config, ...
            retrieve_net_info(group_info, net_config));
        if do_bp_current_net

            work_info_batch.ref.current_group_data_info=data_info;

            my_net_backward(retrieve_net_info(group_info, net_config), ...
                work_info_batch, data_info, net_run_config);
            work_info_batch.ref.leaf_group_bp_flags(group_idx)=true;

            work_info_batch.ref.current_group_data_info=[];

        end

        backward_time=toc(backward_time);
        work_info_batch.ref.backward_time=work_info_batch.ref.backward_time+backward_time;

    else

        switch group_info.child_relation
            case 'chain'
                do_backward_group_child_chain(net_config, work_info_batch, data_info, group_info);
            case 'parallel'
                do_backward_group_child_parallel(net_config, work_info_batch, data_info, group_info);
            otherwise
                error('not support!');
        end

    end
end

data_info.ref.output_info_layers=data_info.ref.output_info_layers(1);

end

function first_output_info=do_backward_child_group( ...
    net_config, work_info_batch, child_group_idx, init_output_info)

    child_data_info=work_info_batch.ref.data_info_groups{child_group_idx};

    if ~child_data_info.ref.need_bp
        first_output_info=[];
        first_output_info.bp_finished=false;
        return;
    end

    if ~check_valid_net_output(init_output_info)
        first_output_info=[];
        first_output_info.bp_finished=false;
        return;
    end

    child_data_info.ref.output_info_layers{end}=init_output_info;
        do_run_one_group(net_config, work_info_batch, child_group_idx, 'backward');

    first_output_info=child_data_info.ref.output_info_layers{1};
    if isempty(first_output_info)
        first_output_info.bp_finished=false;
    end

    child_data_info.ref=[];

end

function one_net_info=retrieve_net_info(group_info, net_config)

one_net_info=group_info.net_info;
if isempty(one_net_info)
    return;
end
if isempty(one_net_info.ref.layers)
    linked_group_info=net_config.ref.group_infos{one_net_info.ref.linked_group_idx};
    one_net_info=linked_group_info.net_info;
end

end


classdef MaxPropTimeReachedValidator < AbstractLaunchVehicleDataValidator
    %MaxPropTimeReachedValidator Summary of this class goes here
    %   Detailed explanation goes here

    properties
        lvdData LvdData
    end

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

        function [errors, warnings] = validate(obj)
            errors = LaunchVehicleDataValidationError.empty(0,1);
            warnings = LaunchVehicleDataValidationWarning.empty(0,1);

            maxPropTime = obj.lvdData.settings.maxScriptPropTime;
            lastRunExecTime = obj.lvdData.script.lastRunExecTime;

            if(lastRunExecTime >= maxPropTime)
                str = sprintf('Maximum script propagation time of %.3f sec reached or exceeded.  Propagation terminated.  Consider increasing the maximum script propagation time.', maxPropTime);
                warnings(end+1) = LaunchVehicleDataValidationWarning(str);
            end
        end
    end
end


classdef dme_gen3p_opf < mp.dme_gen3p & mp.dme_shared_opf

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

%     properties
%     end     %% properties

%     methods
%     end     %% methods
end         %% classdef


function gui_LoadResult
% function pf_load
%   Opens a open dialog to load result data
%   and invokes the display dialog
%
% Danijel Schorlemmer
% August 22, 2002

global bDebug;
if bDebug
  report_this_filefun(mfilename('fullpath'));
end

% Invoke the open dialog
[newfile, newpath] = uigetfile('*.mat', 'Load calculated data');
% Cancel pressed?
if newfile == 0
  return;
end
% Everything ok?
newfile = [newpath newfile];
if length(newfile) > 1
  % Load the data
  load(newfile, 'vResults');
  % Open dialog
  hResultFig = gui_result(vResults);
end


function varargout = cvx_run_solver( sfunc, varargin )
global cvx___
settings_arg = varargin{end};
settings     = varargin{end-1};
inputs       = varargin(1:end-nargout-2);
dumpfile = '';
custom_on = false;
if isstruct( settings ),
    for f = fieldnames( settings )',
        sval = settings.(f{1});
        if isequal( f{1}, 'dumpfile' ),
            dumpfile = sval;
        else
            custom_on = true;
            inputs{settings_arg}.(f{1}) = sval;
        end
    end
end
if custom_on,
    fprintf( 'NOTE: custom settings have been set for this solver.\n' );
end
if ~isempty( dumpfile ),
    if ~ischar( dumpfile ) || size( dumpfile, 1 ) > 1,
        cvx_throw( 'Invalid filename for the dumpfile.' );
    elseif length(dumpfile) < 4 || ~strcmpi(dumpfile(end-3:end),'.mat'),
        dumpfile = [ dumpfile, '.mat' ];
    end
    fprintf( 'Saving output to: %s\n', dumpfile );
    fprintf( '------------------------------------------------------------\n');
    inp_names = cell(1,length(inputs));
    for k = 1 : length(inp_names),
        inp_names{1,k} = inputname(k+1);
    end
    dstruct = cell2struct( inputs, inp_names, 2 ); %#ok
    save( dumpfile, '-struct', 'dstruct' );
    diaryfile = [ dumpfile, '.txt' ];
    fid = fopen( diaryfile, 'w+' );
    if fid ~= 0,
        fclose( fid );
        diary( diaryfile );
    end
elseif custom_on,
    fprintf( '------------------------------------------------------------\n');
end
errmsg = [];
if cvx___.isoctave,
    fflush(1);
end
try
   [ varargout{1:nargout} ] = sfunc( inputs{:} );
catch errmsg
   [ varargout{1:nargout} ] = deal( [] );
end
if ~isempty( dumpfile ),
    if fid ~= 0,
        diary( 'off' );
        fid = fopen( diaryfile, 'r' );
        if fid ~= 0,
            output = fread( fid, Inf, '*char' )';
            fclose( fid );
            delete( diaryfile );
        end
    end
    if fid == 0,
        output = '<Could not save>';
    end
    otp_names = varargin(end-nargout-1:end-2);
    dstruct = cell2struct( [ inputs, varargout, output ], [ inp_names, otp_names, 'output' ], 2 ); %#ok
    save( dumpfile, '-struct', 'dstruct' );
end
if ~isempty( errmsg ),
    rethrow( errmsg );
end

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


function varargout = gui_stat_analyticStats(varargin)
%
% GUI_STAT_ANALYTICSTATS M-file for gui_stat_analyticStats.fig
%      GUI_STAT_ANALYTICSTATS, by itself, creates a new GUI_STAT_ANALYTICSTATS or raises the existing
%      singleton*.
%
%      H = GUI_STAT_ANALYTICSTATS returns the handle to a new GUI_STAT_ANALYTICSTATS or the handle to
%      the existing singleton*.
%
%      GUI_STAT_ANALYTICSTATS('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in GUI_STAT_ANALYTICSTATS.M with the given input arguments.
%
%      GUI_STAT_ANALYTICSTATS('Property','Value',...) creates a new GUI_STAT_ANALYTICSTATS or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before gui_stat_analyticStats_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to gui_stat_analyticStats_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 gui_stat_analyticStats

% Last Modified by GUIDE v2.5 28-Jun-2012 15:12:51

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @gui_stat_analyticStats_OpeningFcn, ...
                   'gui_OutputFcn',  @gui_stat_analyticStats_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 gui_stat_analyticStats is made visible.
function gui_stat_analyticStats_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 gui_stat_analyticStats (see VARARGIN)

set(hObject,'name','Analytic Statistics');

handles.output = hObject;

% set default termination behavior
handles.ExitButtonClicked = 'Cancel';

% extract some data from command-line input
if isempty(varargin)
    error('You must pass ALLEEG to gui_analyticStats');
end

% Extract input parameters/data and store
handles.ud.ALLEEG  = varargin{1};
varargin(1) = [];

% set default EEGLAB background and text colors
%-----------------------------------------------
try, icadefs;
catch,
	GUIBACKCOLOR        =   [.8 .8 .8];
	GUIPOPBUTTONCOLOR   =   [.8 .8 .8];
	GUITEXTCOLOR        =   [0 0 0];
end;

allhandlers = hObject;

hh = findobj(allhandlers,'style', 'text');
%set(hh, 'BackgroundColor', get(hObject, 'color'), 'horizontalalignment', 'left');
set(hh, 'Backgroundcolor', GUIBACKCOLOR);
set(hh, 'foregroundcolor', GUITEXTCOLOR);
set(hObject, 'color',GUIBACKCOLOR );
% set(hh, 'horizontalalignment', g.horizontalalignment);

hh = findobj(allhandlers, 'style', 'edit');
set(hh, 'BackgroundColor', [1 1 1]); %, 'horizontalalignment', 'right');

hh =findobj(allhandlers, 'parent', hObject, 'style', 'pushbutton');
if ~strcmpi(computer, 'MAC') && ~strcmpi(computer, 'MACI') % this puts the wrong background on macs
    set(hh, 'backgroundcolor', GUIPOPBUTTONCOLOR);
    set(hh, 'foregroundcolor', GUITEXTCOLOR);
end;
hh =findobj(allhandlers, 'parent', hObject, 'style', 'popupmenu');
set(hh, 'backgroundcolor', GUIPOPBUTTONCOLOR);
set(hh, 'foregroundcolor', GUITEXTCOLOR);
hh =findobj(allhandlers, 'parent', hObject, 'style', 'checkbox');
set(hh, 'backgroundcolor', GUIBACKCOLOR);
set(hh, 'foregroundcolor', GUITEXTCOLOR);
hh =findobj(allhandlers, 'parent', hObject, 'style', 'listbox');
set(hh, 'backgroundcolor', GUIPOPBUTTONCOLOR);
set(hh, 'foregroundcolor', GUITEXTCOLOR);
hh =findobj(allhandlers, 'parent', hObject, 'style', 'radio');
set(hh, 'foregroundcolor', GUITEXTCOLOR);
set(hh, 'backgroundcolor', GUIPOPBUTTONCOLOR);
set(hObject, 'visible', 'on');

set(handles.pnlPropertyGrid,'backgroundcolor', GUIBACKCOLOR);
set(handles.pnlPropertyGrid,'foregroundcolor', GUITEXTCOLOR);
%-----------------------------------------------

drawnow

% render the PropertyGrid in the correct panel
handles.PropertyGridHandle = arg_guipanel( ...
                 handles.pnlPropertyGrid, ...
                'Function',@stat_analyticStats, ...
                'params',{'ALLEEG',handles.ud.ALLEEG, varargin{:}});

% Update handles structure
guidata(hObject, handles);

% Wait for user to click OK, Cancel or close figure
uiwait(handles.gui_analyticStats);

% --- Outputs from this function are returned to the command line.
function varargout = gui_stat_analyticStats_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)

if isempty(handles)
    % user closed the figure
    varargout = {[] hObject};
elseif strcmpi(handles.ExitButtonClicked,'OK')
    % user clicked OK
    % get PropertySpecification
    varargout = {handles.PropertyGridHandle handles.output};
else
    % user clicked cancel
    varargout = {[] handles.output};
end

try, close(hObject);
catch; end

function cmdCancel_Callback(hObject, eventdata, handles)

handles.ExitButtonClicked = 'Cancel';
guidata(hObject,handles);
uiresume(handles.gui_analyticStats)

function cmdOK_Callback(hObject, eventdata, handles)

handles.ExitButtonClicked ='OK';
guidata(hObject,handles);
uiresume(handles.gui_analyticStats);

function cmdHelp_Callback(hObject, eventdata, handles)
doc('stat_analyticStats');

function gui_analyticStats_ResizeFcn(hObject, eventdata, handles)


function params = retinoGetParams(vw, dt, scan)
% Get visual field mapping ("retinotopic", though it doesn't need
% to be) parameters for the selected scan.
%
% params = retinoGetParams(vw, <dt, scan>);
%
% dt and scan specify the data type and scans to use, and
% default to the view's current dt/scan if omitted.
%
% The parameters are stored in
%   dataTYPES(dt).blockedAnalysisParameters(scan).visualFieldMap.
%
% Use retinoSetParams to update the parameters.
%
%
% ras, 01/06: testing the waters if this code is needed. I see many
% other places where similar parameters are set, but none of them
% seem immediately useable to me.
if notDefined('vw'),    vw = getCurView;               end
if notDefined('dt'),    dt = viewGet(vw, 'curdt');     end
if notDefined('scan'),  scan = viewGet(vw, 'curscan'); end

mrGlobals;

if ischar(dt),    dt = existDataType(dt);               end

if checkfields(dataTYPES(dt), 'blockedAnalysisParams', 'visualFieldMap') && ...
    ~isempty(dataTYPES(dt).blockedAnalysisParams(scan).visualFieldMap)
        params = dataTYPES(dt).blockedAnalysisParams(scan).visualFieldMap;
else
    params = [];
end

return


function dataTYPES = CreateNewDataTypes(mrSESSION)
% Create top-level dataTYPES strycture.
%
%  dataTYPES = CreateNewDataTypes(mrSESSION);
%
% We should use the dtGet/Set/Create suite.
%
% We shouldn't set such specific parameters for the default; we should set
% the values empty.  Also, it is awkward to have the same values
% represented in dataTYPES and mrSESSION because the two may lose
% synchronization. (BW)
%
% See also:
%
% Programming Notes
% djh 9/26/2001
% ras, 03/04: added more eventAnalysisParams, since it's assumed they'll
% be created anyway down the line (e.g., if detrend option is 2, mrLoadRet
% looks for the detrendFrames in eventAnalysisParams).
% ras, 02/06: also added the parfile and scanGroup fields for event-
% related analyses, so they're there even if they're not used.

disp('CreateNewDataTypes is obsolete:  Use dtCreate');
evalin('caller','mfilename')

dataTYPES.name = 'Original';

for iScan = 1:length(mrSESSION.functionals)
    dataTYPES.scanParams(iScan).annotation = '';
    dataTYPES.scanParams(iScan).nFrames = mrSESSION.functionals(iScan).nFrames;
    dataTYPES.scanParams(iScan).framePeriod = mrSESSION.functionals(iScan).framePeriod;
    dataTYPES.scanParams(iScan).slices = mrSESSION.functionals(iScan).slices;
    dataTYPES.scanParams(iScan).cropSize = mrSESSION.functionals(iScan).cropSize;
    dataTYPES.scanParams(iScan).PfileName = mrSESSION.functionals(iScan).PfileName;
    dataTYPES.scanParams(iScan).parfile = '';
    dataTYPES.scanParams(iScan).scanGroup = '';
    dataTYPES.blockedAnalysisParams(iScan).blockedAnalysis = 1;
    dataTYPES.blockedAnalysisParams(iScan).detrend = 1;
    dataTYPES.blockedAnalysisParams(iScan).inhomoCorrect = 1;
    dataTYPES.blockedAnalysisParams(iScan).temporalNormalization = 1;
    dataTYPES.blockedAnalysisParams(iScan).nCycles = 8;
    dataTYPES.eventAnalysisParams(iScan) = er_defaultParams;
end

dataTYPES.retinotopyModelParams = [];

return


function val = ft_getopt(opt, key, default, emptymeaningful)

% FT_GETOPT gets the value of a specified option from a configuration structure
% or from a cell-array with key-value pairs.
%
% Use as
%   val = ft_getopt(s, key, default, emptymeaningful)
% where the input values are
%   s               = structure or cell-array
%   key             = string
%   default         = any valid MATLAB data type (optional, default = [])
%   emptymeaningful = boolean value (optional, default = false)
%
% If the key is present as field in the structure, or as key-value pair in the
% cell-array, the corresponding value will be returned.
%
% If the key is not present, ft_getopt will return the default, or an empty array
% when no default was specified.
%
% If the key is present but has an empty value, then the emptymeaningful flag
% specifies whether the empty value or the default value should be returned.
% If emptymeaningful==true, then the empty array will be returned.
% If emptymeaningful==false, then the specified default will be returned.
%
% See also FT_SETOPT, FT_CHECKOPT

% Copyright (C) 2011-2012, 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$

if nargin<3
  default = [];
end

if nargin < 4
  emptymeaningful = false;
end

if isa(opt, 'struct') || isa(opt, 'config')
  % get the key-value from the structure
  fn = fieldnames(opt);
  if ~any(strcmp(key, fn))
    val = default;
  else
    val = opt.(key);
  end

elseif isa(opt, 'cell')
  % get the key-value from the cell-array
  if mod(length(opt),2)
    error('optional input arguments should come in key-value pairs, i.e. there should be an even number');
  end

  % the 1st, 3rd, etc. contain the keys, the 2nd, 4th, etc. contain the values
  keys = opt(1:2:end);
  vals = opt(2:2:end);

  % the following may be faster than cellfun(@ischar, keys)
  valid = false(size(keys));
  for i=1:numel(keys)
    valid(i) = ischar(keys{i});
  end

  if ~all(valid)
    error('optional input arguments should come in key-value pairs, the optional input argument %d is invalid (should be a string)', i);
  end

  hit = find(strcmpi(key, keys));
  if isempty(hit)
    % the requested key was not found
    val = default;
  elseif length(hit)==1
    % the requested key was found
    val = vals{hit};
  else
    error('multiple input arguments with the same name');
  end

elseif isempty(opt)
  % no options are specified, return default
  val = default;
end % isstruct or iscell or isempty

if isempty(val) && ~isempty(default) && ~emptymeaningful
  % use the default value instead of the empty input that was specified:
  % this applies for example if you do functionname('key', []), where
  % the empty is meant to indicate that the user does not know or care
  % what the value is
  val = default;
end


function [a]=add(a,d)

% function [a]=add(a,d)
%
% add a single algorithm or a cell array algorithms to an algs
% object

  d=make_cell(d);
  r=a.child;
  if ~isempty(r) r={r{1:length(r)} d{1:length(d)}}; else r=d; end
  a.child=r;


function [handles] = spm_uitab(hparent,labels,callbacks,tag,active,height,tab_height)
% Create tabs in a figure
% FORMAT [handles] = spm_uitab(hparent,labels,callbacks,tag,active,height,tab_height)
% This function creates tabs in the SPM graphics window.
% These tabs may be associated with different sets of axes and uicontrol,
% through the use of callback functions linked to the tabs.
% Inputs:
%   hparent    - the handle of the parent of the tabs (can be the SPM
%                graphics windows, or the handle of the uipanel of a former
%                spm_uitab...)
%   labels     - a cell array of string containing the labels of the tabs
%   callbacks  - a cell array of strings which will be evaluated using the
%                'eval' function when clicking on a tab [default: {[]}]
%   tag        - a string which is the tag associated with the tabs
%                (useful for finding them in a window...) [default: '']
%   active     - the index of the active tab when creating the uitabs
%                [default: 1, ie the first tab is active]
%   height     - the relative height of the tab panels within its parent
%                spatial extent [default: 1]
%   tab_height - the relative height of the tabs within its parent spatial
%                extent [default: 0.025]
% Output:
%   handles    - a structure of handles for the differents tab objects.
%__________________________________________________________________________
% Copyright (C) 2008-2014 Wellcome Trust Centre for Neuroimaging

% Jean Daunizeau
% $Id: spm_uitab.m 6067 2014-06-26 15:33:30Z guillaume $

Ntabs = length(labels);

if ~exist('callbacks','var') || isempty(callbacks)
    for i=1:Ntabs
        callbacks{i} = [];
    end
end
if  ~exist('tag','var') || isempty(tag)
    tag = '';
end
if  ~exist('active','var') || isempty(active)
    active = 1;
end
if  ~exist('height','var') || isempty(height)
    height = 1;
end
if  ~exist('tab_height','var') || isempty(tab_height)
    tab_height = 0.025;
end
if ~isequal(get(hparent,'type'),'figure')
    set(hparent,'units','normalized')
    POS = get(hparent,'position');
    pos1 = [POS(1)+0.02,POS(2)+0.01,POS(3)-0.04,POS(4)-(tab_height+0.035)];
    dx = 0.095*(POS(3)-0.04)./0.98;
    dx2 = [0.04,0.93]*(POS(3)-0.04)./0.98;
else
    pos1 = [0.01 0.005 0.98 1-(tab_height+0.01)];
    dx = 0.095;
    dx2 = [0.04,0.93];
end
pos1(4) = pos1(4).*height;

COLOR = 0.95*[1 1 1];

handles.hp = uipanel(...
    'parent',hparent,...
    'position',pos1,...
    'BorderType','beveledout',...
    'BackgroundColor',COLOR,...
    'tag',tag);
set(handles.hp,'units','normalized');

xl = pos1(1);
yu = pos1(2) +pos1(4);
ddx = 0.0025;
ddy = 0.005;
dy = tab_height;

if Ntabs > 9
    handles.hs(1) = uicontrol(...
        'parent',hparent,...'enable','off',...
        'style','pushbutton',...
        'units','normalized','position',[xl yu dx2(1) dy],...
        'SelectionHighlight','off',...
        'BackgroundColor',COLOR,...
        'callback',@doScroll,...
        'value',0,'min',0,'max',Ntabs-9,...
        'string','<',...
        'tag',tag,...
        'BusyAction','cancel',...
        'Interruptible','off');

    handles.hs(2) = uicontrol(...
        'parent',hparent,...
        'style','pushbutton',...
        'units','normalized','position',[xl+dx2(2) yu 0.05 dy],...
        'SelectionHighlight','off',...
        'BackgroundColor',COLOR,...
        'callback',@doScroll,...
        'value',1,'min',1,'max',Ntabs-9,...
        'string','>',...
        'tag',tag,...
        'BusyAction','cancel',...
        'Interruptible','off');
    set(handles.hs,'units','normalized')
    xl = xl + dx2(1);
end

for i =1:min([Ntabs,9])
    pos = [xl+dx*(i-1) yu dx dy];
    handles.htab(i) = uicontrol(...
        'parent',hparent,...
        'style','pushbutton',...
        'units','normalized','position',pos,...
        'SelectionHighlight','off',...
        'string',labels{i},...
        'BackgroundColor',COLOR,...
        'tag',tag);
    set(handles.htab(i),'units','normalized')
    pos = [xl+dx*(i-1)+ddx yu-ddy dx-2*ddx 2*ddy];
    handles.hh(i) = uicontrol(...
        'parent',hparent,...
        'style','text',...
        'units','normalized','position',pos,...
        'BackgroundColor',COLOR,...
        'tag',tag);
    set(handles.hh(i),'units','normalized')
end
try
    set(handles.hh(active),'visible','on')
catch
    active = 1;
    set(handles.hh(active),'visible','on')
end
others = setdiff(1:min([Ntabs,9]),active);
set(handles.htab(active),...
    'FontWeight','bold');
set(handles.hh(others),'visible','off');
set(handles.htab(others),...
    'ForegroundColor',0.25*[1 1 1]);
ud.handles = handles;
ud.Ntabs = Ntabs;
for i =1:min([Ntabs,9])
    ud.ind = i;
    ud.callback = callbacks{i};
    set(handles.htab(i),'callback',@doChoose,'userdata',ud,...
        'BusyAction','cancel',...
        'Interruptible','off');
    if i > 9
        set(handles.htab(i),'visible','off');
    end
end

if Ntabs > 9
    UD.in = [1:9];
    UD.Ntabs = Ntabs;
    UD.h = handles;
    UD.active = active;
    UD.who = -1;
    UD.callbacks = callbacks;
    UD.labels = labels;
    set(handles.hs(1),'userdata',UD,'enable','off');
    UD.who = 1;
    set(handles.hs(2),'userdata',UD);
end

%==========================================================================
% doChoose
%==========================================================================
function doChoose(o1,o2)
ud = get(o1,'userdata');
% Do nothing if called tab is current (active) tab
if ~strcmp(get(ud.handles.htab(ud.ind),'FontWeight'),'bold')
    spm('pointer','watch');
    set(ud.handles.hh(ud.ind),'visible','on');
    set(ud.handles.htab(ud.ind),...
        'ForegroundColor',0*[1 1 1],...
        'FontWeight','bold');
    others = setdiff(1:length(ud.handles.hh),ud.ind);
    set(ud.handles.hh(others),'visible','off');
    set(ud.handles.htab(others),...
        'ForegroundColor',0.25*[1 1 1],...
        'FontWeight','normal');
    if ud.Ntabs >9
        UD = get(ud.handles.hs(1),'userdata');
        UD.active = UD.in(ud.ind);
        UD.who = -1;
        set(ud.handles.hs(1),'userdata',UD);
        UD.who = 1;
        set(ud.handles.hs(2),'userdata',UD);
    end
    drawnow
    if ~isempty(ud.callback)
        if isa(ud.callback, 'function_handle')
            feval(ud.callback);
        else
            eval(ud.callback);
        end
    end
    drawnow
    spm('pointer','arrow');
end

%==========================================================================
% doScroll
%==========================================================================
function doScroll(o1,o2)
ud = get(o1,'userdata');
% active = ud.in(ud.active);
ud.in = ud.in + ud.who;
if min(ud.in) ==1
    set(ud.h.hs(1),'enable','off');
    set(ud.h.hs(2),'enable','on');
elseif max(ud.in) ==ud.Ntabs
    set(ud.h.hs(1),'enable','on');
    set(ud.h.hs(2),'enable','off');
else
    set(ud.h.hs,'enable','on');
end
UD.handles = ud.h;
UD.Ntabs = ud.Ntabs;
for i = 1:length(ud.in)
    UD.ind = i;
    UD.callback = ud.callbacks{ud.in(i)};
    set(ud.h.htab(i),'userdata',UD,...
        'string',ud.labels{ud.in(i)});
    if ismember(ud.active,ud.in)
        ind = find(ud.in==ud.active);
        set(ud.h.hh(ind),'visible','on');
        set(ud.h.htab(ind),...
            'ForegroundColor',0*[1 1 1],...
            'FontWeight','bold');
        others = setdiff(1:9,ind);
        set(ud.h.hh(others),'visible','off');
        set(ud.h.htab(others),...
            'ForegroundColor',0.25*[1 1 1],...
            'FontWeight','normal');
    else
        others = 1:9;
        set(ud.h.hh(others),'visible','off');
        set(ud.h.htab(others),...
            'ForegroundColor',0.25*[1 1 1],...
            'FontWeight','normal');
    end
end
ud.who = -1;
set(ud.h.hs(1),'userdata',ud)
ud.who = 1;
set(ud.h.hs(2),'userdata',ud)


% Stores the result of a classifier
classdef ClassificationResult < Data
    properties (Access = public)
        predictedClasses;
        table;
    end

    properties (Dependent)
        classNames;
        truthClasses;
    end

    methods
        function classNames = get.classNames(obj)
            classNames = obj.table.classNames;
        end

        function set.classNames(obj, classNames)
            obj.table.classNames = classNames;
        end

        function truthClasses = get.truthClasses(obj)
            truthClasses = obj.table.label;
        end

        function set.truthClasses(obj, truthClasses)
            obj.table.label = truthClasses;
        end
    end

    methods (Access = public)
        function obj = ClassificationResult(predictedClasses,table)
            if nargin > 0
                obj.predictedClasses = predictedClasses;
                obj.table = table;
            end
            obj.type = DataType.kClassificationResult;
        end
    end
end


function [varargout] = minus(varargin)

% MINUS compile the missing mex file on the fly

% Copyright (C) 2012, Donders Centre for Cognitive Neuroimaging, Nijmegen, NL
%
% 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$

% remember the original working directory
pwdir = pwd;

% determine the name and full path of this function
funname = mfilename('fullpath');
mexsrc  = [funname '.c'];
[mexdir, mexname] = fileparts(funname);

try
  % try to compile the mex file on the fly
  warning('trying to compile MEX file from %s', mexsrc);
  cd(mexdir);
  mex(mexsrc);
  cd(pwdir);
  success = true;

catch
  % compilation failed
  disp(lasterr);
  error('could not locate MEX file for %s', mexname);
  cd(pwdir);
  success = false;
end

if success
  % execute the mex file that was just created
  funname   = mfilename;
  funhandle = str2func(funname);
  [varargout{1:nargout}] = funhandle(varargin{:});
end


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

%%
clear; close all; clc;

%% Syntax
% |exportGif(optStruct);|

%% 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 [ctf] = ctf_read_badchannels(folder,ctf);

% ctf_read_badchannels - read BadChannels file from a CTF .ds folder
%
% [ctf] = ctf_read_badchannels(folder,ctf)
%
% This function reads the BadChannels text file in a .ds folder.
%
% The BadChannels file is a text file that contains the channel names of
% any bad channels.  The channel names are assumed to be listed in a single
% column, one channel per line.
%
% INPUTS
%
% If you do not wish to specify an input option, use [], but keep the order
% of the input options as above.  Only specify as many input options as
% required.  With no input options, the function will prompt for a folder
% and read the BadChannels file (if it exists).
%
% folder - the directory of the .ds data set to read.  By
% default, a gui prompts for the folder.
%
% ctf - a struct with folder, setup, sensor and data fields.
%
% OUTPUTS
%
% ctf.sensor.bad - a string cell array of channel labels
%
%      <>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> %
%      <                                                       > %
%      <                      DISCLAIMER:                      > %
%      <                                                       > %
%      < THIS PROGRAM IS INTENDED FOR RESEARCH PURPOSES ONLY.  > %
%      < THIS PROGRAM IS IN NO WAY INTENDED FOR CLINICAL OR    > %
%      <                     OFFICIAL USE.                     > %
%      <                                                       > %
%      <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<> %
%

% $Revision: 1.1 $ $Date: 2009-01-30 03:49:27 $

% Copyright (C) 2005  Darren L. Weber
%
% 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 2
% 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, write to the Free Software
% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

% Modified: 01/2005, Darren.Weber_at_radiology.ucsf.edu
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%-----------------------------------------------
% ensure we have the folder

if exist('folder','var'),
  if exist('ctf','var'),
    ctf = ctf_folder(folder,ctf);
  else
    ctf = ctf_folder(folder);
  end
else
  if exist('ctf','var'),
    ctf = ctf_folder([],ctf);
  else
    ctf = ctf_folder;
  end
end

%--------------------------------------------------------------
ver = '$Revision: 1.1 $ $Date: 2009-01-30 03:49:27 $';
fprintf('\nCTF_READ_BADCHANNELS [v %s]\n',ver(11:15)); tic;

%----------------------------------------------------------------
% read the file

[folderPath,folderName,folderExt] = fileparts(ctf.folder);
BadChannelsFile = findBadChannelsFile( ctf.folder );

ctf.sensor.bad = textread(BadChannelsFile,'%s','delimiter','\n');

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

return

% -------------------------------------------------------
function BadChannelsFile = findBadChannelsFile( folder )

filename = dir([ folder filesep 'BadChannels' ]);
if isempty(filename)
    filename = dir([ folder filesep 'badchannels' ]);
end;

if isempty(filename)
    error('No BadChannels file in selected folder');
else
    BadChannelsFile = [ folder filesep filename.name ];
end;

return


function [hdl, inf] = dxAviOpen(fname);
	hdl = [];
	inf = [];
	if ~exist(fname,'file')
		fprintf(2,'dxAviOpen error, cannot find file %s\n', fname);
		return;
	end
	[hdl, t] = dxAviOpenMex(fname);
	if length(hdl) == 0;
		error(['Error opening video file ', fname]);
		return;
	end
	inf.Width = t(1);
	inf.Height = t(2);
	inf.NumFrames = t(3);
	inf.FrameRate = t(4);
	inf.TotalDuration = t(5);


%demo_SingleRoomDRIR - Demonstrates the upgrade from SingleRoomDRIR to SingleRoomSRIR.
% The demo script downloads the file from the SOFA database,
% upgrades the conventions and saves it as a new file in the local database.

% #Author: Michael Mihocic: (23.12.2022)
%
% SOFA Toolbox - demo script
% Copyright (C) Acoustics Research Institute - Austrian Academy of Sciences
% Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European Commission - subsequent versions of the EUPL (the "License")
% You may not use this work except in compliance with the License.
% You may obtain a copy of the License at: https://joinup.ec.europa.eu/software/page/eupl
% Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
% See the License for the specific language governing  permissions and limitations under the License.

%% Load SOFA file
db='thk';
fn='DRIR_CR1_VSA_50RS_L.sofa';
Obj=SOFAload(['db://' fullfile('database',db,fn)]);

%% Upgrade convention
disp(['Old conventions: ' Obj.GLOBAL_SOFAConventions ' v' Obj.GLOBAL_SOFAConventionsVersion])
[Obj,modified] = SOFAupgradeConventions(Obj);
disp(['New conventions: ' Obj.GLOBAL_SOFAConventions ' v' Obj.GLOBAL_SOFAConventionsVersion])

%% save the SOFA file
SOFAfn=fullfile([SOFAdbPath,'\','sofatoolbox_test','\',fn]);
disp(['Saving:  ' SOFAfn]);
Obj=SOFAsave(SOFAfn, Obj);


% eegplugin_mffmatlabio() - plugin for importing and exporting MFF files
%
% Usage:
%   >> eegplugin_mffmatlabio(fig, trystrs, catchstrs);
%
% Inputs:
%   fig        - [integer] eeglab figure.
%   trystrs    - [struct] "try" strings for menu callbacks.
%   catchstrs  - [struct] "catch" strings for menu callbacks.
%
% Main files
% ----------
% eegplugin_mffmatlabio.m - create menu in the EEGLAB interface
% pop_mffimport.m     - import MFF file into EEGLAB (graphic interface)
% pop_mffexport.m     - export EEGLAB structure to MFF file/folder (graphic interface)
%
% Support files
% -------------
% mff_import.m          - import MFF file/folder to EEGLAB structure
% mff_importcategories.m   - import 'categories.xml' file
% mff_importcoordinates.m  - import 'coordinates.xml' file
% mff_importepochs.m       - import 'epochs.xml' file
% mff_importevents.m       - import 'eventsxxxx.xml' file(s)
% mff_importinfo.m         - import 'info.xml' file
% mff_importinfon.m        - import 'info1.xml' file
% mff_importpnsset.m       - import PNS file
% mff_importsensorlayout.m - import 'sensorlayout.xml' file
% mff_importsignal.m       - import 'signal1.bin' file
% mff_importsubject.m      - import subject file
% mff_export.m             - export MFF file/folder from EEGLAB structure
% mff_createmff.m          - create empty MFF file/folder
% mff_exportcategories.m   - export 'categories.xml' file
% mff_exportcoordinates.m  - export 'coordinates.xml' file
% mff_exportepochs.m       - export 'epochs.xml' file
% mff_exportevents.m       - export 'events.xml' file
% mff_exportinfo.m         - export 'info.xml' file
% mff_exportinfon.m        - export 'info1.xml' file
% mff_exportpnsset.m       - export PNS file
% mff_exportsensorlayout.m - export 'sensorlayout.xml' file
% mff_exportsignal.m       - export 'signal1.bin' file
% mff_exportsubject.m      - export subject file
% mff_decodetime.m         - convert MFF time to Matlab time
% mff_encodetime.m         - convert Matlab time to MFF time
% mff_getobj.m             - convert Java object to Matlab
% mff_setobj.m             - convert Matlab object to Java
% pop_mffimport.m          - EEGLAB import GUI
% pop_mffexport.m          - EEGLAB export GUI
% eegplugin_mffmatlabio.m  - EEGLAB startup function
% eeg_compare.m            - Function to compare EEGLAB sturtures
% mff_fileio_read_data.m   - File-IO function to read data
% mff_fileio_read_header.m - File-IO function to read header
% mff_fileio_read_event.m  - File-IO function to read event
% mff_fileio_write.m       - File-IO function to write data and events

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

function versionstr = eegplugin_mffmatlabio(fig, trystrs, catchstrs)

    %global EEG
    versionstr = '3.4';
    if nargin < 3
        disp('eegplugin_mffmatlabio requires 3 arguments');
        return
    end

    % add amica folder to path
    % -----------------------
    if ~exist('mff_import')
        p = which('eegplugin_mffmatlabio');
        p = p(1:findstr(p,'eegplugin_mffmatlabio.m')-1);
        addpath(p);
    end

    % find tools menu
    % ---------------
    menui = findobj(fig, 'tag', 'import data');
    menue = findobj(fig, 'tag', 'export');

    % menu callback commands
    % ----------------------
    comload    = [  trystrs.no_check '[EEG, LASTCOM] = pop_mffimport;' catchstrs.store_and_hist ];
    comwrite   = [  trystrs.no_check 'LASTCOM = pop_mffexport(EEG);' catchstrs.store_and_hist ];

    % create menus (CHANGING THESE MENUS AFFECTS THE MAIN eeglab.m FUNCTION)
    % ------------
    submenu = uimenu( menui, 'Label', 'Import EGI/Philips .mff file', 'separator', 'on', 'CallBack', comload);
    submenu = uimenu( menue, 'Label', 'Export EGI/Philips .mff file', 'separator', 'on', 'CallBack', comwrite);


function varargout = StrainMeasurement(varargin)

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @StrainMeasurement_OpeningFcn, ...
                   'gui_OutputFcn',  @StrainMeasurement_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

function StrainMeasurement_OpeningFcn(hObject, eventdata, handles, varargin)

handles.output = hObject;
guidata(hObject, handles);

global Status Parameters Files

%ENTER DEFAULT DIRECTORY:
Files.DefaultDir = 'C:\';

Files.OldDir = cd;

Status.Loop = 2;
while Status.Loop ~= 0
    if Status.Loop == 2
        Files.AFile = 0;
        Files.APath = 0;
        Files.ZFile = 0;
        Files.ZPath = 0;
        Status.InPar(1:5)=[0 0 0 0 0];
        Status.Analysis = 0;
        cla(handles.Axes_Image)
        cla(handles.Axes_Intensity)
        xlabel(handles.Axes_Intensity, 'pixel  [-]', 'Color', 'w')
        ylabel(handles.Axes_Intensity, 'intensity  [-]', 'Color', 'w')
        set(handles.Button_FileChange, 'Enable', 'off')
        set(handles.Button_TBSet, 'Enable', 'off')
        set(handles.Button_LRSet, 'Enable', 'off')
        set(handles.Button_Initialize, 'Enable', 'off')
        set(handles.Text_FileA, 'String', '- no data selected -', 'ForegroundColor', [1 0 0])
        set(handles.Text_FileZ, 'String', '- no data selected -', 'ForegroundColor', [1 0 0])
        set(handles.Text_TBound, 'String', '---', 'ForegroundColor', [1 0 0])
        set(handles.Text_BBound, 'String', '---', 'ForegroundColor', [1 0 0])
        set(handles.Text_LBound, 'String', '---', 'ForegroundColor', [1 0 0])
        set(handles.Text_RBound, 'String', '---', 'ForegroundColor', [1 0 0])
        set(handles.Text_CurrentFile, 'String', '- - -', 'ForegroundColor', [1 1 0])
        Files.CurrentDir = Files.DefaultDir;
        cd (Files.CurrentDir);

    end
    if (Status.InPar - 1) == zeros
        set(handles.Button_Start, 'Enable', 'on')
    else
        set(handles.Button_Start, 'Enable', 'off')
    end
    if Status.InPar(5) == 0
        set(handles.Text_Status, 'String', '-  N O T   I N I T I A L I Z E D  -', 'ForegroundColor', [1 0 0])
    else
        set(handles.Text_Status, 'String', '-  R E A D Y  -', 'ForegroundColor', [0 1 0])
    end
    Status.Loop = 0;
    figure(handles.Main)
    uiwait(handles.Main)
end

close all
cd (Files.OldDir);

function varargout = StrainMeasurement_OutputFcn(hObject, eventdata, handles)
%varargout{1} = handles.output;

function Button_FileALoad_Callback(hObject, eventdata, handles)
    global Status Parameters Files
    Status.Loop = 1;
    [Files.AFile, Files.APath] = uigetfile({'*.bmp;*.tif;*.jpg;*.TIF;*.BMP;*.JPG','image files (*.bmp,*.tif,*.jpg)';'*.*',  'all files (*.*)'}, 'SELECT FIRST IMAGE', Files.CurrentDir);
    if Files.APath ~= 0
        set(handles.Text_FileA, 'String', Files.AFile, 'ForegroundColor', [0 1 0])
        Files.CurrentDir = Files.APath;
        Status.InPar(1) = 1;
        [Files.ZFile, Files.ZPath] = uigetfile({'*.bmp;*.tif;*.jpg;*.TIF;*.BMP;*.JPG','image files (*.bmp,*.tif,*.jpg)';'*.*',  'all files (*.*)'}, 'SELECT LAST FILE', Files.CurrentDir);
        if Files.ZPath ~= 0
            set(handles.Text_FileZ, 'String', Files.ZFile, 'ForegroundColor', [0 1 0])
            Files.CurrentDir = Files.ZPath;
            Status.InPar(2) = 1;
        end
    end
    if Status.InPar(1:2)-1 == 0
        CreateFilelist(handles)
    end
    uiresume

function Button_FileChange_Callback(hObject, eventdata, handles)
    global Status Parameters Files
    Status.Loop = 1;
    set(handles.Panel_ChangeFile, 'Visible', 'on')
    set(handles.Listbox_File, 'String', Files.Filelist)

function Button_TBSet_Callback(hObject, eventdata, handles)
    global Status Parameters Files
    Status.Loop = 1;
    set(handles.Text_Status, 'String', sprintf('Click TOP and BOTTOM of the integration range \nin the UPPER IMAGE.'), 'ForegroundColor', [1 1 0])
    axes(handles.Axes_Image)
    Input = ginput(2);
    Input = sort(Input, 1, 'ascend');
    Parameters.TB = round(Input(1, 2));
    Parameters.BB = round(Input(2, 2));
    Status.InPar(3) = 1;
    DisplayImage(handles, Files.ActualFile)
    uiresume

function Button_LRSet_Callback(hObject, eventdata, handles)
    global Status Parameters Files
    Status.Loop = 1;
    set(handles.Text_Status, 'String', sprintf('Click LEFT BORDER and RIGHT BORDER \nof the integration range.'), 'ForegroundColor', [1 1 0])
    axes(handles.Axes_Intensity)
    Input = ginput(2);
    Input = sort(Input,1, 'ascend');
    Parameters.LB = round(Input(1, 1));
    Parameters.RB = round(Input(2, 1));
    Status.InPar(4) = 1;
    DisplayImage(handles, Files.ActualFile)
    uiresume

function Checkbox_IIP_Callback(hObject, eventdata, handles)

function Button_Start_Callback(hObject, eventdata, handles)
    global Status Parameters Files
    set(handles.Button_FileALoad, 'Enable', 'off')
    set(handles.Button_FileChange, 'Enable', 'off')
    set(handles.Button_TBSet, 'Enable', 'off')
    set(handles.Button_LRSet, 'Enable', 'off')
    set(handles.Button_Start, 'Enable', 'off')
    set(handles.Button_Initialize, 'Enable', 'off')
    Status.Loop = 1;
    FileCount = 0;
    AnalysisLoop = 1;
    Status.Analysis = 1;
    Parameters.VAR = get(handles.Checkbox_VAR, 'Value');
    Parameters.ICB = get(handles.Checkbox_ICB, 'Value');
    xtest = [1 : Parameters.ImageSize(1)];

    while AnalysisLoop == 1
        FileCount = FileCount + 1;
        DisplayImage(handles, Files.Filelist(FileCount, :))
        xdata = Parameters.IntegratedIntensity(:,1);
        ydata = Parameters.IntegratedIntensity(:,2);
        axes(handles.Axes_Intensity)
        hold on
        % data fit with two error functions, fixed at y(x0) = y(x1) = 0
        if FileCount == 1
            FitGuess = [max(ydata)/2, 0.1, Parameters.InitialGuess(1), 0.1, Parameters.InitialGuess(2)];
        end
        if Parameters.ICB == 1
            %data correction
            MaxLeft = 2/FitGuess(2)+FitGuess(3);
            MaxRight = FitGuess(5) - 2/FitGuess(4);
            Range = [0,0];
            i = 0;
            while Range(1) == 0
                i = i + 1;
                if xdata(i) >= MaxLeft
                	Range(1) = i;
                end
            end
            while Range(2) == 0
            	i = i + 1;
                if xdata(i) >= MaxRight
                	Range(2) = i-1;
                end
            end
            ydata(Range(1):Range(2)) = Parameters.UpperValue;
            FitGuess(1) = Parameters.UpperValue/2;
            plot(xdata(Range(1):Range(2)), ydata(Range(1):Range(2)), 'g-')
        end
        Exitflag = 0;
        LineHandle = 0;
        j = 0;
        while Exitflag == 0
            j = j + 1;
            [FitData, Resnom, Residual, Exitflag] = lsqcurvefit(@(FitData, xdata)  FitData(1)*(erf(FitData(2)*(xdata-FitData(3)))-erf(FitData(4)*(xdata-FitData(5)))), FitGuess, xdata, ydata);
            ytest = FitData(1)*(erf(FitData(2)*(xtest-FitData(3)))-erf(FitData(4)*(xtest-FitData(5))));
            if LineHandle ~= 0
                delete(LineHandle)
            end
            LineHandle = plot (xtest, ytest, 'y-');
            FitGuess = FitData;
            if j == 10
                Exitflag = 1;
            end
        end
        clear xdata ydata ytest
        if FileCount == 1
            RelAnalysisRange = [Parameters.LB - FitData(3), Parameters.RB - FitData(5)];
        end
        if Parameters.VAR == 1
            Parameters.LB = round(FitData(3) + RelAnalysisRange(1));
            Parameters.RB = round(FitData(5) + RelAnalysisRange(2));
            if Parameters.LB < 1
                Parameters.LB = 1;
            end
            if Parameters.RB > Parameters.ImageSize(1)
                Parameters.RB = Parameters.ImageSize(1);
            end
        end
        MarkerPosition(FileCount, 1:2) = [FitData(3), FitData(5)];
        if FileCount == (size(Files.Filelist, 1))
            AnalysisLoop = 0;
        end
        Completed = round(FileCount/size(Files.Filelist, 1) * 100);
        set(handles.Text_Status, 'String', ['A N A L Y S I S   R U N N I N G   -   ', num2str(Completed), '%   C O M P L E T E D'], 'ForegroundColor', [1 0 0])

    end
    Status.Analysis = 0;
    ImgNo(:,1) = [1:FileCount];
    MarkerDistance(:,1) = MarkerPosition(:,2) - MarkerPosition(:,1);
    Strain(:,1) = MarkerDistance(:,1)/MarkerDistance(1,1)-1;
    OutData(:, 1) = ImgNo(:,1);
    OutData(:, 2) = MarkerPosition(:,1);
    OutData(:, 3) = MarkerPosition(:,2);
    OutData(:, 4) = MarkerDistance(:,1);
    OutData(:, 5) = Strain(:,1);
    save([Files.Path, 'StrainMeasurement.dat'], 'OutData', '-ascii', '-tabs')
    save([Files.Path, 'StrainX.dat'], 'Strain', '-ascii', '-tabs')
    PlotHandle = figure;
    plot(ImgNo(:,1), Strain(:,1), 'bo')
    ylabel('strain  [-]')
    xlabel('image no.  [-]')
    set(gca, 'Box', 'on')
    saveas(PlotHandle, [Files.Path, '\StrainX.fig'])
    figure(handles.Main)
    set(handles.Button_FileALoad, 'Enable', 'on')
    set(handles.Button_FileChange, 'Enable', 'on')
    set(handles.Button_TBSet, 'Enable', 'on')
    set(handles.Button_LRSet, 'Enable', 'on')
    set(handles.Button_Start, 'Enable', 'on')
    set(handles.Button_Initialize, 'Enable', 'on')
    set(handles.Text_Status, 'String', '-  A N A L Y S I S   C O M P L E T E D  -', 'ForegroundColor', [0 1 0])
    clear xtest MarkerPosition ImgNo MarkerDistance Strain OutData
    DisplayImage(handles, Files.Filelist(1,:))

    uiresume

function Button_Initialize_Callback(hObject, eventdata, handles)
    global Status Parameters Files
    Status.Loop = 1;
    set(handles.Text_Status, 'String', sprintf('Click CENTER of the LEFT SLOPE \nand CENTER of the RIGHT SLOPE \nin the LOWER GRAPH.'), 'ForegroundColor', [1 1 0])
    axes(handles.Axes_Intensity)
    Input = ginput(2);
    Input = sort(Input,1, 'ascend');
    Parameters.InitialGuess(1:2) = Input(1:2, 1);
    Status.InPar(5) = 1;
    uiresume

function CreateFilelist(handles)
    global Status Parameters Files
    String = get(handles.Text_Status, 'String');
    set(handles.Text_Status, 'String', 'WAIT.....')
    Files.Filelist = [];
    FileLength(1) = size(Files.AFile,2);
    FileLength(2) = size(Files.ZFile,2);
    FileType(1,:) = Files.AFile((FileLength(1)-3):FileLength(1));
    FileType(2,:) = Files.ZFile((FileLength(2)-3):FileLength(2));
    FileStart = str2num(Files.AFile((FileLength(1)-6):(FileLength(1)-4)));
    FileEnd = str2num(Files.ZFile((FileLength(2)-6):(FileLength(2)-4)));
    FileLabel(1,:) = Files.AFile(1:(FileLength(1)-7));
    FileLabel(2,:) = Files.ZFile(1:(FileLength(2)-7));

    if FileType(1,:) ~= FileType(2,:)
        fprintf('CRITICAL FILENAME ERROR - SCRIPT TERMINATED \n');
        uiresume
    end
    if FileLabel(1,:) ~= FileLabel(2,:)
        fprintf('CRITICAL FILENAME ERROR - SCRIPT TERMINATED \n');
        uiresume
    end
    if Files.APath ~= Files.ZPath
        fprintf('CRITICAL FILENAME ERROR - SCRIPT TERMINATED \n');
        uiresume
    end

    j = 0;
    for i = FileStart:FileEnd
        j = j + 1;
        FileNo = num2str(i + 1000);
        Filename(j,:) = [FileLabel(1,:), FileNo(:,2:4), FileType(1,:)];
    end
    Files.Filelist = Filename;
    Parameters.FileType = FileType(1,:);
    Parameters.FileLabel = FileLabel(1,:);
    Files.Path = Files.APath;
    clear Filename FileLength FileType FileLabel

    Files.ActualFile = Files.Filelist(1,:);
    DisplayImage(handles, Files.ActualFile)

    set(handles.Button_FileChange, 'Enable', 'on')
    set(handles.Button_TBSet, 'Enable', 'on')
    set(handles.Button_LRSet, 'Enable', 'on')
    Status.InPar(3:5) = [0 0 0];

    set(handles.Button_Initialize, 'Enable', 'on')

function DisplayImage(handles, Filename)
    global Status Parameters Files

    set(handles.Text_CurrentFile, 'String', Filename)
    TempData = imread([Files.Path, Filename]);
    ImageData = mean(double(TempData), 3);
    Parameters.ImageSize = [size(ImageData, 2) size(ImageData, 1)];
    clear TempData

    axes(handles.Axes_Image)
    cla(handles.Axes_Image)
    axis ij
    hold on
    imagesc(ImageData);
    if Status.InPar(3) == 0
        Parameters.TB = 1;
        Parameters.BB = size(ImageData, 1);
    else
        plot([1 Parameters.ImageSize(1)], [Parameters.TB Parameters.TB], 'w-')
        plot([1 Parameters.ImageSize(1)], [Parameters.BB Parameters.BB], 'w-')
    end
    if Status.InPar(4) == 0
        Parameters.LB = 1;
        Parameters.RB = size(ImageData, 2);
    else
        plot([Parameters.LB Parameters.LB], [1 Parameters.ImageSize(2)], 'w-')
        plot([Parameters.RB Parameters.RB], [1 Parameters.ImageSize(2)], 'w-')
    end
    set(handles.Axes_Image, 'Box', 'on', 'XColor', 'w', 'YColor', 'w', 'XTickLabelMode', 'manual', 'XTickLabel', [], 'XTickMode', 'manual', 'XTick', [],'YTickLabelMode', 'manual', 'YTickLabel', [], 'YTickMode', 'manual', 'YTick', [], 'XLim', [1 Parameters.ImageSize(1)], 'YLim', [1 Parameters.ImageSize(2)])
    set(handles.Text_TBound, 'String', Parameters.TB, 'ForegroundColor', [0 1 0])
    set(handles.Text_BBound, 'String', Parameters.BB, 'ForegroundColor', [0 1 0])
    set(handles.Text_LBound, 'String', Parameters.LB, 'ForegroundColor', [0 1 0])
    set(handles.Text_RBound, 'String', Parameters.RB, 'ForegroundColor', [0 1 0])
    Status.InPar(3:4) = [1 1];
    Status.InPar(5) = 0;

    IntegratedIntensity = [];
    Parameters.IntegratedIntensity = [];
    Parameters.UpperValue = 0;
    IntegratedIntensity(1:(Parameters.RB-Parameters.LB+1), 1:2) = zeros;
    IntegratedIntensity(1:(Parameters.RB-Parameters.LB+1), 1) = [Parameters.LB:Parameters.RB];
    for i = Parameters.TB:Parameters.BB
        TempData(:,1) = ImageData(i, Parameters.LB:Parameters.RB);
        IntegratedIntensity(:,2) = IntegratedIntensity(:,2) + TempData;
        if Status.Analysis == 1 & Parameters.ICB == 1
        	TempData = sort(TempData, 'descend');
            Parameters.UpperValue = Parameters.UpperValue + mean(TempData(1:round(0.1*size(TempData, 1)), 1));
        end
    end
    axes(handles.Axes_Intensity)
    hold off
    plot(IntegratedIntensity(:,1), IntegratedIntensity(:,2), 'g.')
    set(handles.Axes_Intensity, 'Color', [0 0 0], 'Box', 'on', 'XColor', 'w', 'YColor', 'w', 'XLim', [1, Parameters.ImageSize(1)])
    xlabel(handles.Axes_Intensity, 'pixel  [-]', 'Color', 'w')
    ylabel(handles.Axes_Intensity, 'intensity  [-]', 'Color', 'w')

    Parameters.IntegratedIntensity = IntegratedIntensity;
    clear IntegratedIntensity TempData UpperValueTemp

function Listbox_File_Callback(hObject, eventdata, handles)
    global Status Parameters Files
    FileNo = get(handles.Listbox_File, 'Value');
    Files.ActualFile = Files.Filelist(FileNo, :);
    set(handles.Panel_ChangeFile, 'Visible', 'off')
    DisplayImage(handles, Files.ActualFile)

    uiresume

function Button_Reset_Callback(hObject, eventdata, handles)
    global Status Parameters Files
    Status.Loop = 2;
    Files.Filelist = [];

    uiresume


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

%%
clear; close all; clc;

%% Syntax
% |[cMap]=igviridis(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 w = load_from_datasource(ds, chans, startt, endt, combine_waves, usewkaround)
   %load_from_datasource
   %
   % w = load_from_datasource(ds, chans, startt, endt, combine_waves)

   % determine the load function based upon the datasource's type

   if isVoidInterpreter(ds)
      ds = setinterpreter(ds, get_load_routine(ds, usewkaround));
   end
   request = packDataRequest(ds, chans, startt, endt, combine_waves);
   getter = get(ds,'interpreter');
   %w = getter(request, combine_waves);
   w = getter(request);

   % TODO: Trim waveform to request
   % maybe we're already done?
   return
   % -------------------------------------------------------------------
   % if the datasource is file based, or if it requires a user-defined
   % intepreter function, then do what follows.  Otherwise, we're done

   if ~isVoidInterpreter(ds)
      myLoadFunc = get(ds,'interpreter');

      %user_defined datasource
      ALLOW_MULTIPLE = true;
      ERROR_ON_EMPTY = true;
      for j = 1:numel(startt)
         myStartTime = startt(j);
         myEndTime = endt(j);

         % grab all files for date range, discarding duplicates
         fn = getfilename(ds, chans,subdivide_files_by_date(ds,myStartTime, myEndTime));
         fn = unique(fn);

         %load all waveforms for these files
         clear somew

         for i=1:numel(fn)
            w = load_from_file(myLoadFunc,fn{i},ALLOW_MULTIPLE, ERROR_ON_EMPTY);
            %w = w(ismember([w.cha_tag],[chans])); %keep only appropriate station/chan
            ct = w.cha_tag;
            w = w(ct.matching(chans)); %Not 100% sure about this one
            w = filter_by_time(w, myStartTime, myEndTime);
            if numel(w) > 0
               somew(i) = {w};
            end
         end %for fn
         if ~exist('somew','var')
            w = waveform; w = w([]);
         else
            if combine_waves,
               w = combine([somew{:}]);
            else
               w = [somew{:}];
            end
         end
         allw(j) = {w};
      end %each start time
      w = [allw{:}];
   end %~isVoidInterpreter
end

function tf = isVoidInterpreter(ds)
   tf = strcmpi(func2str(get(ds,'interpreter')),'void_interpreter');
end


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

%%
clear; close all; clc;

%% Syntax
% |[varargout]=febioOutputView(pathName,febio_spec);|

%% 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 isUniformized = isUniformStr(structNum,planC)
%function isUniformized = isUniformStr(structnum,planC)
%
%This function checks whether the strucutre structNum has been uniformized
%
%APA, 04/23/2010
%
% 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/>.

if ~exist('planC','var')
    global planC
end
indexS = planC{end};
[scanSet,relStrNum] = getStructureAssociatedScan(structNum, planC);

if relStrNum<=52
    cellNum = 1;
    bitsM = planC{indexS.structureArray}(scanSet).bitsArray;
    bitGetM = bitget(bitsM, structNum);
else
    cellNum = ceil((relStrNum-52)/8)+1;
    bitsM = planC{indexS.structureArrayMore}(scanSet).bitsArray{cellnum};
    bitGetM = bitget(bitsM, relStrNum-52-(cellNum-2)*8);
end

if any(bitGetM)
    isUniformized = 1;
else
    isUniformized = 0;
end

return;


function err = procstreamOrderCheckDlg(elem)
    % Check the processing stream order
    [fn_error, missing_args, prereqs] = elem.CheckProcStreamOrder();
    if isa(fn_error, 'FuncCallClass')
        l1 = sprintf('The following function: %s', fn_error.nameUI);
        l2 = sprintf('cannot run because of unavailable input(s) %s.\n', cell2str(missing_args));
        if ~isempty(prereqs)
           l3 = sprintf('Add one of the following prerequisite functions to the processing stream:\n%s', strtrim(prereqs));
        else
           l3 = 'Ensure that a function which outputs the necessary inputs appears before the function in the processing stream.';
        end
        choice = questdlg({l1, l2, l3}, ...
        'Invalid Processing Stream', ...
        'Continue Anyway','Cancel', 'Cancel');
        switch choice
            case 'Continue Anyway'
                err = 0;
            case 'Cancel'
                err = -1;
            otherwise
                err = -1;
        end
    else
       err = 0;
    end
end


classdef EventAnnotation < handle
    properties
        sample;
        label;
    end

    methods
        function obj = EventAnnotation(sample,label)
            if nargin>1
                obj.sample = sample;
                obj.label = label;
            end
        end
    end
end


function qualityMeasure = imageQuality_srm(sr, gt)

% Making sure that only functions in the sr-metric folder can be called
addpath(genpath('../algorithms/qualityMeasures/sr-metric/'));

path = pwd;
cd(['..', filesep, 'algorithms', filesep, 'qualityMeasures', filesep, 'sr-metric']);

% Making sure that only functions in the sr-metric folder can be called
addpath('external/matlabPyrTools','external/randomforest-matlab/RF_Reg_C');

qualityMeasure = quality_predict(sr);

% Making sure that only functions in the sr-metric folder can be called
rmpath('external/matlabPyrTools','external/randomforest-matlab/RF_Reg_C');

cd(path);

% Making sure that only functions in the sr-metric folder can be called
rmpath(genpath('../algorithms/qualityMeasures/sr-metric/'));


function all_parts = add_sp_parts(sp, sp_list)
% Sp are made of parts of original superpixelation. This function gives the
% list of combined parts of a collection of sp.

all_parts = [];

for i = sp_list
    all_parts = [all_parts, sp{i}.parts];
end