function labels_plot(expdirs,jabs,T0,T1,varargin)
% Labelgram
% labels_plot(expdirs,jabs,T0,T1,varargin)

if ~exist('expdirs','var')
  expdirs = {};
end
assert(iscellstr(expdirs));
if ~exist('jabs','var')
  jabs = [];
end
if isempty(jabs)
  [tfsuccess,jabs] = ExpPP.uiGetJabFiles;
  if ~tfsuccess
    return;
  end
end
validateattributes(T0,{'numeric'},{'scalar' 'integer'});
validateattributes(T1,{'numeric'},{'scalar' 'integer'});
assert(T1>=T0,'T1 must be greater than or equal to T0.');
% if ~exist('nframesplot','var')
%   nframesplot = [];
% elseif ~isempty(nframesplot)
%   assert(isnumeric(nframesplot));
%   assert(isscalar(nframesplot) || numel(nframesplot)==2,'Invalid nframesplot');
% end

assert(isscalar(jabs),'Currently expect single jab/macguffin.');
if iscellstr(jabs)
  jabfiles = jabs;
  jabs = loadAnonymous(jabs{1});
elseif isa(jabs,'Macguffin');
  jabfiles = {[]};
else
  assert(false,'''jabs'' argument must be either a jab filename or object.');
end

if isempty(expdirs)
  expdirs = jabs.expDirNames;
end
Nexp = numel(expdirs);

jab = jabs;
%jab.modernize();

% get the labels for expdirs
assert(numel(jab.expDirNames)==numel(jab.labels));
[tf,loc] = ismember(expdirs,jab.expDirNames);
lbls = Labels.labels(Nexp);
lbls(tf) = jab.labels(loc(tf));

% AL: loading Trx takes forever
% % Trx/T0/T1/nframesplot
% trxfname = jab.file.trxfilename;
% trxstarts = nan(Nexp,1);
% trxends = nan(Nexp,1);
% for i = 1:Nexp
%   trxfile = fullfile(expdirs{i},trxfname);
%   tmp = load(trxfile,'trx');
%   trxstarts(i) = min([tmp.trx.firstframe]);
%   trxends(i) = max([tmp.trx.endframe]);
% end
% T0 = min(trxstarts);
% T1 = max(trxends)-1;
% if ~isempty(nframesplot)
%   if numel(nframesplot)==1,
%     T1 = min(T1,T0+nframesplot-1);
%   else
%     assert(numel(nframesplot)==2);
%     T0 = nframesplot(1);
%     T1 = min(T1,nframesplot(2));
%   end
% end

% go
behnames = Labels.verifyBehaviorNames(jab.behaviors.names);
m = Labels.labelMatrix(lbls,T0,T1,behnames);
ethogram_plot_core(figure,m,T0,T1,expdirs,behnames,repmat(jabfiles,numel(behnames),1));


function cerrFeatS = calcIBSI1PhantomRadiomics(config)
% Compute features using IBSI reference Lung CT image and configurations.
%--------------------------------------------------------------------------
% INPUTS
% config : 'C' or 'A' (to use settings corresponding to IBSI coonfig C or A).
%--------------------------------------------------------------------------
% AI 06/25/2020

%% Get config file path
switch(config)

    case 'C'
        configPath_avg = fullfile(fileparts(fileparts(getCERRPath)),...
            'Unit_Testing/settings_for_comparisons/IBSIconfigC_avg.json');
        configPath_merge = fullfile(fileparts(fileparts(getCERRPath)),...
            'Unit_Testing/settings_for_comparisons/IBSIconfigC_merge.json');

    case 'A'
        configPath_avg = fullfile(fileparts(fileparts(getCERRPath)),...
            'Unit_Testing/settings_for_comparisons/IBSIconfigA_avg.json');
        configPath_merge = fullfile(fileparts(fileparts(getCERRPath)),...
            'Unit_Testing/settings_for_comparisons/IBSIconfigA_merge.json');

end

%% Load IBSI CT phantom
fpath = fullfile(fileparts(fileparts(getCERRPath)),...
    'Unit_Testing/data_for_cerr_tests/IBSI1_CT_phantom/IBSILungCancerCTImage.mat.bz2');
planC = loadPlanC(fpath,tempdir);
planC = updatePlanFields(planC);
planC = quality_assure_planC(fpath,planC);
indexS = planC{end};

%% Compute features using CERR
%Read config files
param1S = getRadiomicsParamTemplate(configPath_avg);
param2S = getRadiomicsParamTemplate(configPath_merge);

%Get struct name
strName = param1S.structuresC;
strName = strName{1};
strC = {planC{indexS.structures}.structureName};
structNum = getMatchingIndex(strName,strC,'exact');
scanNum = getStructureAssociatedScan(structNum,planC);

%Compute features (avg)
cerrFeatS = calcGlobalRadiomicsFeatures...
    (scanNum, structNum, param1S, planC);

%Compute features (merge)
cerrFeat2S = calcGlobalRadiomicsFeatures...
    (scanNum, structNum, param2S, planC);
mergeFieldsC = intersect(fieldnames(cerrFeatS),fieldnames(cerrFeat2S));

for m = 1:length(mergeFieldsC)
    mergeFeatC = intersect( fieldnames(cerrFeatS.(mergeFieldsC{m})),...
        fieldnames(cerrFeat2S.(mergeFieldsC{m})));
    for n = 1:length(mergeFeatC)
        addFieldC = fieldnames(cerrFeat2S.(mergeFieldsC{m}).(mergeFeatC{n}));
        cerrFeatS.(mergeFieldsC{m}).(mergeFeatC{n}).(addFieldC{1}) ...
            = cerrFeat2S.(mergeFieldsC{m}).(mergeFeatC{n}).(addFieldC{1});
    end
end

end


function y = cvx_isconcave( x, full )
persistent remap
if isempty( remap ),
	remap = cvx_remap('concave');
end
y = remap( cvx_classify( x ) );
if nargin < 2 || ~full,
	y = all( y );
else
	y = reshape( y, x.size_ );
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 ADMINcreateDictionary(D, HOMEIMAGES, thSize)
% VISUAL OBJECT DICTIONARY
%
% Creates a visual index of all the objects in the database
%
% ADMINcreateDictionary(D, HOMEIMAGES)

homethumbnails = 'objectDictionary';
if nargin<3
    thSize = 64;
    thSize = 48;
end
minNumInstances = 0;

% List of objects
[names, counts, imagendx, objectndx, descriptionndx] = LMobjectnames(D);

% remove unfrequent objects
if minNumInstances>0
    j = find(counts>=minNumInstances);
    names  = names(j);
    counts = counts(j);
    jj = find(ismember(descriptionndx, j));
    imagendx  = imagendx(jj);
    objectndx = objectndx(jj);
    descriptionndx = descriptionndx(jj);
    [foo,descriptionndx] = ismember(descriptionndx, unique(descriptionndx));
end

% sort objects
[foo, ndx] = sort(counts, 'descend');
%[foo, ndx] = sort(names);
Nnames = length(names);
Ninstances = sum(counts);%length(imagendx);

% Create index with global names and with local instances
fid = fopen('dictionary.js', 'w');
fprintf(fid, 'var d=new Array();\n')
fprintf(fid, 'var n=new Array();\n')
fprintf(fid, 'var x=new Array();\n')
fprintf(fid, 'var a=new Array();\n')
fprintf(fid, 'var p=new Array();\n')
fprintf(fid, 'var q=new Array();\n')
fprintf(fid, 'var Nnames=%d;\n', Nnames)
fprintf(fid, 'var Ninstances=%d;\n', Ninstances)
fprintf(fid, 'var nrows=%d;\n', Nnames)
fprintf(fid, 'var ncols=%d;\n', 1)

C = 0;
for i = 1:Nnames
    na = strrep(names{ndx(i)}, '''', '');
    if length(na)>1
        na = [upper(na(1)) lower(na(2:end))];
        fprintf(fid, 'd[%d]=''%s'';\n', i, na);          % strings, object names
        fprintf(fid, 'n[%d]=''%d'';\n', i, counts(ndx(i)));         % number of instances
        fprintf(fid, 'x[%d]=''%d'';\n', i, ndx(i)); % instance index
        fprintf(fid, 'a[%d]=%d;\n', i, C); % instance index
        C = C+counts(ndx(i));
    else
        disp('short name:')
        disp(na)
    end
end

m=0;
for i = 1:Nnames
    k = find(descriptionndx==ndx(i));
    for j= 1:length(k)
        m = m+1;
        o = objectndx(k(j));
        im = imagendx(k(j));
        %page = [D(im).annotation.folder '&image=' D(im).annotation.filename];
        %page = strrep(page, '.jpg', '');
        fprintf(fid, 'p[%d]="%s";\n', m, D(im).annotation.folder);  % strings, object names
        fprintf(fid, 'q[%d]="%s";\n', m, strrep(D(im).annotation.filename, '.jpg', ''));  % strings, object names
    end
end

fclose(fid)

% Loop on D, loop on object
instancesCounts = zeros(Nnames,1);
problems = {''};
for i = 1:length(D)
    disp(i)
    k = find(imagendx==i);

    if ~isempty(k)
        o = objectndx(k);
        d = descriptionndx(k);

        % get thumbnail and extract object and mask
        try
            [annotation, img] = LMread(D, i, HOMEIMAGES);
            for n = 1:length(o)
                %[imgCrop, scaling] = LMobjectnormalizedcrop(img, annotation, o(n), 2, 64, 64);
                imgCrop = LMobjectcrop(img, annotation, o(n), 3);
                %T = imresize(imgCrop, thSize/max(size(imgCrop)), 'bilinear');
                %[foo, T] = LMimpad('', T, [thSize thSize]+6, 255);
                T = imresize(imgCrop, thSize/size(imgCrop,1), 'bilinear');
                [foo, T] = LMimpad('', T, [size(T,1) size(T,2)]+2, 255);

                %thumb = LMobjectThumbnail(D(i).annotation, img, o(n), [64 64]);

                %T = thumb(:,1:end/2-1,:);
                instancesCounts(d(n)) = instancesCounts(d(n))+1;

                %folder = fullfile(homethumbnails, sprintf('obj_%d', d(n)));
                na = strrep(names{d(n)}, '''', '');
                if length(na)>1
                    na = [upper(na(1)) lower(na(2:end))];
                    %folder = fullfile(homethumbnails, strrep(na, ' ', '_'));
                    folder = fullfile(homethumbnails, sprintf('obj_%d', d(n)));

                    filename = fullfile(folder, sprintf('ins_%d.jpg', instancesCounts(d(n))));

                    mkdir(folder)
                    filename
                    imwrite(T, filename, 'jpg', 'quality', 90)

                    %imshow(T)
                    %size(T)
                    %drawnow

                    % Add to description file: folder, SUN name
                    fid = fopen(fullfile(folder, 'description.txt'), 'a');
                    fprintf(fid, '%s/%s \n', D(i).annotation.folder, D(i).annotation.filename)
                    fclose(fid)
                end
            end
        catch
            a = lasterror
            problems = [problems; a.message];
        end
    end
end

% Loop on folders and sort object instances by prototypicality. We can
% estimate prototypicality by training a classifier and sorting the samples
% using the classification score.


function sS=transpose(sS)
% transpose list of slipSystem

sS.b = sS.b.';
sS.n = sS.n.';
sS.CRSS = sS.CRSS.';


% pop_chansel() - pop up a graphic interface to select channels
%
% Usage:
%   >> [chanlist] = pop_chansel(chanstruct); % a window pops up
%   >> [chanlist strchannames cellchannames] = ...
%                        pop_chansel(chanstruct, 'key', 'val', ...);
%
% Inputs:
%   chanstruct     - channel structure. See readlocs()
%
% Optional input:
%   'withindex'      - ['on'|'off'] add index to each entry. May also a be
%                      an array of indices
%   'select'         - selection of channel. Can take as input all the
%                      outputs of this function.
%   'selectionmode' - selection mode 'multiple' or 'single'. See listdlg2().
%
% Output:
%   chanlist      - indices of selected channels
%   strchannames  - names of selected channel names in a concatenated string
%                   (channel names are separated by space characters)
%   cellchannames - names of selected channel names in a cell array
%
% Author: Arnaud Delorme, CNL / Salk Institute, 3 March 2003

% Copyright (C) 3 March 2003 Arnaud Delorme, Salk Institute, arno@salk.edu
%
% 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

function [chanlist,chanliststr, allchanstr] = pop_chansel(chans, varargin);

    if nargin < 1
        help pop_chansel;
        return;
    end;
    if isempty(chans), disp('Empty input'); return; end;
    if isnumeric(chans),
        for c = 1:length(chans)
            newchans{c} = num2str(chans(c));
        end;
        chans = newchans;
    end;
    chanlist    = [];
    chanliststr = {};
    allchanstr  = '';

    g = finputcheck(varargin, { 'withindex'     {  'integer' 'string' } { [] {'on' 'off'} }   'off';
                                'select'        { 'cell' 'string' 'integer' } [] [];
                                'selectionmode' 'string' { 'single' 'multiple' } 'multiple'});
    if isstr(g), error(g); end;
    if ~isstr(g.withindex), chan_indices = g.withindex; g.withindex = 'on';
    else                    chan_indices = 1:length(chans);
    end;

    % convert selection to integer
    % ----------------------------
    if isstr(g.select) & ~isempty(g.select)
        g.select = parsetxt(g.select);
    end;
    if iscell(g.select) & ~isempty(g.select)
        if isstr(g.select{1})
            tmplower = lower( chans );
            for index = 1:length(g.select)
                matchind = strmatch(lower(g.select{index}), tmplower, 'exact');
                if ~isempty(matchind), g.select{index} = matchind;
                else error( [ 'Cannot find ''' g.select{index} '''' ] );
                end;
            end;
        end;
        g.select = [ g.select{:} ];
    end;
    if ~isnumeric( g.select ), g.select = []; end;

    % add index to channel name
    % -------------------------
	tmpstr = {chans};
    if isnumeric(chans{1})
        tmpstr = [ chans{:} ];
        tmpfieldnames = cell(1, length(tmpstr));
        for index=1:length(tmpstr),
            if strcmpi(g.withindex, 'on')
                tmpfieldnames{index} = [ num2str(chan_indices(index)) '  -  ' num2str(tmpstr(index)) ];
            else
                tmpfieldnames{index} = num2str(tmpstr(index));
            end;
        end;
    else
        tmpfieldnames = chans;
        if strcmpi(g.withindex, 'on')
            for index=1:length(tmpfieldnames),
                tmpfieldnames{index} = [ num2str(chan_indices(index)) '  -  ' tmpfieldnames{index} ];
            end;
        end;
    end;
    [chanlist,tmp,chanliststr] = listdlg2('PromptString',strvcat('(use shift|Ctrl to', 'select several)'), ...
                'ListString', tmpfieldnames, 'initialvalue', g.select, 'selectionmode', g.selectionmode);
    if tmp == 0
        chanlist = [];
        chanliststr = '';
        return;
    else
        allchanstr = chans(chanlist);
    end;

    % test for spaces
    % ---------------
    spacepresent = 0;
    if ~isnumeric(chans{1})
        tmpstrs = [ allchanstr{:} ];
        if ~isempty( find(tmpstrs == ' ')) | ~isempty( find(tmpstrs == 9))
            spacepresent = 1;
        end;
    end;

    % get concatenated string (if index)
    % -----------------------
    if strcmpi(g.withindex, 'on') | spacepresent
        if isnumeric(chans{1})
            chanliststr = num2str(celltomat(allchanstr));
        else
            chanliststr = '';
            for index = 1:length(allchanstr)
                if spacepresent
                    chanliststr = [ chanliststr '''' allchanstr{index} ''' ' ];
                else
                    chanliststr = [ chanliststr allchanstr{index} ' ' ];
                end;
            end;
            chanliststr = chanliststr(1:end-1);
        end;
    end;

    return;


function varargout = edgesEval( model, varargin )
% Run and evaluate structured edge detector on BSDS500.
%
% This function first runs the trained structured edge detector on every
% test or validation image in BSDS then call edgesEvalDir.m to perform the
% actual edge evaluation. edgesEval is specific to the structured edge
% detector and BSDS, edgesEvalDir is general purpose edge evaluation code.
% For example usage of edgesEval see edgesDemo.
%
% USAGE
%  varargout = edgesEval( model, prms )
%
% INPUTS
%  model      - structured edge model trained with edgesTrain
%  prms       - parameters (struct or name/value pairs)
%   .dataType   - ['test'] should be either 'test' or 'val'
%   .name       - [''] name to append to evaluation
%   .opts       - {} list of model opts to overwrite
%   .show       - [0] if true plot results using edgesEvalPlot
%   .pDistr     - [{'type','parfor'}] parameters for fevalDistr
%   .cleanup    - [0] if true delete temporary files
%   .thrs       - [99] number or vector of thresholds for evaluation
%   .maxDist    - [.0075] maximum tolerance for edge match
%
% OUTPUTS
%  varargout  - same outputs as edgesEvalDir
%
% EXAMPLE
%
% See also edgesDemo, edgesDetect, edgesEvalDir, edgesEvalPlot
%
% Structured Edge Detection Toolbox      Version 3.01
% Code written by Piotr Dollar, 2014.
% Licensed under the MSR-LA Full Rights License [see license.txt]

% get default parameters
dfs={'dataType','test', 'name','', 'opts',{}, 'show',0, ...
  'pDistr',{{'type','parfor'}}, 'cleanup',0, 'thrs',99, 'maxDist',.0075 };
p=getPrmDflt(varargin,dfs,1);

% load model and update model.opts acoording to opts
if( ischar(model) ), model=load(model); model=model.model; end
for i=1:length(p.opts)/2, model.opts.(p.opts{i*2-1})=p.opts{i*2}; end
rgbd=model.opts.rgbd; model.opts.nms=1;

% get list of relevant directories (image, depth, gt, results)
name = [model.opts.modelFnm,p.name];
imgDir = fullfile(model.opts.bsdsDir,'images',p.dataType);
depDir = fullfile(model.opts.bsdsDir,'depth',p.dataType);
gtDir  = fullfile(model.opts.bsdsDir,'groundTruth',p.dataType);
resDir = fullfile(model.opts.modelDir,p.dataType,name);
assert(exist(imgDir,'dir')==7); assert(exist(gtDir,'dir')==7);

% run edgesDetect() on every image in imgDir and store in resDir
if( ~exist(fullfile([resDir '-eval'],'eval_bdry.txt'),'file') )
  if(~exist(resDir,'dir')), mkdir(resDir); end
  ids=dir(imgDir); ids=ids([ids.bytes]>0); ids={ids.name}; n=length(ids);
  ext=ids{1}(end-2:end); for i=1:n, ids{i}=ids{i}(1:end-4); end
  res=cell(1,n); for i=1:n, res{i}=fullfile(resDir,[ids{i} '.png']); end
  do=false(1,n); for i=1:n, do(i)=~exist(res{i},'file'); end
  ids=ids(do); res=res(do); m=length(ids);
  parfor i=1:m, id=ids{i};
    I = imread(fullfile(imgDir,[id '.' ext])); D=[];
    if(rgbd), D=single(imread(fullfile(depDir,[id '.png'])))/1e4; end
    if(rgbd==1), I=D; elseif(rgbd==2), I=cat(3,single(I)/255,D); end
    E=edgesDetect(I,model); imwrite(uint8(E*255),res{i});
  end
end

% perform actual evaluation using edgesEvalDir
varargout=cell(1,max(1,nargout));
[varargout{:}] = edgesEvalDir('resDir',resDir,'gtDir',gtDir,...
  'pDistr',p.pDistr,'cleanup',p.cleanup,'thrs',p.thrs,'maxDist',p.maxDist);
if( p.show ), figure(p.show); edgesEvalPlot(resDir,name); end

end


function encseq=huffencode(huf,seq)
l=length(seq);
h=length(huf);
hufstr=struct2cell(huf);
hufstr=hufstr(1,1:h);
hufstr=cell2mat(hufstr);
encseq='';
 for i=1:l
     idx=find(seq(i)==hufstr);
     encseq=strcat(encseq,cell2mat(huf(idx).code));
 end
end


% mff_importcoordinates - import information from MFF 'coordinates.xml' file
%
% Usage:
%   [chanlocs, ref] = mff_importcoordinates(mffFile);
%
% Inputs:
%  mffFile - filename/foldername for the MFF file
%
% Output:
%  chanlocs - EEGLAB channel location structure
%  ref      - reference

% 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 [chanlocs, reference, rVal] = mff_importcoordinates(mffFile)

chanlocs = [];
rVal = true;

p = fileparts(which('mff_importsignal.m'));
warning('off', 'MATLAB:Java:DuplicateClass');
javaaddpath(fullfile(p, 'MFF-1.2.2-jar-with-dependencies.jar'));
warning('on', 'MATLAB:Java:DuplicateClass');

% Create an MFFFactory object.
mfffactorydelegate = javaObject('com.egi.services.mff.api.LocalMFFFactoryDelegate');
mfffactory = javaObject('com.egi.services.mff.api.MFFFactory', mfffactorydelegate);

% Create Signal object and read in event track file.
% Note that 3 is the value associated with the event track resource type.
sLayoutURI = fullfile(mffFile, 'coordinates.xml');
sensorLayoutType = javaObject('com.egi.services.mff.api.MFFResourceType', javaMethod('valueOf', 'com.egi.services.mff.api.MFFResourceType$MFFResourceTypes', 'kMFF_RT_Coordinates'));

cLayout = mfffactory.openResourceAtURI(sLayoutURI, sensorLayoutType);

listfid  = [];
ref      = [];
reference = {};
if ~isempty(cLayout)

    %try

    if cLayout.loadResource()

        %  The information about the Coordinate Layout Resource.
        fprintf('Coordinate acquisition Time: %s\n', char(cLayout.getAcquisitionTime()));
        fprintf('Coordinate acquisition Method: %s\n', char(cLayout.getAcquisitionMethod()));

        %  Check to see if we have a default subject.
        %  fprintf('Default Subject: %d\n', cLayout.getDefaultSubject());

        %  Get the sesnors.
        sLayout =  cLayout.getSensorLayout();

        if ~isempty(sLayout )

            %  Information about the sensor layout.

            fprintf('Coordinate Layout Name: %s\n', char(sLayout.getName()));

            %  If Montage
            if ~isempty(sLayout.getOriginalLayout())
                fprintf('Cordinate Original Layout Name: %s\n', char(sLayout.getOriginalLayout()) );
            end
            sensors = sLayout.getSensors();

            if ~isempty(sensors )

                for iSensor = 1:sensors.size
                    sensor = sensors.get(iSensor-1);
                    description = char(sensor.getName());
                    chanlocs(iSensor).labels = [ 'E' num2str(sensor.getNumber()) ];
                    chanlocs(iSensor).description = description;
                    chanlocs(iSensor).X = sensor.getX();
                    chanlocs(iSensor).Y = sensor.getY();
                    chanlocs(iSensor).Z = sensor.getZ();
                    chanlocs(iSensor).identifier = sensor.getIdentifier();
                    sensorType = sensor.getType();
                    switch sensorType
                        case 0, chanlocs(iSensor).type = 'EEG';
                        case 1, chanlocs(iSensor).type = 'EEG'; ref = [ref iSensor]; reference = { reference{:} chanlocs(iSensor).labels };
                        case 2, chanlocs(iSensor).type = 'FID'; listfid = [ listfid iSensor ];
                    end
                end

            end
        else
            fprintf('Error: Coordinate Layout is null\n');
            rVal = false;
        end

    else
        fprintf('Error: could not load the coordinates resource.\n');
        rVal = false;
    end

end

if ~isempty(ref)
    for iSensor = 1:length(chanlocs)
        if strcmpi(chanlocs(iSensor).type, 'EEG'), chanlocs(iSensor).ref = [ chanlocs(ref).labels ]; end
    end
end

if ~isempty(chanlocs)
    chanlocs = convertlocs(chanlocs, 'cart2all');
end


function nodesInFaces=findFaceNodes(mesh,group)
% Here's a little problem - outsideNodes can contain groups linked by long, thin chains
% These mess up the perimeter-finder since each group contains a closed perim.
% Get rid of them here by finding only those nodes that are in faces

facesInGroup=findFacesInGroup(mesh,group);
nodesInFaces=unique(mesh.uniqueFaceIndexList(facesInGroup,:));


%io_CSIload_rda.m
%Brenden Kadota, SunnyBrook Hosptial 2021.
%
% USAGE:
% [out] = io_CSIload_rda(rda_filename);
%
% DESCRIPTION:
% Reads in siemens rda data (.rda file).
%
% io_CSIload_rda outputs the data in CSI structure format, with fields corresponding to time
% scale, fids, frequency scale, spectra, and header fields containing
% information about the acquisition.  The resulting matlab structure can be
% operated on by the other functions in this CSI toolbox.
%
% INPUTS:
% rda_filename   = filename of Siemens rda data to load.
%
% OUTPUTS:
% out        = Input dataset in FID-A structure format.

function [out] = io_CSIload_rda(rda_filename)

    file = fopen(rda_filename);

    head_start_text = '>>> Begin of header <<<';
    head_end_text   = '>>> End of header <<<';

    tline = fgets(file);

    while (~contains(tline , head_end_text))
        tline = fgets(file);
        if (~contains(tline , head_start_text) + ~contains(tline , head_end_text ) == 2)

            % Store this data in the appropriate format

            occurence_of_colon = strfind(tline, ':');
            variable = tline(1:occurence_of_colon-1) ;
            value    = tline(occurence_of_colon+1 : length(tline)) ;

            switch variable
                case { 'PatientID' , 'PatientName' , 'StudyDescription' , 'PatientBirthDate' , 'StudyDate' , 'StudyTime' , 'PatientAge' , 'SeriesDate' , ...
                        'SeriesTime' , 'SeriesDescription' , 'ProtocolName' , 'PatientPosition' , 'ModelName' , 'StationName' , 'InstitutionName' , ...
                        'DeviceSerialNumber', 'InstanceDate' , 'InstanceTime' , 'InstanceComments' , 'SequenceName' , 'SequenceDescription' , 'Nucleus' ,...
                        'TransmitCoil' }
                    rda.(variable) = value;
                case { 'PatientSex' }
                    % Sex converter! (int to M,F,U)
                    switch value
                        case 0
                            rda.sex = 'Unknown';
                        case 1
                            rda.sex = 'Male';
                        case 2

                            rda.sex = 'Female';
                    end

                case {  'SeriesNumber' , 'InstanceNumber' , 'AcquisitionNumber' , 'NumOfPhaseEncodingSteps' , 'NumberOfRows' , 'NumberOfColumns' , 'VectorSize' }
                    %Integers
                    rda.(variable) = str2double(value);
                case { 'PatientWeight' , 'TR' , 'TE' , 'TM' , 'DwellTime' , 'NumberOfAverages' , 'MRFrequency' , 'MagneticFieldStrength' , 'FlipAngle' , ...
                        'SliceThickness' ,  'FoVHeight' , 'FoVWidth', 'FoV3D' , 'PercentOfRectFoV' , 'PixelSpacingRow' , 'PixelSpacingCol', 'PixelSpacing3D'}
                    %Floats
                    rda.(variable) = str2double(value);
                case {'SoftwareVersion[0]' }
                    rda.software_version = value;
                case {'CSIMatrixSize[0]' }
                    rda.CSIMatrix_Size(1) = str2double(value);
                case {'CSIMatrixSize[1]' }
                    rda.CSIMatrix_Size(2) = str2double(value);
                case {'CSIMatrixSize[2]' }
                    rda.CSIMatrix_Size(3) = str2double(value);
                case {'CSIMatrixSizeOfScan[0]'}
                    rda.CSIMatrixSizeOfScan(1) = str2double(value);
                case {'CSIMatrixSizeOfScan[1]'}
                    rda.CSIMatrixSizeOfScan(2) = str2double(value);
                case {'CSIMatrixSizeOfScan[2]'}
                    rda.CSIMatrixSizeOfScan(3) = str2double(value);
                case {'PositionVector[0]' }
                    rda.PositionVector(1) = str2double(value);
                case {'PositionVector[1]' }
                    rda.PositionVector(2) = str2double(value);
                case {'PositionVector[2]' }
                    rda.PositionVector(3) = str2double(value);
                case {'RowVector[0]' }
                    rda.RowVector(1) = str2double(value);
                case {'RowVector[1]' }
                    rda.RowVector(2) = str2double(value);
                case {'RowVector[2]' }
                    rda.RowVector(3) = str2double(value);
                case {'ColumnVector[0]' }
                    rda.ColumnVector(1) = str2double(value);
                case {'ColumnVector[1]' }
                    rda.ColumnVector(2) = str2double(value);
                case {'ColumnVector[2]' }
                    rda.ColumnVector(3) = str2double(value);
                case {'VOIPositionSag' }
                    rda.imageOrigin(1) = str2double(value);
                case {'VOIPositionCor' }
                    rda.imageOrigin(2) = str2double(value);
                case {'VOIPositionTra' }
                    rda.imageOrigin(3) = str2double(value);
                case {'VOINormalSag' }
                    rda.sliceVector(1) = str2double(value);
                case {'VOINormalCor' }
                    rda.sliceVector(2) = str2double(value);
                case {'VOINormalTra' }
                    rda.sliceVector(3) = str2double(value);

                otherwise
                    % We don't know what this variable is.  Report this just to keep things clear
                    %disp(['Unrecognised variable ' , variable ]);
            end

        else
            % Don't bother storing this bit of the output
        end

    end

    %
    % So now we should have got to the point after the header text
    %
    % Siemens documentation suggests that the data should be in a double complex format (8bytes for real, and 8 for imaginary?)
    %

    bytes_per_point = 16;
    complex_data = fread(file , rda.CSIMatrix_Size(1) * rda.CSIMatrix_Size(2) * rda.CSIMatrix_Size(3) *rda.VectorSize * 2 , 'double');
    %fread(fid , 1, 'double');  %This was a check to confirm that we had read all the data (it passed!)
    fclose(file);

    % Now convert this data into something meaningful

    %Reshape so that we can get the real and imaginary separated
    hmm = reshape(complex_data,  2 , rda.VectorSize , rda.CSIMatrix_Size(1) ,  rda.CSIMatrix_Size(2) ,  rda.CSIMatrix_Size(3) );

    %Combine the real and imaginary into the complex matrix
    fids = complex(hmm(1,:,:,:,:),hmm(2,:,:,:,:));
    fids = squeeze(fids);

    %fids = conj(fids);

    % make calculations for the output mrs structure
    sz = size(fids);
    dwelltime = rda.DwellTime/1000000;
    spectralwidth = 1/dwelltime;
    txfrq = rda.MRFrequency*1000000;
    dims.t = 1;
    dims.subSpecs = 0;
    dims.x = 2;
    fids = flip(fids, dims.x);
    dims.y = 3;
    dims.z = 0;
    dims.coils = 0;
    dims.averages = 0;
    dims.extras = 0;
    dims.ky = 0;
    dims.kx = 0;
    Bo = rda.MagneticFieldStrength;
    rawAverages = rda.NumberOfAverages;
    averages = 1;
    subspecs =1;
    rawSubspecs = 'na';
    date = strip(rda.StudyDate);
    seq = rda.SequenceDescription;
    TE = rda.TE;
    TR = rda.TR;
    pointsToLeftShift = 'N/A';

    %Calculate t and ppm arrays using the calculated parameters:
    f = createCoordinates(spectralwidth/2, spectralwidth/sz(1));
    ppm = -f/(Bo*42.577);
    ppm = ppm+4.6082;

    t = 0:dwelltime:(sz(1)-1)*dwelltime;

    out = struct();
    %FILLING IN DATA STRUCTURE
    out = setData(out, fids);
    out = setSize(out, sz);
    out = setPPM(out, ppm);
    out = setAdcTime(out, t);
    out = setSpectralTime(out, t);
    out = setSpectralDwellTime(out, dwelltime);
    out = setSpectralWidth(out, spectralwidth);
    out.txfrq = txfrq;
    out.date = datetime(str2double(date(1:4)), str2double(date(5:6)), str2double(date(7:8)));
    out.dims = dims;
    out.Bo = Bo;
    out.averages = averages;
    out.rawAverages = rawAverages;
    out.subspecs = subspecs;
    out.rawSubspecs = rawSubspecs;
    out.seq = seq;
    out.te = TE;
    out.tr = TR;
    out.pointsToLeftshift = pointsToLeftShift;
    out = setFov(out, 'x', rda.FoVHeight);
    out = setFov(out, 'y', rda.FoVWidth);
    out = setFov(out, 'z', rda.FoV3D);
    out = setVoxelSize(out, 'x', getFov(out, 'x')/getSizeFromDimensions(out, {'x'}));
    out = setVoxelSize(out, 'y', getFov(out, 'y')/getSizeFromDimensions(out, {'y'}));
    if(getDimension(out, 'z') ~= 0)
        out = setVoxelSize(out, 'z', getFov(out, 'z')/getSizeFromDimensions(out, {'z'}));
    else
        out = setVoxelSize(out, 'z', getFov(out, 'z'));
    end

    affine_matrix = calculateAffineMatrix(rda);
    out.affineMatrix = affine_matrix;
    out = setImageOrigin(out, rda.imageOrigin);
    out = findCoordinates(out);
    out = setFlags(out);
end

function affine_matrix = calculateAffineMatrix(rda)
    %may have to update x and y orientations
    affine_matrix_rotation = [rda.RowVector', rda.ColumnVector', rda.sliceVector', [0 0 0]'];
    affine_matrix_rotation = cat(1, affine_matrix_rotation,  [0, 0, 0, 1]);

    affine_matrix_translate = eye(4);
    affine_matrix_translate(1,4) = rda.PositionVector(1);
    affine_matrix_translate(2,4) = rda.PositionVector(2);
    affine_matrix_translate(3,4) = rda.PositionVector(3);

    affine_matrix_scale = eye(4);
    affine_matrix_scale(1,1) = rda.PixelSpacingCol;
    affine_matrix_scale(2,2) = rda.PixelSpacingRow;
    affine_matrix_scale(3,3) = rda.PixelSpacing3D;

    % for some reason rotation seems to be in the wrong direction. Fix here
    affine_reverse_rotation = affine_matrix_rotation';
    middleVoxelY = rda.CSIMatrix_Size(2)/2;
    middleVoxelX = rda.CSIMatrix_Size(1)/2;
    middleCoordinate = affine_matrix_scale * [middleVoxelX; middleVoxelY; 0; 1];
    middleCoordinateRoate = affine_reverse_rotation * middleCoordinate;
    adjacentTriangleEdge = middleCoordinateRoate(2);
    hypotenuseLength = middleCoordinate(2);
    rotationDistanceAxial = acos(adjacentTriangleEdge/hypotenuseLength);
    oppositeTriangleEdge = sin(rotationDistanceAxial) * hypotenuseLength;
    affine_matrix_coorection = [1 0 0 0
                                0 1 0 0
                                0 0 1 -abs(2*oppositeTriangleEdge)
                                0 0 0 1];

    affine_matrix = affine_matrix_translate * affine_matrix_coorection * affine_reverse_rotation * affine_matrix_scale;
end

function out = setFlags(out)
    %FILLING IN THE FLAGS
    out.flags.writtentostruct = 1;
    out.flags.gotparams = 1;
    out.flags.leftshifted = 0;
    out.flags.filtered = 0;
    out.flags.zeropadded = 0;
    out.flags.freqcorrected = 0;
    out.flags.phasecorrected = 0;
    out.flags.averaged = 1;
    out.flags.addedrcvrs = 1;
    out.flags.subtracted = 0;
    out.flags.writtentotext = 0;
    out.flags.downsampled = 0;
    out.flags.spatialFT = 1;
    out.flags.spectralFT = 0;
    out.flags.isCartesian = 1;
    if out.dims.subSpecs == 0
        out.flags.isISIS = 0;
    else
        out.flags.isISIS = (out.sz(out.dims.subSpecs)==4);
    end
end

function out = findCoordinates(out)
    xCoordinate = createCoordinates(getFov(out, 'x')/2, getVoxSize(out, 'x'));
    yCoordinate = createCoordinates(getFov(out, 'y')/2, getVoxSize(out, 'y'));
    zCoordinate = createCoordinates(getFov(out, 'z')/2, getVoxSize(out, 'z'));
    out = setCoordinates(out, 'x', xCoordinate);
    out = setCoordinates(out, 'y', yCoordinate);
    out = setCoordinates(out, 'z', zCoordinate);
end


function drawRawLines(SenFig,Raw)

% DRAWRAWLINES  Draw raw lines.
%   DRAWRAWLINES(SENFIG,RAW)  redraws the 2D segments in RAW on figure
%   SenFig.

%   Copyright 2008-2009 Joan Sola @ LAAS-CNRS.

if ~isempty(Raw.data.segments.coord)

    m = size(Raw.data.segments.coord,2); % number of segments
    pn = {'xdata','ydata'};
    pv = mat2cell(Raw.data.segments.coord([1 3 2 4],:)',ones(1,m),[2 2]);

    set(SenFig.raw.segments(1:m),...
        pn,     pv,...
        'vis',  'on')
    set(SenFig.raw.segments(m+1:end),...
        'vis',  'off')

end

% ========== End of function - Start GPL license ==========

%   # START GPL LICENSE

%---------------------------------------------------------------------
%
%   This file is part of SLAMTB, a SLAM toolbox for Matlab.
%
%   SLAMTB 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.
%
%   SLAMTB 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 SLAMTB.  If not, see <http://www.gnu.org/licenses/>.
%
%---------------------------------------------------------------------

%   SLAMTB is Copyright:
%   Copyright (c) 2008-2010, Joan Sola @ LAAS-CNRS,
%   Copyright (c) 2010-2013, Joan Sola,
%   Copyright (c) 2014-2015, Joan Sola @ IRI-UPC-CSIC,
%   SLAMTB is Copyright 2009
%   by Joan Sola, Teresa Vidal-Calleja, David Marquez and Jean Marie Codol
%   @ LAAS-CNRS.
%   See on top of this file for its particular copyright.

%   # END GPL LICENSE


classdef CutMeshProvisionalLine < CutMesh

    properties (Access = private)
        connec
        coord
        cutEdgesComputer
        cutCoordComputer
    end

    properties (Access = private)
        isoCoord
    end

    methods (Access = public)

        function obj = CutMeshProvisionalLine(cParams)
            obj.init(cParams)
            obj.isoCoord = [-1 1];
        end

        function compute(obj)
            obj.computeCutCoordinate();
            obj.coord = obj.cutCoordComputer.coord;
            obj.computeConnec();
            obj.computeXcoordIso();
            obj.cellContainingSubcell = obj.cutCells;
            obj.computeMesh();
            obj.computeInnerCutMesh();
        end

    end

    methods (Access = private)

        function computeCutCoordinate(obj)
            s.levelSet      = obj.levelSet;
            s.nodesInEdges  = obj.backgroundMesh.connec;
            obj.cutEdgesComputer = CutEdgesComputer(s);
            obj.cutEdgesComputer.compute();

            s.coord            = obj.backgroundMesh.coord;
            s.nodesInEdges     = obj.backgroundMesh.connec;
            s.xCutEdgePoint    = obj.cutEdgesComputer.xCutEdgePoint;
            s.isEdgeCut        = obj.cutEdgesComputer.isEdgeCut;
            cComputer = CutCoordinatesComputer(s);
            cComputer.compute();
            obj.cutCoordComputer = cComputer;
        end

        function computeConnec(obj)
            nodeA = obj.backgroundMesh.connec(:,1);
            nodeB = obj.backgroundMesh.connec(:,2);
            lsA = obj.levelSet(nodeA);
            isNodeAinterior = lsA < 0;
            isNodeBinterior = ~isNodeAinterior;
            interiorNode(isNodeAinterior,1) = nodeA(isNodeAinterior);
            interiorNode(isNodeBinterior,1) = nodeB(isNodeBinterior);
            lastNode = size(obj.backgroundMesh.coord,1);
            nElem    = obj.backgroundMesh.nelem;
            boundaryNode(:,1) = lastNode + (1:nElem);
            obj.connec = [interiorNode boundaryNode];
        end

        function computeXcoordIso(obj)
            nodeA = obj.backgroundMesh.connec(:,1);
            lsA = obj.levelSet(nodeA);
            isNodeAinterior = lsA < 0;
            isNodeBinterior = ~isNodeAinterior;
            nDim = 1;
            nnode = 2;
            nelem = length(obj.cutCells);
            xIso = zeros(nDim,nnode,nelem);
            xIso(1,1,:) = obj.cutEdgesComputer.xCutEdgePoint;
            xIso(1,2,isNodeAinterior) = obj.isoCoord(1);
            xIso(1,2,isNodeBinterior) = obj.isoCoord(2);
            obj.xCoordsIso = xIso;
        end

        function computeMesh(obj)
            s.connec = obj.connec;
            s.coord  = obj.coord;
            s.kFace  = obj.backgroundMesh.kFace;
            obj.mesh = Mesh(s);
        end

    end

end


function title = p28_title ( )

%*****************************************************************************80
%
%% P28_TITLE returns the title of problem P28.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 February 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, string TITLE, the title of the problem.
%
  title = 'Problem 28, Enright and Pryce #F3';

  return
end


function seg = segBuildMesh(seg, savePath, varargin);
%
% Build a new mesh structure for a mrVista2 segmentation object.
%
% seg = segBuildMesh(seg, [savePath=dialog], [options]);
%
% INPUTS:
%
% seg: segmentation structure (see segCreate).
%
% savePath: optional path to save the mesh; if entered as 'dialog', will
% pop up a user dialog to choose the save location.
%
% Optional input arguments:
%   'visualize', [val]: set visualize flag to 1 or 0 [default 1]. If 1,
%                       will open up the new mesh in mrMesh.
%   'numGrayLayers', [val]: set the # of gray layers to grow. [Default 0]
%   'meshName', [name]: set the name of the meah. [Default: same name as
%                       segmentation, plus a number if there are already
%                       other meshes attached]
%
%
%
% OUTPUTS:
%
% seg: modified segmentation with a new mesh structure attached to the
% seg.mesh{} field.
%
% ras, 10/2006.
if notDefined('savePath'), savePath = ''; end

%% params / defaults
visualize = 1;
numGrayLayers = 0;
meshName = seg.name;
if ~isempty(seg.mesh), meshName = [meshName num2str(length(seg.mesh)+1)]; end

%% parse options
for i = 1:2:length(varargin)
    switch lower(varargin{i})
        case 'visualize', visualize = varargin{i+1};
        case {'numgraylayers' 'nlayers'}, numGrayLayers = varargin{i+1};
        case {'name' 'meshname'}, meshName = varargin{i+1};
    end
end

%% get the WM classification
C = segGet(seg, 'classification');

% Create a volume which designates the white matter locations
wm = uint8( zeros(C.header.xsize, C.header.ysize, C.header.zsize) );
xx = C.header.voi(1):C.header.voi(2);
yy = C.header.voi(3):C.header.voi(4);
zz = C.header.voi(5):C.header.voi(6);
wm(xx,yy,zz) = wm(xx,yy,zz) | (C.data == C.type.white);

% add gray layers if specified
if numGrayLayers > 0
    [nodes edges C] = mrgGrowGray(C, numGrayLayers);
    wm = uint8( (C.data(xx,yy,zz) == C.type.white) | ...
                (C.data(xx,yy,zz) == C.type.gray) );
end

%% build the new mesh
[newMesh tenseMesh] = mrmBuild(wm, seg.voxelSize, 1, visualize);

%% attach the 'tense' (unsmoothed) mesh to the new mesh as the
%% 'initVertices' field (very useful to hold on to)
initVertices = meshGet(tenseMesh, 'vertices');
newMesh = meshSet(newMesh, 'initialvertices', initVertices);
if isempty(seg.nodes) | isempty(seg.edges)
    [seg.nodes seg.edges] = segGet(seg, 'gray');
end
v2g = mrmMapVerticesToGray(initVertices, seg.nodes, seg.voxelSize, seg.edges);

newMesh = meshSet(newMesh, 'vertexGrayMap', v2g);
newMesh = meshSet(newMesh, 'name', meshName);
newMesh = meshSet(newMesh, 'nGrayLayers', numGrayLayers);

%% attach new mesh to segmentation
seg.mesh{end+1} = newMesh;

% set the new mesh as the selected one
seg.settings.mesh = length(seg.mesh);

%% save if selected
if ~isempty(savePath)
    if isequal(lower(savePath), 'dialog')
        savePath = mrSelectDataFile('stayput', 'w', '*.mat',...
                                    'Save Mesh File As...');
        if isempty(savePath)
            disp('Not Saving Mesh')
            return
        end
    end

    try
        mrmWriteMeshFile(newMesh, savePath);
    catch
        msg = sprintf(['Couldn''t save file %s. Not erroring, but you ' ...
                       'should try saving again.'], savePath);
        myWarnDlg(msg);
    end
end

return


function msh = meshCreate(mshType)
% mrMesh creation routine
%
%   msh = meshCreate(mshType);
%
% We only create a vistaMesh type.  In the future we may design additional
% mesh structures.  See notes below about the properties of the msh fields.
%
% See also:  meshSet/Get  and mrmSet/Get
%
% Example:
%    msh = meshCreate;
%    msh = meshCreate('vista mesh');
%
% Stanford VISTA team

if ieNotDefined('mshType'), mshType = 'vistaMesh'; end

mshType = mrvParamFormat(mshType);

switch lower(mshType)
    case 'vistamesh'
        msh = vistaMeshCreate;
    otherwise
        error('Unknown mesh type %s\n',mshType);
end

return;

%------------------------------
function msh = vistaMeshCreate
%Default settings for a mrVista mesh
%
%   msh = vistaMeshCreate;
%
%  * The triangles are triplets of vertices.
%  * The vertices are numbered from [0,n-1], consistent with C numbering,
%  but not Matlab numbering.  This is necessary to work with mrMeshSrv.
%
%
% fields = {'name', 'host', 'id', 'actor', 'mmPerVox', 'lights', 'origin', ...
%     'initialvertices', 'vertices', 'triangles', 'colors', 'normals', 'curvature',...
%     'ngraylayers', 'vertexGrayMap', 'fibers',...
%     'smooth_sinc_method', 'smooth_relaxation', 'smooth_iterations', 'mod_depth'};
%
% (c) Stanford VISTA Team

msh.name = '';
msh.type = 'vistaMesh';
msh.host = 'localhost';
msh.id   = -1;    % Figure this out as soon as possible.
msh.filename = [];
msh.path = [];
msh.actor = 33;   % This is default.  But we should be able to change.
msh.mmPerVox = [1 1 1];
msh.lights   = {};
msh.origin   = [];
msh.initVertices = [];   % Initial vertices, without smoothing.
msh.vertices = [];
msh.triangles = [];

% Surface shading typically for pseudo-color or for showing curvature
msh.colors = [];
msh.mod_depth = 0.25;

msh.normals = [];   % Normals to the patches.  Can be computed using Matlab

msh.curvature = []; % Not sure how we compute this.  Uh oh.

% Not sure why these are here.  They relate the vertices to gray map.
% Probably essential for VISTASOFT/mrBOLD
msh.grayLayers = [];
msh.vertexGrayMap =[];

% Not sure why these are here too, but probably related to mrDiffusion
msh.fibers = [];

% Mesh smoothing related
msh.smooth_sinc_method = 0;
msh.smooth_relaxation = 0.5;
msh.smooth_iterations = 32;

return;


function check_cluster_data(cl)
% loads the first 5 images from the first voxel
%
% :Usage:
% ::
%
%     check_cluster_data(cl)
%
% ..
%    tor wager
%    needs Tom's orthviews
% ..

%cl(1).imnames(1:5,:)
cl(1).XYZ(:,1:5), cl(1).XYZmm(:,1:5),
spm_orthviews('Reposition',cl(1).XYZmm(:,1))
%cl(1).all_data(1:5,1)
cl(1).raw_data(1:5,1,2)

return


classdef empty2dLayer < nnet.layer.Layer
    % 主要想用于导入yolov3中route层的单个跳层连接
    % 2019.9.8
    % 2020.4.29加入属性connectID，用于连接前面的层
    properties
        connectID %connectID 是以cfg文件中第一个非[net]开始的module为0开始的计数
    end

    methods
        function layer = empty2dLayer(name,con)
            layer.Name = name;
            text = ['[', num2str(1), ' ', num2str(1), '] emptyLayer '];
            layer.Description = text;
            layer.Type = 'empty2dLayer';
            layer.connectID= con;
        end

        function Z = predict(layer, X)
               Z = X;
        end

        function [dX] = backward( layer, X, ~, dZ, ~ )
            dX = dZ;
        end
    end
end
%%
% 参考：https://ww2.mathworks.cn/matlabcentral/fileexchange/71277-deep-learning-darknet-importer


% STD_GETDATASET - Constructs and returns EEG dataset from STUDY design.
%
% Usage:
%     >> EEG = std_getdataset(STUDY, ALLEEG, 'key', 'val', ...);
%
% Inputs:
%   STUDY      - EEGLAB STUDY set
%   ALLEEG     - vector of the EEG datasets included in the STUDY structure
%
% Optional inputs:
%   'design'     - [numeric vector] STUDY design index. Default is to use
%                  the current design.
%   'cell'       - [integer] index of the STUDY design cell to convert to
%                  an EEG dataset. Default is the first cell.
%   'dataset'    - [integer] bypass cell and design above. Simply get
%                  dataset with a given index.
%   'rmcomps'    - [integer array] remove artifactual components (this entry
%                  is ignored when plotting components). This entry contains
%                  the indices of the components to be removed. Default is none.
%   'rmclust'    - [integer array] which cluster(s) to remove from the data
%                  Default is none.
%   'interp'     - [struct] channel location structure containing electrode
%                  to interpolate ((this entry is ignored when plotting
%                  components). Default is no interpolation.
%   'onecomppercluster' - ['on'|'off'] when 'on' enforces one component per
%                  cluster. Default is 'off'.
%   'interpcomponent' - ['on'|'off'] when 'on' interpolating component
%                  scalp maps. Default is 'off'.
%   'cluster'    - [integer] which cluster(s). When this option is being
%                  used, only the component contained in the selected
%                  clusters are being loaded in the dataset.
%   'checkonly'  - ['on'|'off'] use in conjunction with the option above.
%                  When 'on', no dataset is returned. Default is 'off'.
%
% Outputs:
%   EEG          - EEG dataset structure corresponding to the selected
%                  STUDY design cell (element)
%   complist     - list of components selected
%
% Example to build the dataset corresponding to the first cell of the first
% design:
%   EEG = std_getdataset(STUDY, ALLEEG, 'design', 1, 'cell', 1);
%
% Example to check that all datasets in the design have exactly one
% component per cluster for cluster 2, 3, 4 and 5.
%   std_getdataset(STUDY, ALLEEG, 'design', 1, 'cell',
%   [1:length(STUDY.design(1).cell)], 'cluster', [2 3 4 5], 'checkonly', 'on');
%
% Authors: Arnaud Delorme, SCCN, INC, UCSD, January, 2012

% Copyright (C) Arnaud Delorme, SCCN, INC, UCSD, October 12, 2004, arno@sccn.ucsd.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function [EEGOUT listcomp rmlistcomp] = std_getdataset(STUDY, ALLEEG, varargin);

if nargin < 2
    help std_getdataset;
    return;
end

opt = finputcheck( varargin, { 'design'  'integer'   []    STUDY.currentdesign;
                               'interp'  'struct'    { }   struct([]);
                               'rmcomps' 'integer'	 []    [];
                               'cluster' 'integer'   []    [];
                               'rmclust' 'integer'   []    [];
                               'dataset' 'integer'   []    [];
                               'onecomppercluster' 'string'   {'on' 'off'}    'off';
                               'interpcomponent'   'string'   {'on' 'off'}    'off';
                               'checkonly' 'string'   {'on' 'off'}    'off';
                               'cell'    'integer'   []    1                    }, 'std_getdataset');
%                               'mode'   'string'   { 'channels' 'components' }  'channels';
if ischar(opt), error(opt); end

if length(opt.cell) > 1
    % recursive call if more than one dataset
    % ---------------------------------------
    indcell = strmatch('cell', varargin(1:2:end));
    for index = 1:length(opt.cell)
        varargin{2*indcell} = index;
        EEGOUT(index) = std_getdataset(STUDY, ALLEEG, varargin{:});
    end
else
    if ~isempty(opt.dataset)
        mycell.dataset = opt.dataset;
        mycell.trials  = { [1:ALLEEG(opt.dataset).trials] };
    else
        mycell = STUDY.design(opt.design).cell(opt.cell);
    end

    % find components in non-artifactual cluster
    if ~isempty(opt.cluster)
        listcomp = [];
        for index = 1:length(opt.cluster)
            clsset  = STUDY.cluster(opt.cluster(index)).sets;
            clscomp = STUDY.cluster(opt.cluster(index)).comps;

            [indrow indcomp] = find(clsset == mycell.dataset(1));
            if length(indcomp) ~= 1 && strcmpi(opt.onecomppercluster, 'on')
                error(sprintf('Dataset %d must have exactly 1 components in cluster %d', mycell.dataset(1), opt.cluster(index)));
            end
            listcomp = [listcomp clscomp(indcomp')];
        end
    end

    % find components in artifactual clusters
    if ~isempty(opt.rmclust)
        rmlistcomp = [];
        for index = 1:length(opt.rmclust)
            clsset  = STUDY.cluster(opt.rmclust(index)).sets;
            clscomp = STUDY.cluster(opt.rmclust(index)).comps;
            [indrow indcomp] = find(clsset == mycell.dataset(1));
            rmlistcomp = [rmlistcomp clscomp(indcomp')];
        end
        if ~isempty(opt.rmcomps)
            disp('Both ''rmclust'' and ''rmcomps'' are being set. Artifact components will be merged');
        end
        opt.rmcomps = [ opt.rmcomps rmlistcomp ];
    end;
    rmlistcomp  = opt.rmcomps;
    if strcmpi(opt.checkonly, 'on'), EEGOUT = 0; return; end

    % get data
    EEG = ALLEEG(mycell.dataset);
    EEGOUT = EEG(1);
    EEGOUT.data = eeg_getdatact(EEG, 'channel', [], 'trialindices', mycell.trials, 'rmcomps', opt.rmcomps, 'interp', opt.interp);
    EEGOUT.trials   = size(EEGOUT.data,3);
    EEGOUT.nbchan   = size(EEGOUT.data,1);
    if ~isempty(opt.interp)
        EEGOUT.chanlocs = opt.interp;
    end
    EEGOUT.event  = [];
    EEGOUT.epoch  = [];
    if isfield(mycell, 'filebase')
        EEGOUT.filename = mycell.filebase;
        EEGOUT.condition = mycell.value{1};
        EEGOUT.group     = mycell.value{2};
        EEGOUT.subject   = mycell.case;
    end
    if ~isempty(opt.cluster)
        if ~isempty(opt.interp) && strcmpi(opt.interpcomponent, 'on')
            TMPEEG = EEGOUT;
            TMPEEG.chanlocs = EEG(1).chanlocs;
            TMPEEG.data = EEG(1).icawinv;
            TMPEEG.nbchan = size(TMPEEG.data,1);
            TMPEEG.pnts   = size(TMPEEG.data,2);
            TMPEEG.trials = 1;
            TMPEEG = eeg_interp(TMPEEG, opt.interp, 'spherical');
            EEGOUT.icawinv = TMPEEG.data(:, listcomp);
        else
            EEGOUT.icawinv = EEGOUT.icawinv(:, listcomp);
        end
        EEGOUT.icaact         = eeg_getdatact(EEG, 'component', listcomp, 'trialindices', mycell.trials );
        EEGOUT.icaweights     = EEGOUT.icaweights(listcomp,:);
        EEGOUT.etc.clustid    = { STUDY.cluster(opt.cluster).name };  % name of each cluster
        EEGOUT.etc.clustcmpid = listcomp;                             % index of each component in original ICA matrix
    else
        EEGOUT = eeg_checkset(EEGOUT);
    end
end


function scanList = selectScans(vw,title,~)
% scanList = selectScans(vw,[title],[scanDir]);
%
%   Gather a list of scans available in Inplane/TSeries
%   and query the user for a sub-selection.
%
%   An alternate function chooseScans uses numScans(view)
%   to determine the number of scans to choose from
%   Use selectScans if you will be analyzing the tSeries.
%   Use chooseScans, if your code does not depend on the
%   presence/absence of the tSeries files.
%
% Input:
%  scanDir (optional): specify the dir that contains
%    'Scan*' subdir. Default is tSeriesDir(view).
% Output:
%  scanList: list of scans selected.
%
% 4/16/99  dbr Initial code
% 3/30/2001, djh, added optional title string
% 10/21/2004, MA, added optional scanDir
% 11/3/04, JL, make scanDir really optional

if ~exist('title','var'), title = 'Choose scans'; end;
%if ~exist('scanDir','var'), scanDir = tSeriesDir(vw,0); end;
%We will no longer use scanDir

scanNum = viewGet(vw,'N Scans');

scanList = 1:scanNum;

scanNames = cell(length(scanList),1);
for i=scanList
    scanNames{i} = num2str(i);
end

% Which scans to analyze?
iSel = buttondlg(title, scanNames);
scanList = scanList(find(iSel));

return;


%CHECK12 Decide between monadic and dyadic datafile operations
%
% [CHECK,A,B] = CHECK12(A,B)


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


function [cfg] = ft_neighbourplot(cfg, data)

% FT_NEIGHBOURPLOT visualizes neighbouring channels in a particular channel
% configuration. The positions of the channel are specified in a
% gradiometer or electrode configuration or from a layout.
%
% Use as
%   ft_neighbourplot(cfg)
% or as
%   ft_neighbourplot(cfg, data)
%
% Where the configuration can contain
%   cfg.verbose       = string, 'yes' or 'no', whether the function will print feedback text in the command window
%   cfg.neighbours    = neighbourhood structure, see FT_PREPARE_NEIGHBOURS (optional)
%   cfg.visible       = string, 'on' or 'off', whether figure will be visible (default = 'on')
%   cfg.enableedit    = string, 'yes' or 'no', allows you to interactively add or remove edges between vertices (default = 'no')
%
% and either one of the following options
%   cfg.layout        = filename of the layout, see FT_PREPARE_LAYOUT
%   cfg.elec          = structure with electrode positions or filename, see FT_READ_SENS
%   cfg.grad          = structure with gradiometer definition or filename, see FT_READ_SENS
%   cfg.opto          = structure with gradiometer definition or filename, see FT_READ_SENS
%
% If cfg.neighbours is not defined, this function will call
% FT_PREPARE_NEIGHBOURS to determine the channel neighbours. The
% following data fields may also be used by FT_PREPARE_NEIGHBOURS
%   data.elec         = structure with electrode positions
%   data.grad         = structure with gradiometer definition
%   data.opto         = structure with optode definition
%
% If cfg.neighbours is empty, no neighbouring sensors are assumed.
%
% Use cfg.enableedit to interactively add or remove edges in your own neighbour structure.
%
% See also FT_PREPARE_NEIGHBOURS, FT_PREPARE_LAYOUT

% Copyright (C) 2011, J?rn M. Horschig, 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/>.

% these are used by the ft_preamble/ft_postamble function and scripts
ft_revision = '$Id$';
ft_nargin   = nargin;
ft_nargout  = nargout;

% do the general setup of the function
ft_defaults
ft_preamble init
ft_preamble debug
ft_preamble loadvar data
ft_preamble provenance data
ft_preamble trackconfig

% the ft_abort variable is set to true or false in ft_preamble_init
if ft_abort
  return
end

% the data can be passed as input arguments or can be read from disk
hasdata = exist('data', 'var');

if hasdata
  % check if the input data is valid for this function
  data = ft_checkdata(data);
end

% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'renamed', {'elecfile', 'elec'});
cfg = ft_checkconfig(cfg, 'renamed', {'gradfile', 'grad'});
cfg = ft_checkconfig(cfg, 'renamed', {'optofile', 'opto'});

% set the defaults
cfg.enableedit = ft_getopt(cfg, 'enableedit', 'no');
cfg.visible    = ft_getopt(cfg, 'visible', 'on');
cfg.renderer   = ft_getopt(cfg, 'renderer'); % let MATLAB decide on the default

if isfield(cfg, 'neighbours')
  cfg.neighbours = cfg.neighbours;
elseif hasdata
  cfg.neighbours = ft_prepare_neighbours(cfg, data);
else
  cfg.neighbours = ft_prepare_neighbours(cfg);
end

if ~isfield(cfg, 'verbose')
  cfg.verbose = 'no';
elseif strcmp(cfg.verbose, 'yes')
  cfg.verbose = true;
end

% get the the grad or elec
if hasdata
  sens = ft_fetch_sens(cfg, data);
else
  sens = ft_fetch_sens(cfg);
end

% insert sensors that are not in neighbourhood structure
if isempty(cfg.neighbours)
  nsel = 1:numel(sens.label);
else
  nsel = find(~ismember(sens.label, {cfg.neighbours.label}));
end

for i=1:numel(nsel)
  cfg.neighbours(end+1).label = sens.label{nsel(i)};
  cfg.neighbours(end).neighblabel = {};
end

[tmp, sel] = match_str(sens.label, {cfg.neighbours.label});
cfg.neighbours = cfg.neighbours(sel);

% give some graphical feedback
if all(sens.chanpos(:,3)==0)
  % the sensor positions are already projected on a 2D plane
  proj = sens.chanpos(:,1:2);
else
  % use 3-dimensional data for plotting
  proj = sens.chanpos;
end
hf = figure('visible', cfg.visible);
axis equal
axis vis3d
axis off
hold on;
hl = [];
for i=1:length(cfg.neighbours)
  this = cfg.neighbours(i);

  sel1 = match_str(sens.label, this.label);
  sel2 = match_str(sens.label, this.neighblabel);
  % account for missing sensors
  this.neighblabel = sens.label(sel2);
  for j=1:length(this.neighblabel)
    x1 = proj(sel1,1);
    y1 = proj(sel1,2);
    x2 = proj(sel2(j),1);
    y2 = proj(sel2(j),2);
    X = [x1 x2];
    Y = [y1 y2];
    if size(proj, 2) == 2
      hl(sel1, sel2(j)) = line(X, Y, 'color', 'r');
    elseif size(proj, 2) == 3
      z1 = proj(sel1,3);
      z2 = proj(sel2(j),3);
      Z = [z1 z2];
      hl(sel1, sel2(j)) = line(X, Y, Z, 'color', 'r');
    end
  end
end

% this is for putting the channels on top of the connections
hs = [];
for i=1:length(cfg.neighbours)
  this = cfg.neighbours(i);
  sel1 = match_str(sens.label, this.label);
  sel2 = match_str(sens.label, this.neighblabel);
  % account for missing sensors
  this.neighblabel = sens.label(sel2);
  if isempty(sel1)
    continue;
  end
  if size(proj, 2) == 2
    hs(i) = line(proj(sel1, 1), proj(sel1, 2),                                            ...
      'MarkerEdgeColor',  'k',                                        ...
      'MarkerFaceColor',  'k',                                        ...
      'Marker',           'o',                                        ...
      'MarkerSize',       .125*(2+numel(cfg.neighbours(i).neighblabel))^2, ...
      'UserData',         i,                                          ...
      'ButtonDownFcn',    @showLabelInTitle);

  elseif size(proj, 2) == 3
    hs(i) = line(proj(sel1, 1), proj(sel1, 2), proj(sel1, 3),                                ...
      'MarkerEdgeColor',  'k',                                        ...
      'MarkerFaceColor',  'k',                                        ...
      'Marker',           'o',                                        ...
      'MarkerSize',       .125*(2+numel(cfg.neighbours(i).neighblabel))^2, ...
      'UserData',         i,                        ...
      'ButtonDownFcn',    @showLabelInTitle);
  else
    ft_error('Channel coordinates are too high dimensional');
  end
end

hold off
title('[Click on a sensor to see its label]');

% store what is needed in UserData of figure
userdata.lastSensId = [];
userdata.cfg = cfg;
userdata.sens = sens;
userdata.hs = hs;
userdata.hl = hl;
userdata.quit = false;
hf = getparent(hf);
set(hf, 'UserData', userdata);

if istrue(cfg.enableedit)
  set(hf, 'CloseRequestFcn', @cleanup_cb);
  while ~userdata.quit
    uiwait(hf);
    userdata = get(hf, 'UserData');
  end
  cfg = userdata.cfg;

  hf = getparent(hf);
  delete(hf);
end

% remove SCALE and COMNT
desired = ft_channelselection({'all', '-SCALE', '-COMNT'}, {cfg.neighbours.label});

neighb_idx = ismember({cfg.neighbours.label}, desired);
cfg.neighbours = cfg.neighbours(neighb_idx);

% this is needed for the figure title
if isfield(cfg, 'dataname') && ~isempty(cfg.dataname)
  dataname = cfg.dataname;
elseif isfield(cfg, 'inputfile') && ~isempty(cfg.inputfile)
  dataname = cfg.inputfile;
elseif nargin>1
  dataname = arrayfun(@inputname, 2:nargin, 'UniformOutput', false);
else
  dataname = {};
end

% set the figure window title
if ~isempty(dataname)
  set(gcf, 'Name', sprintf('%d: %s: %s', double(gcf), mfilename, join_str(', ', dataname)));
else
  set(gcf, 'Name', sprintf('%d: %s', double(gcf), mfilename));
end
set(gcf, 'NumberTitle', 'off');

% set renderer if specified
if ~isempty(cfg.renderer)
  set(gcf, 'renderer', cfg.renderer)
end

% do the general cleanup and bookkeeping at the end of the function
ft_postamble debug
ft_postamble trackconfig
ft_postamble previous data
ft_postamble provenance
ft_postamble savefig

% add a menu to the figure, but only if the current figure does not have subplots
menu_fieldtrip(gcf, cfg, false);

if ~ft_nargout
  % don't return anything
  clear cfg
end

end % main function

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function showLabelInTitle(gcbo, EventData, handles)

userdata    = get(gcf, 'UserData');
lastSensId  = userdata.lastSensId;
cfg         = userdata.cfg;
hs          = userdata.hs;
curSensId   = get(gcbo, 'UserData');

if lastSensId == curSensId

  title('[Click on a sensor to see its label]');
  set(hs(curSensId), 'MarkerFaceColor', 'k');
  userdata.lastSensId = [];

elseif isempty(lastSensId) || ~istrue(cfg.enableedit)

  userdata.lastSensId = curSensId;
  if istrue(cfg.enableedit)
    title(['Selected channel: ' cfg.neighbours(curSensId).label ' click on another to (dis-)connect']);
  else
    title(['Selected channel: ' cfg.neighbours(curSensId).label]);
  end
  if cfg.verbose
    str = sprintf('%s, ', cfg.neighbours(curSensId).neighblabel{:});
    if length(str)>2
      % remove the last comma and space
      str = str(1:end-2);
    end
    fprintf('Selected channel %s, which has %d neighbours: %s\n', ...
      cfg.neighbours(curSensId).label, ...
      length(cfg.neighbours(curSensId).neighblabel), ...
      str);
  end
  set(hs(curSensId), 'MarkerFaceColor', 'g');
  set(hs(lastSensId), 'MarkerFaceColor', 'k');

elseif istrue(cfg.enableedit)
  hl    = userdata.hl;
  sens  = userdata.sens;
  if all(sens.chanpos(:,3)==0)
    % the sensor positions are already projected on a 2D plane
    proj = sens.chanpos(:,1:2);
  else
    % use 3-dimensional data for plotting
    proj = sens.chanpos;
  end

  % find out whether they are connected
  connected1 = ismember(cfg.neighbours(curSensId).neighblabel, cfg.neighbours(lastSensId).label);
  connected2 = ismember(cfg.neighbours(lastSensId).neighblabel, cfg.neighbours(curSensId).label);

  if any(connected1) % then disconnect
    cfg.neighbours(curSensId).neighblabel(connected1) = [];
    cfg.neighbours(lastSensId).neighblabel(connected2) = [];
    title(['Disconnected channels ' cfg.neighbours(curSensId).label ' and ' cfg.neighbours(lastSensId).label]);
    delete(hl(curSensId, lastSensId));
    hl(curSensId, lastSensId) = 0;
    delete(hl(lastSensId, curSensId));
    hl(lastSensId, curSensId) = 0;
  else % then connect
    cfg.neighbours(curSensId).neighblabel{end+1} = cfg.neighbours(lastSensId).label;
    cfg.neighbours(lastSensId).neighblabel{end+1} = cfg.neighbours(curSensId).label;
    title(['Connected channels ' cfg.neighbours(curSensId).label ' and ' cfg.neighbours(lastSensId).label]);

    % draw new edge
    x1 = proj(curSensId,1);
    y1 = proj(curSensId,2);
    x2 = proj(lastSensId,1);
    y2 = proj(lastSensId,2);
    X = [x1 x2];
    Y = [y1 y2];
    if size(proj, 2) == 2
      hl(curSensId, lastSensId) = line(X, Y, 'color', 'r');
      hl(lastSensId, curSensId) = line(X, Y, 'color', 'r');
    elseif size(proj, 2) == 3
      z1 = proj(curSensId,3);
      z2 = proj(lastSensId,3);
      Z =[z1 z2];
      hl(curSensId, lastSensId) = line(X, Y, Z, 'color', 'r');
      hl(lastSensId, curSensId) = line(X, Y, Z, 'color', 'r');
    end

  end
  % draw nodes on top again
  delete(hs(curSensId));
  delete(hs(lastSensId));
  if size(proj, 2) == 2
    hs(curSensId) = line(proj(curSensId, 1), proj(curSensId, 2),                                            ...
      'MarkerEdgeColor',  'k',                                        ...
      'MarkerFaceColor',  'k',                                        ...
      'Marker',           'o',                                        ...
      'MarkerSize',       .125*(2+numel(cfg.neighbours(curSensId).neighblabel))^2, ...
      'UserData',         curSensId,                                          ...
      'ButtonDownFcn',    @showLabelInTitle);
    hs(lastSensId) = line(proj(lastSensId, 1), proj(lastSensId, 2),                                            ...
      'MarkerEdgeColor',  'k',                                        ...
      'MarkerFaceColor',  'k',                                        ...
      'Marker',           'o',                                        ...
      'MarkerSize',       .125*(2+numel(cfg.neighbours(lastSensId).neighblabel))^2, ...
      'UserData',         lastSensId,                                          ...
      'ButtonDownFcn',    @showLabelInTitle);

  elseif size(proj, 2) == 3
    hs(curSensId) = line(proj(curSensId, 1), proj(curSensId, 2), proj(curSensId, 3),                                ...
      'MarkerEdgeColor',  'k',                                        ...
      'MarkerFaceColor',  'k',                                        ...
      'Marker',           'o',                                        ...
      'MarkerSize',       .125*(2+numel(cfg.neighbours(curSensId).neighblabel))^2, ...
      'UserData',         curSensId,                        ...
      'ButtonDownFcn',    @showLabelInTitle);
    hs(lastSensId) = line(proj(lastSensId, 1), proj(lastSensId, 2), proj(lastSensId, 3),                                ...
      'MarkerEdgeColor',  'k',                                        ...
      'MarkerFaceColor',  'k',                                        ...
      'Marker',           'o',                                        ...
      'MarkerSize',       .125*(2+numel(cfg.neighbours(lastSensId).neighblabel))^2, ...
      'UserData',         lastSensId,                        ...
      'ButtonDownFcn',    @showLabelInTitle);
  else
    ft_error('Channel coordinates are too high dimensional');
  end

  if cfg.verbose
    str = sprintf('%s, ', cfg.neighbours(curSensId).neighblabel{:});
    if length(str)>2
      % remove the last comma and space
      str = str(1:end-2);
    end
    fprintf('Selected channel %s, which has %d neighbours: %s\n', ...
      cfg.neighbours(curSensId).label, ...
      length(cfg.neighbours(curSensId).neighblabel), ...
      str);
  end
  set(hs(curSensId), 'MarkerFaceColor', 'g');
  set(hs(lastSensId), 'MarkerFaceColor', 'k');
  userdata.lastSensId = curSensId;
  userdata.hl = hl;
  userdata.hs = hs;
  userdata.cfg = cfg;
  set(gcf, 'UserData', userdata);
  return;
else
  % can never happen, so do nothing
end

set(gcf, 'UserData', userdata);
end % subfunction

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function cleanup_cb(h, eventdata)
userdata = get(h, 'UserData');
h   = getparent(h);
userdata.quit = true;
set(h, 'UserData', userdata);
uiresume
end % subfunction

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function h = getparent(h)
p = h;
while p~=0
  h = p;
  p = get(h, 'parent');
end
end % subfunction


function info = fcnTest(varargin)

run matconvnet/matlab/vl_setupnn ;
addpath matconvnet/examples ;

% experiment and data paths
opts.expDir = 'data/fcn32s-voc11' ;
opts.dataDir = 'data/voc11' ;
opts.modelPath = 'data/fcn32-voc11/net-epoch-50.mat' ;
opts.modelFamily = 'matconvnet' ;
[opts, varargin] = vl_argparse(opts, varargin) ;

% experiment setup
opts.imdbPath = fullfile(opts.expDir, 'imdb.mat') ;
opts.vocEdition = '11' ;
opts.vocAdditionalSegmentations = true ;
opts.vocAdditionalSegmentationsMergeMode = 2 ;
opts.gpus = [] ;
opts = vl_argparse(opts, varargin) ;

resPath = fullfile(opts.expDir, 'results.mat') ;
if exist(resPath)
  info = load(resPath) ;
  return ;
end

if ~isempty(opts.gpus)
  gpuDevice(opts.gpus(1))
end

% -------------------------------------------------------------------------
% Setup data
% -------------------------------------------------------------------------

% Get PASCAL VOC 11/12 segmentation dataset plus Berkeley's additional
% segmentations
if exist(opts.imdbPath)
  imdb = load(opts.imdbPath) ;
else
  imdb = vocSetup('dataDir', opts.dataDir, ...
    'edition', opts.vocEdition, ...
    'includeTest', false, ...
    'includeSegmentation', true, ...
    'includeDetection', false) ;
  if opts.vocAdditionalSegmentations
    imdb = vocSetupAdditionalSegmentations(...
      imdb, ...
      'dataDir', opts.dataDir, ...
      'mergeMode', opts.vocAdditionalSegmentationsMergeMode) ;
  end
  mkdir(opts.expDir) ;
  save(opts.imdbPath, '-struct', 'imdb') ;
end

% Get validation subset
val = find(imdb.images.set == 2 & imdb.images.segmentation) ;

% Compare the validation set to the one used in the FCN paper
% valNames = sort(imdb.images.name(val)') ;
% valNames = textread('data/seg11valid.txt', '%s') ;
% valNames_ = textread('data/seg12valid-tvg.txt', '%s') ;
% assert(isequal(valNames, valNames_)) ;

% -------------------------------------------------------------------------
% Setup model
% -------------------------------------------------------------------------

switch opts.modelFamily
  case 'matconvnet'
    net = load(opts.modelPath) ;
    net = dagnn.DagNN.loadobj(net.net) ;
    net.mode = 'test' ;
    for name = {'objective', 'accuracy'}
      net.removeLayer(name) ;
    end
    net.meta.normalization.averageImage = reshape(net.meta.normalization.rgbMean,1,1,3) ;
    predVar = net.getVarIndex('prediction') ;
    inputVar = 'input' ;
    imageNeedsToBeMultiple = true ;

  case 'ModelZoo'
    net = dagnn.DagNN.loadobj(load(opts.modelPath)) ;
    net.mode = 'test' ;
    predVar = net.getVarIndex('upscore') ;
    inputVar = 'data' ;
    imageNeedsToBeMultiple = false ;

  case 'TVG'
    net = dagnn.DagNN.loadobj(load(opts.modelPath)) ;
    net.mode = 'test' ;
    predVar = net.getVarIndex('coarse') ;
    inputVar = 'data' ;
    imageNeedsToBeMultiple = false ;
end

if ~isempty(opts.gpus)
  gpuDevice(opts.gpus(1)) ;
  net.move('gpu') ;
end
net.mode = 'test' ;

% -------------------------------------------------------------------------
% Train
% -------------------------------------------------------------------------

numGpus = 0 ;
confusion = zeros(21) ;

for i = 1:numel(val)
  imId = val(i) ;
  name = imdb.images.name{imId} ;
  rgbPath = sprintf(imdb.paths.image, name) ;
  labelsPath = sprintf(imdb.paths.classSegmentation, name) ;

  % Load an image and gt segmentation
  rgb = vl_imreadjpeg({rgbPath}) ;
  rgb = rgb{1} ;
  anno = imread(labelsPath) ;
  lb = single(anno) ;
  lb = mod(lb + 1, 256) ; % 0 = ignore, 1 = bkg

  % Subtract the mean (color)
  im = bsxfun(@minus, single(rgb), net.meta.normalization.averageImage) ;

  % Soome networks requires the image to be a multiple of 32 pixels
  if imageNeedsToBeMultiple
    sz = [size(im,1), size(im,2)] ;
    sz_ = round(sz / 32)*32 ;
    im_ = imresize(im, sz_) ;
  else
    im_ = im ;
  end

  if ~isempty(opts.gpus)
    im_ = gpuArray(im_) ;
  end

  net.eval({inputVar, im_}) ;
  scores_ = gather(net.vars(predVar).value) ;
  [~,pred_] = max(scores_,[],3) ;

  if imageNeedsToBeMultiple
    pred = imresize(pred_, sz, 'method', 'nearest') ;
  else
    pred = pred_ ;
  end

  % Accumulate errors
  ok = lb > 0 ;
  confusion = confusion + accumarray([lb(ok),pred(ok)],1,[21 21]) ;

  % Plots
  if mod(i - 1,30) == 0 || i == numel(val)
    clear info ;
    [info.iu, info.miu, info.pacc, info.macc] = getAccuracies(confusion) ;
    fprintf('IU ') ;
    fprintf('%4.1f ', 100 * info.iu) ;
    fprintf('\n meanIU: %5.2f pixelAcc: %5.2f, meanAcc: %5.2f\n', ...
            100*info.miu, 100*info.pacc, 100*info.macc) ;

    figure(1) ; clf;
    imagesc(normalizeConfusion(confusion)) ;
    axis image ; set(gca,'ydir','normal') ;
    colormap(jet) ;
    drawnow ;

    % Print segmentation
    figure(100) ;clf ;
    displayImage(rgb/255, lb, pred) ;
    drawnow ;

    % Save segmentation
    imPath = fullfile(opts.expDir, [name '.png']) ;
    imwrite(pred,labelColors(),imPath,'png');
  end
end

% Save results
save(resPath, '-struct', 'info') ;

% -------------------------------------------------------------------------
function nconfusion = normalizeConfusion(confusion)
% -------------------------------------------------------------------------
% normalize confusion by row (each row contains a gt label)
nconfusion = bsxfun(@rdivide, double(confusion), double(sum(confusion,2))) ;

% -------------------------------------------------------------------------
function [IU, meanIU, pixelAccuracy, meanAccuracy] = getAccuracies(confusion)
% -------------------------------------------------------------------------
pos = sum(confusion,2) ;
res = sum(confusion,1)' ;
tp = diag(confusion) ;
IU = tp ./ max(1, pos + res - tp) ;
meanIU = mean(IU) ;
pixelAccuracy = sum(tp) / max(1,sum(confusion(:))) ;
meanAccuracy = mean(tp ./ max(1, pos)) ;

% -------------------------------------------------------------------------
function displayImage(im, lb, pred)
% -------------------------------------------------------------------------
subplot(2,2,1) ;
image(im) ;
axis image ;
title('source image') ;

subplot(2,2,2) ;
image(uint8(lb-1)) ;
axis image ;
title('ground truth')

cmap = labelColors() ;
subplot(2,2,3) ;
image(uint8(pred-1)) ;
axis image ;
title('predicted') ;

colormap(cmap) ;

% -------------------------------------------------------------------------
function cmap = labelColors()
% -------------------------------------------------------------------------
N=21;
cmap = zeros(N,3);
for i=1:N
  id = i-1; r=0;g=0;b=0;
  for j=0:7
    r = bitor(r, bitshift(bitget(id,1),7 - j));
    g = bitor(g, bitshift(bitget(id,2),7 - j));
    b = bitor(b, bitshift(bitget(id,3),7 - j));
    id = bitshift(id,-3);
  end
  cmap(i,1)=r; cmap(i,2)=g; cmap(i,3)=b;
end
cmap = cmap / 255;


function [s,error] = openDEeph( s, denum, ineph, dontSave )
% open a binary JPL planetary ephemeris file and sets initial values
% short int ephem_open (char *ephem_name,
%                       double *jd_begin, double *jd_end,
%                       short int *de_number)
%
% ------------------------------------------------------------------------
%
%    PURPOSE:
%       This function opens a JPL planetary ephemeris file and
%       sets initial values.  This function must be called
%       prior to calls to the other JPL ephemeris functions.
%
%    REFERENCES:
%       Standish, E.M. and Newhall, X X (1988). "The JPL Export
%          Planetary Ephemeris"; JPL document dated 17 June 1988.
%
%    INPUT
%    ARGUMENTS:
%       *ephem_name (char)
%          Name of the direct-access ephemeris file.
%
%    OUTPUT
%    ARGUMENTS:
%       *jd_begin (double)
%          Beginning Julian date of the ephemeris file.
%       *jd_end (double)
%          Ending Julian date of the ephemeris file.
%       *de_number (short int)
%          DE number of the ephemeris file opened.
%
%    RETURNED
%    VALUE:
%       (short int)
%           0   ...file exists and is opened correctly.
%           1   ...file does not exist/not found.
%           2-10...error reading from file header.
%           11  ...unable to set record length; ephemeris (DE number)
%                  not in look-up table.
%
%    GLOBALS
%    USED:
%       SS                eph_manager.h
%       JPLAU             eph_manager.h
%       PC                eph_manager.h
%       VC                eph_manager.h
%       TWOT              eph_manager.h
%       EM_RATIO          eph_manager.h
%       BUFFER            eph_manager.h
%       IPT               eph_manager.h
%       LPT               eph_manager.h
%       NRL               eph_manager.h
%       KM                eph_manager.h
%       NP                eph_manager.h
%       NV                eph_manager.h
%       RECORD_LENGTH     eph_manager.h
%       EPHFILE           eph_manager.h
%
%    FUNCTIONS
%    CALLED:
%       fclose            stdio.h
%       free              stdlib.h
%       fopen             stdio.h
%       fread             stdio.h
%       calloc            stdlib.h
%
%    VER./DATE/
%    PROGRAMMER:
%       V1.0/06-90/JAB (USNO/NA)
%       V1.1/06-92/JAB (USNO/AA): Restructure and add initializations.
%       V1.2/07-98/WTH (USNO/AA): Modified to open files for different
%                                 ephemeris types. (200,403,404,405,406)
%       V1.3/11-07/WKP (USNO/AA): Updated prolog.
%       V1.4/09-10/WKP (USNO/AA): Changed ncon and denum variables and
%                                 sizeof ipt array to type 'int' for
%                                 64-bit system compatibility.
%       V1.5/09-10/WTH (USNO/AA): Added support for DE421, default case
%                                 for switch, close file on error.
%       V1.6/10-10/WKP (USNO/AA): Renamed function to lowercase to
%                                 comply with coding standards.
%
%    NOTES:
%       KM...flag defining physical units of the output states.
%          = 1, km and km/sec
%          = 0, AU and AU/day
%       Default value is 0 (KM determines time unit for nutations.
%                           Angle unit is always radians.)
%
% ------------------------------------------------------------------------
  persistent m;
  if isempty(m)
    m = containers.Map('KeyType','char','ValueType','any');
  end
  if nargin < 4
    dontSave = false;
  end
  s.de_number = 0;
  s.jd_begin = 0.0;
  s.jd_end = 0.0;
  if isnumeric(denum)
    denum = sprintf('%d',denum);
  end
  error = 0;
  if isempty(ineph)
    error = 1;
    return;
  elseif exist(ineph, 'file') ~= 2
    inasc = ineph;
    inasc(1:3) = 'asc';
    Ephem.asc2eph(denum,inasc,ineph);
  end
  if exist(ineph, 'file') == 2
    % found locally
    if m.isKey(ineph)
      st = m(ineph);
    else
      EPHFILE = fopen (ineph,'rb');
      if EPHFILE ~= -1
        for i=1:3
          [st.ttl{i},count] = fread (EPHFILE, Ephem.TTLsize, '*char');
          if count ~= Ephem.TTLsize
            error = 1;
            fprintf(2,'openDEeph: Error TTL retrieved %d from "%s", expected %d\n',...
              count,ineph,Ephem.TTLsize);
          end
          st.ttl{i} = strcat(transpose(st.ttl{i}));
        end
        % pos 252
        for i=1:Ephem.OLDCONMAX
          [st.CNAM{i},count] = fread (EPHFILE, Ephem.CNAMsize, '*char');
          if count ~= Ephem.CNAMsize
            error = 1;
            fprintf(2,'openDEeph: Error CNAM retrieved %d from "%s", expected %d\n',...
              count,ineph,Ephem.CNAMsize);
          end
          st.CNAM{i} = strcat(transpose(st.CNAM{i}));
        end
        % pos 2652
        [st.SS,count] = fread (EPHFILE, 3, 'double');
        if count ~= 3
          error = 1;
          fprintf(2,'openDEeph: Error SS retrieved %d from "%s", expected %d\n',...
            count,ineph,3);
        end
        [st.NCON,count] = fread (EPHFILE, 1, 'int32');
        if count ~= 1
          error = 1;
          fprintf(2,'openDEeph: Error NCON retrieved %d from "%s", expected %d\n',...
            count,ineph,1);
        end
        [st.JPLAU,count] = fread (EPHFILE, 1, 'double');
        if count ~= 1
          error = 1;
          fprintf(2,'openDEeph: Error JPLAU retrieved %d from "%s", expected %d\n',...
            count,ineph,1);
        end
        [st.EM_RATIO,count] = fread (EPHFILE, 1, 'double');
        if count ~= 1
          error = 1;
          fprintf(2,'openDEeph: Error EM_RATIO retrieved %d from "%s", expected %d\n',...
            count,ineph,1);
        end
        % pos 2652+8*3+4+8+8
        for i=1:12
          for j=1:3
            [st.IPT(j,i),count] = fread (EPHFILE, 1, 'int32');
            if count ~= 1
              error = 1;
              fprintf(2,'openDEeph: Error IPT retrieved %d from "%s", expected %d\n',...
                count,ineph,1);
            end
          end
        end
        % pos 2652+8*3+4+8+8+12*3*4
        [st.de_number,count] = fread (EPHFILE, 1, 'int32');
        st.de_number = sprintf('%d',st.de_number);
        if count ~= 1
          error = 1;
          fprintf(2,'openDEeph: Error de_number retrieved %d from "%s", expected %d\n',...
            count,ineph,1);
        end
        % pos 2652+8*3+4+8+8+12*3*4+4
        if strcmp(st.de_number,denum(1:min(length(st.de_number),length(denum)))) == false
          if s.output > 0
            fprintf(s.output,'openDEeph: Warning DE# retrieved %s from "%s", expected %s\n',...
              st.de_number,ineph,denum);
          end
        end
        [LPT,count] = fread (EPHFILE, 3, 'int32');
        if count ~= 3
          error = 1;
          fprintf(2,'openDEeph: Error LPT retrieved %d from "%s", expected %d\n',...
            count,ineph,3);
        end
        % pos 2652+8*3+4+8+8+12*3*4+4+3*4
        for i=Ephem.OLDCONMAX+1:st.NCON
          [st.CNAM{i},count] = fread (EPHFILE, Ephem.CNAMsize, '*char');
          if count ~= Ephem.CNAMsize
            error = 1;
            fprintf(2,'openDEeph: Error CNAM retrieved %d from "%s", expected %d\n',...
              count,ineph,Ephem.CNAMsize);
          end
          st.CNAM{i} = strcat(transpose(st.CNAM{i}));
        end
        [RPT,count] = fread (EPHFILE, 3, 'int32');
        if count ~= 3
          error = 1;
          fprintf(2,'openDEeph: Error RPT retrieved %d from "%s", expected %d\n',...
            count,ineph,3);
        end
        [TPT,count] = fread (EPHFILE, 3, 'int32');
        if count ~= 3
          error = 1;
          fprintf(2,'openDEeph: Error TPT retrieved %d from "%s", expected %d\n',...
            count,ineph,3);
        end
        for i=1:3
          st.IPT(i,13) = LPT(i);
          st.IPT(i,14) = RPT(i);
          st.IPT(i,15) = TPT(i);
        end
        st.NCOEFF = Ephem.numCoeff( st.IPT );
        st.RECORD_LENGTH = 8*st.NCOEFF;
        status = fseek(EPHFILE,(2-1)*st.RECORD_LENGTH,'bof');
        if status == -1
          fprintf(2,'openDEeph seek error at %d\n',2);
        end
        [st.CVAL,count] = fread (EPHFILE, st.NCON, 'double');
        if count ~= st.NCON
          error = 1;
          fprintf(2,'openDEeph: Error CVAL retrieved %d from "%s", expected %d\n',...
            count,ineph,st.NCON);
        end
        for i=1:st.NCON
          cnm = deblank(st.CNAM{i});
          indx = strfind(cnm,'.');
          for j=1:length(indx)
            cnm(indx(j)) = '_';
          end
          if ~isempty(cnm)
            st.(cnm) = st.CVAL(i);
          else
            st.('blank') = st.CVAL(i);
          end
        end
        st.masses(Ephem.Mercury) = st.GM1;
        st.masses(Ephem.Venus) = st.GM2;
        st.masses(Ephem.Mars) = st.GM4;
        st.masses(Ephem.Jupiter) = st.GM5;
        st.masses(Ephem.Saturn) = st.GM6;
        st.masses(Ephem.Uranus) = st.GM7;
        st.masses(Ephem.Neptune) = st.GM8;
        st.masses(Ephem.Pluto) = st.GM9;
        st.masses(Ephem.Sun) = st.GMS;
        st.masses(Ephem.EarthMoonBarycenter) = st.GMB;
        st.masses(Ephem.Moon) = st.GMB/(1+s.EM_RATIO);
        st.masses(Ephem.Earth) = st.GMB*s.EM_RATIO/(1+s.EM_RATIO);
        mm = 0;
        for i=Ephem.Mercury:Ephem.Sun
          mm = mm + st.masses(i);
        end
        st.masses(Ephem.SolarSystemBarycenter) = mm;

        pos = 1;
        status = fseek(EPHFILE,(3-1)*st.RECORD_LENGTH,'bof');
        if status == -1
          if s.output > 0
            fprintf(s.output,'openDEeph: Bad fseek of "%s"\n',ineph);
          end
          fclose (EPHFILE);
          error = 9;
          return;
        end
        st.scan = zeros(1,0);
        for NROUT = 3:281474976710655
          [sc,count] = fread (EPHFILE,st.NCOEFF,'double');
          if isempty(sc) || count == 0 % expected end
            break;
          end
          if st.NCOEFF ~= count
            fprintf(2,'openDEeph: Error COEFF retrieved %d from "%s", expected %d\n',...
              count,ineph,st.NCOEFF);
            %break;
          else
            for K=1:st.NCOEFF
              st.scan(pos) = sc(K);
              pos = pos + 1;
            end
          end
        end
        fclose (EPHFILE);
        if isempty(st.scan)
          if s.output > 0
            fprintf(s.output,'openDEeph: Bad textscan of "%s"\n',ineph);
          end
          error = 9;
          return;
        end
        if dontSave == false
          m(ineph) = st;
        end
      else
        if s.output > 0
          fprintf(s.output,'openDEeph: Could not open "%s"\n',ineph);
        end
        error = 10;
        return;
      end
    end
  else
    if s.output > 0
      fprintf(2,'openDEeph: Bad file access for "%s"\n',ineph);
    end
    error = 10;
    return;
  end

  s.scan = st.scan;
  s.SS = st.SS;
  s.de_number = denum;
  s.RECORD_LENGTH = st.RECORD_LENGTH;
  s.IPT = st.IPT;
  s.JPLAU = st.JPLAU;
  s.EM_RATIO = st.EM_RATIO;
  for i=Ephem.Mercury:Ephem.EarthMoonBarycenter
    s.masses(i) = st.masses(i);
  end

  s.jd_begin = s.SS(1);
  s.jd_end = s.SS(2);
  s.jd_inc = s.SS(3);
  s.numRecs =  1 + (s.jd_end-s.jd_begin)/s.jd_inc;
  if mod(s.numRecs,1.0) ~= 0
    if s.output > 0
      fprintf(s.output,'openDEeph: DE%s Bad jd_inc (%g) numRecs (%g) should be integer\n',...
        denum,s.indexInc,s.numRecs);
    end
    s.jd_begin = 0.0;
    s.jd_end = 0.0;
    s.jd_inc = 0.0;
    error = 12;
    return;
  end
  s.indexInc = s.RECORD_LENGTH / 8;
  s.indexOffset = -1;
end


function bbs = acfDetect( I, detector, fileName )
% Run aggregate channel features object detector on given image(s).
%
% The input 'I' can either be a single image (or filename) or a cell array
% of images (or filenames). In the first case, the return is a set of bbs
% where each row has the format [x y w h score] and score is the confidence
% of detection. If the input is a cell array, the output is a cell array
% where each element is a set of bbs in the form above (in this case a
% parfor loop is used to speed execution). If 'fileName' is specified, the
% bbs are saved to a comma separated text file and the output is set to
% bbs=1. If saving detections for multiple images the output is stored in
% the format [imgId x y w h score] and imgId is a one-indexed image id.
%
% A cell of detectors trained with the same channels can be specified,
% detected bbs from each detector are concatenated. If using multiple
% detectors and opts.pNms.separate=1 then each bb has a sixth element
% bbType=j, where j is the j-th detector, see bbNms.m for details.
%
% USAGE
%  bbs = acfDetect( I, detector, [fileName] )
%
% INPUTS
%  I          - input image(s) of filename(s) of input image(s)
%  detector   - detector(s) trained via acfTrain
%  fileName   - [] target filename (if specified return is 1)
%
% OUTPUTS
%  bbs        - [nx5] array of bounding boxes or cell array of bbs
%
% EXAMPLE
%
% See also acfTrain, acfModify, bbGt>loadAll, bbNms
%
% Piotr's Image&Video Toolbox      Version 3.20
% Copyright 2013 Piotr Dollar & Ron Appel.  [pdollar-at-caltech.edu]
% Please email me if you find bugs, or have suggestions or questions!
% Licensed under the Simplified BSD License [see external/bsd.txt]

% run detector on every image
if(nargin<3), fileName=''; end; multiple=iscell(I);
if(~isempty(fileName) && exist(fileName,'file')), bbs=1; return; end
if(~multiple), bbs=acfDetectImg(I,detector); else
  n=length(I); bbs=cell(n,1);
  parfor i=1:n, bbs{i}=acfDetectImg(I{i},detector); end
end

% write results to disk if fileName specified
if(isempty(fileName)), return; end
d=fileparts(fileName); if(~isempty(d)&&~exist(d,'dir')), mkdir(d); end
if( multiple ) % add image index to each bb and flatten result
  for i=1:n, bbs{i}=[ones(size(bbs{i},1),1)*i bbs{i}]; end
  bbs=cell2mat(bbs);
end
dlmwrite(fileName,bbs); bbs=1;

end

function bbs = acfDetectImg( I, detector )
% Run trained sliding-window object detector on given image.
Ds=detector; if(~iscell(Ds)), Ds={Ds}; end; nDs=length(Ds);
opts=Ds{1}.opts; pPyramid=opts.pPyramid; pNms=opts.pNms;
imreadf=opts.imreadf; imreadp=opts.imreadp;
shrink=pPyramid.pChns.shrink; pad=pPyramid.pad;
separate=nDs>1 && isfield(pNms,'separate') && pNms.separate;
% perform actual computations
if(all(ischar(I))), I=feval(imreadf,I,imreadp{:}); end
P = chnsPyramid(I,pPyramid); bbs = cell(P.nScales,nDs);
for i=1:P.nScales
  for j=1:nDs, opts=Ds{j}.opts;
    modelDsPad=opts.modelDsPad; modelDs=opts.modelDs;
    bb = acfDetect1(P.data{i},Ds{j}.clf,shrink,...
      modelDsPad(1),modelDsPad(2),opts.stride,opts.cascThr);
    shift=(modelDsPad-modelDs)/2-pad;
    bb(:,1)=(bb(:,1)+shift(2))/P.scaleshw(i,2);
    bb(:,2)=(bb(:,2)+shift(1))/P.scaleshw(i,1);
    bb(:,3)=modelDs(2)/P.scales(i);
    bb(:,4)=modelDs(1)/P.scales(i);
    if(separate), bb(:,6)=j; end; bbs{i,j}=bb;
  end
end; bbs=cat(1,bbs{:});
if(~isempty(pNms)), bbs=bbNms(bbs,pNms); end
end


function Pout = filename_get_new_root_dir(P,newroot,nlevels)
% :Usage:
% ::
%
%     Pout = filename_get_new_root_dir(P,newroot,nlevels)
%
% :Inputs:
%
%   **P:**
%        is files (string matrix)
%
%   **newroot:**
%        Append a new root directory to filenames
%        if newroot is empty, prompt
%
%   **nlevels:**
%        Keeps nlevels dirs deep from old directory:
%          - keeps only filename
%          - keeps filename plus last subdir
%          - keeps filename plus last 2 subdirs, etc.
%
% :Examples:
% ::
%
%    Pout = filename_get_new_root_dir(EXPT.SNPM.P{3},pwd,2)
%
%    % Change root dir to pwd for all images in EXPT
%    for i=1:length(EXPT.SNPM.P), EXPT.SNPM.P{i} = filename_get_new_root_dir(EXPT.SNPM.P{i},pwd,2); end
%
% Note: see regexprep.m for a simpler way!!! This function could be
% improved by using it.
%
% ..
%    tor wager
% ..

if isempty(newroot), newroot = spm_get(-1,'*','Get new root directory'); end

Pout = get_Pout(P(1,:),newroot,nlevels);

for i = 2:size(P,1)

    Pout = str2mat(Pout,get_Pout(P(i,:),newroot,nlevels));

end

for i = 1:size(Pout, 1)
    isfile(i) = exist(deblank(Pout(i,:)), 'file');
end
fprintf(1,'Found %3.0f valid files.\n', sum(isfile > 0));

return

function Pout = get_Pout(p,str,nlevels);

p = deblank(p);
[d,f,e] = fileparts(p);
filename = [f e];

for i = 2:nlevels
    [d,dd] = fileparts(d);
    filename = fullfile(dd,filename);
end

Pout = fullfile(str,filename);

return


function conf = voc_config_car_grammar()
% Set up configuration variables

% AUTORIGHTS
% -------------------------------------------------------
% Copyright (C) 2011-2012 Ross Girshick
%
% This file is part of the voc-releaseX code
% (http://people.cs.uchicago.edu/~rbg/latent/)
% and is available under the terms of an MIT-like license
% provided in COPYING. Please retain this notice and
% COPYING if you use this file (or a portion of it) in
% your project.
% -------------------------------------------------------

conf.project = 'rel5-dev/car-grammar-3';

conf.training.C                    = 0.006;
conf.training.wlssvm_M             = 1;
conf.training.lbfgs.options.optTol = 0.0001;

conf.eval.max_thresh = -1.4;


function movex_text(h_txt,x_pos)
%MOVEX_TEXT moves text horizontally.

% Copyright 2004-2010 The MathWorks, Inc.

FmtSpec=getappdata(get(get(h_txt,'parent'),'parent'),'FmtSpec');
msg=sprintf(FmtSpec,x_pos);
pos=get(h_txt,'position');
pos(1)=x_pos;
set(h_txt,'Position',pos,'String',msg)


function tapas_validate_data(data)
%% Check that data complies with the inferface.
%
% aponteeduardo@gmail.com
% copyright (C) 2016
%

if ~isstruct(data)
    error('tapas:validate:data', 'data is not a structure')
end

if ~isfield(data, 'y')
    error('tapas:validate:data', 'data lacks field y');
end

if ~isfield(data, 'u')
    error('tapas:validate:data', 'data lacks field u');
end

end


%--- help for abstvar/posterior_mode ---
%
%  Return the posterior mode from the BVAR estimation
%
%  ::
%
%     dd = posterior_mode(self)
%
%  Args:
%     self (var object): var object
%
%  Returns:
%     :
%
%     - **dd** (struct): posterior mode of the parameters
%
%


function [ cnt ] = opt_eegStruct( dat, field )
% opt_eegStruct:
%
% Description:
%     This function converts the eeg data into a struct in OpenBMI format.
%
% Example:
%    marker={'1','right';'2','left';'3','foot'};
%    field={'x','t','fs','y_dec','y_logic','y_class','class', 'chan'};
%    [EEG.data, EEG.marker, EEG.info]=Load_EEG(file,{'device','brainVision';'marker',marker;'fs',fs});
%    CNT=opt_eegStruct({EEG.data, EEG.marker, EEG.info}, field);
%
% Input:
%     dat   - EEG data structure in a cell type
%     field - Selected necessary fields you want to get in a cell
%
% Output:
%     cnt   - Raw EEG data in OpenBMI format with fields of input 'field'
%
% Min-ho Lee
% mhlee@image.korea.ac.kr
%

if isempty(field)
    error('OpenBMI: There''s no field information')
elseif ~prod(ismember(field,{'x','t','fs','y_dec','y_logic','y_class','class', 'chan'}))
    error('OpenBMI: Unacceptable field name')
end

for i=1:length(field)
    [cnt.(field{i})]=[];
end

stc=struct;
if iscell(dat)
    nC=length(dat);
    for i=1:nC
        t_stc=opt_selectField(dat{i},field);
        stc=opt_catStruct(stc,t_stc);
    end
end

for i=1:length(field)
    if ~isempty(stc.(field{i}))
        cnt(:).(field{i})= stc.(field{i});
    else
        warn_str=sprintf('OpenBMI: The field "%s" is empty', field{i});
        disp(warn_str);
    end
end

end