function installDevTools(repoName)
% checks if the MATLAB.devTools are already present and installs the
% MATLAB.devTools next to the cloned folder cobratoolbox (if not present yet)
%
% USAGE:
%    installDevTools(repoName)
%
% OPTIONAL INPUT:
%    repoName:     Name of the repository (default: 'opencobra/cobratoolbox')
%
% NOTE:
%    In order to install the devTools, please make sure that the SSH key is
%    configured properly as explained `here <https://opencobra.github.io/MATLAB.devTools/stable/installation.html>`__.
%    The full documentation of the MATLAB.devTools is `here <https://opencobra.github.io/MATLAB.devTools>`__.
%
% .. Author: Laurent Heirendt, June 2017

    global ENV_VARS
    global CBTDIR

    % make sure that The COBRA Toolbox is properly installed;
    % git and curl are tested here
    if isempty(ENV_VARS)
        ENV_VARS.printLevel = false;
        initCobraToolbox(false); %Don't update the toolbox automatically
        ENV_VARS.printLevel = true;
    end

    currentDir = pwd;

    % change to the local directory
    localDir = [CBTDIR filesep '..'];
    cd(localDir);

    % set the default repoName
    if ~exist('repoName', 'var')
        repoName = 'opencobra/cobratoolbox';
    end

    % add the public key from github.com to the known hosts
    addKeyToKnownHosts();

    installFlag = false;

    % check if the devTools already exist
    if exist([CBTDIR filesep '..' filesep 'MATLAB.devTools'], 'dir') == 7

        reply = input([' > There is already a copy of the MATLAB.devTools installed in the default location.\n   Do you want to enter another location to install the MATLAB.devTools? Y/N [Y]: '], 's');
        localDir = '';

        % enter another location for the MATLAB.devTools
        if isempty(reply) || strcmpi(reply, 'y') || strcmpi(reply, 'yes')
            dirReply = '';
            while isempty(dirReply)
                dirReply = input(['\n -> Please define the installation path of the MATLAB.devTools\n    Enter the path: '], 's');

                if exist([dirReply filesep 'MATLAB.devTools'], 'dir') == 7
                    fprintf(['\n   The directory ', [dirReply filesep 'MATLAB.devTools'], ' already exists. Please enter a different directory.\n']);
                    dirReply = '';
                end

                % if the entered directory is not empty, try to add it to the path
                if ~isempty(dirReply)
                    addpath(dirReply);
                    if exist(dirReply, 'dir') == 7
                        localDir = dirReply;
                        break;
                    else
                        fprintf('\n   -> The directory does not exist. Please try again.\n');
                        dirReply = '';
                    end
                end
            end

            installFlag = true;
        else
            installFlag = false;
            fprintf(' > You cannot install the MATLAB.devTools. Please delete the folder %s\n', [CBTDIR filesep '..' filesep 'MATLAB.devTools']);
        end
    else
        installFlag = true;
    end

    % install a new copy of the MATLAB.devTools
    if installFlag

        % changing to the local directory
        cd(localDir);

        % install the devTools properly speaking
        fprintf(['\n > Installing the MATLAB.devTools into ' localDir ' (might take some time) ... ']);

        [status_gitClone, result_gitClone] = system(['git clone -c http.sslVerify=false --depth=1 git@github.com:opencobra/MATLAB.devTools.git']);

        if status_gitClone == 0

            if ~isempty(localDir)
                devToolsDir = localDir;
            end

            fprintf(['Done.\n > Location of the MATLAB.devTools: ', strrep(devToolsDir, '\', '\\'), '\n\n']);

            % add the path to the devTools
            addpath(genpath(devToolsDir));

            % removing .git folder
            rmpath(genpath([devToolsDir filesep '.git']));

            fprintf([' > In order to start contributing, you can now run:\n\n >> contribute(''' repoName '''); \n\n']);
        else
            fprintf(result_gitClone);
            error(['The MATLAB.devTools could not be cloned. Please make sure that your SSH key is configured correctly.']);
        end
    end

    % change back to the current directory
    cd(currentDir);
end


for i=1:21
    index = i;
    disp(num2str(index));

    fuse_path1 = ['./fused_infrared/fused',num2str(index),'_vgg19_zca1.png'];
    fuse_path2 = ['./fused_infrared/fused',num2str(index),'_vgg19_zca2.png'];
    fuse_path3 = ['./fused_infrared/fused',num2str(index),'_vgg19_zca3.png'];
    fuse_path4 = ['./fused_infrared/fused',num2str(index),'_vgg19_zca4.png'];
%     fuse_path5 = ['./fused_infrared/fused',num2str(index),'_vgg19_zca5.png'];

    image1 = imread(fuse_path1);
    image2 = imread(fuse_path2);
    image3 = imread(fuse_path3);
    image4 = imread(fuse_path4);
%     image5 = imread(fuse_path5);

    imwrite(image1,['./fused_infrared/fused',num2str(index),'_vgg19_nu_zca1.png'],'png');
    imwrite(image2,['./fused_infrared/fused',num2str(index),'_vgg19_nu_zca2.png'],'png');
    imwrite(image3,['./fused_infrared/fused',num2str(index),'_vgg19_nu_zca3.png'],'png');
    imwrite(image4,['./fused_infrared/fused',num2str(index),'_vgg19_nu_zca4.png'],'png');
%     imwrite(image5,['./fused_infrared/fused',num2str(index),'_vgg19_nu_zca5.png'],'png');

    delete(fuse_path1);
    delete(fuse_path2);
    delete(fuse_path3);
    delete(fuse_path4);
%     delete(fuse_path5);
end


function color=gen_color(curve_idx)

colors=[];
colors{end+1}='r';
colors{end+1}='b';
colors{end+1}='g';
colors{end+1}='m';
colors{end+1}='c';
colors{end+1}='black';
colors{end+1}=[0.7 0 0.7 ];
colors{end+1}=[0 0.7 0.7 ];
colors{end+1}=[ 0.83 0.33 0];

sel_idx=mod(curve_idx-1, length(colors))+1;
color=colors{sel_idx};

end


% APM Load Data File
%
% response = csv_load(server,app,filename)
%
% Function csv_load uploads the data file (csv) to the web-server
%   with the following arguments:
%
%   server = address of server
%      app = application name
% filename = data filename
%
% A response is returned indicating whether the file was
%   uploaded successfully to the server
%
function [response] = csv_load(server,app,filename)
   % load model
   fid=fopen(filename,'r');
   tline = [];
   while 1
      aline = fgets(fid);
      if ~ischar(aline), break, end
      % remove any double quote marks
      aline = [strrep(aline,'"',' ')];
      tline = [tline aline];
   end
   fclose(fid);

   % send to server once for every 2000 characters
   ts = size(tline,2);
   block = 2000;
   cycles = ceil(ts/block);
   for i = 1:cycles,
      if i<cycles,
         csv_block = ['csva ' tline((i-1)*block+1:i*block)];
      else
         csv_block = ['csv ' tline((i-1)*block+1:end)];
      end
      response = apm(server,app,csv_block);
   end
   response = 'Successfully loaded CSV file';


function ground_truth = get_ground_truth( database, image_id )
    if strcmp(database,'pascal2012')
        ground_truth.object = imread(fullfile(database_root_dir(database), 'SegmentationObject', [image_id '.png']));
        ground_truth.class  = imread(fullfile(database_root_dir(database), 'SegmentationClass', [image_id '.png']));
    elseif strcmp(database,'bsds500')
        ground_truth = loadvar(fullfile(database_root_dir(database), 'ground_truth', [image_id '.mat']),'gt_seg');
    else
        error(['Unknown database: ' database]);
    end
end


function gui_l (x, y)
%
% This file is needed by FASTICAG

% The load dialog for loading new data
% and new initial guess.

% @(#)$Id$

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Global variables

% Handle to the window
global hf_FastICA_Load;

% Handles to some of the controls in window
global he_FastICA_file;

% What is the load type of load dialog
global g_FastICA_loadType;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Configuration options
FIGURENAME = 'FastICA: Load';
FIGURETAG = 'f_FastICALoad';
FIGURESIZE = [x y 450 150];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Check to see if this figure is already open - it should not!
% Can't have more than one copy - otherwise the global
% variables and handles can get mixed up.
if ~isempty(findobj('Tag',FIGURETAG))
  error('Error: load dialog already open!');
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Initialize some of the controls' values

% What are we loading - who is calling?
caller = get(gcf, 'CurrentObject');

switch get(caller, 'Tag')
 case 'b_LoadData'                             % Do we load new data...
  loadString = 'Load data from variable in Matlab.';
  g_FastICA_loadType = 'data';
  FIGURENAME = 'FastICA: Load data';

 case 'b_LoadGuess'                            % ... or new initial guess?
  loadString = 'Load initial guess for mixing matrix A from variable in Matlab.';
  g_FastICA_loadType = 'guess';
  FIGURENAME = 'FastICA: Load initial guess';
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Create the figure
a = figure('Color',[0.8 0.8 0.8], ...
	   'PaperType','a4letter', ...
	   'Name', FIGURENAME, ...
	   'NumberTitle', 'off', ...
	   'Tag', FIGURETAG, ...
	   'Position', FIGURESIZE, ...
	   'MenuBar', 'none');
set (a, 'Resize', 'off');

hf_FastICA_Load = a;

set(hf_FastICA_Load, 'HandleVisibility', 'callback');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% From here on it get's ugly as I have not had time to clean it up

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Create the frames
pos_l=2;
pos_w=FIGURESIZE(3)-4;
pos_h=FIGURESIZE(4)-4;
pos_t=2;
h_f_load_background = uicontrol('Parent',a, ...
  'BackgroundColor',[0.701961 0.701961 0.701961], ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'Style','frame', ...
  'Tag','f_load_background');

pos_w=120;
pos_l=FIGURESIZE(3)-(pos_w+2+2);
pos_h=FIGURESIZE(4)-2*4;
pos_t=4;
h_f_load_side = uicontrol('Parent',a, ...
  'BackgroundColor',[0.701961 0.701961 0.701961], ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'Style','frame', ...
  'Tag','f_load_side');

pos_l=4;
pos_w=FIGURESIZE(3)-8-pos_w-2;
pos_h=FIGURESIZE(4)-8;
pos_t=4;
h_f_load = uicontrol('Parent',a, ...
  'BackgroundColor',[0.701961 0.701961 0.701961], ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'Style','frame', ...
  'Tag','f_load');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Controls in f_load
bgc = get(h_f_load, 'BackgroundColor');

pos_w=230;

pos_frame=get(h_f_load, 'Position');
pos_h = 40;
pos_t = pos_frame(2) + pos_frame(4) - pos_h - 6;
pos_l = pos_frame(1) + 6;

b = uicontrol('Parent',a, ...
  'BackgroundColor',bgc, ...
  'HorizontalAlignment','left', ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'String',loadString, ...
  'Style','text', ...
  'Tag','t_93');

pos_h = 20;
pos_t = pos_t - pos_h - 10;
pos_l = pos_frame(1) + 6;

b = uicontrol('Parent',a, ...
  'BackgroundColor',bgc, ...
  'HorizontalAlignment','left', ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'String','Name of the variable:', ...
  'Style','text', ...
  'Tag','t_92');

pos_w = 200;
pos_l = pos_l + 30;
pos_t = pos_t - pos_h;
he_FastICA_file = uicontrol('Parent',a, ...
  'BackgroundColor',[1 1 1], ...
  'HorizontalAlignment','left', ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'String','', ...
  'Style','edit', ...
  'Tag','e_file');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Controls in f_load_side
pos_vspace = 6;
pos_hspace = 10;
pos_frame = get(h_f_load_side, 'Position');
pos_w = 100;
pos_h = 30;
pos_l = pos_frame(1) + pos_hspace;
pos_t = pos_frame(2) + pos_frame(4) - pos_h - pos_vspace;
b = uicontrol('Parent',a, ...
  'BackgroundColor',[0.701961 0.701961 0.701961], ...
  'Callback','gui_lc Load', ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'String','Load', ...
  'Tag','b_lLoad');

pos_t=pos_t-pos_h-pos_vspace;
b = uicontrol('Parent',a, ...
  'BackgroundColor',[0.701961 0.701961 0.701961], ...
  'Callback','gui_lc Cancel', ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'String','Cancel', ...
  'Tag','b_lCancel');

pos_t = pos_frame(2) + pos_vspace;
b = uicontrol('Parent',a, ...
  'BackgroundColor',[0.701961 0.701961 0.701961], ...
  'Callback','gui_lc Help', ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'String','Help', ...
  'Tag','b_lHelp');


function display(pot)

disp('moment Gaussian potential object');
disp(struct(pot));


function results_image = PTKGetPrunedAirwayImageFromCentreline(parent_bronchi, child_bronchi, airway_root, template, colour_by_segment_index)
    % PTKGetPrunedAirwayImageFromCentreline.
    %
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2012.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    airways_image = PTKGetAirwayImageFromCentreline(parent_bronchi, airway_root, template, colour_by_segment_index);
    airways_image_child = PTKGetAirwayImageFromCentreline(child_bronchi, airway_root, template, colour_by_segment_index);

    results_image = airways_image.BlankCopy;
    results_image_raw = airways_image.RawImage;
    results_image_raw(airways_image_child.RawImage ~= 7) = 0;
    results_image.ChangeRawImage(results_image_raw);
    results_image.ImageType = PTKImageType.Colormap;
end


classdef MimEditCyan < MimGuiPlugin
    % MimEditCyan. Gui Plugin for setting paint colour
    %
    %     You should not use this class within your own code. It is intended to
    %     be used by the gui of the TD MIM Toolkit.
    %
    %     MimEditCyan is a Gui Plugin for the MIM Toolkit.
    %
    %
    %     Licence
    %     -------
    %     Part of the TD MIM Toolkit. https://github.com/tomdoel
    %     Author: Tom Doel, Copyright Tom Doel 2014.  www.tomdoel.com
    %     Distributed under the MIT licence. Please see website for details.
    %

    properties
        ButtonText = 'Cyan'
        SelectedText = 'Cyan'
        ToolTip = 'Edit with cyan label'
        Category = 'Segmentation label'
        Visibility = 'Dataset'
        Mode = 'Edit'

        HidePluginInDisplay = false
        PTKVersion = '1'
        ButtonWidth = 5
        ButtonHeight = 1
        Icon = 'paint.png'
        IconColour = GemMarkerPoint.DefaultColours{4}
        Location = 34
    end

    methods (Static)
        function RunGuiPlugin(gui_app)
            gui_app.ImagePanel.PaintBrushColour = 4;
        end

        function enabled = IsEnabled(gui_app)
             enabled = gui_app.IsDatasetLoaded && gui_app.ImagePanel.OverlayImage.ImageExists && ...
                isequal(gui_app.ImagePanel.SelectedControl, 'Paint');
        end

        function is_selected = IsSelected(gui_app)
            is_selected = gui_app.ImagePanel.PaintBrushColour == 4;
        end
    end
end


function [ output_meta ] = meta2sicd_aimidb( aimidb_struct )
%META2SICD_AIMIDB Converts metadata stored in the AIMIDB NITF TRE into a
% SICD metadata format
%
% Written by: Wade Schwartzkopf, NGA/IDT
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

if any(~isspace(aimidb_struct.COUNTRY)) % Could be blank
    output_meta.CollectionInfo.CountryCode=aimidb_struct.COUNTRY;
end
output_meta.ImageFormation.SegmentIdentifier=aimidb_struct.CURRENT_SEGMENT;
try
    output_meta.Timeline.CollectStart=datenum(aimidb_struct.ACQUISITION_DATE,'yyyymmddHHMMSS');
end

end

% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////


% ----------------------------------------------------------------------------
% function hfssExportToFile(fid, ReportName, FileName, Type)
%
% Description :
% -------------
% Exports the report data to file, so it can be postprocesed.
%
% Parameters :
% ------------
% fid        - file identifier of the HFSS script file.
% ReportName - name of the report to export.
% FileName   - name of the file.
% Type       - There are four possible types:
%               * txt: Post processor format file
%               * csv: Comma-delimited data file
%               * tab: Tab-separated file
%               * dat: Ansoft plot data file
%
% Note :
% ------
% In HFSS's scripting help (scripting.pdf), the example given is:
%   oDesign.ExportToFile "Plot1", "c:\report1.dat"
% However, it is wrong, since it should use oModule, instead of
% oDesign.
%
% Example :
% ---------
% hfssExportToFile(fid, 'Plot1', 'MyData', 'csv'); % Saves in the same dir.
% hfssExportToFile(fid, 'Plot2', 'C:\MyData2', 'tab');
% ----------------------------------------------------------------------------

% ----------------------------------------------------------------------------
% CHANGELOG
%
% 29-Sept-2012: *Initial release.
% ----------------------------------------------------------------------------

% ----------------------------------------------------------------------------
% Written by Daniel R. Prado
% danysan@gmail.com / drprado@tsc.uniovi.es
% 29 September 2012
% ----------------------------------------------------------------------------
function hfssExportToFile(fid, ReportName, FileName, Type)

% Arguments processor.
if (nargin < 4)
	error('Insufficient # of arguments !');
end

% Preamble.
fprintf(fid, '\n');
fprintf(fid, 'Set oModule = oDesign.GetModule("ReportSetup")\n');

% Parameters.
fprintf(fid, 'oModule.ExportToFile "%s", "%s.%s"\n', ReportName, FileName, Type);


%--- help for mdd/swz ---
%
%mdd/swz is a function.
%    [log_mdd, extras] = swz(obj, swz_pvalue, opts)
%


function n=length(X)
%LENGTH (overloaded)

n = max(X.dim);


function results = YahooGeoCodeAddress(appId, location)
% YAHOOGEOCODEADDRESS given a developer Application ID (appId)
% and string representing an address LOCATION, returns
% a structure containing the possible matches for the location. This
% function uses the Yahoo Maps Service - Geocoding API
% For more information please visit to get an appId
% http://developer.yahoo.com/maps/rest/V1/geocode.html

% Examples
% This is only a demo AppId 'YD-9G7bey8_JXxQP6rxl.fBFGgCdNjoDMACQA--'
% invalid data may result in using this AppId, you must get a real appId.
%
% results = GeoCodeAddress('YD-9G7bey8_JXxQP6rxl.fBFGgCdNjoDMACQA--','The MathWorks, Natick MA')
% results = GeoCodeAddress('YD-9G7bey8_JXxQP6rxl.fBFGgCdNjoDMACQA--','3 Apple Hill drive, Natick MA')
% results = GeoCodeAddress('YD-9G7bey8_JXxQP6rxl.fBFGgCdNjoDMACQA--','Natick MA')

% Throw a warning if they are using the demo AppId
if strcmp(appId,'YD-9G7bey8_JXxQP6rxl.fBFGgCdNjoDMACQA--')
   warning('YAHOOGEOCODE:usingdemoappid',...
       ['You are using the demo AppId provided by yahoo.', char(13),...
       'To get a valid AppID you must register at',char(13),...
       'http://developer.yahoo.com/maps/rest/V1/geocode.html']);
end

% The URL for Yahoos GeoCode API
url = 'http://local.yahooapis.com/MapsService/V1/geocode';

% Replace spaces with + signs, so it can go inside a URL
location = regexprep(location,'\s+','+');

% Query yahoo for the data
try
    docNode = xmlread([url '?appid=' appId '&location=' location]);
catch  %#ok<CTCH>
    error('YAHOOGEOCODE:urlreaderror',...
        ['Could not reach Yahoo server, please check your AppID ', char(13),...
        'to make sure it is valid.']);
end

% Check for errors
if docNode.getElementsByTagName('Error').getLength>0
   % Display the first error
   errorMessage = ...
       char(docNode.getElementsByTagName('Error').item(0).getTextContent);
   error('YAHOOGEOCODE:yahooerror',errorMessage);
end

% Loop over the results and create a struct for them
resultList = docNode.getElementsByTagName('Result');
results = [];
for idx = 1:resultList.getLength
    resultNode = resultList.item(idx-1);
    results(idx).precision = char(resultNode.getAttribute('precision')); %#ok<*AGROW>
    results(idx).Latitude = GetElementText(resultNode,'Latitude');
    results(idx).Longitude = GetElementText(resultNode,'Longitude');
    results(idx).Address = GetElementText(resultNode,'Address');
    results(idx).City = GetElementText(resultNode,'City');
    results(idx).State = GetElementText(resultNode,'State');
    results(idx).Zip = GetElementText(resultNode,'Zip');
    results(idx).Country = GetElementText(resultNode,'Country');
end
end

function elementText = GetElementText(resultNode,elementName)
% GETELEMENTTEXT given a result node and an element name
% returns the text within that node

elementText = ...
    resultNode.getElementsByTagName(elementName).item(0).getTextContent;

% remove any rogue commas and casts to a char
elementText = regexprep(char(elementText),',','');
end


function sendToSamiam(pedigree, factorList, alleleList, phenotypeList, positions, outputFileName)
% This function creates a file for Samiam using a list of factors and a
% pedigree.
% Input:
%   pedigree: Data structure that includes names and parent-child
%   relationships
%   factorList: List of factors
%	alleleList: List of alleles
%   phenotypeList: List of phenotypes
%   pedigreePositionsFileName: List with positions for the nodes for
%   each person in the family -- each row is for a person, and the contents
%   of each row is (genotype horizontal position, genotype vertical
%   position, phenotype horizontal position, phenotype vertical position)
%   outputFileName: Name of the file that will go to Samiam, should end in
%   .net

numPeople = length(pedigree.names);

outputFileName = strcat(outputFileName, '.net');
fid = fopen(outputFileName, 'w+');
fprintf(fid, '%s', 'net');
fprintf(fid, '\n', '');
fprintf(fid, '%s', '{');
fprintf(fid, '\n', '');
fprintf(fid, '\t', '');
fprintf(fid, '%s', 'node_size = (90 36);');
fprintf(fid, '\n', '');
fprintf(fid, '%s', '}');
fprintf(fid, '\n', '');
fprintf(fid, '\n', '');

for i = 1:numPeople
    % Make a genotype node and a phenotype node for each person
    fprintf(fid, '%s', 'node ');
    name = pedigree.names{i};
    fprintf(fid, '%s', name);
    fprintf(fid, '%s', 'Genotype');
    fprintf(fid, '\n', '');
    fprintf(fid, '%s', '{');
    fprintf(fid, '\n', '');
    fprintf(fid, '\t', '');
    fprintf(fid, '%s', 'label = "');
    fprintf(fid, '%s', name);
    fprintf(fid, '%s', 'Genoytpe";');
    fprintf(fid, '\n', '');
    fprintf(fid, '\t', '');
    fprintf(fid, '%s', 'position = (');
    fprintf(fid, '%d', positions(i,1));
    fprintf(fid, '%s', ' ');
    fprintf(fid, '%d', positions(i,2));
    fprintf(fid, '%s', ');');
    fprintf(fid, '\n', '');
    fprintf(fid, '\t', '');
    fprintf(fid, '%s', 'states = (');
    for j = 1:length(alleleList)
        % Iterate through alleles
        for k = j:length(alleleList)
            % Iterate through pairs of alleles
            fprintf(fid, '%s', '"');
            fprintf(fid, '%s', alleleList{j});
            fprintf(fid, '%s', alleleList{k});
            fprintf(fid, '%s', '"');
            if (j ~= length(alleleList)) || (k ~= length(alleleList))
                % Put in a space because there will be another genotype
                fprintf(fid, '%s', ' ');
            end
        end
    end
    fprintf(fid, '%s', ');');
    fprintf(fid, '\n', '');
    fprintf(fid, '%s', '}');
    fprintf(fid, '\n', '');
    fprintf(fid, '\n', '');

    fprintf(fid, '%s', 'node ');
    fprintf(fid, '%s', name);
    fprintf(fid, '%s', 'Phenotype');
    fprintf(fid, '\n', '');
    fprintf(fid, '%s', '{');
    fprintf(fid, '\n', '');
    fprintf(fid, '\t', '');
    fprintf(fid, '%s', 'label = "');
    fprintf(fid, '%s', name);
    fprintf(fid, '%s', 'Phenotype";');
    fprintf(fid, '\n', '');
    fprintf(fid, '\t', '');
    fprintf(fid, '%s', 'position = (');
    fprintf(fid, '%d', positions(i,3));
    fprintf(fid, '%s', ' ');
    fprintf(fid, '%d', positions(i,4));
    fprintf(fid, '%s', ');');
    fprintf(fid, '\n', '');
    fprintf(fid, '\t', '');
    fprintf(fid, '%s', 'states = (');
    for j = 1:length(phenotypeList)
        % Iterate through phenotypes
        fprintf(fid, '%s', '"');
        fprintf(fid, '%s', phenotypeList{j});
        fprintf(fid, '%s', '"');
        if j ~= length(phenotypeList)
            fprintf(fid, '%s', ' ');
        end
    end
    fprintf(fid, '%s', ');');
    fprintf(fid, '\n', '');
    fprintf(fid, '%s', '}');
    fprintf(fid, '\n', '');
    fprintf(fid, '\n', '');
end

for i = 1:2*numPeople
    % Iterate through factors and make a potential for each
    factor = factorList(i);
    fprintf(fid, '%s', 'potential (');
    firstNode = factor.var(1);
    if firstNode <= numPeople
        % Genotype node
        firstName = pedigree.names{firstNode};
        fprintf(fid, '%s', firstName);
        fprintf(fid, '%s', 'Genotype |');
        if pedigree.parents(firstNode, 1) ~= 0
            % Person has parents
            parentOneName = pedigree.names{factor.var(2)};
            parentTwoName = pedigree.names{factor.var(3)};
            fprintf(fid, '%s', ' ');
            fprintf(fid, '%s', parentOneName);
            fprintf(fid, '%s', 'Genotype ');
            fprintf(fid, '%s', parentTwoName);
            fprintf(fid, '%s', 'Genotype');
        end
        fprintf(fid, '%s', ')');
        fprintf(fid, '\n', '');
        fprintf(fid, '%s', '{');
        fprintf(fid, '\n', '');
        fprintf(fid, '\t', '');
        fprintf(fid, '%s', 'data = ');
        fprintf(fid, '%s', '(');
        for k = 1:length(factor.val)
            % Iterate through the values of the factor
            fprintf(fid, '%f', factor.val(k));
            if k == length(factor.val)
                % At end of factor
                fprintf(fid, '%s', ')');
                fprintf(fid, '%s', ';');
                fprintf(fid, '\n', '');
                fprintf(fid, '%s', '}');
                fprintf(fid, '\n', '');
                fprintf(fid, '\n', '');
            else
                fprintf(fid, '%s', ' ');
            end
        end
    else
        nameNode = factor.var(2);
        name = pedigree.names{nameNode};
        fprintf(fid, '%s', name);
        fprintf(fid, '%s', 'Phenotype | ');
        fprintf(fid, '%s', name);
        fprintf(fid, '%s', 'Genotype)');
        fprintf(fid, '\n', '');
        fprintf(fid, '%s', '{');
        fprintf(fid, '\n', '');
        fprintf(fid, '\t', '');
        fprintf(fid, '%s', 'data = ');
        for k = 1:length(factor.var)
            fprintf(fid, '%s', '(');
        end
        varIndexes = ones(1, length(factor.var));
        for k = 1:length(factor.val)
            % Iterate through the values of the factor
            fprintf(fid, '%f', factor.val(k));
            closedParen = 0;
            j = length(factor.var);
            while j > 0
                % Iterate through variables to see what closed parentheses are
                % necessary
                if varIndexes(j) == factor.card(j)
                    % Need to close parentheses
                    closedParen = closedParen + 1;
                    fprintf(fid, '%s', ')');
                    varIndexes(j) = 1;
                else
                    varIndexes(j) = varIndexes(j) + 1;
                    break
                end
                j = j - 1;
            end
            if (closedParen > 0) && (closedParen < length(factor.var))
                % Need a new line
                fprintf(fid, '\n', '');
                fprintf(fid, '\t', '');
                fprintf(fid, '\t', '');
                for j = 1:closedParen
                    % Make new open parentheses
                    fprintf(fid, '%s', '(');
                end
            elseif closedParen == length(factor.var)
                % At end of factor
                fprintf(fid, '%s', ';');
                fprintf(fid, '\n', '');
                fprintf(fid, '%s', '}');
                fprintf(fid, '\n', '');
                fprintf(fid, '\n', '');
            else
                fprintf(fid, '%s', ' ');
            end
        end
    end
end

fclose(fid);


%V_M2HTMLPWD - create html documentation of files in current directory
%
% M2HTML must be on the matlab path
% available from http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=4039&objectType=FILE

%      Copyright (C) Mike Brookes 1998
%      Version: $Id: v_m2htmlpwd.m 10865 2018-09-21 17:22:45Z dmb $
%
%   VOICEBOX is a MATLAB toolbox for speech processing.
%   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   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 can obtain a copy of the GNU General Public License from
%   http://www.gnu.org/copyleft/gpl.html or by writing to
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

pd=pwd;
tl=pd(max([find(pd=='\') find(pd=='/')])+1:end);
cd('..');
m2html('mfiles',tl,'htmldir',[tl '\doc']);
cd(pd);
winopen(['doc\' tl '\index.html']);


function b = strendswith(s, pat)
%STRENDSWITH Determines whether a string ends with a specified pattern
%
%   b = strstartswith(s, pat);
%       returns whether the string s ends with a sub-string pat.
%

%   History
%   -------
%       - Created by Dahua Lin, on Oct 9, 2008
%

%% main

sl = length(s);
pl = length(pat);

b = (sl >= pl && strcmp(s(sl-pl+1:sl), pat)) || isempty(pat);


% -*- INTERNAL UNDOCUMENTED FUNCTION -*-
function msh = msh_2d (breaks, qn, qw, geo, varargin)

warning ('geopdes:obsolete', 'The class MSH_2D is obsolete. Using MSH_CARTESIAN instead')

msh = msh_cartesian (breaks, qn, qw, geo, varargin{:});


function startParallelPool(appFigure, writeOutput, numWorkers)
    p = gcp('nocreate');
    if(isempty(p) || p.NumWorkers ~= numWorkers)
        try
            beep off;
            %                     h = msgbox('Attempting to start parallel computing workers.  Please wait...','modal');
            h = uiprogressdlg(appFigure, 'Message', 'Attempting to start parallel computing workers.  Please wait...', ...
                'Title','Launch Vehicle Designer', ...
                'Indeterminate','on');

            if(not(isempty(p)))
                delete(p);
            end

            pp=parpool('local',numWorkers);
            pp.IdleTimeout = 99999; %we don't want the pool to shutdown
            if(isvalid(h))
                close(h);
            end
            writeOutput('Parallel optimization mode enabled.','append');
            beep on;
        catch ME
            if(ishandle(h))
                close(h);
            end
            msg = sprintf('Parallel mode start failed.  Optimization will run in serial.  Message:\n\n%s',ME.message);
            %                     msgbox(msg);
            uialert(appFigure, msg, 'Launch Vehicle Designer', "Icon",'warning');
            disp(ME.message);
            beep on;
        end
    else
        writeOutput('Parallel optimization mode enabled.','append');
    end
end


function mlstripcommentsfile(infile, outfile)
%MLSTRIPCOMMENTSFILE Strip comments from a file with MATLAB code.
%
%   MLSTRIPCOMMENTSFILE(INFILE, OUTFILE) reads the m-file INFILE, line by line,
%   strips all MATLAB comments , and writes the result to the file OUTFILE.
%
%   Note that you should never specify the same value for INFILE and OUTFILE.
%   Since the output file is opened for writing before any data is read from
%   the input file, the file will be empty and the data will be lost.
%
%   See also MLSTRIPCOMMENTSFID, MLSTRIPCOMMENTSSTR.

%   Author:      Peter J. Acklam
%   Time-stamp:  2004-03-18 08:23:19 +0100
%   E-mail:      pjacklam@online.no
%   URL:         http://home.online.no/~pjacklam

   % Check number of input arguments.
   error(nargchk(1, 2, nargin));

   % See if the input file exists.
   if ~exist(infile, 'file')
      error([infile ': no such file or directory.']);
   end

   % Open the input file for reading.
   ifid = fopen(infile, 'rt');
   if ifid < 0
      error([infile ': can''t open file for reading.']);
   end

   % Open the output file for writing.
   ofid = fopen(outfile, 'wt');
   if ofid < 0
      closefid(ifid, infile);
      error([outfile ': can''t open file for writing.']);
   end

   % Strip MATLAB comments.
   status = mlstripcommentsfid(ifid, ofid);

   % See if an error occurred while writing to file.
   if status < 0
      closefid(ifid, infile);
      closefid(ofid, outfile);
      error([outfile ': error while writing to file.']);
   end

   % Close input and output file handles.
   closefid(ifid, infile);
   closefid(ofid, outfile);

function closefid(fid, filename)
%CLOSEFID Close a file identifier.
%
%   CLOSEFID(IFID, FILENAME) closes the specified file identifier.

   status = fclose(fid);
   if status < 0
      error([filename ': can''t close file.']);
   end


function GCO_LoadLib()
% GCO_LoadLib    Attempt to load the GCO_MATLAB library.
%    GCO_LoadLib is used internally by all other GCO_MATLAB commands
%    to compile (if necessary), load, and bind the wrapper library.

if (isempty(getenv('GCO_MATLAB')))
	GCO_BuildLib(struct('Force',false));
	if (exist('gco_matlab') ~= 3)
	    error('Failed to load gco_matlab library');
	end
	warning on GCO:int32;
	setenv('GCO_MATLAB','LOADED'); % environment variables 10x faster than 'exists'
end

end


function PTKSaveTreeAsNodes(tree_root, file_path, filename_prefix, coordinate_system, template_image, reporting)
    % PTKSaveTreeAsNodes. Exports a tree structure into node and element files
    %
    % Two text files are produced; a node file and an element file.
    %
    % The node file describes points which comprise the start point of the
    % tree (at the top of the trachea), each bifurcation point, and each
    % end point. The first line contains the number of node points.
    % Subequent lines are in the following text format:
    % node_number, x_coord, y_coord, z_coord, radius_approx, is_bifurcation_point
    %
    % Note the radius approximation is for the element ending at this node.
    %
    % The element file describes which nodes are linked together.
    % The first line contains the number of element points.
    % Subsequent lines are in the following text format:
    % node_1, node_2
    % where node_1 and node_2 are connected by the tree
    %
    %     Syntax
    %     ------
    %
    %         PTKSaveTreeAsNodes(tree_root, file_path, base_filename, reporting)
    %
    %             tree_root       is the root branch in a PTKTreeModel structure
    %             file_path       is the path where the node and element files
    %                             are to be stored
    %             filename_prefix is the filename prefix. The node and element
    %                             files will have '_node.txt' and '_element.txt'
    %                             appended to this prefix before saving.
    %             coordinate_system  a MimCoordinateSystem enumeration
    %                             specifying the coordinate system to use
    %             template_image  A PTKImage providing voxel size and image size
    %                             parameters
    %             reporting       an object implementing CoreReportingInterface
    %                             for reporting progress and warnings
    %
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2012.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    if nargin < 4
        reporting.Error('PTKSaveTreeAsNodes:BadArguments', 'No coordinate_system parameter specified');
    end

    if ~isa(coordinate_system, 'MimCoordinateSystem')
        reporting.Error('PTKSaveTreeAsNodes:BadArguments', 'coordinate_system parameter is not of type MimCoordinateSystem');
    end

    reporting.ShowProgress('Saving tree');
    reporting.UpdateProgressValue(0);

    node_file_name = fullfile(file_path, [filename_prefix '_node.txt']);
    element_file_name = fullfile(file_path, [filename_prefix '_element.txt']);

    linear_branch_list = tree_root.GetBranchesAsList;

    num_branches = length(linear_branch_list);

    % Create the node file (contains the coordinates and radius)
    node_file_handle = fopen(node_file_name, 'w');
    if node_file_handle == -1
        reporting.Error('PTKSaveTreeAsNodes:CreateFileFailed', ['I could not create the file ' node_file_name '. Please check the disk permissions to ensure I have write access.']);
    end

    element_file_handle = fopen(element_file_name, 'w');
    if element_file_handle == -1
        fclose(node_file_handle);
        reporting.Error('PTKSaveTreeAsNodes:CreateFileFailed', ['I could not create the file ' element_file_name '.']);
    end

    % The first file entry is the number of nodes
    fprintf(node_file_handle, '%u\r\n', num_branches);
    fprintf(element_file_handle, '%u\r\n', num_branches);

    % Create the first node from the trachea start point. The first element
    % connects this point to itself
    first_point = tree_root.StartPoint;

    dicom_coordinates = MimImageCoordinateUtilities.ConvertFromPTKCoordinates([first_point.CoordX, first_point.CoordY, first_point.CoordZ], coordinate_system, template_image);
    start_x_mm = dicom_coordinates(1);
    start_y_mm = dicom_coordinates(2);
    start_z_mm = dicom_coordinates(3);

    start_radius_mm = tree_root.Radius;
    start_density_mgml = tree_root.Density;

    PrintNodeToFile(node_file_handle, 0, start_x_mm, start_y_mm, start_z_mm, start_radius_mm, start_density_mgml, false);
    PrintElementToFile(element_file_handle, 0, 0);

    % The first branch in the tree will be converted to a node at its endpoint.
    % We need this to be connected to the first node we created above, so set
    % its parent index to zero, the index of the first node
    linear_branch_list(1).TemporaryIndex = 0;
    current_node_index = 1;

    for branch = linear_branch_list
        reporting.UpdateProgressStage(current_node_index, num_branches);

        parent_node_index = branch.TemporaryIndex;

        % Write branch to node file (the end point will be the node coordinate).
        PrintBranchToFileAsNode(node_file_handle, current_node_index, branch, coordinate_system, template_image);

        % Write (parent, current_node_index) to element file
        PrintElementToFile(element_file_handle, parent_node_index, current_node_index)

        % Set the parent node index for each child branch to be the current branch
        % node index
        if ~isempty(branch.Children)
            for child = branch.Children
                child.TemporaryIndex = current_node_index;
            end
        end

        current_node_index = current_node_index + 1;
    end

    % Close the files
    fclose(node_file_handle);
    fclose(element_file_handle);

    reporting.CompleteProgress;
end

function PrintElementToFile(fid, parent_index, child_index)
    fprintf(fid, '%u,%u\r\n', parent_index, child_index);
end

function PrintBranchToFileAsNode(fid, node_index, branch, coordinate_system, template_image)

    % We define nodes using the end coordinate of each branch, since this is the
    % bifurcation point
    last_point = branch.EndPoint;

    dicom_coordinates = MimImageCoordinateUtilities.ConvertFromPTKCoordinates([last_point.CoordX, last_point.CoordY, last_point.CoordZ], coordinate_system, template_image);
    x_mm = dicom_coordinates(1);
    y_mm = dicom_coordinates(2);
    z_mm = dicom_coordinates(3);

    radius_mm = branch.Radius;
    density_mgml = branch.Density;

    is_final_node = isempty(branch.Children);
    PrintNodeToFile(fid, node_index, x_mm, y_mm, z_mm, radius_mm, density_mgml, is_final_node);
end

function PrintNodeToFile(fid, node_index, x_mm, y_mm, z_mm, radius_mm, density, is_final_node)
    if is_final_node
        is_final_node = 'y';
    else
        is_final_node = 'n';
    end
    output_string = sprintf('%u,%6.6g,%6.6g,%6.6g,%2.2g,%6.6g,%c\r\n', node_index, x_mm, y_mm, z_mm, radius_mm, density, is_final_node);
    fprintf(fid, regexprep(output_string, ' ', ''));
end


function [varargout] = rdir(rootdir,varargin)
% RDIR - Recursive directory listing
%
%  D = rdir(ROOT)
%  D = rdir(ROOT, TEST)
%  D = rdir(ROOT, TEST, RMPATH)
%  D = rdir(ROOT, TEST, 1)
%  D = rdir(ROOT, '', ...)
%  [D, P] = rdir(...)
%  rdir(...)
%
%
% *Inputs*
%
% * ROOT
%
% rdir(ROOT) lists the specified files.
% ROOT can be a pathname, filename, or can include both. One can use
% absolute and relative pathnames and wildcards (*). Wildcard can be placed
% anywhere and used many times like 'path*\*.m'
%
% One can also use a double wildcard (**) to match multiple directory
% levels. For example ROOT = 'path\**\*.m' will match all ".m" files in
% "path" and all subdirectories of "path".
%
% NOTE : ".svn" directories created by SubVersion (SVN) are excluded from
% the recursive listing.
%
% * TEST
%
% Optional test that can be performed on the returned files.
%
% TEST is a string indicating expression to be evaluated on selected field
% of rdir output.
% All fields (ie name, date, bytes, isdir and datenum) can be used.
%
% Tests are strings similar to what one would use in a "if" statement e.g.
%  'bytes>1024 & datenum>now-7'
%
% One can also use function like "regexp" or "strfind" with string fields
% like "name" and "date" e.g 'regexp(name, 'expr')'. In that case, tests
% that return a non empty value are considered as true.
%
% regexp(name, '(\.m$)|(\.mdl$)')
%
% Test can also be a function handle as used in arrayfun/cellfun, e.g.
% @(f)f.bytes>1024
%
% * RMPATH
%
% Optional path to remove from beginning of "name" field in returned
% output. Specified path must be common to all items found.
%
% If RMPATH = 1 or true, path to remove is part of ROOT before the first
% wildcard.
%
%
% *Outputs*
%
% * D
%
% D is a structure with the same fields as Matlab DIR output.
%
% The "name" field includes the relative path as well as the name to the
% file that was found. Path can be shorten or ommited when using 3rd
% argument RMPATH.
%
% * P
%
% Common path or RMPATH (if specified) for the file list returned in D.
%
% * Screen output
%
% If not output variable is specified then the output is sent to the
% screen.
%
%
% *Versions*
%
% * 1.0 - 2009, Gus Brown
% * 2.0 - 26/05/2011 Thomas Vanaret
%         No longer exclude all directories from a simple search (no *);
%         Fixing bug on returned path;
%         Exclude ".svn" directories;
%         Extended test possibilies;
%         Subfunctions created;
% * 2.1 - 14/07/2011 Thomas Vanaret
%         New argument allowing to remove common path from name;
%         Comments review;
% * 2.2 - 20/12/2011 Thomas Vanaret
%         Fixing bug on display with 0b files;
%         Specific display when no file match filter;
% * 2.3 - 19/01/2014 Thomas Vanaret
%         Adding improvements suggested by X. Mo :
%         - function handle as TEST input
%         - code optimisation (avoiding loop)
%         Fixing possible bug when using a wildcard at the beginning;
%         Common path as 2nd optionnal output;
%
%
% *Examples*
%
%   D = rdir('*.m');
%     for ii=1:length(D), disp(D(ii).name); end;
%
%   % to find all files in the current directory and sub directories
%   D = rdir('**\*')
%
%   % If no output is specified then the files are sent to
%   % the screen.
%   rdir('c:\program files\windows *\*.exe');
%   rdir('c:\program files\windows *\**\*.dll');
%
%   % Using the test function to find files modified today
%   rdir('c:\win*\*','datenum>floor(now)');
%   % Using the test function to find files of a certain size
%   rdir('c:\program files\win*\*.exe','bytes>1024 & bytes<1048576');
%   % Using the test function to find files modified in 2011
%   rdir('c:\win*\*','strfind(date, ''2011'')');
%
%   % Using the 3rd input to shorten output name
%   rdir([matlabroot, '\*.txt'], '', 'C:\Program Files\')
%   % Using the 3rd input to shorten output name
%   rdir([matlabroot, '\*.txt'], '', 1)
%
%
% See also DIR
%

%--------------------------------------------------------------------------
%% Input validation

% use the current directory if nothing is specified
if ~exist('rootdir','var'),
  rootdir = '*';
end

prepath = '';       % the path before the wild card
wildpath = '';      % the path wild card
postpath = rootdir; % the path after the wild card
I = find(rootdir==filesep,1,'last');

% Directory separator for current platform
if filesep == '\'
  % On PC, filesep is '\'
  anti_filesep = '/';
else
  % On UNIX system, filesep is '/'
  anti_filesep = '\';
end

if isempty(I) && ~isempty(strfind(rootdir, anti_filesep))
  error([mfilename, ':FileSep'],...
    'Use correct directory separator "%s".', filesep)
end

%--------------------------------------------------------------------------
%% Split rootdir
% split the file path around the wild card specifiers

if ~isempty(I),
  prepath = rootdir(1:I);
  postpath = rootdir(I+1:end);
  I = find(prepath=='*',1,'first');
  if ~isempty(I),
    postpath = [prepath(I:end) postpath];
    prepath = prepath(1:I-1);
    I = find(prepath==filesep,1,'last');
    if ~isempty(I),
      wildpath = prepath(I+1:end);
      prepath = prepath(1:I);
    end;
    I = find(postpath==filesep,1,'first');
    if ~isempty(I),
      wildpath = [wildpath postpath(1:I-1)];
      postpath = postpath(I:end);
    end;
  end;
end;

% disp([' "' prepath '" ~ "' wildpath '" ~ "' postpath '" ']);

%--------------------------------------------------------------------------
%% Recursive listing
% Search for matching files until all wildcards have been considered.

if isempty(wildpath)
  % If no directory wildcards then just get files and directories list

  D = dir([prepath postpath]);

  % Exclude ".", ".." and ".svn" directories from the list
  excl = isdotdir(D) | issvndir(D);
  D(excl) = [];

  if isdir([prepath postpath]);
    fullpath = [prepath postpath];
  else
    fullpath = prepath;
  end

  % Place directories on the top of the list
  is_dir = [D.isdir]';
  D = [D(is_dir); D(~is_dir)];

  % Add path before name
  for ii = 1:length(D)
    D(ii).name = fullfile(fullpath, D(ii).name);
  end

  % disp(sprintf('Scanning "%s"   %g files found',[prepath postpath],length(D)));

elseif strcmp(wildpath,'**')
  % A double wildcards directory means recurs down into sub directories

  % first look for files in the current directory (remove extra filesep)
  D = rdir([prepath postpath(2:end)]);

  % then look for sub directories
  D_sd = dir([prepath '*']);

  % Exclude ".", "..", ".svn" directories and files from the list
  excl = isdotdir(D_sd) | issvndir(D_sd) | ~([D_sd.isdir]');
  D_sd(excl) = [];

  % Process each sub directory found
  % Performance tweak: avoid growing array within loop (X. Mo)
  c_D = arrayfun(@(x) rdir([prepath x.name filesep wildpath postpath]),...
    D_sd, 'UniformOutput', false);

  D = [D; cell2mat( c_D ) ];

else
  % Process directory wild card looking for sub directories that match

  D_sd = dir([prepath wildpath]);

  % Exclude ".", "..", ".svn" directories and files from the list
  excl = isdotdir(D_sd) | issvndir(D_sd) | ~([D_sd.isdir]');
  D_sd(excl) = [];

  if ~isdir(prepath) || ( numel(D_sd)==1 && strcmp(D_sd.name, prepath))
    % Fix case like rdir('path*\...') where prepath is not a full directoty
    % name OR case were prepath match a unique directory.
    % Previous "dir" return then the matching directory name(s).
    % prepath is cleaned to use them.
    %
    % In else case, prepath is a valid path which must be kept.
    prepath = '';
  end

  % Process each directory found
  Dt = dir('');

  c_D = arrayfun(@(x) rdir([prepath x.name postpath]),...
    D_sd, 'UniformOutput', false);

  D = [Dt; cell2mat( c_D ) ];

end

%--------------------------------------------------------------------------
%% Apply filter
% If specified, apply the filter to refine the search.

nb_before_filt = length(D);
warning_msg = '';

if (nargin>=2 && ~isempty(varargin{1})),
  try
    if isa(varargin{1}, 'function_handle')
        test_tf = arrayfun(varargin{1}, D);
    else
        test_tf = evaluate(D, varargin{1});
    end

    D = D(test_tf);

  catch
    if isa(varargin{1}, 'function_handle')
      test_expr = func2str(varargin{1});
    else
      test_expr = varargin{1};
    end

    warning_msg = sprintf('Invalid TEST "%s" : %s', test_expr, lasterr);
  end
end

%--------------------------------------------------------------------------
%% Remove path
% If specified, remove given or common path from each returned path.

common_path = '';
if (nargin>=3 && ~isempty(varargin{2})),

  arg2 = varargin{2};
  if ischar(arg2)
    common_path = arg2;
  elseif (isnumeric(arg2) || islogical(arg2)) && arg2
    common_path = prepath;
  end

  rm_path = regexptranslate('escape', common_path);

  % Check that path is common to all
  start = regexp({D.name}', ['^', rm_path]);

  % Convert to a logical.
  is_common = not( cellfun(@isempty, start) );

  if all(is_common)
    for k = 1:length(D)
      D(k).name = regexprep(D(k).name, ['^', rm_path], '');
    end

  else
    common_path = '';
  end

  % 19/07/2012 : ajouter common_path en sortie optionnelle

end

%--------------------------------------------------------------------------
%% Display listing if no output variables are specified
% Screen display.

nout = nargout;

if nout == 0
  if isempty(D)
    if nb_before_filt == 0
      fprintf('%s not found.\n', rootdir)
    else
      fprintf('No item matching filter.\n')
    end
  else

    if ~isempty(common_path)
     fprintf('All in : %s\n', common_path)
    end

    pp = {'' 'k' 'M' 'G' 'T'};
    for ii = 1:length(D)
      if D(ii).isdir
        % Directory item : display name
        disp(sprintf(' %29s %-64s','',D(ii).name));
      else
        % File item : display size, modification date and name
        sz = D(ii).bytes;
        if sz > 0
          ss = min(4,floor(log2(sz)/10));
        else
          ss = 0;
        end
        disp(sprintf('%4.0f %1sb  %20s  %-64s ',...
          sz/1024^ss, pp{ss+1}, datestr(D(ii).datenum, 0), D(ii).name));
      end
    end
  end
elseif nout == 1
  % send list out
  varargout{1} = D;
else
  % send list and common path out
  varargout{1} = D;
  varargout{2} = common_path;
end;

if ~isempty(warning_msg)
  warning([mfilename, ':InvalidTest'],...
    warning_msg); % ap aff
end

%---------------------------- end of main function ------------------------

%% ------------------------------------------------------------------------
function tf = issvndir(d)
% True for ".svn" directories.
% d is a structure returned by "dir"
%

is_dir = [d.isdir]';

is_svn = strcmp({d.name}, '.svn')';
%is_svn = false; % uncomment to disable ".svn" filtering

tf = (is_dir & is_svn);

%---------------------------- end of subfunction --------------------------

%% ------------------------------------------------------------------------
function tf = isdotdir(d)
% True for "." and ".." directories.
% d is a structure returned by "dir"
%

is_dir = [d.isdir]';

is_dot = strcmp({d.name}, '.')';
is_dotdot = strcmp({d.name}, '..')';

tf = (is_dir & (is_dot | is_dotdot) );

%---------------------------- end of subfunction --------------------------

%% ------------------------------------------------------------------------
function tf = evaluate(d, expr)
% True for item where evaluated expression is correct or return a non empty
% cell.
% d is a structure returned by "dir"
%

% Get fields that can be used
name = {d.name}'; %#ok<NASGU>
date = {d.date}'; %#ok<NASGU>
datenum = [d.datenum]'; %#ok<NASGU>
bytes = [d.bytes]'; %#ok<NASGU>
isdir = [d.isdir]'; %#ok<NASGU>

tf = eval(expr); % low risk since done in a dedicated subfunction.

% Convert cell outputs returned by "strfind" or "regexp" filters to a
% logical.
if iscell(tf)
  tf = not( cellfun(@isempty, tf) );
end

%---------------------------- end of subfunction --------------------------

%---------------------------- END OF FUNCTION -----------------------------


function [varargout]=wfdbloadlib(varargin)
%
% [isloaded,config]=wfdbloadlib(debugLevel,networkWaitTime)
%
% Loads the WDFDB libarary if it has not been loaded already into the
% MATLAB classpath. And optionally prints configuration environment and debug information
% regarding the settings used by the classes in the JAR file.
%
% Inputs:
%
% debugLevel
%       (Optional) 1x1 integer between 0 and 5 represeting the level of debug information to output from
%       Java class when output configuration information. Level 0 (no debug information),
%       level =5 is maximum level of information output by the class (logger set to finest). Default is level 0.
%
% networkWaitTime
%       (Optional) 1x1 integer representing the longest time in
%       milliseconds  for which the JVM should wait for a data stream from
%       PhysioNet (default is =1000  , ie one second). If you need to change this time to a
%       longer value across the entire toolbox, it is better modify to default value in the source
%       code below and restart MATLAB.
%
%
% Written by Ikaro Silva, 2013
%         Last Modified: April 7, 2015
% Since 0.0.1
%
%

%endOfHelp
mlock;
persistent isloaded wfdb_path wfdb_native_path config

%%%%% SYSTEM WIDE CONFIGURATION PARAMETERS %%%%%%%
%%% Change these values for system wide configuration of the WFDB binaries

%If you are using your own custom version of the WFDB binaries, set this to true
%NOTE: this parameter is completely ignored if the 'WFDB_COMMAND_PATH' parameter
%described above is set (i.e.: the library will used the WFDB commands located
% according to the path in 'WFDB_COMMAND_PATH').
%You will need to restart MATLAB/Octave if to sync the changes.
%The default is to used commands shipped with the toolbox, this location can be obtained by running the command:
%[~,config]=wfdbloadlib; config.WFDB_NATIVE_BIN
WFDB_CUSTOMLIB=0;

%WFDB_PATH: If empty, will use the default given config.WFDB_PATH
%this is where the toolbox searches  for data files (*.dat, *.hea etc).
%When unistalling the toolbox, you may wish to clear this directory to save space.
%See http://www.physionet.org/physiotools/wag/setwfd-1.htm for more details.
WFDB_PATH=[];

%WFDBCAL: If empty, will use the default giveng confing.WFDBCAL
%The WFDB library require calibration data in order to convert between sample values
%(expressed in analog-to-digital converter units, or adus) and physical units.
%See http://www.physionet.org/physiotools/wag/wfdbca-5.htm for more details.
WFDBCAL=[];

%CACHE: If CACHE==1, the toolbox will attemp to download data from
%CACHE_SOURCE to CACHE_DEST if the record is not found no the standard
%WFDB PATH. Change CACHE_DEST path to a PhysioNet mirror, if you wish to
%use a server closer to your geographical location. It is safe to delete files on
%CACHE_SOURCE, as they can be re-downloaded if need me.

CACHE=1; %Default is to use the cache system
CACHE_SOURCE=[]; %If empty, defaults to last element of WFDB_PATH
CACHE_DEST=[]; %If empty, defaults to WFDB_JAVA_HOME/../database

%debugLevel: Ouput JVM information while running commands
debugLevel=0;

%networkWaitTime: Setting maximum waiting period for fetching data from
%PhysioNet servers (default location: http://physionet.org/physiobank).
networkWaitTime=1000;

%%%% END OF SYSTEM WIDE CONFIGURATION PARAMETERS

%If called without arguments, keep the current configuration.
%Explicit arguments override the default settings above.
if(~isempty(config))
    debugLevel=config.DEBUG_LEVEL;
    networkWaitTime=config.NETWORK_WAIT_TIME;
end

inputs={'debugLevel','networkWaitTime'};
for n=1:nargin
    if(~isempty(varargin{n}))
        eval([inputs{n} '=varargin{n};']);
    end
end

inOctave=is_octave;
fsep=filesep;
if(ispc && inOctave)
	fsep=['\\']; %Need to escape '\' for regexp in Octave and Windows
end
if(isempty(isloaded))
    jar_path=which('wfdbloadlib');
    cut=strfind(jar_path,'wfdbloadlib.m');
    wfdb_path=jar_path(1:cut-1);

    if(~inOctave)
        ml_jar_version=version('-java');
    else
        %In Octave
        ml_jar_version=javaMethod('getProperty','java.lang.System','java.version');
        ml_jar_version=['Java ' ml_jar_version];
    end
    %Check if path has not been added yet
    wfdb_path=[wfdb_path 'wfdb-app-JVM7-0-10-0.jar'];
    javaaddpath(wfdb_path);
    isloaded=1;

    %Check if there are any empty space on the path directory, and
    %issue a warning if there is
    warnMe=strfind(wfdb_path,' ');
    if(~isempty(warnMe))
       warning('Your WFDB Toolbox installation  path contain white spaces!! This may cause issues with the WFDB Toolbox!');
       warning(['The installation path is set to: ' wfdb_path]);
    end

    if(isunix)
        % work around the fact that glibc requires thread stack size
        % to include space for thread-local variables
        % (https://sourceware.org/bugzilla/show_bug.cgi?id=11787)
        % and JVM "process reaper" threads use a tiny stack by default
        javaMethod('setProperty','java.lang.System','jdk.lang.processReaperUseDefaultStackSize','true');
    end
end

%set configuration
if(isempty(config))
        config.MATLAB_VERSION=version;
        config.inOctave=inOctave;
        if(inOctave)
            javaWfdbExec=javaObject('org.physionet.wfdb.Wfdbexec','wfdb-config',WFDB_CUSTOMLIB);
            javaWfdbExec.setLogLevel(debugLevel);
            config.WFDB_VERSION=char(javaMethod('execToStringList',javaWfdbExec,{'--version'}));
        else
            javaWfdbExec=org.physionet.wfdb.Wfdbexec('wfdb-config',WFDB_CUSTOMLIB);
            javaWfdbExec.setLogLevel(debugLevel);
            config.WFDB_VERSION=char(javaWfdbExec.execToStringList('--version'));
        end
        env=regexp(char(javaWfdbExec.getEnvironment),',','split');
        for e=1:length(env)
            tmpstr=regexp(env{e},'=','split');
            varname=strrep(tmpstr{1},'[','');
            varname=strrep(varname,' ','');
            varname=strrep(varname,']','');
            eval(['config.' varname '=''' tmpstr{2} ''';']);
        end
        config.MATLAB_PATH=strrep(which('wfdbloadlib'),'wfdbloadlib.m','');
        wver=regexp(wfdb_path,fsep,'split');
        config.WFDB_JAVA_VERSION=wver{end};
        config.MATLAB_ARCH=computer('arch');
        %Remove empty spaces from arch name
        del=strfind(config.osName,' ');
        config.osName(del)=[];

        %Define WFDB Environment variables
        if(isempty(WFDB_PATH))
            tmpCache=[config.MATLAB_PATH '..' filesep 'database' filesep];
            WFDB_PATH=['. ' tmpCache ' http://physionet.org/physiobank/database/'];
        end
        if(isempty(WFDBCAL))
            WFDBCAL=[config.WFDB_JAVA_HOME fsep 'database' fsep 'wfdbcal'];
        end
        config.WFDB_PATH=WFDB_PATH;
        config.WFDBCAL=WFDBCAL;
        config.WFDB_CUSTOMLIB=WFDB_CUSTOMLIB;
            warnMe=strfind(wfdb_path,' ');
    if(~isempty(warnMe))
       warning('Your WFDB Toolbox installation  path contain white spaces!! This may cause issues with the WFDB Toolbox!');
    end

    %Set CACHE configurations
    if(isempty(CACHE_SOURCE) && CACHE)
        ind=strfind(config.WFDB_PATH,'http');
        if(~isempty(ind))
            CACHE_SOURCE=config.WFDB_PATH(ind:end);
        else
            warning(['Could not set CACHE, CACHE_SOURCE invalid']);
            CACHE=0;
        end
    end
    config.CACHE_SOURCE=CACHE_SOURCE;

    if(isempty(CACHE_DEST) && CACHE)
        CACHE_DEST=[config.MATLAB_PATH '..' filesep 'database' filesep];
        if(~isdir(CACHE_DEST))
            mkdir(CACHE_DEST);
        end
        if(~isdir(CACHE_DEST))
            warning(['Could not set CACHE, CACHE_DEST directory does not exist: ' CACHE_DEST]);
            CACHE=0;
        end
    end
    config.CACHE_DEST=CACHE_DEST;
    config.CACHE=CACHE;

    %Set enviroment variables used by WFBD
    setenv('WFDB',config.WFDB_PATH);
    setenv('WFDBCAL',config.WFDBCAL);
end

%Set dynamic configuration parameters
config.DEBUG_LEVEL=debugLevel;
config.NETWORK_WAIT_TIME=networkWaitTime;

outputs={'isloaded','config'};
for n=1:nargout
    eval(['varargout{n}=' outputs{n} ';']);
end

%% subfunction that checks if we are in octave
function r = is_octave ()
    r = exist ('OCTAVE_VERSION', 'builtin')>0;


function [x,y] = swap(x,y)
tempx = x;
x = y;
y = tempx;
clear tempx;


function imageOrigin = getImageOrigin(MRSIStruct, dimension)
    switch(lower(dimension))
        case 'x'
            imageOrigin = MRSIStruct.imageOrigin(1);
        case 'y'
            imageOrigin = MRSIStruct.imageOrigin(2);
        case 'z'
            imageOrigin = MRSIStruct.imageOrigin(3);
        otherwise
            error('voxSize not found for dimension %s', dimension);
    end
end


function [iNewSurfaces, OutputSurfacesFiles, nVertices] = import_surfaces(iSubject, SurfaceFiles, FileFormat, isApplyMriOrient, OffsetMri, SelLabels, Comment)
% IMPORT_SURFACES: Import a set of surfaces in a Subject of Brainstorm database.
%
% USAGE: iNewSurfaces = import_surfaces(iSubject, SurfaceFiles, FileFormat, offset=[], SelLabels=[all], Comment=[])
%        iNewSurfaces = import_surfaces(iSubject)   : Ask user the files to import
%
% INPUT:
%    - iSubject     : Indice of the subject where to import the surfaces
%                     If iSubject=0 : import surfaces in default subject
%    - SurfaceFiles : Cell array of full filenames of the surfaces to import (format is autodetected)
%                     => if not specified : files to import are asked to the user
%    - FileFormat   : String representing the file format to import.
%                     Please see in_tess.m to get the list of supported file formats
%    - isApplyMriOrient: {0,1}
%    - OffsetMri    : (x,y,z) values to add to the coordinates of the surface before converting it to SCS
%    - SelLabels    : Cell-array of labels, when importing atlases
%    - Comment      : Comment of the output file
%
% OUTPUT:
%    - iNewSurfaces : Indices of the surfaces added in database

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

%% ===== PARSE INPUTS =====
% Check command line
if ~isnumeric(iSubject) || (iSubject < 0)
    error('Invalid subject indice.');
end
if (nargin < 3) || isempty(SurfaceFiles)
    SurfaceFiles = {};
    FileFormat = [];
else
    if ischar(SurfaceFiles)
        SurfaceFiles = {SurfaceFiles};
    end
    if (nargin == 2) || ((nargin >= 3) && isempty(FileFormat))
        error('When you pass a SurfaceFiles argument, FileFormat must be defined too.');
    end
end
if (nargin < 4) || isempty(isApplyMriOrient)
    isApplyMriOrient = [];
end
if (nargin < 5) || isempty(OffsetMri)
    OffsetMri = [];
end
if (nargin < 6) || isempty(SelLabels)
    SelLabels = [];
end
if (nargin < 7) || isempty(Comment)
    Comment = [];
end
iNewSurfaces = [];
OutputSurfacesFiles = {};
nVertices = [];
Labels = [];

% Get Protocol information
ProtocolInfo = bst_get('ProtocolInfo');
% Get subject directory
sSubject = bst_get('Subject', iSubject);
subjectSubDir = bst_fileparts(sSubject.FileName);
% Check the presence of the MRI: warning if no MRI
if isempty(sSubject.Anatomy)
    res = java_dialog('confirm', ...
        ['WARNING: To import correctly surface files, the subject''s MRI is needed.' 10 10 ...
        'Import subject''s MRI now?' 10 10], 'Import surfaces');
    if res
        import_mri(iSubject, [], [], 1);
        return
    end
end

%% ===== SELECT SURFACE FILES =====
% If surface files to load are not defined : open a dialog box to select it
if isempty(SurfaceFiles)
    % Get last used directories and formats
    LastUsedDirs = bst_get('LastUsedDirs');
    DefaultFormats = bst_get('DefaultFormats');
    if isempty(DefaultFormats.SurfaceIn)
        DefaultFormats.SurfaceIn = 'ALL';
    end
    % Get Surface files
    [SurfaceFiles, FileFormat, FileFilter] = java_getfile( 'open', ...
       'Import surfaces...', ...     % Window title
       LastUsedDirs.ImportAnat, ...   % Default directory
       'multiple', 'files', ...      % Selection mode
       bst_get('FileFilters', 'surface'), ...
       DefaultFormats.SurfaceIn);
    % If no file was selected: exit
    if isempty(SurfaceFiles)
        return
    end
    % Save default import directory
    LastUsedDirs.ImportAnat = bst_fileparts(SurfaceFiles{1});
    bst_set('LastUsedDirs', LastUsedDirs);
    % Save default import format
    DefaultFormats.SurfaceIn = FileFormat;
    bst_set('DefaultFormats',  DefaultFormats);
end

%% ===== APPLY MRI TRANSFORM =====
% Load MRI
if ~isempty(sSubject.Anatomy)
    sMri = bst_memory('LoadMri', sSubject.Anatomy(sSubject.iAnatomy).FileName);
else
    sMri = [];
end
% If user transformation on MRI: ask to apply transformations on surfaces
isMni = isequal(FileFormat, 'MRI-MASK-MNI');
if ~isMni && isempty(isApplyMriOrient) && ~isempty(sMri) && isfield(sMri, 'InitTransf') && ~isempty(sMri.InitTransf)
    isApplyMriOrient = java_dialog('confirm', ['MRI orientation was non-standard and had to be reoriented.' 10 10 ...
                                   'Apply the same transformation to the surfaces ?' 10 ...
                                   'Default answer is: NO', 10 10], 'Import surfaces');
else
    isApplyMriOrient = 0;
end

%% ===== LOAD EACH SURFACE =====
% Process all the selected surfaces
for iFile = 1:length(SurfaceFiles)
    TessFile = SurfaceFiles{iFile};

    % ===== LOAD SURFACE FILE =====
    bst_progress('start', 'Importing tesselation', ['Loading file "' TessFile '"...']);
    % Load surfaces(s)
    [Tess, Labels] = in_tess(TessFile, FileFormat, sMri, OffsetMri, SelLabels);
    if isempty(Tess)
        bst_progress('stop');
        return
    end

    % ===== INITIALIZE NEW SURFACE =====
    % Get imported base name
    if strcmpi(FileFormat, 'FS')
        [tmp__, fBase, fExt] = bst_fileparts(TessFile);
        importedBaseName = [fBase, strrep(fExt, '.', '_')];
    else
        [tmp__, importedBaseName] = bst_fileparts(TessFile);
    end
    importedBaseName = strrep(importedBaseName, 'tess_', '');
    importedBaseName = strrep(importedBaseName, '_tess', '');
    importedBaseName = strrep(importedBaseName, 'subjectimage_', '');
    importedBaseName = strrep(importedBaseName, '_volatlas', '');
    % Only one surface
    if (length(Tess) == 1)
        % Surface mesh
        if isfield(Tess, 'Faces')
            NewTess = db_template('surfacemat');
            NewTess.Comment  = Tess(1).Comment;
            NewTess.Vertices = Tess(1).Vertices;
            if isfield(Tess, 'Faces')   % Volume meshes do not have Faces field
                NewTess.Faces = Tess(1).Faces;
            end
        % Volume FEM mesh
        else
            NewTess = Tess;
        end
    % Multiple surfaces
    else
        [Tess(:).Atlas] = deal(db_template('Atlas'));
        NewTess = tess_concatenate(Tess, [], [], Labels);
        NewTess.iAtlas  = find(strcmpi({NewTess.Atlas.Name}, 'Structures'));
        NewTess.Comment = importedBaseName;
    end
    % Comment
    if ~isempty(Comment)
        NewTess.Comment = Comment;
    elseif isempty(NewTess.Comment)
        NewTess.Comment = importedBaseName;
    end

    % ===== APPLY MRI ORIENTATION =====
    if isApplyMriOrient
        % History: Apply MRI transformation
        NewTess = bst_history('add', NewTess, 'import', 'Apply transformation that was applied to the MRI volume');
        % Apply MRI transformation
        NewTess = ApplyMriTransfToSurf(sMri.InitTransf, NewTess);
    end

    % ===== SAVE BST FILE =====
    % History: File name
    NewTess = bst_history('add', NewTess, 'import', ['Import from: ' TessFile]);
    % Produce a default surface filename (surface of volume mesh)
    if isfield(NewTess, 'Faces')
        BstTessFile = bst_fullfile(ProtocolInfo.SUBJECTS, subjectSubDir, ['tess_' importedBaseName '.mat']);
    else
        BstTessFile = bst_fullfile(ProtocolInfo.SUBJECTS, subjectSubDir, ['tess_fem_' importedBaseName '.mat']);
    end
    % Make this filename unique
    BstTessFile = file_unique(BstTessFile);
    % Save new surface in Brainstorm format
    bst_save(BstTessFile, NewTess, 'v7');

    % ===== UPDATE DATABASE ======
    % Add new surface to database
    BstTessFileShort = file_short(BstTessFile);
    iNewSurfaces(end+1) = db_add_surface(iSubject, BstTessFileShort, NewTess.Comment);
    % Unload surface from memory (if this surface with the same name was previously loaded)
    bst_memory('UnloadSurface', BstTessFile);
    % Save output filename
    OutputSurfacesFiles{end+1} = BstTessFile;
    % Return number of vertices
    nVertices(end+1) = length(NewTess.Vertices);
end

% Save database
db_save();
bst_progress('stop');
end

%% ===== APPLY MRI ORIENTATION =====
function sSurf = ApplyMriTransfToSurf(MriTransf, sSurf)
    % Apply transformation to vertices
    sSurf.Vertices = ApplyMriTransfToPts(MriTransf, sSurf.Vertices);
    % Update faces order: If the surfaces were flipped an odd number of times, invert faces orientation
    if (mod(nnz(strcmpi(MriTransf(:,1), 'flipdim')), 2) == 1)
        sSurf.Faces = sSurf.Faces(:,[1 3 2]);
    end
end

function pts = ApplyMriTransfToPts(MriTransf, pts)
    % Apply step by step all the transformations that have been applied to the MRI
    for i = 1:size(MriTransf,1)
        ttype = MriTransf{i,1};
        val   = MriTransf{i,2};
        switch (ttype)
            case 'flipdim'
                % Detect the dimensions that have constantly negative coordinates
                iDimNeg = find(sum(sign(pts) == -1) == size(pts,1));
                if ~isempty(iDimNeg)
                    pts(:,iDimNeg) = -pts(:,iDimNeg);
                end
                % Flip dimension
                pts(:,val(1)) = val(2)/1000 - pts(:,val(1));
                % Restore initial negative values
                if ~isempty(iDimNeg)
                    pts(:,iDimNeg) = -pts(:,iDimNeg);
                end
            case 'permute'
                pts = pts(:,val);
            case 'vox2ras'
                % Do nothing, applied earlier
        end
    end
end


function name = p26_name ( )

%*****************************************************************************80
%
%% P26_NAME returns the name of problem 26.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 March 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, string NAME, the name of the problem.
%
  name = 'Patterson #1';

  return
end


function [ref,listRxnColour] = addColour(parsed,listRxn_Color,colorScheme)
% Changes colour attributes of the reaction links in a parsed `CellDesigner`
% model structure given a list of reaction IDs
%
% USAGE:
%
%    [ref, listRxnColour] = addColour(parsed, listRxn_Color, colorScheme)
%
% INPUTS:
%    parsed:          A parsed model structure generated by `parseCD` function
%    listRxn_Color:   A list of reaction IDs that need to be highilighted by
%                     changing the colour attributes of the reaciton links in
%                     the `CellDesigner` model. The first column stores a list
%                     of reaction IDs whose reaction links need to be
%                     highlighted, whereas the second column saves a list of
%                     html Colours.
%
% OUTPUT:
%
%    ref:             An updated parsed `CellDesigner` model structure
%    listRxnColour:
%
% .. Author: - Longfei Mao October 2014

if nargin<3

    colorScheme=2;

end

ref=parsed;
listRxn=listRxn_Color(:,1); % coloumn 1: reaction IDs;
a=size(listRxn_Color)
if length(a)<2
    listColor=[];
    listColor=listRxn_Color(:,2); % coloumn 2: html colour codes;
    p=1;
else
    p=0;
end

cScheme={{'#f16359';'#f18d59';'#f9ea76';'#acf3be';'#117e9a'}; % 'Strawberry' % Strawberry Orchard Color Palette
    {'#def595';'#cae45b';'#81c828';'#3dc800';'#279700'};  % 'Spring' Spring Growth Color Palette
    {'#ffedad';'#ffd599';'#ffc471';'#ffb93f';'#ffac37'};  % 'Tangerine' Tangerine Color Palette
    {'#00f9ff';'#009fff';'#0078ff';'#005eff';'#0900ff'};  % Blue Vibes
    {'#fe8181';'#fe5757';'#fe2e2e';'#cb2424';'#b62020'}}  % Red pt1

hexCode={};

for i=1:size(cScheme,1);
    for m=1:size(cScheme{1},1)
        if length(cScheme{i}{m})<9;
            hexCode{i}{m}=[cScheme{i}{m}(1),'ff',cScheme{i}{m}(2:end)]
        end
    end
end

num=0;

%results=[];

[ID_row,ID_Column]=size(ref.r_info.ID);

for m=1:ID_row;
    for n=1:ID_Column;
        r=iscellstr(ref.r_info.ID(m,n));
        if ~r;
            %results(or,1)=m;
            %results(or,2)=n;
            ref.r_info.ID{m,n}=' '
        end;
    end;
end
% listRxnColour=listRxn;
column=[];
for r=1:length(listRxn);

%     if numCol>0;
%
%         indRxns=find(ismember(ref.r_info.ID(:,numCol),listRxn{r}));
%         newRxnName=ref.r_info.ID(indRxns,2);
%
%     else

        newRxnName=listRxn{r};
        id=find(ismember(ref.r_info.ID,listRxn(r)))
        if numel(id)>1;
            id=id(1);
        end
% %         if id
% %             [m,n]=size(ref.r_info.ID);
% %             if id>m*(n-1)  % the third column of ref.r_info.ID contains reaction ID; for example: {'re5160','re8','DESAT16_2'}
% %                 newRxnName=ref.r_info.ID{id-2*m}; % newRxnName is defined to be the ID in the first column of ref.r_info.ID.
% %                 column=3;
% %             end
% %         end
        found=0;
        if id

            for rr=1:n;
                if id<m
                    newRxnName=ref.r_info.ID{id};
                    break;
                elseif and(id>rr*m,id<(rr+1)*m);
                    newRxnName=ref.r_info.ID{id-rr*m};
                    break;
                end
            end
        else
            if ~isfield(ref,listRxn{r})
                newRxnName=strcat('R_',listRxn{r});
                if  isempty(strfind(newRxnName,'(e)'))
                    newRxnName=strrep(newRxnName,'(e)','_e');
                end
            end
        end

    if ~isfield(ref,newRxnName)
        disp(listRxn{r});
        fprintf('error ! the listRxn{%d}',r);
        r=r+1
    else
        [rw,cw]=size(ref.(newRxnName).color)
        for  ddr=1:rw
            if ischar(ref.(newRxnName).width{ddr,1}) % if it is char such as ('1.0');then convert it into double;
                ref.(newRxnName).width{ddr,1}=str2double(ref.(newRxnName).width{ddr,1})
            end
            %                 try
            w(1)=ref.(newRxnName).width{ddr,1}
            %             catch
            % %                 disp(w(1))
            %                  disp(newRxnName);
            %                 disp(ref.(newRxnName).width{ddr,1});
            %             end

            %disp(ref.(newRxnName).width(ddr,1));disp('dddd');
            %disp(w(1));
            %              if isempty(w)
            %                  w=0;
            %              end            %
            fprintf('w value is %d\n',w(1));
            if w(1)>=0&&w(1)<=10;  % flux ranges from 2 to 10 will be highligthed
                if p==0;
                    %                     the colours (Hex triplet, e.g.,
                    %                     https://closedxml.codeplex.com/wikipage?title=Excel%20Indexed%20Colors)
                    %% 'FF' as in '#FF0000FF' is the prefix

                    if  w(1)==0
                        colorStr='#ffaed5fc';
                    elseif w(1)>0&&w(1)<=3;
                        colorStr=hexCode{colorScheme}{1} % '#FF0000FF' % flux between 1 and 2 will be highlighted in blue.
                    elseif w(1)>2&&w(1)<=4
                        colorStr=hexCode{colorScheme}{2} % flux between 2 and 5 will be highlighted in pink.

                    elseif w(1)>3&&w(1)<=5;
                        colorStr=hexCode{colorScheme}{3}

                    elseif w(1)>4&&w(1)<=6;
                        colorStr=hexCode{colorScheme}{4}
                    elseif w(1)>6;
                        colorStr=hexCode{colorScheme}{5} % flux between 2 and 5 will be highlighted in red.
                    end
                    if w(1)~=0
                    num=num+1;
                    listRxnColour(num,1)={newRxnName};
                    listRxnColour(num,2)={colorStr};
                    end

                elseif p==1
                    colorStr=listColor{ddr};  % ddr is the row number for each reaction;
                end
                fprintf('p value is %d\n',p);
                colorStr=strrep(colorStr,'#','');
                fprintf('colorStr is %s\n',colorStr);
                if strcmp(newRxnName,'re9103');
                    disp('goodl');
                end

                for  ddc=1:cw
                    ref.(newRxnName).color{ddr,ddc}=colorStr;
                    fprintf('set %s ''s colour to %s \n',newRxnName,ref.(newRxnName).color{ddr,ddc});
                end
            end
        end

    end
end


function done = save_model_expansion(method,goal_vexity,F_graph,properties)
global ALREADY_MODELLED REMOVE_THESE_IN_THE_END ALREADY_MODELLED_INDEX

done = 0;

for variables = properties.models
    save_place = find(variables == ALREADY_MODELLED_INDEX);
    if ~isempty(save_place)%length(ALREADY_MODELLED)>=variables & ~isempty(ALREADY_MODELLED{variables})
        % Ouch, we have already modelled this-one
        if strcmpi(ALREADY_MODELLED{save_place}.method,method)
            % Ok, already modelled using same approach
            done = 1;
            return
        elseif strcmpi(ALREADY_MODELLED{save_place}.method,'graph') & (strcmpi(method,'callback') | strcmpi(method,'integer') | strcmpi(method,'exact'))
            % Replace old graph model with exact model
            REMOVE_THESE_IN_THE_END = [REMOVE_THESE_IN_THE_END  ALREADY_MODELLED{save_place}.index];
            ALREADY_MODELLED{save_place}.goal_vexity = goal_vexity;
            ALREADY_MODELLED{save_place}.method = method;
            ALREADY_MODELLED{save_place}.index  = getlmiid(F_graph);
            ALREADY_MODELLED{save_place}.properties  = properties;
        elseif ((strcmpi(ALREADY_MODELLED{save_place}.method,'integer') | strcmpi(ALREADY_MODELLED{save_place}.method,'exact') | strcmpi(ALREADY_MODELLED{save_place}.method,'callback')) & strcmpi(method,'graph'))
            % Keep old stuff, we are done
            done = 1;
            return
        end
    else
        ALREADY_MODELLED{end+1}.goal_vexity = goal_vexity;
        ALREADY_MODELLED{end}.method = method;
        ALREADY_MODELLED{end}.index  = getlmiid(F_graph);
        ALREADY_MODELLED{end}.properties = properties;
        ALREADY_MODELLED_INDEX = [ALREADY_MODELLED_INDEX;variables];
    end
end


function g = hsvargplvmLogLikeGradients(model)

%%%%%TEMP: to test the parallel function
   %g=hsvargplvmLogLikeGradientsPar(model);
   %return

%%%%%%

try
    pool_open = matlabpool('size')>0;
catch e
    pool_open = 0;
end

if pool_open && (isfield(model,'parallel') && model.parallel)
    % Run the parallel version of the current function.
    g=hsvargplvmLogLikeGradientsPar(model);
    % A 'dirty' trick to fix some parameters
    if isfield(model, 'fixParamIndices') && ~isempty(model.fixParamIndices)
        g(model.fixParamIndices) = 0;
    end
    return
end

if (model.H == 1 && isfield(model.layer{1}, 'dynamics') && ~isempty(model.layer{1}.dynamics))
    model.layer{1}.numModels = model.layer{1}.M;
    for m = 1:length(model.layer{1}.comp)
        model.layer{1}.comp{m}.vardist = model.layer{1}.vardist;
        model.layer{1}.comp{m}.dynamics = model.layer{1}.dynamics;
    end
    g = svargplvmLogLikeGradients(model.layer{1});
    %-----TMP
%     mm = model.layer{1}.comp{1};
%     mm.dynamics = model.layer{1}.dynamics;
%     mm.vardist = model.layer{1}.vardist;
%     pp = vargplvmExtractParam(mm);
%     mm = vargplvmExpandParam(mm, pp);
%     g = vargplvmLogLikeGradients(mm);
    %---
    % A 'dirty' trick to fix some parameters
    if isfield(model, 'fixParamIndices') && ~isempty(model.fixParamIndices)
        g(model.fixParamIndices) = 0;
    end
    return
end

g_leaves = hsvargplvmLogLikeGradientsLeaves(model.layer{1});

[g_nodes g_sharedLeaves] = hsvargplvmLogLikeGradientsNodes(model);
% Amend the vardistr. derivatives of the leaves only with those of the
% higher layer.
%%% TEMP %%%% !!
%g_leaves(1:model.layer{1}.vardist.nParams) = g_leaves(1:model.layer{1}.vardist.nParams).*0;
%%%%%%%%%%
g_leaves(1:model.layer{1}.vardist.nParams) = g_leaves(1:model.layer{1}.vardist.nParams) + g_sharedLeaves;

if model.H > 1 % NEW
    g_entropies = hsvargplvmLogLikeGradientsEntropies(model.layer{1});
else
    g_entropies = zeros(1,model.layer{1}.N*model.layer{1}.q);
end

% This is the gradient of the entropies (only affects covars). It's just -0.5*I
N = model.layer{1}.N;
Q1 = model.layer{1}.q;
%g_entropies = -0.5.*g_leaves(N*Q1+1:model.layer{1}.vardist.nParams);
g_leaves(N*Q1+1:model.layer{1}.vardist.nParams) = g_leaves(N*Q1+1:model.layer{1}.vardist.nParams) + g_entropies;

% Augment the derivatives of the vardistr. covars of each layer with the derivs.
% of the entropies (the leaves are done separately)
% Remember g_nodes has derivs for h=2 and upwards!!!
offset=1;
for h=2:model.H-1
    % g_entropies is the same for all models (constant) or changes only if
    % each layer has different Q.
    g_entropiesCur = hsvargplvmLogLikeGradientsEntropies(model.layer{h});
    % Find the indices for the var. covariances %%%%%%%%%% THIS IS WRONG
    NQ=N*model.layer{h}.q; % size of var. means (and var covars)
    % Inds of the vardistr.covars of the prev. node
    indStart = offset+NQ;
    indEnd = indStart + NQ - 1;
    g_nodes(indStart:indEnd)=g_nodes(indStart:indEnd)+g_entropiesCur;
    offset = offset + model.layer{h}.nParams;
end
g = [g_leaves  g_nodes];

%%%-- TEMP
%params = hsvargplvmExtractParam(model);
%g=zeros(1, length(params));
%g(1:length([g_leaves g_nodes])) = [g_leaves g_nodes];
%return
%%--

dynUsed = (isfield(model.layer{end},'dynamics') && ~isempty(model.layer{end}.dynamics));
% We only have to amend the parent's var. distr. derivatives if there are
% no dynamics, because then the derivs. are only calculated from the
% likelihood term. If there are dynamics, the derivs are calculated from
% the svargplvm function including the KL part.
if ~dynUsed
    % Amend the derivatives of the parent's var.distr. with the terms coming
    % from the KL
    g_parent = hsvargplvmLogLikeGradientsParent(model.layer{model.H});
    startInd = model.nParams-model.layer{model.H}.nParams+1;
    endInd = startInd + model.layer{model.H}.vardist.nParams-1;
    g(startInd:endInd) = g(startInd:endInd) + g_parent;
end

%--- NEW!! TEST
% If there are priors on parameters, add the contribution here
% %{
for h=1:model.H
    priorFound{h} = 0;
    for mm=1:model.layer{h}.M
        if isfield(model.layer{h}.comp{mm}, 'paramPriors') && ~isempty(model.layer{h}.comp{mm}.paramPriors)
            priorFound{h} = 1;
            break
        end
    end
end
c=1;
for h=1:model.H
    % TODO!!! Perhaps this M>1 should be forbidden if ANY layer has a
    % prior, check!!
    if priorFound{h}
        ind_cur = c:c+model.layer{h}.nParams-1;
        c=c+length(ind_cur);
        if model.layer{h}.M > 1
            error('Not implemented M > 1 yet!');
        end
        g(ind_cur) = g(ind_cur) + vargplvmParamPriorGradients(model.layer{h}.comp{1}, length(g(ind_cur)));
    end
end
% %}
%----

% A 'dirty' trick to fix some parameters
if isfield(model, 'fixParamIndices') && ~isempty(model.fixParamIndices)
    g(model.fixParamIndices) = 0;
end

end

%---------------  HELPER LOCAL FUNCTIONS ------------------------------%

% The derivatives for the leaves, ie only the likelihood part (no KL) of
% the X^1 -> Y bayesian gplvm model (svargplvm, actually) of layer 1.
% The gradients of the vardist part of this layer are incomplete, because
% they need to be amended with the derivatives of the higher layer. This
% extra derivatives are found in hsvargplvmLogLikeGradientNodes and the
% summation is done in the higher level of this function.
function g = hsvargplvmLogLikeGradientsLeaves(model)

g = [];
gShared = zeros(1, model.vardist.nParams);

for i=1:model.M
    model.comp{i}.vardist = model.vardist;
    model.comp{i}.onlyLikelihood = true;
    g_i = vargplvmLogLikeGradients(model.comp{i});
    % Now add the derivatives for the shared parameters (vardist)
    gShared = gShared + g_i(1:model.vardist.nParams);
    g_i = g_i((model.vardist.nParams+1):end);
    g = [g g_i];
end
g = [gShared g];
end

% g: The gradients for the "likelihood"+vardist part (ie no entropies, no
% KL) of all nodes
% gSharedLeaves: The gradients for the vardist part of the variational
% distribution of the first layer only, which has to be amended with the
% gradient obtained by hsvargplvmLogLikeGradientsLeaves. The vardist.
% gradients of the variational distributions of the other layers (apart from
% the parent) is handled internally (no need if H == 2)
function [g gSharedLeaves] = hsvargplvmLogLikeGradientsNodes(model)
g=[]; % Final derivative
gSharedLeavesMeans = zeros(model.layer{1}.N, model.layer{1}.q);
gSharedLeavesCovars = zeros(model.layer{1}.N, model.layer{1}.q);
for h=2:model.H
    dynUsed = false;
    if (h==model.H && (isfield(model.layer{h},'dynamics') && ~isempty(model.layer{h}.dynamics)));
        dynUsed = true;
    end

    g_sharedPrevNode = zeros(1,model.layer{h-1}.vardist.nParams);
    gSharedNodeMeans = zeros(model.layer{h-1}.N, model.layer{h-1}.q);
    gSharedNodeCovars = zeros(model.layer{h-1}.N, model.layer{h-1}.q);

    g_h = []; % Derivative wrt params of layer h

    % If we don't have dynamics, then we compute the gradients only of the
    % likelihood part, and then g_parent (in the main function of this
    % file) is calculated and amends with the KL part. However, if dynamics
    % kernel is used, then the gradients of the var. params are using the
    % likelihood and KL part in a mixed way and have to be computed
    % together. This is taken care of in the svargplvmLogLikeGradients
    % function, since the upper layer is, basically, an svargplvm. In that
    % case, we won't have to add the g_parent, as we will do everything
    % here at once.
    if ~dynUsed
        gShared = zeros(1, model.layer{h}.vardist.nParams); % Derivatives of the var. distr. of layer h
        for i=1:model.layer{h}.M % Derivative of the likelihood term of the m-th model of layer h
            model.layer{h}.comp{i}.vardist = model.layer{h}.vardist;
            model.layer{h}.comp{i}.onlyLikelihood = true;

            % Calculates the derivatives for the vardist. params and the other
            % params (apart from the KL) of the layer h > 1
            g_i = vargplvmLogLikeGradients(model.layer{h}.comp{i});

            % Now add the derivatives for the shared parameters (vardist)
            gShared = gShared + g_i(1:model.layer{h}.vardist.nParams);

            % g_i will now hold all the non-vardist. derivatives (the rest are
            % taken care of in gShared)
            g_i = g_i((model.layer{h}.vardist.nParams+1):end);

            g_h = [g_h g_i];
        end % for m...
        g_h = [gShared g_h];
    else
        model.layer{h}.numModels = model.layer{h}.M;
        for i=1:model.layer{h}.M
            model.layer{h}.comp{i}.vardist = model.layer{h}.vardist;
            model.layer{h}.comp{i}.dynamics = model.layer{h}.dynamics;
        end
        g_h = svargplvmLogLikeGradients(model.layer{h});
    end

    % Find the quantity that needs to be added to the PREVIOUS gShared.
    % This quantity is either the 'gSharedLeaves' which is returned and
    % added outside of this function (in the main body) or the
    % gSharedPrevNode , which is added in this function, after this for
    % loop finishes.
    for i=1:model.layer{h}.M
        means = model.layer{h-1}.vardist.means;
        covars = model.layer{h-1}.vardist.covars;

        %if model.centerMeans
        % TODO
        %end

        if ~isempty(model.layer{h}.comp{i}.latentIndices)
            latInd = model.layer{h}.comp{i}.latentIndices;
        else
            % All indices (M == 1)
            latInd = 1:model.layer{h-1}.vardist.latentDimension;
        end
        % In this layer h the "means" ie the X of layer h-1 are
        % here outputs. If we also have multOutput option, i.e. only
        % the full output space "means" will be grouped into
        % smaller subpsaces as defined in latentIndices. If we
        % don't have the multOutput>1 option, then means/covars will be the
        % original ones.
        means = means(:, latInd);
        covars = covars(:, latInd);

        %-- Amend the gShared OF THE PREVIOUS LAYER with the new terms due to the expectation
        % If multOutput(h) is set, then the expectation of <\tilde{F}>_{q(X_{h-1}} will
        % be split into Q expectations wrt q(X_{h-1}(:,q)), q=1,...,Q. In
        % general (not tested yet!!!) it will not be grouped by q, but
        % it could be defined as arbitrary subsets of X_{h-1}.
        beta = model.layer{h}.comp{i}.beta;
        if h == 2
            %-- Previous layer is leaves
            % Amend for the F3 term of the bound
            gSharedLeavesMeans(:, latInd) = beta * ...
                model.layer{h}.comp{i}.Z' * means;
            gSharedLeavesCovars(:, latInd) = 0.5*beta * ...
                repmat(diag(model.layer{h}.comp{i}.Z), 1, size(means,2));

            % Amend for the F0 term of the bound
            gSharedLeavesMeans(:, latInd) = gSharedLeavesMeans(:, latInd) - beta * means;
            gSharedLeavesCovars(:, latInd) = gSharedLeavesCovars(:, latInd) - 0.5*beta * ones(size(gSharedLeavesCovars(:, latInd)));

            % Reparametrization: from dF/dS -> dF/d log(S)
            gSharedLeavesCovars(:, latInd) = covars.*gSharedLeavesCovars(:, latInd);
        else % h > 2
           % error('H > 2 not implemented yet!!')
            % TODO!!!! For > 2 layers:
            % Previous layer is intermediate nodes
            % TODO: Here, we don't return the result but we added directly
            % to the previous iterations derivative (since everything
            % happens in the same function).

            % These computations are as above for the leaves case...

            % Amend for the F3 term of the bound
            gSharedNodeMeans(:, latInd) = beta * ...
                model.layer{h}.comp{i}.Z' * means;
            gSharedNodeCovars(:, latInd) = 0.5*beta * ...
                repmat(diag(model.layer{h}.comp{i}.Z), 1, size(means,2));

            % Amend for the F0 term of the bound
            gSharedNodeMeans(:, latInd) = gSharedNodeMeans(:, latInd) - beta * means;
            gSharedNodeCovars(:, latInd) = gSharedNodeCovars(:, latInd) - 0.5*beta * ones(size(gSharedNodeCovars(:, latInd)));

            % Reparametrization: from dF/dS -> dF/d log(S)
            gSharedNodeCovars(:, latInd) = covars.*gSharedNodeCovars(:, latInd);
            gSharedNodeVardist = [gSharedNodeMeans(:)' gSharedNodeCovars(:)'];

            g_sharedPrevNode(1:model.layer{h-1}.vardist.nParams) = ...
                    g_sharedPrevNode(1:model.layer{h-1}.vardist.nParams) + gSharedNodeVardist;

        end
        %--
    end

    % (for H > 2)
    if h > 2
        % The gShared of the PREVIOUS iteration needs to be augmented
           % Inds of the vardistr of the prev. node
        indStart = length(g) - model.layer{h-1}.nParams+1;
        indEnd = indStart + model.layer{h-1}.vardist.nParams - 1;
        g(indStart:indEnd) = g(indStart:indEnd) + g_sharedPrevNode;
    end

    % Now we can add the g_h of the current iteration
    g = [g g_h];
end % for h...
gSharedLeaves = [gSharedLeavesMeans(:)' gSharedLeavesCovars(:)'];
end

% The entropies of all variational distributions q(X^h) (this does not
% include the parent var. distr q(Z), for which we need to instead
% calculate a KL quantity.
function g = hsvargplvmLogLikeGradientsEntropies(model)
g=0.5*ones(1,model.N * model.q);
if isfield(model, 'DEBUG_entropy') && model.DEBUG_entropy
    g = -g;
end
end

% This calculates the derivatives of the KL quantity of the parent node
% It can be sped up by NOT calculating gKern, gInd etc, which are not used.
function gVar = hsvargplvmLogLikeGradientsParent(modelParent)

if isfield(modelParent, 'learnInducing')
    learnInducing = modelParent.learnInducing;
else
    learnInducing = true;
end

model = modelParent.comp{1};
model.vardist = modelParent.vardist;

%--- Now this is "copied" from vargplvmLogLikeGradients
gVarmeans = - model.vardist.means(:)';
% !!! the covars are optimized in the log space (otherwise the *
% becomes a / and the signs change)
gVarcovs = 0.5 - 0.5*model.vardist.covars(:)';

%{
% The following is not needed... parent node is not connected to any
% inducing points...!!!
if isfield(model, 'fixInducing') & model.fixInducing
    % TODO!!!
    warning('Implementation for fixing inducing points is not complete yet...')
    % Likelihood terms (coefficients)
    [gK_uu, gPsi0, gPsi1, gPsi2, g_Lambda, gBeta, tmpV] = vargpCovGrads(model);

    % Get (in three steps because the formula has three terms) the gradients of
    % the likelihood part w.r.t the data kernel parameters, variational means
    % and covariances (original ones). From the field model.vardist, only
    % vardist.means and vardist.covars and vardist.lantentDimension are used.
    [gKern1, gVarmeans1, gVarcovs1, gInd1] = kernVardistPsi1Gradient(model.kern, model.vardist, model.X_u, gPsi1',learnInducing);
    [gKern2, gVarmeans2, gVarcovs2, gInd2] = kernVardistPsi2Gradient(model.kern, model.vardist, model.X_u, gPsi2,learnInducing);
    [gKern0, gVarmeans0, gVarcovs0] = kernVardistPsi0Gradient(model.kern, model.vardist, gPsi0);

    %%% Compute Gradients with respect to X_u %%%
    gKX = kernGradX(model.kern, model.X_u, model.X_u);
    % The 2 accounts for the fact that covGrad is symmetric
    gKX = gKX*2;
    dgKX = kernDiagGradX(model.kern, model.X_u);
    for i = 1:model.k
        gKX(i, :, i) = dgKX(i, :);
    end
    % Allocate space for gX_u
    gX_u = zeros(model.k, model.q);
    % Compute portion associated with gK_u
    for i = 1:model.k
        for j = 1:model.q
            gX_u(i, j) = gKX(:, j, i)'*gK_uu(:, i);
        end
    end
    % This should work much faster
    %gX_u2 = kernKuuXuGradient(model.kern, model.X_u, gK_uu);
    gInd = gInd1 + gInd2 + gX_u(:)';
    %gVarmeans(model.inducingIndices, :) = gVarmeans(model.inducingIndices,
    %:) + gInd; % This should work AFTER reshaping the matrices...but here
    %we use all the indices anyway.
    gVarmeans = gVarmeans + gInd;
end
%}

gVar = [gVarmeans gVarcovs];
if isfield(model.vardist,'paramGroups')
    gVar = gVar*model.vardist.paramGroups;
end

end


function json = spm_jsonread(filename, opts)
% JSON (JavaScript Object Notation) parser - a compiled routine
% FORMAT json = spm_jsonread(filename, opts)
% filename - name of a JSON file or JSON string
% json     - JSON structure
% opts     - structure of optional parameters:
%              replacementStyle: string to control how non-alphanumeric
%                characters are replaced {'underscore','hex','delete','nop'}
%                [Default: 'underscore']
%
% References:
%   JSON Standard: http://www.json.org/
%   JSMN C parser: http://zserge.com/jsmn.html
%   jsondecode: http://www.mathworks.com/help/matlab/ref/jsondecode.html
%__________________________________________________________________________
% Copyright (C) 2015-2017 Wellcome Trust Centre for Neuroimaging

% Guillaume Flandin
% $Id: spm_jsonread.m 7045 2017-03-17 10:41:12Z guillaume $

%-This is merely the help file for the compiled routine
error('spm_jsonread.c not compiled - see Makefile')


classdef  VideoMaker_TopOpt_levelSet3D_DoubleMirroring < VideoMaker_TopOpt_levelSet
  properties

  end

  methods (Access = public)

        function Make_video_design_variable(obj,output_video_name)
            post = Postprocess_TopOpt_levelSet();
            field2print = post.levelSet_name;
            componentfield = post.levelSet_name_component;
            obj.Make_video_characteristic_function(field2print,componentfield,output_video_name)
        end

  end

  methods (Access = private)
         function Make_video_characteristic_function(obj,field2print,componentfield,output_video_name_in)
            file_tcl_name = 'tcl_gid.tcl';
            file_list = obj.create_file_list(obj.iterations_to_print,obj.file_name,obj.files_folder);

            [output_video_name] = obj.replace_special_character(output_video_name_in);
            [output_photo]=obj.replace_special_character(strcat(obj.files_folder,'\',obj.file_name,'.png'));
            [file_list] = obj.replace_special_character(file_list);

            min_value = -1e-32;

            file_tcl_name_with_path = fullfile(obj.files_folder,file_tcl_name);
            file_path_in = fullfile(pwd,'FEM','PostProcess','Make_Video_characteristic3D_DoubleMirroring.tcl');
            filepath = obj.replace_special_character(file_path_in);

            fid = fopen(file_tcl_name_with_path,'w+');

            fprintf(fid,'GiD_Process PostProcess \n');
            fprintf(fid,'%s\n',['set arg1 "',file_list,'"']);
            fprintf(fid,'%s\n',['set arg2 "',output_video_name,'"']);
            fprintf(fid,'%s\n',['set arg3 "',field2print,'"']);
            fprintf(fid,'%s\n',['set arg4 "',componentfield,'"']);
            fprintf(fid,'%s\n',['set arg5 "',num2str(min_value),'"']);
            fprintf(fid,'%s\n',['set arg6 "',output_photo,'"']);

            fprintf(fid,'%s\n',['source "',filepath,'"']);
            fprintf(fid,'%s\n',['Make_Video_characteristic $arg1 $arg2 $arg3 $arg4 $arg5 $arg6']);
            fprintf(fid,'%s\n',['GiD_Process Mescape Quit']);
            fclose(fid);
            obj.execute_tcl_files(obj.gidPath,file_tcl_name_with_path)
        end

  end
end


function d = setyname(d, n)

%tstoolbox/@description/setyname
%   Syntax:
%     * d = setyunit(d, string)
%
%   Set signal's y-name
%   e.g. d = setyunit(d, 'V')
%
% Copyright 1997-2001 DPI Goettingen, License http://www.physik3.gwdg.de/tstool/gpl.txt

narginchk(2,2);

if isa(n, 'char')
	d.yname = n;
else
	error('Wrong type of argument(s) given');
end