function [varargout]=gpatch(varargin)

% function [h]=gpatch(F,V,C,CE,A,L)
% ------------------------------------------------------------------------
% This function is a short-hand version of the |patch| command. The inputs
% for |gpatch| are the faces (F), the vertices (V), the color description
% (C), the edge color description CE, the transparancy (A), and the edge
% width (L).
% The color data descriptions C (or equivalently CE for edges) can be:
% 1) A string such as 'g' for green
% 2) A triplet of RGD values e.g. [1 0 0] is blue
% 3) A nx1 or a mx1 array of colormapped colors (where n=size(F,1) or
% m=size(V,1))
% 4) (simiarl to 3) A nx3 or a mx3 RGB color value array for the faces or
% vertices respectively.
%
%
% Kevin Mattheus Moerman
% gibbon.toolbox@gmail.com
%
% 2017
% 2018/02/07 Added support for colormapped edges
%------------------------------------------------------------------------

switch nargin
    case 1
        error('Not enough input arguments, provide at least faces and vertices');
    case 2
        F=varargin{1};
        V=varargin{2};
        C='g';
        CE='k';
        A=1;
        L=[];
    case 3
        F=varargin{1};
        V=varargin{2};
        C=varargin{3};
        CE='k';
        A=1;
        L=[];
    case 4
        F=varargin{1};
        V=varargin{2};
        C=varargin{3};
        CE=varargin{4};
        A=1;
        L=[];
    case 5
        F=varargin{1};
        V=varargin{2};
        C=varargin{3};
        CE=varargin{4};
        A=varargin{5};
        L=[];
    case 6
        F=varargin{1};
        V=varargin{2};
        C=varargin{3};
        CE=varargin{4};
        A=varargin{5};
        L=varargin{6};
    otherwise
        error('Wrong number of input arguments');
end

if isempty(C)
    C='g';
end

if isempty(CE)
    C='k';
end

if isa(F,'cell') %Assume all entries are cells defining multiple patch data sets
    for q=1:1:numel(F)
        f=F{q};

        if isa(V,'cell')
            v=V{q};
        else
            v=V;
        end

        if isa(C,'cell')
            c=C{q};
        else
            c=C;
        end

        if isa(CE,'cell')
            ce=CE{q};
        else
            ce=CE;
        end

        if isa(A,'cell')
            a=A{q};
        else
            a=A;
        end

        hp(q)=plotPatch(f,v,c,ce,a,L);
    end
else
    hp=plotPatch(F,V,C,CE,A,L);
end

if nargout==1
    varargout{1}=hp;
end

end

%%
function hp=plotPatch(F,V,C,CE,A,L)

% hf=gcf;
% if isempty(hf.Children)
%     gca;
%     view(3);
% end

argInPatch.Faces=F;
argInPatch.Vertices=V;
argInPatch.EdgeColor=CE;

if ischar(C) %Plain single color
    argInPatch.FaceColor=C;
    if strcmp(C,'kw')
        argInPatch.FaceColor=grayColor(0.5);
    end
    if strcmp(C,'rw')
        argInPatch.FaceColor=[1 0.5 0.5];
    end
    if strcmp(C,'gw')
        argInPatch.FaceColor=[0.5 1 0.5];
    end
    if strcmp(C,'bw')
        argInPatch.FaceColor=[0.5 0.5 1];
    end
    if strcmp(C,'yw')
        argInPatch.FaceColor=[1 1 0.5];
    end
    if strcmp(C,'cw')
        argInPatch.FaceColor=[0.5 1 1];
    end
    if strcmp(C,'mw')
        argInPatch.FaceColor=[1 0.5 1];
    end
elseif size(C,2)==1
    argInPatch.FaceColor='flat';
    argInPatch.CData=double(C);
elseif size(C,2)==3 && size(C,1)==1 %Assume single RGB level
    argInPatch.FaceColor=double(C);
elseif size(C,2)==3 && size(C,1)>1 %Assume RGB array
    argInPatch.FaceColor='flat';
    argInPatch.FaceVertexCData=double(C);
else
    error('Invalid face-vertex color data input');
end

if ischar(CE) %Plain single color
    argInPatch.EdgeColor=CE;
    if strcmp(CE,'kw')
        argInPatch.EdgeColor=grayColor(0.5);
    end
    if strcmp(CE,'rw')
        argInPatch.EdgeColor=[1 0.5 0.5];
    end
    if strcmp(CE,'gw')
        argInPatch.EdgeColor=[0.5 1 0.5];
    end
    if strcmp(CE,'bw')
        argInPatch.EdgeColor=[0.5 0.5 1];
    end
    if strcmp(CE,'yw')
        argInPatch.EdgeColor=[1 1 0.5];
    end
    if strcmp(CE,'cw')
        argInPatch.EdgeColor=[0.5 1 1];
    end
    if strcmp(CE,'mw')
        argInPatch.EdgeColor=[1 0.5 1];
    end
elseif size(CE,2)==1
    if size(CE,1)>1
        if size(CE,1)==size(F,1)
            [CE]=faceToVertexMeasure(F,V,CE);
            argInPatch.EdgeColor='flat';
            argInPatch.CData=double(CE);
        end
        if size(CE,1)==size(V,1)
            argInPatch.EdgeColor='flat';
            argInPatch.CData=double(CE);
        end
    else
        argInPatch.EdgeColor='flat';
        argInPatch.CData=double(CE)*ones(size(V,1),1);
    end
elseif size(CE,2)==3 && size(CE,1)==1 %Assume single RGB level
    argInPatch.EdgeColor=double(CE);
elseif size(CE,2)==3 && size(CE,1)>1 %Assume RGB array
    argInPatch.EdgeColor='flat';
    argInPatch.FaceVertexCData=double(CE);
else
    error('Invalid edge color data input');
end

if numel(A)==1 %Plain single alpha
    argInPatch.FaceAlpha=A;
elseif size(A,2)==1 %Alpha mapping
    argInPatch.FaceAlpha='flat';
    argInPatch.FaceVertexAlphaData=A;
else
    error('Invalid alpha data input');
end

if ~isempty(L)
    argInPatch.LineWidth=L;
end

hp=patch(argInPatch);

end

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


function copyScan(sessionDir,dataType,scan)
%
% function copyScan(sessionDir,dataType,scan)
%
% Copy a scan from a different session.
% Creates dataType 'Copied' if it doesn't already exist.
%
% sessionDir: path string to the other session
% dataType, scan: specifies where to find the tSeries within that session
%
% Output is a new set of tSeries files in a new Scan subdirectory
% under the Copied dataType directory.
%
% djh, 2/28/2001

mrGlobals

% Make sure dataType 'Copied' exists
if ~existDataType('Copied')
    addDataType('Copied');
end

% Open hidden gray
hiddenView = initHiddenGray;
hiddenView = selectDataType(hiddenView,existDataType('Copied'));

% update dataTYPES.scanParams with the new scan,
% copying scanParams, blockedAnalysisParams, & eventAnalysisParams
% from the other session.
newScanNum = numScans(hiddenView)+1;
ndataType = hiddenView.curDataType;
% load dataTYPES from other session
s = load(fullfile(sessionDir,'mrSESSION.mat'));
% get scanParams, blockedAnalysisParams, & eventAnalysisParams from other session
ndataTypeOtherSession = existDataType(dataType,s.dataTYPES);
scanParams = s.dataTYPES(ndataTypeOtherSession).scanParams(scan);
% blast slices & cropSize because inplane view of new scan is bogus
scanParams.slices = [];
scanParams.cropSize = [];
blockedAnalysisParams = s.dataTYPES(ndataTypeOtherSession).blockedAnalysisParams(scan);
eventAnalysisParams = s.dataTYPES(ndataTypeOtherSession).eventAnalysisParams(scan);
dataTYPES(ndataType).scanParams(newScanNum) = scanParams;
dataTYPES(ndataType).blockedAnalysisParams(newScanNum) = blockedAnalysisParams;
dataTYPES(ndataType).eventAnalysisParams(newScanNum) = eventAnalysisParams;
dataTYPES(ndataType).scanParams(newScanNum).annotation = ['Copied from ',sessionDir,', dataType: ',dataType,', scan: ',num2str(scan)];

% Load gray coords from other session.
% Compute intersection of their coords with my gray coords.
grayCoordsFile = fullfile(sessionDir,'Gray','coords.mat');
s = load(grayCoordsFile);
[c,ia,ib] = intersectCols(hiddenView.coords,s.coords);
% Load the tSeries from the other session
tSeriesPath = fullfile(sessionDir,'Gray',dataType,'TSeries',['Scan',num2str(scan)],'tSeries1.mat');
s = load(tSeriesPath);

tSeries = NaN*ones([size(s.tSeries,1) size(hiddenView.coords,2)]);
tSeries(:,ia) = s.tSeries(:,ib);
%This should be able to be used the same as before as the gray view has not
%yet been updated
savetSeries(tSeries,hiddenView,newScanNum,1);
saveSession

% Loop through the open views, switch their curDataType appropriately,
% and update the dataType popups
INPLANE = resetDataTypes(INPLANE,ndataType);
VOLUME = resetDataTypes(VOLUME,ndataType);
FLAT = resetDataTypes(FLAT,ndataType);

return;

function viewList=resetDataTypes(viewList,ndataType)
% Loops through the views, updating the dataType to reflect the additional scan.
% The call to selectDataType updates the dataType popup.
for s=1:length(viewList)
    if ~isempty(viewList{s})
        if viewList{s}.curDataType == ndataType
            viewList{s} = selectDataType(viewList{s},1);
            viewList{s} = selectDataType(viewList{s},ndataType);
        end
    end
end
return

% Debug/test

clear all; close all;
sessionDirs = {'e:/mri/test','j:/djhRetinotopy/030701a'};
newSession = 'e:/mri/foo';
mergeSessions(sessionDirs,newSession);
chdir(newSession)
mrLoadRet
copyScan(sessionDirs{1},'Original',1);
copyScan(sessionDirs{1},'Original',2);
copyScan(sessionDirs{2},'Averages',1);
copyScan(sessionDirs{2},'Averages',2);


function gmt_xy(hLine, sOutput, sPrefix)

% Get attributes
sLineStyle = lower(get(hLine, 'LineStyle'));
sMarker = get(hLine, 'Marker');

if ~((strcmp(sLineStyle, 'none'))  &&  (strcmp(sMarker, 'none')))

  % Get data
  mXData = get(hLine, 'XData');
  mYData = get(hLine, 'YData');

  % Transform data and save it
  [nRow, nCnt] = size(mXData);
  if nRow == 1
    mXData = mXData';
  end
  [nRow, nCnt] = size(mYData);
  if nRow == 1
    mYData = mYData';
  end
  mXYValues = [mXData mYData];
  save([sPrefix '_xy.tmp'], 'mXYValues', '-ascii');

  hFile = fopen(sOutput, 'a');
  fprintf(hFile, '# Plot xy\n');

  unix(['sed -f xy.sed ' sPrefix '_xy.tmp > ' sPrefix '_xy.dat']);
  unix(['rm -f ' sPrefix '_xy.tmp']);

  % Get attributes
  sLineStyle = lower(get(hLine, 'LineStyle'));
  fLineWidth = get(hLine, 'LineWidth');
  sMarker = get(hLine, 'Marker');
  fMarkerSize = get(hLine, 'MarkerSize');
  vColor = get(hLine, 'Color');

  if ~strcmp(sLineStyle, 'none')
    sS = '';
    sW = sprintf('-W%s/%s/%s/%s ', num2str(fLineWidth), num2str(vColor(1)*255), num2str(vColor(2)*255), num2str(vColor(3)*255));
    sM = '-M ';
    fprintf(hFile, 'psxy %s $default %s %s %s -O -K >> $output\n', [sPrefix '_xy.dat'], sW, sM, sS);
  end
  if ~strcmp(sMarker, 'none')
    switch sMarker
    case '^',         % triangle upwards
      sSymbol = 't';
    case '.',         % point
      sSymbol = 'p';
    case 'hexagram',  % hexagram
      sSymbol = 'a';
    case 'o',         % circle
      sSymbol = 'c';
    case 'square',    % square
      sSymbol = 's';
    case 'x',         % cross
      sSymbol = 'x';
    case '*',         % asterix
      sSymbol = 'a';
    otherwise         % point as default
      sSymbol = 'p';
    end
    vEdgeColor = get(hLine, 'MarkerEdgeColor');
    if strcmp(vEdgeColor, 'auto')
      vEdgeColor = get(hLine, 'Color');
    end
    vFaceColor = get(hLine, 'MarkerFaceColor');
    if ~strcmp(vFaceColor, 'none')
      sG = sprintf('-G%s/%s/%s ', num2str(vFaceColor(1)*255), num2str(vFaceColor(2)*255), num2str(vFaceColor(3)*255));
    else
      sG = '';
    end
    sS = ['-S' sSymbol num2str(fMarkerSize) 'p ']

    sW = sprintf('-W%s/%s/%s/%s ', num2str(fLineWidth), num2str(vEdgeColor(1)*255), num2str(vEdgeColor(2)*255), num2str(vEdgeColor(3)*255));
    fprintf(hFile, 'psxy %s $default %s %s %s -O -K >> $output\n', [sPrefix '_xy.dat'], sW, sG, sS);
  end
  fclose(hFile);
end


function [NNF, nUpdate]= sc_update_NNF(trgPatch, img, NNF, modelPlane, modelReg, optS)

% SC_UPDATE_NNF
%
% Update the nearest neighbor field using the PatchMatch algorithm
%
% Input:
%   - trgPatch
%   - img:
%   - NNF
%   - modelPlane
%   - modelReg
%   - optS
% Output:
%   - NNF
%   - nUpdate

nUpdate = zeros(1,3);

for i = 1:optS.numPassPerIter
    % propagate along four directions
    for iDirect = 1:4
        [NNF, n] = sc_propagate(trgPatch, img, NNF, modelPlane, optS, iDirect);
        nUpdate(1) = nUpdate(1) + n;
    end

    % Random sampling
    %     [NNF, n] = sc_regular_search(trgPatch, img, NNF, modelPlane, modelReg, optS);
    %     nUpdate(3) = nUpdate(3) + n;

    % Regularity guided sampling
    [NNF, n] = sc_random_search(trgPatch, img, NNF, modelPlane, optS);
    nUpdate(2) = nUpdate(2) + n;
end

end

% PatchMatch - propagate step
function [NNF, nUpdateTotal] = sc_propagate(trgPatch, img, NNF, modelPlane, optS, iDirect)

% SC_PROPAGATE: update the nearest neighbor field using propagation
% Input:
%   - trgPatch:     target patch
%   - img:          image at current level
%   - NNF:          current nearest neighbor field
%   - modelPlane:   planar structure model
%   - optS
%   - indDirection: propagation direction
% Output:
%   - NNF, nUpdateTotal

nUpdateTotal = 0;

% The positions of neighboring pixels
uvPixN = NNF.uvPixN{iDirect};
uvPixActiveInd = uvPixN.validInd;

numUpdatePix = NNF.uvPix.numPix;
while(numUpdatePix ~= 0)
    % Prepare uvPix, uvPixNCur
    uvPix.sub     = NNF.uvPix.sub(uvPixActiveInd, :);  uvPix.ind     = NNF.uvPix.ind(uvPixActiveInd, :);
    uvPixNCur.sub = uvPixN.sub(uvPixActiveInd, :);     uvPixNCur.ind = uvPixN.ind(uvPixActiveInd, :);

    uvDtBdPixPosCur = NNF.uvDtBdPixPos(uvPixActiveInd);

    trgPatchCur   = trgPatch(:,:, uvPixActiveInd);
    srcPosCur     = NNF.uvTform.data(uvPixActiveInd, 7:8);
    uvCostCur     = NNF.uvCost.data(uvPixActiveInd);
    uvPlaneIDCur  = NNF.uvPlaneID.data(uvPixActiveInd);

    % Get srcPosMap for computing coherence cost
    srcPosMapCur  = NNF.uvTform.map(:,:,7:8);

    % Active pixel positions
    uvPixActivePos = find(uvPixActiveInd);

    % Get candidate uvTform candidates
    uvTformCand = sc_uvMat_from_uvMap(NNF.uvTform.map, uvPixNCur.ind);

    % Generate candidate transformation by propagation
    uvTformCand = sc_trans_tform(uvTformCand, optS.propDir(iDirect,:));

    % Check if the nearest neighbors are valid source patches
    uvValidSrcInd = sc_check_valid_uv(uvTformCand(:,7:8), NNF.validPix.mask);

    % Check if the nearest neighbors are already the same as the existing one
    diff = abs(uvTformCand(:,7:8) - srcPosCur);
    uvValidDistInd = ((diff(:,1) > 1 ) | (diff(:,2) > 1 ));

    % Valid pixel indices
    uvValidInd = uvValidSrcInd & uvValidDistInd;

    numUvValid = sum(uvValidInd);

    if(numUvValid ~= 0)
        uvPixValid.sub = uvPix.sub(uvValidInd,:);
        uvPixValid.ind = uvPix.ind(uvValidInd);

        uvDtBdPixPosCur = uvDtBdPixPosCur(uvValidInd);

        trgPatchCur    = trgPatchCur(:,:, uvValidInd);
        uvTformCand    = uvTformCand(uvValidInd, :);
        uvCostCur      = uvCostCur(uvValidInd);
        uvPlaneIDCand  = uvPlaneIDCur(uvValidInd);

        uvPixUpdatePos = uvPixActivePos(uvValidInd);

        % Grab source patches
        srcPatch = sc_prep_source_patch(img, uvTformCand, optS);

        % Compute patch matching cost
        [costPatchCandAll, uvBiasCand] = ...
            sc_patch_cost(trgPatchCur, srcPatch, modelPlane, uvPlaneIDCand, ...
            uvPixValid.sub, uvTformCand, srcPosMapCur, uvDtBdPixPosCur, optS);
        costPatchCand = sum(costPatchCandAll, 2);

        % Check which one to update
        updateInd = costPatchCand < uvCostCur;

        uvPixUpdatePos = uvPixUpdatePos(updateInd);
        numUpdatePix = size(uvPixUpdatePos, 1);
    else
        numUpdatePix = 0;
    end

    % Update NNF data
    if(numUpdatePix ~= 0)
        nUpdateTotal = nUpdateTotal + numUpdatePix;

        % === Update NNF data ===
        NNF.uvTform.data(uvPixUpdatePos, :) = uvTformCand(updateInd,:);
        NNF.uvCost.data(uvPixUpdatePos)     = costPatchCand(updateInd);
        NNF.uvPlaneID.data(uvPixUpdatePos)  = uvPlaneIDCand(updateInd);

        % Apply bias correction
        if(optS.useBiasCorrection)
            NNF.uvBias.data(:,:,uvPixUpdatePos)   = uvBiasCand(:,:,updateInd);
        end
        %         NNF.update.data(uvPixUpdatePos)   = 1; % updateInd;

        % === Update NNF map ===
        uvPixValidInd = uvPixValid.ind(updateInd);
        NNF.uvTform.map    = sc_update_uvMap(NNF.uvTform.map, uvTformCand(updateInd,:), uvPixValidInd);
        NNF.uvCost.map     = sc_update_uvMap(NNF.uvCost.map, costPatchCand(updateInd), uvPixValidInd);
        NNF.uvPlaneID.map  = sc_update_uvMap(NNF.uvPlaneID.map, uvPlaneIDCand(updateInd), uvPixValidInd);

        %         NNF.update.map  = sc_update_uvMap(NNF.update.map, 1, uvPixValidInd);

        % === Update uvPixActiveInd ===
        uvPixNextSub = uvPixValid.sub(updateInd,:);
        uvPixNextSub = bsxfun(@plus, uvPixNextSub, optS.propDir(iDirect,:));
        uvPixNextInd = sub2ind([NNF.imgH, NNF.imgW], uvPixNextSub(:,2), uvPixNextSub(:,1));

        updateMap = NNF.uvPix.mask;
        updateMap(uvPixNextInd) = 0;
        uvPixActiveInd = ~updateMap(NNF.uvPix.ind);
        uvPixActiveInd = uvPixActiveInd & uvPixN.validInd;
    end
end

end

% PatchMatch - random search step
function [NNF, nUpdateTotal] = sc_random_search(trgPatch, img, NNF, modelPlane, optS)

% SC_RANDOM_SEARCH: update the nearest neighbor using random sampling

[imgH, imgW, nCh] = size(img);

uvPix    = NNF.uvPix;
numUvPix = size(uvPix.sub, 1);

searchRad = max(imgH, imgW)/2;
nUpdateTotal = 0;

% uvPixActiveInd = true(numUvPix, 1);
iter = 1;
% while(iter <= optS.numRandSample)
while(searchRad > 1)
    iter = iter + 1;
    % Reduce search radius by half
    searchRad = searchRad/2;
    if(searchRad < 1)
        break;
    end

    % Get srcPosMap for computing coherence cost
    srcPosMapCur  = NNF.uvTform.map(:,:,7:8);

    uvTformCandCur = sc_uvMat_from_uvMap(NNF.uvTform.map, uvPix.ind);

    % Draw random samples
    srcPos = uvTformCandCur(:,7:8) + 2*searchRad*(rand(numUvPix, 2) - 0.5);

    % Draw plane ID candidate
    uvPlaneIDCand = sc_draw_plane_id(NNF.uvPlaneID.planeProbAcc);

    % Estimate the domain transformation
    uvTformCand = sc_src_domain_tform(uvPlaneIDCand, modelPlane, [], srcPos, NNF.uvPix.sub, 1);

    % === Reject invalid samples ===
    % Check if the scale of the source patch valid
    uvTformScale    = sc_scale_tform(uvTformCand);
    uvValidScaleInd = (uvTformScale > optS.minScale) & (uvTformScale < optS.maxScale);
    % Check if the souce patch is valid
    uvValidSrcInd   = sc_check_valid_uv(uvTformCand(:,7:8), NNF.validPix.mask);

    uvValidInd = uvValidSrcInd & uvValidScaleInd;

    % Active pixels
    uvPixActivePos = find(uvValidInd);
    numActPix = size(uvPixActivePos, 1);

    if(numActPix~=0)
        % Update
        trgPatchCur      = trgPatch(:,:,uvValidInd);
        uvCostDataCur    = NNF.uvCost.data(uvValidInd);
        uvTformCandCur   = uvTformCand(uvValidInd, :);
        uvPlaneIDCandCur = uvPlaneIDCand(uvValidInd);

        uvPixValid.sub   = uvPix.sub(uvValidInd,:);
        uvPixValid.ind   = uvPix.ind(uvValidInd);

        uvDtBdPixPosCur = NNF.uvDtBdPixPos(uvValidInd);

        % Grab source patches
        srcPatch = sc_prep_source_patch(img, uvTformCandCur, optS);

        [costPatchCandAll, uvBiasCand] = ...
            sc_patch_cost(trgPatchCur, srcPatch, modelPlane, uvPlaneIDCandCur, ...
            uvPixValid.sub, uvTformCandCur, srcPosMapCur, uvDtBdPixPosCur, optS);
        costPatchCand = sum(costPatchCandAll, 2);
        % Check which one to update
        updateInd = (costPatchCand < uvCostDataCur);
        nUpdate = sum(updateInd);

        if(nUpdate~=0)
            uvPixActivePos = uvPixActivePos(updateInd);

            nUpdateTotal = nUpdateTotal + nUpdate;

            % === Update NNF data ===
            NNF.uvTform.data(uvPixActivePos, :) = uvTformCandCur(updateInd,:);
            NNF.uvPlaneID.data(uvPixActivePos)  = uvPlaneIDCandCur(updateInd);
            NNF.uvCost.data(uvPixActivePos)     = costPatchCand(updateInd);
            if(optS.useBiasCorrection)
                NNF.uvBias.data(:,:,uvPixActivePos)   = uvBiasCand(:,:,updateInd);
            end

            % === Update NNF map ===
            uvPixValidInd     = uvPixValid.ind(updateInd);
            NNF.uvTform.map   = sc_update_uvMap(NNF.uvTform.map, uvTformCandCur(updateInd,:), uvPixValidInd);
            NNF.uvPlaneID.map = sc_update_uvMap(NNF.uvPlaneID.map, uvPlaneIDCandCur(updateInd), uvPixValidInd);
            NNF.uvCost.map    = sc_update_uvMap(NNF.uvCost.map, costPatchCand(updateInd), uvPixValidInd);
        end
    end
end
end


%  mcmc object makes diagnostic plots from mcmc draws
%
%
%    Reference page in Doc Center
%       doc mcmc
%
%


function addAnnotationTracks(infile)

Q = load(infile);
Q.trx(2) = Q.trx(1);
Q.trx(3) = Q.trx(1);
Q.trx(1).x(:) = Q.trx(1).arena.food(1);
Q.trx(1).y(:) = Q.trx(1).arena.food(2);
Q.trx(2).x(:) = Q.trx(1).arena.mouth(1);
Q.trx(2).y(:) = Q.trx(1).arena.mouth(2);
Q.trx(3).x(:) = Q.trx(1).arena.perch(1);
Q.trx(3).y(:) = Q.trx(1).arena.perch(2);

save(infile,'-struct','Q');


function [ODS,OIS,AP] = stEvalBsds( model, varargin )
% Evaluate sketch token edge detector on BSDS500.
%
% USAGE
%  [ODS,OIS,AP] = stEvalBsds( model, parameters )
%
% INPUTS
%  model      - sketch token model or model filename
%  parameters - parameters (struct or name/value pairs)
%   .dataType   - ['test'] should be either 'test' or 'val'
%   .nThresh    - [99] number of thresholds for evaluation
%   .cleanup    - [0] if true delete temporary files
%   .show       - [0] figure for displaying results (or 0)
%   .modelDir   - [] directory for storing models
%   .bsdsDir    - [] directory of BSDS dataset
%   .name       - [''] name to append to evaluation
%   .pDistr     - [{'type','parfor'}] parameters for fevalDistr
%
% OUTPUTS
%  ODS        - standard error measure on BSDS500
%  OIS        - standard error measure on BSDS500
%  AP         - standard error measure on BSDS500
%
% EXAMPLE
%
% See also stDetect, stTrain
%
% Sketch Token Toolbox     V0.95
% Copyright 2013 Joseph Lim [lim@csail.mit.edu]
% Please email me if you find bugs, or have suggestions or questions!
% Licensed under the Simplified BSD License [see bsd.txt]

    % get default parameters
    dfs={'dataType','test', 'nThresh',99, 'cleanup',0, 'show',0, ...
      'modelDir',[], 'bsdsDir',[], 'name','', 'pDistr',{{'type','parfor'}} };
    p=getPrmDflt(varargin,dfs,1);
    if( ischar(model) ),
        model=load(model);
        model=model.model;
    end
    if( isempty(p.modelDir )),
        p.modelDir=model.opts.modelDir;
    end
    if( isempty(p.bsdsDir )),
        p.bsdsDir=model.opts.bsdsDir;
    end
    p.modelDir = [p.modelDir '/' p.dataType '/'];

    % eval on either validation set or test set
    imgDir = [p.bsdsDir '/images/' p.dataType '/'];
    gtDir = [p.bsdsDir '/groundTruth/' p.dataType '/'];
    evalDir = [p.modelDir model.opts.modelFnm p.name '-eval/'];
    resDir = [p.modelDir model.opts.modelFnm p.name '/'];
    assert(exist(imgDir,'dir')==7);
    assert(exist(gtDir,'dir')==7);

    % if evaluation exists collect results and display
    if(exist([evalDir '/eval_bdry.txt'],'file'))
        [ODS,~,~,~,OIS,~,~,AP]=collect_eval_bdry(evalDir);
        fprintf('ODS=%.3f OIS=%.3f AP=%.3f\n',ODS,OIS,AP);
        if( p.show ),
            plot_eval(evalDir,'r');
        end;
        return;
    end

    % get image ids
    ids=dir([imgDir '*.jpg']);
    ids={ids.name};
    n=length(ids);
    for i=1:n,
        ids{i}=ids{i}(1:end-4);
    end

    % extract sketch tokens and save results
    if(~exist(resDir,'dir')),
        mkdir(resDir);
    end;
    do=false(1,n);

    for i=1:n,
        do(i)=~exist([resDir ids{i} '.png'],'file');
    end
    do=find(do);
    m=length(do);
    parfor i=1:m,
        id=ids{do(i)}; %#ok<PFBNS>

        I = imread([imgDir id '.jpg']);
        st = max(min(1,stDetect(I,model)),0);
        E = stToEdges(st,1);

        imwrite(uint8(E*255),[resDir id '.png']);
    end

    % perform evaluation on each image (Linux only, slow)
    if(ispc),
        error('Evaluation code runs on Linux ONLY.');
    end
    do=false(1,n);
    jobs=cell(1,n);
    for i=1:n,
        do(i)=~exist([evalDir ids{i} '_ev1.txt'],'file');
    end
    for i=1:n,
        id=ids{i};
        jobs{i}={[resDir id '.png'],...
        [gtDir id '.mat'],[evalDir id '_ev1.txt'],p.nThresh};
    end
    if(~exist(evalDir,'dir')),
        mkdir(evalDir);
    end
    fevalDistr('evaluation_bdry_image',jobs(do),p.pDistr{:});

    % collect results and display
    [ODS,~,~,~,OIS,~,~,AP]=collect_eval_bdry(evalDir);
    fprintf('ODS=%.3f OIS=%.3f AP=%.3f\n',ODS,OIS,AP);
    if( p.show ),
        plot_eval(evalDir,'r');
    end
    if( p.cleanup ),
        delete([evalDir '/*_ev1.txt']);
        delete([evalDir '/eval_bdry_img.txt']);
        delete([evalDir '/eval_bdry_thr.txt']);
        delete([resDir '/*.png']); rmdir(resDir);
    end

end


function [structureInitS,tags] = dicomrt_d2c_voi(structureInitS,indexS,voi,xmesh,ymesh,zmesh,tags,scanUID)
% dicomrt_d2c_voi(structureInitS,indexS,voi,ct_zmesh)
%
% Convert DICOM VOI in CERR format
%
% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org)

% Check input data
[study,type,dummylabel]=dicomrt_checkinput(voi);

if strcmpi('VOI',type)~=1
    error('dicomrt_d2c_voi: input data does not have the right format. Exit now!');
else
    type='STRUCTURE';
end

% Accounting for different coordinate system between DICOM and RTOG
[study,xmesh,ymesh,zmesh,tags]=dicomrt_d2c_coordsystem(study,xmesh,ymesh,zmesh,tags);

% Get DICOM-RT toolbox dataset info
study_pointer=study{1,1};
study_array=study{2,1};

% Set parameters
n = indexS.scan;

% Scan info
for i=1:size(study_array,1); % loop through the number of VOIs
    % Fill structureInitS
    structureInitS(i).imageNumber            = tags.nimages + i;
    structureInitS(i).imageType              = type;
    structureInitS(i).caseNumber             = 1;                                         % LEAVE FOR NOW
    structureInitS(i).patientName            = [study_pointer.PatientName.FamilyName];
    try
        structureInitS(i).patientName        = [structureInitS(i).patientName,' ', ...
            study_pointer.PatientName.GivenName]; % may be not present in anonymized studies
    end
    structureInitS(i).structureName          = study_array{i,1};
    structureInitS(i).numberRepresentation   = 'CHARACTER';
    structureInitS(i).structureFormat        = 'SCAN-BASED';
    structureInitS(i).numberOfScans          = tags.nimages;
    structureInitS(i).transferProtocol       = 'DICOM';
    structureInitS(i).DICOMHeaders           = study_pointer;
    % Optional
    structureInitS(i).maximumNumberScans     = '';
    structureInitS(i).structureEdition       = '';
    structureInitS(i).unitNumber             = '';
    structureInitS(i).writer                 = '';
    structureInitS(i).dateWritten            = '';
    structureInitS(i).structureColor         = '';
    structureInitS(i).structureDescription   = '';
    structureInitS(i).studyNumberOfOrigin    = '';
    % build vector containing Z location of VOIs
    [voizdef,index] = dicomrt_getvoiz(study,i);
    for j=1:tags.nimages % loop through CT scans
        % locate position of VOI segment
        locate_voi=find(voizdef==zmesh(j));
        if isempty(locate_voi)==1
            structureInitS(i).contour(length(zmesh)-j+1).segments.points=[];
        else
            for jj=1:length(locate_voi)
                if ~isempty(study_array{i,2})% check for empty structures
                    structureInitS(i).contour(length(zmesh)-j+1).segments(jj).points=study_array{i,2}{index(locate_voi(jj))};
                else
                    structureInitS(i).contour(length(zmesh)-j+1).segments(jj).points=[];
                end
            end
        end
    end
    clear voizdef;
    structureInitS(i).rasterSegments         = '';
    structureInitS(i).DSHPoints              = '';
    structureInitS(i).orientationOfStructure = '';

    %DK
    structureInitS(i).strUID = createUID('STRUCTURE');
    if exist('scanUID')
        structureInitS(i).assocScanUID = scanUID;
    else
        structureInitS(i).assocScanUID = '';
    end
    %end DK
end

% Update nimages
tags.nimages = tags.nimages + size(study_array,1); % number of CT images


function ecgpuwave(varargin)
%
% ecgpuwave(recordName,annFileName,startTime,stopTime,qrsAnn,pflag,signalList)
%
%    Wrapper to the ECGPUWAVE binary written by Pablo Laguna (laguna@posta.unizar.es), Raimon Jan[�e], Eudald Bogatell, and David Vigo Anglada:
%         http://www.physionet.org/physiotools/wag/ecgpuw-1.htm
%
% ECGPUWAVE analyses an ECG signal from the specified record 'recordName', detecting the QRS complexes
% and locating the beginning, peak, and end of the P, QRS, and ST-T waveforms. The output of ecgpuwave
% is written as a standard WFDB-format annotation file associated
% with the specified annotator 'outputAnnFileName'.
%
% The QRS detector is based on the algorithm of Pan and Tompkins (reference 1) with some improvements that
% make use of slope information (reference 2). Optionally, QRS annotations can be provided as input (see option 'qrsAnn'),
% permitting the use of external QRS detectors such as sqrs(1) or manually-edited annotations
% (which can be created using wave(1) ). The waveform limit locator is based on the algorithm
% described in reference 3 and evaluated in references 3 and 4.
%
% The output annotation file contains PWAVE ("p") and TWAVE ("t") annotations
% that indicate the P- and T-wave peaks, as well as QRS annotations (NORMAL ("N") if generated
% by the built-in QRS detector, or copies of the input QRS annotations if these were supplied).
% ECGPUWAVE classifies each T wave as type 0 (normal), 1 (inverted), 2 (positive monophasic),
% 3 (negative monophasic), 4 (biphasic negative-positive), or 5 (biphasic positive-negative);
% this numeric classification is written into the num field of each TWAVE annotation.
% The P, QRS, and T waveform onsets and ends are marked in the output annotation file using
% WFON ("(") and WFOFF (")") annotations. The num field of each WFON and WFOFF annotation designates
% the type of waveform with which it is associated: 0 for a P wave, 1 for a QRS complex, or 2 for a T wave.
%
% WARNING:
%   If ECGPUWAVE is used without providing an annotator file for the R peaks it relies on a Pan-Tompkins detector.
%   This detector may not be optimized for your particular signal, and thus may need to be tuned, yielding anempty annotation
%   file. In this case, you may want to first run a QRS detector to generate an appropriate QRS annotation file,
%   which you can then check manually prior to calling ECGPUWAVE with the
%   'qrsAnn' option described below.
%
% IMPORTANT NOTE:
%     A patch to the original Fortran source files was provided by Roberto Sassi in
%     order to compile ECGPUWAVE in 64-bit arch. This patch requires
%     compiling the source code with gfortran (g77 is not supported in gcc 4.x), which can
%     yield slighly different results. For more information please see:
%           http://www.dti.unimi.it/~sassi/software/wfdb64HowTo.htm
%
%
%
% References:
%1. Pan J and Tompkins WJ. A Real-Time QRS Detection Algorithm. IEEE Transactions on Biomedical Engineering 32(3):230-236, 1985.
%2. Laguna P. New Electrocardiographic Signal Processing Techniques: Application to Long-term Records. Ph. D. dissertation, Science Faculty, University of Zaragoza, 1990.
%3. Laguna P, Jan[�e] R, Caminal P. Automatic Detection of Wave Boundaries in Multilead ECG Signals: Validation with the CSE Database. Computers and Biomedical Research 27(1):45-60, 1994.
%4. Jan[�e] R, Blasi A, Garc[�i]a J, and Laguna P. Evaluation of an automatic threshold based detector of waveform limits in Holter ECG with the QT database. Computers in Cardiology 24:295-298 (1997; available at http://www.physionet.org/physiobank/database/qtdb/eval/ )
%
% Required Parameters:
%
% recordName
%       String specifying the name of the record to annotate with ECGPUWAVE.
%
% annFileName
%       String specifying the output file name that ECPUWAVE will store its
%       output.
%
% ecgpuwave(recordName,outputAnnFileName,startTime,stopTime,qrsAnn,pflag,signalList)
%
% Optional Parameters are:
%
% startTime
%      Either WFDB Time String or 1x1 integer specifying the sample number
%      specifying the starting location.
%
% stopTime
%      Either WFDB Time String or 1x1 integer specifying the sample number
%      specifying the ending location.
%
% qrsAnn
%       A String represengint the QRS annotation file that ECGPUWAVE should
%       use (must be in the WFDP PATH or within the current directory).
%
% pflag
%      A boolean (default = 0), if true all beats are processed, if false,
%      only normal beats are used.
%
% signalList
%     A Nx1 vector of integers specifying which signals in 'recordName' are
%     to be analyzed (default = [0].
%
% Wrapper written by Ikaro Silva, 2013
% Last Modified: May 29 , 2014
% Version 0.0.1
%
%
% %Example - Will go into the WFDB directory of examples to load data
%curdir=pwd;
%[~,config]=wfdbloadlib;eval(['cd ' config.WFDB_JAVA_HOME filesep 'example'])
%ecgpuwave('100s','test');
%[signal,Fs,tm]=rdsamp('100s');
%pwaves=rdann('100s','test',[],[],[],'p');
%plot(tm,signal(:,1));hold on;grid on
%plot(tm(pwaves),signal(pwaves),'or')
%cd(curdir) %CD back to current directory
%
%
% Since 0.9.5
%
%
% See also WFDBDESC, PHYSIONETDB, RDANN, WRANN, SQRS, WQRS, WFDBEXEC

%endOfHelp

javaWfdbExec=getWfdbClass('ecgpuwave');

%Set default pararamter values
inputs={'recordName','annFileName','startTime','stopTime','qrsAnn','pflag','signalList'};
startTime=[];
stopTime=[];
qrsAnn=[];
pflag=[];
signalList=[];
for n=1:nargin
    if(~isempty(varargin{n}))
        eval([inputs{n} '=varargin{n};']);
    end
end

wfdb_argument={'-r',recordName,'-a',annFileName};

if(~isempty(startTime))
    wfdb_argument{end+1}='-f';
    wfdb_argument{end+1}=num2str(startTime-1);
end
if(~isempty(stopTime))
    wfdb_argument{end+1}='-t';
    wfdb_argument{end+1}=num2str(stopTime-1);
end

if(~isempty(signalList))
    wfdb_argument{end+1}='-s ';
    %-1 is necessary because WFDB is 0 based indexed.
    for sInd=1:length(signalList)
        wfdb_argument{end+1}=[num2str(signalList(sInd)-1)];
    end
end

if(~isempty(qrsAnn))
    wfdb_argument{end+1}='-i';
    wfdb_argument{end+1}=qrsAnn;
    if(~isempty(pflag))
        wfdb_argument{end+1}='-n';
        wfdb_argument{end+1}=[num2str(pflag)];
    end
end

javaWfdbExec.execToStringList(wfdb_argument);


% EEG_COUNTEPOCHS Count how many epochs there are of each type
%
% Usage:
%  >> eeg_countepochs(EEG);
%
% Inputs:
%   EEG            - input dataset
%   epochmarker    - ['type'|'eventtype'] indicates which part of the
%   EEG.epoch structure the different trial types are stored in. Depending
%   on what system the data are from and how they were preprocessed, this
%   may be either EEG.epoch.type or EEG.epoch.eventtype. Defaults to
%   'type'.
%
%  Outputs:
%    sweeps          - Scalar structure showing, for each epoch type
%    (sweeps.types) the number of sweeps in the dataset with that type
%    (sweeps.counts)
%
% Example:
% eeg_countepochs( EEG, 'type' )
% eeg_countepochs( EEG, 'eventtype' )
%
% Author: Stephen Politzer-Ahles, University of Kansas, 2013

% Copyright: Stephen Politzer-Ahles, University of Kansas, 2013
%
% 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 [sweeps] = eeg_countepochs(EEG, epochmarker);

if nargin < 1
	help eeg_countepochs;
	return;
end

% Initialize an array which will keep counts
clearvars types counts
types{1} = '';
counts = [0];

% Iterate through all trials
for trial=1:length(EEG.epoch)

    % Default 'epochmarker' to 'type' if no input was provided.
    if nargin < 2
        epochmarker = 'type';
    end

    % Look for epochs that have >1 event and find which event is epoched around
    eventindex = 1; % if only 1 event, eventindex=1
    if length(EEG.epoch(trial).eventlatency) > 1
        for eventnum = 1:length(EEG.epoch(trial).eventlatency)
            if EEG.epoch(trial).eventlatency{eventnum}==0
                eventindex = eventnum;
            end % end if
        end % end for
    end % end if

	% Get the trigger number for this trial
    if strcmp(epochmarker,'eventtype')

        % change event type from cell/number event to string
        if iscell(EEG.epoch(trial).eventtype(eventindex))
            type = EEG.epoch(trial).eventtype{eventindex};
        elseif isnumeric(EEG.epoch(trial).eventtype(eventindex))
            type = num2str( EEG.epoch(trial).eventtype(eventindex) );
        else % is char
            type = EEG.epoch(trial).eventtype;
        end
    elseif strcmp(epochmarker,'type')

        % change cell/number event to string
        if iscell(EEG.epoch(trial).type(eventindex))
            type = EEG.epoch(trial).type{eventindex};
        elseif isnumeric(EEG.epoch(trial).type(eventindex))
            type = num2str( EEG.epoch(trial).type(eventindex) );
        else % is char
            type = EEG.epoch(trial).type;
        end
    end; % end if

	% Find the row of the array that corresponds to this trigger (or if this trigger has not been counted yet)
	index_of_type = find( cellfun(@(x) strcmp(x,type), types) );

	% If this trial has a trigger that has already been counted before,
	% 'row_of_type' will be a number. If not, it will be an empty
	% array.
	if index_of_type

		% If we already have a count for this trigger, increment that count by 1
		counts(index_of_type) = counts(index_of_type) + 1;
	else

		% If not, create a new count for this type
		types = [types type];
        counts(end+1) = 1;
	end; % end if

end; % end for

% Remove the unnecessary first item
types = types(2:end);
counts = counts(2:end);

% Sorts
[Y,I] = sort( types );

% Add types and sweeps to a scalar structure
sweeps.types = types(I);
sweeps.counts = counts(I);

end


function figure2dot(filename, varargin)
%FIGURE2DOT    Save figure in Graphviz (.dot) file.
%  FIGURE2DOT(filename) saves the current figure as dot-file.
%
%  FIGURE2DOT(filename, 'object', HGOBJECT) constructs the graph representation
%  of the specified object (default: gcf)
%
%  You can visualize the constructed DOT file using:
%    - [GraphViz](http://www.graphviz.org) on your computer
%    - [WebGraphViz](http://www.webgraphviz.com) online
%    - [Gravizo](http://www.gravizo.com) for your markdown files
%    - and a lot of other software such as OmniGraffle
%
%  See also: matlab2tikz, cleanfigure, uiinspect, inspect

    ipp = m2tInputParser();
    ipp = ipp.addRequired(ipp, 'filename', @ischar);
    ipp = ipp.addParamValue(ipp, 'object', gcf, @ishghandle);
    ipp = ipp.parse(ipp, filename, varargin{:});
    args = ipp.Results;

    filehandle = fopen(args.filename, 'w');
    finally_fclose_filehandle = onCleanup(@() fclose(filehandle));

    % start printing
    fprintf(filehandle, 'digraph simple_hierarchy {\n\n');
    fprintf(filehandle, 'node[shape=box];\n\n');

    % define the root node
    node_number = 0;
    p = get(args.object, 'Parent');
    % define root element
    type = get(p, 'Type');
    fprintf(filehandle, 'N%d [label="%s"]\n\n', node_number, type);

    % start recursion
    plot_children(filehandle, p, node_number);

    % finish off
    fprintf(filehandle, '}');

    % ----------------------------------------------------------------------------
    function plot_children(fh, h, parent_node)

        children = allchild(h);

        for h = children(:)'
            if shouldSkip(h), continue, end;
            node_number = node_number + 1;

            label = {};
            label = addHGProperty(label, h, 'Type', '');
            try
                hClass = class(handle(h));
                label = addProperty(label, 'Class', hClass);
            catch
                % don't do anything
            end
            label = addProperty(label, 'Handle', sprintf('%g', double(h)));
            label = addHGProperty(label, h, 'Title', '');
            label = addHGProperty(label, h, 'Axes', []);
            label = addHGProperty(label, h, 'String', '');
            label = addHGProperty(label, h, 'Tag', '');
            label = addHGProperty(label, h, 'DisplayName', '');
            label = addHGProperty(label, h, 'Visible', 'on');
            label = addHGProperty(label, h, 'HandleVisibility', 'on');

            % print node
            fprintf(fh, 'N%d [label="%s"]\n', ...
                    node_number, m2tstrjoin(label, '\n'));

            % connect to the child
            fprintf(fh, 'N%d -> N%d;\n\n', parent_node, node_number);

            % recurse
            plot_children(fh, h, node_number);
        end
    end
end
% ==============================================================================
function bool = shouldSkip(h)
    %  returns TRUE for objects that can be skipped
    objType = get(h, 'Type');
    bool = ismember(lower(objType), guitypes());
end
% ==============================================================================
function label = addHGProperty(label, h, propName, default)
    % get a HG property and assign it to a GraphViz node label
    if ~exist('default','var') || isempty(default)
        shouldOmit = @isempty;
    elseif isa(default, 'function_handle')
        shouldOmit = default;
    else
        shouldOmit = @(v) isequal(v,default);
    end

    if isprop(h, propName)
        propValue = get(h, propName);
        if numel(propValue) == 1 && ishghandle(propValue) && isprop(propValue, 'String')
            % dereference Titles, labels, ...
            propValue = get(propValue, 'String');
        elseif ishghandle(propValue)
            % dereference other HG objects to their raw handle value (double)
            propValue = double(propValue);
        elseif iscell(propValue)
            propValue = ['{' m2tstrjoin(propValue,',') '}'];
        end

        if ~shouldOmit(propValue)
            label = addProperty(label, propName, propValue);
        end
    end
end
function label = addProperty(label, propName, propValue)
    % add a property to a GraphViz node label
    if isnumeric(propValue)
        propValue = num2str(propValue);
    elseif iscell(propValue)
        propValue = m2tstrjoin(propValue,sprintf('\n'));
    end
    label = [label, sprintf('%s: %s', propName, propValue)];
end
% ==============================================================================


function [imdbs, roidbs] = subsample_images(imdbs, roidbs, max_num_neg_images, seed)

if ~exist('seed', 'var')
  seed = 6;
end

% class_num = cellfun(@(x) length(x.class_ids), imdbs, 'UniformOutput', true);
% assert(length(unique(class_num)) == 1);
% class_num = unique(class_num);

rois = cellfun(@(x) x.rois(:), roidbs, 'UniformOutput', false);
rois_combine = cell2mat(rois(:));

% fix the random seed for repeatability
prev_rng = seed_rand(seed);
inds = randperm(length(rois_combine), max_num_neg_images);
inds = sort(inds);

img_idx_start = 1;
for i = 1:length(imdbs)
    imdb_img_num = length(imdbs{i}.image_ids);
    img_idx_end = img_idx_start + imdb_img_num - 1;
    inds_start = find(inds >= img_idx_start, 1, 'first');
    inds_end = find(inds <= img_idx_end, 1, 'last');

    inds_sub = inds(inds_start:inds_end);
    inds_sub = inds_sub - img_idx_start + 1;

    imdbs{i}.image_ids = imdbs{i}.image_ids(inds_sub);
    imdbs{i}.sizes = imdbs{i}.sizes(inds_sub, :);
    if isfield(imdbs{i}, 'image_dir')
        imdbs{i}.image_at = @(x) ...
            sprintf('%s/%s.%s', imdbs{i}.image_dir, imdbs{i}.image_ids{x}, imdbs{i}.extension);
    else
       imdbs{i}.image_at = @(x) ...
            sprintf('%s/%s.%s', imdbs{i}.imagedir, imdbs{i}.image_ids{x}, imdbs{i}.extension);
    end
    roidbs{i}.rois = roidbs{i}.rois(inds_sub);

    img_idx_start = img_idx_start + imdb_img_num;
end

% restore previous rng
rng(prev_rng);

end


function id = initmumps()
%
% id = initmumps
% it returns a default matlab MUMPS structure
%
% Use help mumps_help for detailed information
%
errmsg = nargoutchk(1,1,nargout);
if(~isempty(errmsg))
     disp(errmsg);
     return;
end
id = struct('SYM',0,'JOB',-1,'ICNTL',zeros(1,40)-9998,'CNTL',zeros(1,15)-9998,'PERM_IN',-9999,'COLSCA',-9999,'ROWSCA',-9999,'RHS',-9999,'INFOG',zeros(1,40)-9998,'RINFOG',zeros(1,40)-9998,'VAR_SCHUR',-9999,'SCHUR',-9999,'INST',-9999,'SOL',-9999,'REDRHS',-9999,'PIVNUL_LIST',-9999,'MAPPING',-9999,'SYM_PERM',-9999,'UNS_PERM',-9999,'TYPE',0);


function model = vargplvmAddDynamics(model, type, varargin)
% VARGPLVMADDDYNAMICS Add a dynamics structure to the model.
%
%	Description:
%
%	VARGPLVMADDDYNAMICS(MODEL, TYPE, ...) adds a dynamics structure to the
%	VARGPLVM.
%	 Arguments:
%	  MODEL - the model to add dynamics to.
%	  TYPE - the type of dynamics model to add in.
%	  ... - additional arguments to be passed on creation of the
%	   dynamics model.
%
% COPYRIGHT : Andreas C. Damianou, 2010-2011
% COPYRIGHT : Michalis K. Titsias, 2010-2011
% COPYRIGHT : Neil D. Lawrence, 2010-2011
%
%
%	See also
%	MODELCREATE
% VARGPLVM

type = [type 'Dynamics'];
model.dynamics = modelCreate(type, model.q, model.q, model.X, varargin{:}); % e.g. vargpTimeDynamicsCreate
params = vargplvmExtractParam(model);
model.dynamics.nParams = length(modelExtractParam(model.dynamics));
model.nParams = model.nParams + model.dynamics.nParams;
model = vargplvmExpandParam(model, params);

% This will be moved to "initDynamics"
%med = median(model.vardist.covars(:));
%if med < 0.3 || med > 0.7
%   warning('!!! Median value of variational covariances is %1.2f.\n', med);
%end


function info=hdr_read_header(filename)
% function for reading header of HDR/IMG Analyze ( .hdr ) volume file
%
% info = hdr_read_header(filename);
%
% examples:
% 1,  info=hdr_read_header()
% 2,  info=hdr_read_header('volume.hdr');

if(exist('filename','var')==0)
    [filename, pathname] = uigetfile('*.hdr', 'Read hdr-file');
    filename = [pathname filename];
end
if(exist('analyze75info','file')>0)
    info=analyze75info(filename);
else
    info=get_info_analyze_hdr(filename);
end

function info=get_info_analyze_hdr(filename)
% Strings for data type (compatible names with analyze75info)
strImgData{1}.ImgDataType = 'DT_UNKNOWN';
strImgData{1}.ColorType = 'unknown';
strImgData{2}.ImgDataType = 'DT_BINARY';
strImgData{2}.ColorType = 'grayscale';
strImgData{3}.ImgDataType = 'DT_UNSIGNED_CHAR';
strImgData{3}.ColorType = 'grayscale';
strImgData{5}.ImgDataType = 'DT_SIGNED_SHORT';
strImgData{5}.ColorType = 'grayscale';
strImgData{9}.ImgDataType = 'DT_SIGNED_INT';
strImgData{9}.ColorType = 'grayscale';
strImgData{17}.ImgDataType = 'DT_FLOAT';
strImgData{17}.ColorType = 'grayscale';
strImgData{33}.ImgDataType = 'DT_COMPLEX';
strImgData{33}.ColorType = 'grayscale';
strImgData{65}.ImgDataType = 'DT_DOUBLE';
strImgData{65}.ColorType = 'grayscale';
strImgData{129}.ImgDataType = 'DT_RGB';
strImgData{129}.ColorType = 'truecolor';
strImgData{256}.ImgDataType = 'DT_ALL';
strImgData{256}.ColorType = 'unknown';
strOriData{1} = 'Transverse unflipped';
strOriData{2} = 'Coronal unflipped';
strOriData{3} = 'Sagittal unflipped';
strOriData{4} = 'Transverse flipped';
strOriData{5} = 'Coronal flipped';
strOriData{6} = 'Sagittal flipped';
strOriData{7} = 'Orientation unavailable';

% Open the HDR-file, change MachineFormat if not the right
% header size
info.Filename=filename;
fid = fopen(filename,'rb','l'); fseek(fid,0,'bof');
info.ByteOrder='ieee-le';
info.HdrFileSize = fread(fid, 1,'int32');
if(info.HdrFileSize>2000);
    fclose(fid);
    fid = fopen(filename,'rb','b'); fseek(fid,0,'bof');
    info.ByteOrder='ieee-be';
    info.HdrFileSize = fread(fid, 1,'int32');
end

% Read the Whole Analyze Header
info.Format='Analyze';
info.HdrDataType = fread(fid,10,'char=>char')';
info.DatabaseName = fread(fid,18,'char=>char')';
info.Extents = fread(fid, 1,'int32');
info.SessionError = fread(fid, 1,'int16');
info.Regular = fread(fid, 1,'char=>char')';
unused= fread(fid, 1,'uint8')';
dim = fread(fid,8,'int16')';
if (dim(1) < 3), dim(1) = 4; end
info.Dimensions=dim(2:dim(1)+1);
info.Width=info.Dimensions(1);
info.Height=info.Dimensions(2);
info.VoxelUnits = fread(fid,4,'char=>char')';
info.CalibrationUnits = fread(fid,8,'char=>char')';
unused = fread(fid,1,'int16');
ImgDataType = fread(fid,1,'int16');
info.ImgDataType=strImgData{ImgDataType+1}.ImgDataType;
info.ColorType=strImgData{ImgDataType+1}.ColorType;
info.BitDepth = fread(fid,1,'int16');
unused = fread(fid,1,'int16');
PixelDimensions = fread(fid,8,'float')';
info.PixelDimensions=PixelDimensions(2:length(info.Dimensions)+1);
info.VoxelOffset = fread(fid,1,'float');
info.RoiScale = fread(fid,1,'float');
unused = fread(fid,1,'float');
unused = fread(fid,1,'float');
info.CalibrationMax = fread(fid,1,'float');
info.CalibrationMin = fread(fid,1,'float');
info.Compressed = fread(fid,1,'int32');
info.Verified = fread(fid,1,'int32');
info.GlobalMax = fread(fid,1,'int32');
info.GlobalMin = fread(fid,1,'int32');
info.Descriptor = fread(fid,80,'char=>char')';
info.AuxFile = fread(fid,24,'char=>char')';
Orientationt = fread(fid, 1,'uint8');
if((Orientationt>=48)&&(Orientationt<=53)), Orientationt = Orientationt -48; end
info.Orientationt=strOriData{min(Orientationt,5)+1};
info.Originator = fread(fid,10,'char=>char')';
info.Generated = fread(fid,10,'char=>char')';
info.Scannumber = fread(fid,10,'char=>char')';
info.PatientID = fread(fid,10,'char=>char')';
info.ExposureDate = fread(fid,10,'char=>char')';
info.ExposureTime = fread(fid,10,'char=>char')';
unused = fread(fid, 3,'char=>char')';
info.Views = fread(fid, 1,'int32');
info.VolumesAdded = fread(fid, 1,'int32');
info.StartField = fread(fid, 1,'int32');
info.FieldSkip = fread(fid, 1,'int32');
info.Omax = fread(fid, 1,'int32');
info.Omin = fread(fid, 1,'int32');
info.Smax = fread(fid, 1,'int32');
info.Smin = fread(fid, 1,'int32');
fclose(fid);

% Remove empty string parts from the info struct
names = fieldnames(info);
for i=1:length(names)
    value=info.(names{i});
    if(ischar(value))
        value(uint8(value)==0)=[];
        if(isempty(value)), info.(names{i})=''; else info.(names{i})=value; end
    end
end


function currentVal=getImageRotate(view)
%
% currentVal=getImageRotate(view)
%
% Returns the value of the image rotate slider in radians
if isequal(view.name, 'hidden')
	% instead of a handle to the slider, the ImageRotate field will
	% directly store the rotations for hidden views:
	currentVal = view.ui.ImageRotate;
else
	% non-hidden view: view.ui.ImageRotate should be a slider struct
	currentVal = get(view.ui.ImageRotate.sliderHandle, 'Value');
end

return


classdef TestExposureCompensator
    %TestExposureCompensator

    methods (Static)
        function test_1
            etypes = {'GainCompensator', 'BlocksGainCompensator'};
            for i=1:numel(etypes)
                obj = cv.ExposureCompensator(etypes{i});
                typename = obj.typeid();
                validateattributes(typename, {'char'}, {'row', 'nonempty'});

                %{
                %TODO
                obj.feed(corners, images, masks);
                img = obj.apply(index, corner, img, mask);
                if strcmp(etypes{i}, 'GainCompensator')
                    g = obj.gains();
                end
                %}
            end
        end
    end

end


function mtr = mtrSet(mtr,param,val,varargin)
% Set data for MetroTrac (mtr) structure
%
%  val = mtrSet(mtr,param,val,varargin)
%
% Set the parameters of a mtr structure.
% Access this structure should go through this routine and through
%    mtrGet.
%
%

if ieNotDefined('mtr'), error('No MetroTrac structure defined.'); end
if ieNotDefined('param'), error('No parameter defined'); end
if ieNotDefined('val'), val = []; end

switch lower(param)
    case {'name'}
        mtr.name = val;
    case {'type'}
        mtr.type = val;
    case {'tensors_filename'}
        mtr.tensors_filename = val;
    case {'fa_filename'}
        mtr.fa_filename = val;
    case {'pdf_filename'}
        mtr.pdf_filename = val;
    case {'mask_filename'}
        mtr.mask_filename = val;
    case {'xmask_filename'}
        mtr.Xmask_filename = val;
    case {'compute_fa'}
        mtr.compute_fa = val;
    case {'require_way'}
        mtr.require_way = val;
    case {'sampler_type'}
        mtr.sampler_type = val;
    case {'desired_samples'}
        mtr.desired_samples = val;
    case {'burnin'}
        mtr.burnin = val;
    case {'max_nodes'}
        mtr.max_nodes = val;
    case {'min_nodes'}
        mtr.min_nodes = val;
    case {'step_size'}
        mtr.step_size = val;
    case {'skip_samples'}
        mtr.skip_samples = val;
    case {'roi'}
        if length(varargin) ~= 2, error('Incomplete mtrSet'); end
        arg1 = varargin{1};
        arg2 = varargin{2};
        switch lower(arg2)
            case {'coords'}
                mtr.roi{arg1}.coords = val;
            case {'valid_cortex'}
                mtr.roi{arg1}.valid_cortex = val;
            case {'seed_region'}
                mtr.roi{arg1}.seed_region = val;
        end
    case {'translate'}
        mtr.translate = val;
    case {'isr'}
        mtr.isr = val;
    case {'esr'}
        mtr.esr = val;
    case {'temp_swap'}
        mtr.temp_swap = val;
    case {'inv_temp'}
        mtr.inv_temp = val;
    case {'start_path_tries'}
        mtr.start_path_tries = val;
    case {'save_out_spacing'}
        mtr.save_out_spacing = val;
    case {'fa_absorb'}
        mtr.fa_absorb = val;
    case {'abs_normal'}
        mtr.abs_normal = val;
    case {'abs_penalty'}
        mtr.abs_penalty = val;
    case {'smooth_std'}
        mtr.smooth_std = val;
    case {'angel_cutoff'}
        mtr.angle_cutoff = val;
    case {'shape_params_vec'}
        mtr.shape_params_vec = val;
end

return;


function S3G = delete(S3G,ind)
% clear nodes by indece
% Input
%  SOG    - @SO3Grid
%  indece - int32
%
% Output
%   SO3Grid - "not indexed"

% remove orientations
S3G.a(ind) = [];
S3G.b(ind) = [];
S3G.c(ind) = [];
S3G.d(ind) = [];
S3G.i(ind) = [];

S3G.gamma = subGrid(S3G.gamma,~ind);
S3G.alphabeta  = subGrid(S3G.alphabeta,GridLength(S3G.gamma)>0);
S3G.gamma(GridLength(S3G.gamma)==0) = [];


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   Demo file for StructBrowser
%
% H.Lahdili,(hassan.lahdili@crc.ca)
% Communications Research Centre (CRC) | Advanced Audio Systems (AAS)
% www.crc.ca | www.crc.ca/aas
% Ottawa. Canada
%
% 30/04/2003
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

load example
StructBrowser


function DEM = uplus(DEM)
DEM.Z = uplus(DEM.Z);


function img_patch = init_point_vis(img_patch, first_x, third_x, fourth_x, sixth_x, first_y, third_y, fourth_y, sixth_y, xmin, ymin)
    %%normalize 'em bitch
    first_x = max(first_x, xmin) - xmin;
    third_x = max(third_x, xmin) - xmin;
    fourth_x = max(fourth_x, xmin) - xmin;
    sixth_x = max(sixth_x, xmin) - xmin;
    first_y = max(first_y, ymin) - ymin;
    third_y = max(third_y, ymin) - ymin;
    fourth_y = max(fourth_y, ymin) - ymin;
    sixth_y = max(sixth_y, ymin) - ymin;
    img_patch = insertShape(img_patch, 'Circle', [first_x first_y 1], 'Color', 'red', 'LineWidth', 3);
    img_patch = insertShape(img_patch, 'Circle', [third_x third_y 1], 'Color', 'green', 'LineWidth', 3);
    img_patch = insertShape(img_patch, 'Circle', [fourth_x fourth_y 1], 'Color', 'blue', 'LineWidth', 3);
    img_patch = insertShape(img_patch, 'Circle', [sixth_x sixth_y 1], 'Color', 'yellow', 'LineWidth', 3);
end


function [success,message] = xlsappend(file,data,sheet)

% XLSAPPEND Stores numeric array or cell array to the end of specified Excel sheet.
%
%   REQUIRES ONLY ONE CALL TO THE EXCEL ACTXSERVER, so the overhead is less
%   than for successive xlsread/xlswrite calls.
%
%   [SUCCESS,MESSAGE]=XLSAPPEND(FILE,ARRAY,SHEET) writes ARRAY to the Excel
%   workbook, FILE, into the area beginning at COLUMN A and FIRST UNUSED
%   ROW, in the worksheet specified in SHEET.
%   FILE and ARRAY must be specified. If either FILE or ARRAY is empty, an
%   error is thrown and XLSAPPEND terminates. The first worksheet of the
%   workbook is the default. If SHEET does not exist, a new sheet is added at
%   the end of the worksheet collection. If SHEET is an index larger than the
%   number of worksheets, new sheets are appended until the number of worksheets
%   in the workbook equals SHEET. The success of the operation is
%   returned in SUCCESS and any accompanying message, in MESSAGE. On error,
%   MESSAGE shall be a struct, containing the error message and message ID.
%   See NOTE 1.
%
%   [SUCCESS,MESSAGE]=XLSAPPEND(FILE,ARRAY) writes ARRAY to the Excel
%   workbook, FILE, in the first worksheet.
%
%   [SUCCESS,MESSAGE]=XLSAPPEND(FILE,ARRAY) writes ARRAY to the Excel
%   workbook, FILE, starting at cell A[firstUnusedRow] of the first
%   worksheet. The return values are as for the above example.
%
%   XLSAPPEND ARRAY FILE, is the command line version of the above example.
%
%   INPUT PARAMETERS:
%       file:   string defining the workbook file to write to.
%               Default directory is pwd; default extension 'xls'.
%       array:  m x n numeric array or cell array.
%       sheet:  string defining worksheet name;
%               double, defining worksheet index.
%
%   RETURN PARAMETERS:
%       SUCCESS: logical scalar.
%       MESSAGE: struct containing message field and message_id field.
%
%   EXAMPLES:
%
%   SUCCESS = XLSAPPEND('c:\matlab\work\myworkbook.xls',A) will write A to
%   the sheet 1 of workbook file, myworkbook.xls. On success, SUCCESS will
%   contain true, while on failure, SUCCESS will contain false.
%
%   NOTE 1: The above functionality depends upon Excel as a COM server. In
%   absence of Excel, ARRAY shall be written as a text file in CSV format. In
%   this mode, the SHEET argument shall be ignored.
%
% See also XLSREAD, XLSWRITE.
%

% Written by Brett Shoelson, PhD, 8/30/2010.
% Copyright 1984-2010 The MathWorks, Inc.
%==============================================================================

% Set default values.
lastwarn('');
Sheet1 = 1;

if nargin < 3
    sheet = Sheet1;
end

if nargout > 0
    success = true;
    message = struct('message',{''},'identifier',{''});
end

% Handle input.
try
    % handle requested Excel workbook filename.
    if ~isempty(file)
        if ~ischar(file)
            error('MATLAB:xlswrite:InputClass','Filename must be a string.');
        end
        % check for wildcards in filename
        if any(findstr('*', file))
            error('MATLAB:xlswrite:FileName', 'Filename must not contain *.');
        end
        [Directory,file,ext]=fileparts(file);

        if isempty(ext) % add default Excel extension;
            ext = '.xls';
        end
        file = abspath(fullfile(Directory,[file ext]));
        [a1 a2] = fileattrib(file);
        if a1 && ~(a2.UserWrite == 1)
            error('MATLAB:xlswrite:FileReadOnly', 'File cannot be read-only.');
        end
    else % get workbook filename.
        error('MATLAB:xlswrite:EmptyFileName','Filename is empty.');
    end

    % Check for empty input data
    if isempty(data)
        error('MATLAB:xlswrite:EmptyInput','Input array is empty.');
    end

    % Check for N-D array input data
    if ndims(data)>2
        error('MATLAB:xlswrite:InputDimension',...
            'Dimension of input array cannot be higher than two.');
    end

    % Check class of input data
    if ~(iscell(data) || isnumeric(data) || ischar(data)) && ~islogical(data)
        error('MATLAB:xlswrite:InputClass',...
            'Input data must be a numeric, cell, or logical array.');
    end

    % convert input to cell array of data.
     if iscell(data)
        A=data;
     else
         A=num2cell(data);
     end

    if nargin > 2
        % Verify class of sheet parameter.
        if ~(ischar(sheet) || (isnumeric(sheet) && sheet > 0))
            error('MATLAB:xlswrite:InputClass',...
                'Sheet argument must be a string or a whole number greater than 0.');
        end
        if isempty(sheet)
            sheet = Sheet1;
        end
        % Parse sheet
        if ischar(sheet) && ~isempty(strfind(sheet,':'))
            sheet = Sheet1;% Use default sheet.
        end
    end

catch exception
    if ~isempty(nargchk(2,4,nargin))
        error('MATLAB:xlswrite:InputArguments',nargchk(2,4,nargin));
    else
        success = false;
        message = exceptionHandler(nargout, exception);
    end
    return;
end
%------------------------------------------------------------------------------
% Attempt to start Excel as ActiveX server.
try
    Excel = actxserver('Excel.Application');
    % open workbook
    Excel.DisplayAlerts = 0;

    %Workaround for G313142.  For certain files, unless a workbook is
    %opened prior to opening the file, various COM calls return an error:
    %0x800a9c64.  The line below works around this flaw.  Since we have
    %seen only one example of such a file, we have decided not to incur the
    %time penalty involved here.
    %     aTemp = Excel.workbooks.Add(); aTemp.Close();

    ExcelWorkbook = Excel.workbooks.Open(file);
    %ExcelWorkbook.ReadOnly
    format = ExcelWorkbook.FileFormat;
    if  strcmpi(format, 'xlCurrentPlatformText') == 1
        error('MATLAB:xlsread:FileFormat', 'File %s not in Microsoft Excel Format.', file);
    end

    %Sheets = Excel.ActiveWorkBook.Sheets;
    activate_sheet(Excel,sheet);
    readinfo = get(Excel.Activesheet,'UsedRange');
    %get(Excel.Activesheet,'Name')
    if numel(readinfo.value)== 1 && isnan(readinfo.value)
        m2 = 0;
    else
        [m2,n2] = size(readinfo.value);
    end

catch exception %#ok<NASGU>
    warning('MATLAB:xlswrite:NoCOMServer',...
        ['Could not start Excel server for export.\n' ...
        'XLSWRITE will attempt to write file in CSV format.']);
    if nargout > 0
        [message.message,message.identifier] = lastwarn;
    end
    % write data as CSV file, that is, comma delimited.
    file = regexprep(file,'(\.xls[^.]*+)$','.csv');
    try
        dlmwrite(file,data,','); % write data.
    catch exception
        exceptionNew = MException('MATLAB:xlswrite:dlmwrite', 'An error occurred on data export in CSV format.');
        exceptionNew = exceptionNew.addCause(exception);
        if nargout == 0
            % Throw error.
            throw(exceptionNew);
        else
            success = false;
            message.message = exceptionNew.getReport;
            message.identifier = exceptionNew.identifier;
        end
    end
    return;
end
%------------------------------------------------------------------------------
try
    % Construct range string
    % Range was partly specified or not at all. Calculate range.
    % Select range of occupied cells in active sheet.
    % Activate indicated worksheet.
    message = activate_sheet(Excel,sheet);
    [m,n] = size(A);
    range = calcrange('',m,n,m2);
catch exception
    success = false;
    message = exceptionHandler(nargout, exception);
    return;
end

%------------------------------------------------------------------------------
try
    bCreated = ~exist(file,'file');
    ExecuteWrite;
catch exception
    if (bCreated && exist(file, 'file') == 2)
        delete(file);
    end
    success = false;
    message = exceptionHandler(nargout, exception);
end
    function ExecuteWrite
            cleanUp = onCleanup(@()cleaner(Excel, file));
            if bCreated
                % Create new workbook.
                %This is in place because in the presence of a Google Desktop
                %Search installation, calling Add, and then SaveAs after adding data,
                %to create a new Excel file, will leave an Excel process hanging.
                %This workaround prevents it from happening, by creating a blank file,
                %and saving it.  It can then be opened with Open.

                %ExcelWorkbook = Excel.workbooks.Add;
                switch ext
                    case '.xls' %xlExcel8 or xlWorkbookNormal
                       xlFormat = -4143;
                    case '.xlsb' %xlExcel12
                       xlFormat = 50;
                    case '.xlsx' %xlOpenXMLWorkbook
                       xlFormat = 51;
                    case '.xlsm' %xlOpenXMLWorkbookMacroEnabled
                       xlFormat = 52;
                    otherwise
                       xlFormat = -4143;
                end
                ExcelWorkbook.SaveAs(file, xlFormat);
                ExcelWorkbook.Close(false);
            end

            %Open file
            %ExcelWorkbook = Excel.workbooks.Open(file);
            if ExcelWorkbook.ReadOnly ~= 0
                %This means the file is probably open in another process.
                error('MATLAB:xlswrite:LockedFile', 'The file %s is not writable.  It may be locked by another process.', file);
            end
            try % select region.
                % Select range in worksheet.
                Select(Range(Excel,sprintf('%s',range)));

            catch exceptionInner % Throw data range error.
                throw(MException('MATLAB:xlswrite:SelectDataRange', sprintf('Excel returned: %s.', exceptionInner.message)));
            end

            % Export data to selected region.
            set(Excel.selection,'Value',A);
            ExcelWorkbook.Save
    end
end
function cleaner(Excel, filePath)
    try
        %Turn off dialog boxes as we close the file and quit Excel.
        Excel.DisplayAlerts = 0;
        %Explicitly close the file just in case.  The Excel API expects
        %just the filename and not the path.  This is safe because Excel
        %also does not allow opening two files with the same name in
        %different folders at the same time.
        [~, n, e] = fileparts(filePath);
        fileName = [n e];
        Excel.Workbooks.Item(fileName).Close(false);
    catch exception %#ok<NASGU>
        %If something fails in closing, there is nothing to do but attempt
        %to quit.
    end
    Excel.Quit;
end
%--------------------------------------------------------------------------
function message = activate_sheet(Excel,Sheet)
% Activate specified worksheet in workbook.

% Initialise worksheet object
WorkSheets = Excel.sheets;
message = struct('message',{''},'identifier',{''});

% Get name of specified worksheet from workbook
try
    TargetSheet = get(WorkSheets,'item',Sheet);
catch exception  %#ok<NASGU>
    % Worksheet does not exist. Add worksheet.
    TargetSheet = addsheet(WorkSheets,Sheet);
    warning('MATLAB:xlswrite:AddSheet','Added specified worksheet.');
    if nargout > 0
        [message.message,message.identifier] = lastwarn;
    end
end

% activate worksheet
Activate(TargetSheet);
end
%------------------------------------------------------------------------------
function newsheet = addsheet(WorkSheets,Sheet)
% Add new worksheet, Sheet into worsheet collection, WorkSheets.

if isnumeric(Sheet)
    % iteratively add worksheet by index until number of sheets == Sheet.
    while WorkSheets.Count < Sheet
        % find last sheet in worksheet collection
        lastsheet = WorkSheets.Item(WorkSheets.Count);
        newsheet = WorkSheets.Add([],lastsheet);
    end
else
    % add worksheet by name.
    % find last sheet in worksheet collection
    lastsheet = WorkSheets.Item(WorkSheets.Count);
    newsheet = WorkSheets.Add([],lastsheet);
end
% If Sheet is a string, rename new sheet to this string.
if ischar(Sheet)
    set(newsheet,'Name',Sheet);
end
end
%------------------------------------------------------------------------------
function [absolutepath]=abspath(partialpath)

% parse partial path into path parts
[pathname filename ext] = fileparts(partialpath);
% no path qualification is present in partial path; assume parent is pwd, except
% when path string starts with '~' or is identical to '~'.
if isempty(pathname) && isempty(strmatch('~',partialpath))
    Directory = pwd;
elseif isempty(regexp(partialpath,'(.:|\\\\)','once')) && ...
        isempty(strmatch('/',partialpath)) && ...
        isempty(strmatch('~',partialpath));
    % path did not start with any of drive name, UNC path or '~'.
    Directory = [pwd,filesep,pathname];
else
    % path content present in partial path; assume relative to current directory,
    % or absolute.
    Directory = pathname;
end

% construct absulute filename
absolutepath = fullfile(Directory,[filename,ext]);
end
%------------------------------------------------------------------------------
function range = calcrange(range,m,n,offset)
% Calculate full target range, in Excel A1 notation, to include array of size
% m x n

range = upper(range);
cols = isletter(range);
rows = ~cols;
% Construct first row.
if ~any(rows)
    firstrow = offset+1; % Default row.
else
    firstrow = str2double(range(rows)); % from range input.
end
% Construct first column.
if ~any(cols)
    firstcol = 'A'; % Default column.
else
    firstcol = range(cols); % from range input.
end
try
    lastrow = num2str(firstrow+m-1);   % Construct last row as a string.
    firstrow = num2str(firstrow);      % Convert first row to string image.
    lastcol = dec2base27(base27dec(firstcol)+n-1); % Construct last column.

    range = [firstcol firstrow ':' lastcol lastrow]; % Final range string.
catch exception
    error('MATLAB:xlswrite:CalculateRange', 'Invalid data range: %s.', range);
end
end
%----------------------------------------------------------------------
function string = index_to_string(index, first_in_range, digits)

letters = 'A':'Z';
working_index = index - first_in_range;
outputs = cell(1,digits);
[outputs{1:digits}] = ind2sub(repmat(26,1,digits), working_index);
string = fliplr(letters([outputs{:}]));
end
%----------------------------------------------------------------------
function [digits first_in_range] = calculate_range(num_to_convert)

digits = 1;
first_in_range = 0;
current_sum = 26;
while num_to_convert > current_sum
    digits = digits + 1;
    first_in_range = current_sum;
    current_sum = first_in_range + 26.^digits;
end
end
%------------------------------------------------------------------------------
function s = dec2base27(d)

%   DEC2BASE27(D) returns the representation of D as a string in base 27,
%   expressed as 'A'..'Z', 'AA','AB'...'AZ', and so on. Note, there is no zero
%   digit, so strictly we have hybrid base26, base27 number system.  D must be a
%   negative integer bigger than 0 and smaller than 2^52.
%
%   Examples
%       dec2base(1) returns 'A'
%       dec2base(26) returns 'Z'
%       dec2base(27) returns 'AA'
%-----------------------------------------------------------------------------

d = d(:);
if d ~= floor(d) || any(d(:) < 0) || any(d(:) > 1/eps)
    error('MATLAB:xlswrite:Dec2BaseInput',...
        'D must be an integer, 0 <= D <= 2^52.');
end
[num_digits begin] = calculate_range(d);
s = index_to_string(d, begin, num_digits);
end
%------------------------------------------------------------------------------
function d = base27dec(s)
%   BASE27DEC(S) returns the decimal of string S which represents a number in
%   base 27, expressed as 'A'..'Z', 'AA','AB'...'AZ', and so on. Note, there is
%   no zero so strictly we have hybrid base26, base27 number system.
%
%   Examples
%       base27dec('A') returns 1
%       base27dec('Z') returns 26
%       base27dec('IV') returns 256
%-----------------------------------------------------------------------------

if length(s) == 1
   d = s(1) -'A' + 1;
else
    cumulative = 0;
    for i = 1:numel(s)-1
        cumulative = cumulative + 26.^i;
    end
    indexes_fliped = 1 + s - 'A';
    indexes = fliplr(indexes_fliped);
    indexes_in_cells = mat2cell(indexes, 1, ones(1,numel(indexes)));
    d = cumulative + sub2ind(repmat(26, 1,numel(s)), indexes_in_cells{:});
end
end
%-------------------------------------------------------------------------------

function messageStruct = exceptionHandler(nArgs, exception)
    if nArgs == 0
        throwAsCaller(exception);
    else
        messageStruct.message = exception.message;
        messageStruct.identifier = exception.identifier;
    end
end


function mmap=filterjsonmmap(mmap, patterns, isinclude)
%
% mmap=filterjsonmmap(mmap, patterns, isinclude)
%
% filter JSON mmap keys based on inclusive or exclusive string patterns
%
% authors:Qianqian Fang (q.fang <at> neu.edu)
% initially created on 2022/02/13
%
% input:
%      mmap: memory-map returned by loadjson/loadbj of the same data
%            important: mmap must be produced from the same file/string,
%            otherwise calling this function may cause data corruption
%      patterns: a string or a cell array of strings, each string will
%            be tested to match the JSONPath keys in mmap
%      isinclude: 1 (default) to include all mmap entries that match at
%            least one of the patterns, and 0 - exclude those that match
%
% output:
%      mmap: a filtered JSON mmap
%
% examples:
%      str='{"arr":[[1,2],"a",{"c":2}],"obj":{"k":"test"}}';
%      [dat, mmap]=loadjson(str);
%      savejson('',mmap)
%      newmmap=filterjsonmmap(mmap,{'arr.[1]', 'obj.k'});
%      savejson('',newmmap)
%
% license:
%     BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details
%
% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
    if(nargin<3)
        isinclude=1;
    end
    if(nargin>1 && ~isempty(patterns))
        keylist=[mmap{:}];
        keylist=keylist(1:2:end);
        if(~iscell(patterns))
            patterns={patterns};
        end
        mask=zeros(1,length(keylist));
        for i=1:length(patterns)
            mask=mask+cellfun(@length, strfind(keylist,patterns{i}));
        end
        if(isinclude)
            mmap=mmap(mask>0);
        else
            mmap(mask>0)=[];
        end
    end
end


function F = tag(F,t)

if nargin > 1
    F = tag(lmi(F),t);
else
    F = tag(lmi(F));
end


function outargs = hlp_resolve(x,default,context)
% Look up a symbol from the current hlp_scope scope.
% Data = hlp_resolve(Symbol,Default,Context)
%
% More precisely, perform a lookup for a symbol in the current (dynamic) scope formed by (possibly
% nested) hlp_scope(s). Returns a cell array of all the values associated with the symbol. Used to
% implement dynamic scoping across functions, used by parts of the expression & online system.
%
% In:
%   Symbol : a symbol (string or function handle) to look up; if omitted, the entire symbol frame
%            will be returned as a struct
%
%   Default : the default value, if the symbol does not exist (note: you may also omit the default
%             if you prefer to get an error in case the symbol does not exist)
%
%   Context : Optionally the execution context (struct with field .stack) at this point, if known.
%             Can be obtained via dbstack or try/catch.
%
% Out:
%   Data : the data associated with the symbol, or the symbol itself, if the lookup failed
%
% Examples:
%   % resolve the value of the symbol 'test' against the current dynamic scope
%   value = hlp_resolve('test')
%
% See also:
%   hlp_scope
%
%                                Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
%                                2010-05-03

% Copyright (C) Christian Kothe, SCCN, 2010, christian@sccn.ucsd.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

global tracking;

% get stack entries
if nargin < 3
    stack = dbstack;
    entries = {stack.name};
else
    entries = {context.stack.name};
end

% check for all entries whether they refer to a stack frame...
if hlp_matlab_version < 806
    marker = 'make_func/@(f,a,frame__';
else
    marker = '@(f,a,frame__';
end
frames = find(strncmp(entries,marker,length(marker)));

% go through all stack frames...
symbol = char(x);
for k=frames
    frameid = entries{k}(length(marker)+1:end-14);
    % and check if the symbol is present there, then look up
    if isfield(tracking.stack.frames.(frameid),symbol)
        outargs = tracking.stack.frames.(frameid).(symbol);
        return;
    end
end

try
    if isfield(tracking.stack.base,symbol)
        % symbol is fetched from the base workspace
        outargs = tracking.stack.base.(symbol);
    else
        % symbol is not in the base workspace: remains unsubstituted
        outargs = default;
    end
catch
    % base workspace doesn't exist yet: create it...
    tracking.stack.base = struct();
    outargs = default;
end


report_this_filefun(mfilename('fullpath'));

str = [];
[newmatfile, newpath] = uiputfile([ hodo '*.dat'], 'Save As'); %Syntax change Matlab Version 7, no window positioning on macs

s = [a.Longitude   a.Latitude  a.Date  a.Date.Month  a.Date.Day  a.Magnitude  a.Depth a.Date.Hour a.Date.Minute a(:,10) a(:,11) a(:,12) a(:,13) a(:,14) ];
fid = fopen([newpath newmatfile],'w') ;
fprintf(fid,'%7.3f  %7.3f %6.2f %6.0f  %6.0f %6.1f %6.2f  %6.0f  %6.0f  %7.2f  %7.2f  %7.2f %7.2f  %7.2f\n',s');
fclose(fid);
clear s
return


function model = changeRxnBounds(model, rxnNameList, value, boundType)
% Changes upper or lower bounds of a reaction or a set of reactions
%
% USAGE:
%
%    model = changeRxnBounds(model, rxnNameList, value, boundType)
%
% INPUTS:
%    model:          COBRA model structure
%    rxnNameList:    List of reactions (cell array or string)
%    value:          Bound values.
%                    Can either be a vector or a single scalar value if the same
%                    bound value is to be assinged to all reactions
%
% OPTIONAL INPUT:
%    boundType:      'u' - upper, 'l' - lower, 'b' - both (Default = 'b')
%                    Bound type can either be a cell array of strings or a
%                    string with as many letters as there are reactions in  `rxnNameList`
%
% OUTPUT:
%    model:          COBRA model structure with modified reaction bounds
%
% .. Author: -  Markus Herrgard 4/21/06

if (nargin < 4)
    boundType = 'b';
end

if ((length(value) ~= length(rxnNameList) & length(value) > 1) | (length(boundType) ~= length(rxnNameList) & length(boundType) > 1))
   error('Inconsistent lenghts of arguments: rxnNameList, value & boundType');
end

rxnID = findRxnIDs(model,rxnNameList);

% Remove reactions that are not in the model
if (iscell(rxnNameList))
    missingRxns = rxnNameList(rxnID == 0);
    for i = 1:length(missingRxns)
        warning('Reaction %s not in model',missingRxns{i});
    end
    if (length(boundType) > 1)
        boundType = boundType(rxnID ~= 0);
    end
    if (length(value) > 1)
        value = value(rxnID ~= 0);
    end
    rxnID = rxnID(rxnID ~= 0);
else
    if rxnID==0
        warning('Reaction %s not in model',rxnNameList)
    end
end

if (isempty(rxnID))
    %rxnNameList was a cell with a single reaction not found
    %Warning would have already been triggered in line 39 above
    %So do nothing!
elseif (sum(rxnID) == 0)
    warning('Reaction %s not in model',rxnNameList);
else
    nRxns = length(rxnID);
    if (length(boundType) > 1)
        if (length(value) == 1)
            value = repmat(value,nRxns,1);
        end
        for i = 1:nRxns
            switch lower(boundType{i})
                case 'u'
                    model.ub(rxnID(i)) = value(i);
                case 'l'
                    model.lb(rxnID(i)) = value(i);
                case 'b'
                    model.lb(rxnID(i)) = value(i);
                    model.ub(rxnID(i)) = value(i);
            end
        end
    else
        switch lower(boundType)
            case 'u'
                model.ub(rxnID) = value;
            case 'l'
                model.lb(rxnID) = value;
            case 'b'
                model.lb(rxnID) = value;
                model.ub(rxnID) = value;
        end
    end
end


function sPsi = packBPHMMState( Psi );

sPsi.F = Psi.F;
sPsi.gamma = Psi.bpM.gamma;
sPsi.c     = Psi.bpM.c;
sPsi.Eta    = Psi.TransM.seq;
sPsi.alpha  = Psi.TransM.prior.alpha;
sPsi.kappa  = Psi.TransM.prior.kappa;
sPsi.theta  = Psi.ThetaM.theta;
sPsi.stateSeq = Psi.stateSeq;

end


classdef SubcellsMesher_1D < SubcellsMesher_Interior_Abstract

    methods (Access = public)

        function obj = SubcellsMesher_1D(cParams)
           obj.init(cParams);
        end

    end

    methods (Access = protected)

        function computeAllPossibleSubcellsInCell(obj)
            obj.subcells_connec = [1 3; 2 3];
        end

    end
end


function results = spm_cfg_results
% SPM Configuration file for Results Report
%__________________________________________________________________________
% Copyright (C) 2005-2018 Wellcome Trust Centre for Neuroimaging

% $Id: spm_cfg_results.m 7268 2018-02-27 16:48:13Z guillaume $

%--------------------------------------------------------------------------
% spmmat Select SPM.mat
%--------------------------------------------------------------------------
spmmat         = cfg_files;
spmmat.tag     = 'spmmat';
spmmat.name    = 'Select SPM.mat';
spmmat.help    = {'Select the SPM.mat file that contains the design specification.'};
spmmat.filter  = 'mat';
spmmat.ufilter = '^SPM\.mat$';
spmmat.num     = [1 1];

%--------------------------------------------------------------------------
% titlestr Results Title
%--------------------------------------------------------------------------
titlestr         = cfg_entry;
titlestr.tag     = 'titlestr';
titlestr.name    = 'Results Title';
titlestr.help    = {'Heading on results page - determined automatically if left empty'};
titlestr.val     = {''};
titlestr.strtype = 's';
titlestr.num     = [0 Inf];
titlestr.hidden  = true;

%--------------------------------------------------------------------------
% contrasts Contrast(s)
%--------------------------------------------------------------------------
contrasts         = cfg_entry;
contrasts.tag     = 'contrasts';
contrasts.name    = 'Contrast(s)';
contrasts.help    = {
                     'Index of contrast(s). If more than one number is entered, analyse a conjunction hypothesis.'
                     ''
                     'If only one number is entered, and this number is "Inf", then results are printed for all contrasts found in the SPM.mat file.'
}';
contrasts.strtype = 'n';
contrasts.num     = [1 Inf];

%--------------------------------------------------------------------------
% threshdesc Threshold type
%--------------------------------------------------------------------------
threshdesc        = cfg_menu;
threshdesc.tag    = 'threshdesc';
threshdesc.name   = 'Threshold type';
threshdesc.help   = {''};
threshdesc.labels = {'FWE' 'none' 'FDR'};
threshdesc.values = {'FWE' 'none' 'FDR'};
threshdesc.val    = {'FWE'};

%--------------------------------------------------------------------------
% thresh Threshold
%--------------------------------------------------------------------------
thresh         = cfg_entry;
thresh.tag     = 'thresh';
thresh.name    = 'Threshold';
thresh.help    = {''};
thresh.strtype = 'r';
thresh.num     = [1 1];
thresh.val     = {0.05};

%--------------------------------------------------------------------------
% extent Extent (voxels)
%--------------------------------------------------------------------------
extent         = cfg_entry;
extent.tag     = 'extent';
extent.name    = 'Extent (voxels)';
extent.help    = {''};
extent.strtype = 'w';
extent.num     = [1 1];
extent.val     = {0};

%--------------------------------------------------------------------------
% conjunction Conjunction Number
%--------------------------------------------------------------------------
conjunction         = cfg_entry;
conjunction.tag     = 'conjunction';
conjunction.name    = 'Conjunction number';
conjunction.help    = {'Conjunction number. Unused if a simple contrast is entered.'
    'For Conjunction Null, enter 1.'
    'For Global Null, enter the number of selected contrasts.'
    'For Intermediate, enter the number of selected contrasts minus the number of effects under the Null.'}';
conjunction.strtype = 'n';
conjunction.num     = [1 1];
conjunction.val     = {1};

%--------------------------------------------------------------------------
% contrasts Contrast(s)
%--------------------------------------------------------------------------
contrasts1         = cfg_entry;
contrasts1.tag     = 'contrasts';
contrasts1.name    = 'Contrast(s)';
contrasts1.help    = {'Index of contrast(s) for masking.'};
contrasts1.strtype = 'n';
contrasts1.num     = [1 Inf];

%--------------------------------------------------------------------------
% thresh Mask threshold
%--------------------------------------------------------------------------
thresh1         = cfg_entry;
thresh1.tag     = 'thresh';
thresh1.name    = 'Mask threshold';
thresh1.help    = {''};
thresh1.strtype = 'r';
thresh1.num     = [1 1];
thresh1.val     = {0.05};

%--------------------------------------------------------------------------
% mtype Nature of mask
%--------------------------------------------------------------------------
mtype        = cfg_menu;
mtype.tag    = 'mtype';
mtype.name   = 'Nature of mask';
mtype.help   = {''};
mtype.labels = {'Inclusive' 'Exclusive'};
mtype.values = {0 1};

%--------------------------------------------------------------------------
% mask Mask using contrast
%--------------------------------------------------------------------------
contrast      = cfg_branch;
contrast.tag  = 'contrast';
contrast.name = 'Contrast';
contrast.val  = {contrasts1 thresh1 mtype};
contrast.help = {'Masking using contrast.'};

%--------------------------------------------------------------------------
% name Mask image
%--------------------------------------------------------------------------
name         = cfg_files;
name.tag     = 'name';
name.name    = 'Mask image(s)';
name.help    = {''};
name.filter  = {'image'};
name.ufilter = '.*';
name.num     = [1 Inf];

%--------------------------------------------------------------------------
% image Mask using image
%--------------------------------------------------------------------------
image      = cfg_branch;
image.tag  = 'image';
image.name = 'Image';
image.val  = {name mtype};
image.help = {'Masking using image(s).'};

%--------------------------------------------------------------------------
% none No Masking
%--------------------------------------------------------------------------
none      = cfg_const;
none.tag  = 'none';
none.name = 'None';
none.val  = { 1 };
none.help = {'No masking.'};

%--------------------------------------------------------------------------
% mask Masking
%--------------------------------------------------------------------------
mask        = cfg_choice;
mask.tag    = 'mask';
mask.name   = 'Masking';
mask.help   = {''};
mask.values = {none contrast image};
mask.val    = {none};

%--------------------------------------------------------------------------
% conspec Contrast query
%--------------------------------------------------------------------------
conspec      = cfg_branch;
conspec.tag  = 'conspec';
conspec.name = 'Contrast query';
conspec.val  = {titlestr contrasts threshdesc thresh extent conjunction mask};
conspec.help = {''};

%--------------------------------------------------------------------------
% generic Contrasts
%--------------------------------------------------------------------------
generic        = cfg_repeat;
generic.tag    = 'generic';
generic.name   = 'Contrasts';
generic.help   = {''};
generic.values = {conspec};
generic.num    = [1 Inf];

%--------------------------------------------------------------------------
% units Units
%--------------------------------------------------------------------------
units        = cfg_menu;
units.tag    = 'units';
units.name   = 'Data type';
units.help   = {['Data type. This option is only meaningful for M/EEG '...
    'data. Keep the default ''Volumetric'' for any other kind of data.']};
units.labels = {'Volumetric (2D/3D)',...
                'Scalp-Time',...
                'Scalp-Frequency',...
                'Time-Frequency',...
                'Frequency-Frequency'}';
units.values = { 1 2 3 4 5 };
units.val    = { 1 };

%--------------------------------------------------------------------------
% basename Basename
%--------------------------------------------------------------------------
basename         = cfg_entry;
basename.tag     = 'basename';
basename.name    = 'Basename';
basename.help    = {'Enter basename of output files ''spm?_????_<basename>.ext''.'};
basename.strtype = 's';
basename.num     = [1 Inf];

%--------------------------------------------------------------------------
% background Background image
%--------------------------------------------------------------------------
background         = cfg_files;
background.tag     = 'background';
background.name    = 'Background image';
background.help    = {'Background image.'};
background.filter  = {'image'};
background.ufilter = '.*';
background.num     = [1 1];

%--------------------------------------------------------------------------
% orientation Image orientation
%--------------------------------------------------------------------------
orientation        = cfg_menu;
orientation.tag    = 'orientation';
orientation.name   = 'Image orientation';
orientation.help   = {'Image orientation.'};
orientation.labels = {'Axial','Coronal','Sagittal'}';
orientation.values = {'axial','coronal','sagittal'};

%--------------------------------------------------------------------------
% Slices Slices
%--------------------------------------------------------------------------
slices         = cfg_entry;
slices.tag     = 'slices';
slices.name    = 'Slices';
slices.help    = {'Slices to display (mm).'};
slices.strtype = 'r';
slices.num     = [1 Inf];

%--------------------------------------------------------------------------
% nsubj Number of subjects
%--------------------------------------------------------------------------
nsubj         = cfg_entry;
nsubj.tag     = 'nsubj';
nsubj.name    = 'Number of subjects';
nsubj.help    = {'Number of subjects.'};
nsubj.strtype = 'r';
nsubj.num     = [1 1];

%--------------------------------------------------------------------------
% label Label
%--------------------------------------------------------------------------
grplabel         = cfg_entry;
grplabel.tag     = 'label';
grplabel.name    = 'Label';
grplabel.help    = {'Group label.'};
grplabel.strtype = 's';
grplabel.num     = [0 Inf];

%--------------------------------------------------------------------------
% group
%--------------------------------------------------------------------------
group      = cfg_branch;
group.tag  = 'group';
group.name = 'Group';
group.val  = {nsubj grplabel};
group.help = {['Number of subjects and labels per group. ', ...
    'For a single subject analysis, enter "1" and "single subject".']};

%--------------------------------------------------------------------------
% groups
%--------------------------------------------------------------------------
groups        = cfg_repeat;
groups.tag    = 'groups';
groups.name   = 'Groups';
groups.help   = {['Number of groups. ', ...
    'For a single subject analysis, specify one group.']};
groups.values = {group};
groups.num    = [1 Inf];

%--------------------------------------------------------------------------
% modality Modality
%--------------------------------------------------------------------------
modality        = cfg_menu;
modality.tag    = 'modality';
modality.name   = 'Modality';
modality.help   = {'Modality.'};
modality.labels = {'Anatomical MRI',...
                   'Functional MRI',...
                   'Diffusion MRI',...
                   'PET',...
                   'SPECT',...
                   'EEG',...
                   'MEG'
}';
modality.values = {'AMRI','FMRI','DMRI','PET','SPECT','EEG','MEG'};

%--------------------------------------------------------------------------
% refspace Reference space
%--------------------------------------------------------------------------
refspace        = cfg_menu;
refspace.tag    = 'refspace';
refspace.name   = 'Reference space';
refspace.help   = {['Reference space. For an experiment completed only ',...
    'within SPM, choose one of the first four options.']};
refspace.labels = {'Subject space (no normalisation)',...
                   'Normalised space (using segment)',...
                   'Normalised space (using old segment)',...
                   'Customised space',...
                   'Other normalised MNI space',...
                   'Other normalised Talairach space',...
}';
refspace.values = {'subject','ixi','icbm','custom','mni','talairach'};

%--------------------------------------------------------------------------
% exports
%--------------------------------------------------------------------------
exports{1}      = cfg_branch;
exports{1}.tag  = 'tspm';
exports{1}.name = 'Thresholded SPM';
exports{1}.val  = { basename };
exports{1}.help = {'Save filtered SPM{.} as an image.'};

exports{end+1}    = cfg_branch;
exports{end}.tag  = 'binary';
exports{end}.name = 'All clusters (binary)';
exports{end}.val  = { basename };
exports{end}.help = {'Save filtered SPM{.} as a binary image.'};

exports{end+1}    = cfg_branch;
exports{end}.tag  = 'nary';
exports{end}.name = 'All clusters (n-ary)';
exports{end}.val  = { basename };
exports{end}.help = {'Save filtered SPM{.} as an n-ary image.'};

pf = spm_print('format');
for i=1:numel(pf)
    exports{end+1}    = cfg_const;
    exports{end}.tag  = pf(i).label{1};
    exports{end}.name = pf(i).name;
    exports{end}.val  = { true };
    exports{end}.help = {pf(i).name};
end
exports{end+1}    = cfg_const;
exports{end}.tag  = 'csv';
exports{end}.name = 'CSV file';
exports{end}.val  = { true };
exports{end}.help = {exports{end}.name};
if ispc
    exports{end+1}    = cfg_const;
    exports{end}.tag  = 'xls';
    exports{end}.name = 'Excel spreadsheet file';
    exports{end}.val  = { true };
    exports{end}.help = {exports{end}.name};
end

exports{end+1}    = cfg_branch;
exports{end}.tag  = 'montage';
exports{end}.name = 'Montage';
exports{end}.val  = { background orientation slices };
exports{end}.help = {'Display montage.'};

exports{end+1}    = cfg_branch;
exports{end}.tag  = 'nidm';
exports{end}.name = 'NIDM (Neuroimaging Data Model)';
exports{end}.val  = {modality refspace groups};
exports{end}.help = {exports{end}.name};

%--------------------------------------------------------------------------
% export Export results
%--------------------------------------------------------------------------
export        = cfg_repeat;
export.tag    = 'export';
export.name   = 'Export results';
export.help   = {['Select the export format you want. PostScript (PS) is '...
               'the only format that allows to append figures to the same ' ...
               'file.']};
export.values = exports;
uiprintdef    = spm_get_defaults('ui.print');
for i=1:numel(exports)
    if strcmp(uiprintdef,exports{i}.tag)
        export.val = exports(i);
        break;
    end
end

%--------------------------------------------------------------------------
% results Results Report
%--------------------------------------------------------------------------
results      = cfg_exbranch;
results.tag  = 'results';
results.name = 'Results Report';
results.val  = {spmmat generic units export};
results.help = {'Statistical inference.'};
results.prog = @spm_run_results;
results.vout = @vout_results;

%==========================================================================
function dep = vout_results(job)

dep(1)            = cfg_dep;
dep(1).sname      = 'xSPM Variable';
dep(1).src_output = substruct('.','xSPMvar');
dep(1).tgt_spec   = cfg_findspec({{'strtype','e'}});

dep(2)            = cfg_dep;
dep(2).sname      = 'TabDat Variable';
dep(2).src_output = substruct('.','TabDatvar');
dep(2).tgt_spec   = cfg_findspec({{'strtype','e'}});

for i=1:numel(job.export)
    fn = char(fieldnames(job.export{i}));
    if ismember(fn,{'tspm','binary','nary'})
        dep(end+1)          = cfg_dep;
        dep(end).sname      = 'Filtered image';
        dep(end).src_output = substruct('.','filtered');
        dep(end).tgt_spec   = cfg_findspec({{'filter','image','strtype','e'}});
        break; % so far, a single dependency pointing to the last exported image
    end
end