function s = path_to_convert()
  % PATH_TO_CONVERT
  %
  % s = path_to_convert()
  %
  % Outputs:
  %   s path to convert executable
  %
  % See also: path_to_qslim
  %

  if ispc
    warning([ ...
      'Dear Ladislav, is there a standard place to put executables on a pc?' ...
      'Could you put convert there and change this accordingly?' ...
      'Thanks, Alec']);
    s = 'c:/prg/lib/convert/Release/convert.exe';
  elseif isunix || ismac
    % I guess this means linux
    [status, s] = system('which convert');
    s = strtrim(s);
    if isempty(s)
      guesses = { ...
        '/usr/local/bin/convert', ...
        '/opt/local/bin/convert'};
      E = cellfun(@(guess) exist(guess,'file'),guesses);
      assert(any(E),'Could not find convert');
      s = guesses{find(E,1,'first')};
    end
  end
end


function [betas] = esvm_perform_platt_calibration(grid, imageset, models, ...
                                                  params)
% Perform calibration by learning the sigmoid parameters (linear
% transformation of svm scores) for each model independently. This
% type of SVM classifier calibration is due to John Platt who used
% this trick to convert SVM output scors into probabilities for
% comparison.  If we perform an operation such as NMS, we will now
% have "comparable" scores.  This is performed on the 'trainval' set
% for PASCAL VOC.
%
% Copyright (C) 2011-12 by Tomasz Malisiewicz
% All rights reserved.
%
% This file is part of the Exemplar-SVM library and is made
% available under the terms of the MIT license (see COPYING file).
% Project homepage: https://github.com/quantombone/exemplarsvm

if length(grid) == 0 || length(models) == 0
  betas = [];
  ALL_bboxes = [];
  return;
end

if length(params.dataset_params.localdir) > 0
  CACHE_FILES = 1;
else
  CACHE_FILES = 0;
end

%if enabled, do NMS, if disabled return raw detections
DO_NMS = 0;

% if enabled, display images
display = params.dataset_params.display;

% if display is enabled and dump_images is enabled, then dump images
% into DUMPDIR
dump_images = 0;

models_name = '';
if length(models)>=1 && isfield(models{1},'models_name') && ...
      isstr(models{1}.models_name)
  models_name = models{1}.models_name;
end

DUMPDIR = sprintf('%s/www/calib/',params.dataset_params.localdir, ...
                  models_name);

if dump_images==1 && ~exist(DUMPDIR,'dir')
  mkdir(DUMPDIR);
end
% show A NxN grid of top detections (if display is turned on)
SHOW_TOP_N_SVS = 10;

if nargin < 1
  fprintf(1,'Not enough arguments, need at least the grid\n');
  return;
end

final_dir = ...
    sprintf('%s/models',params.dataset_params.localdir);

if CACHE_FILES == 1 && ~exist(final_dir','dir')
  mkdir(final_dir);
end

final_file = ...
    sprintf('%s/%s-betas.mat',...
            final_dir, ...
            models_name);

if CACHE_FILES == 1
  lockfile = [final_file '.lock'];
  if fileexists(final_file) || (mymkdir_dist(lockfile)==0)

    %wait until lockfiles are gone
    wait_until_all_present({lockfile},5,1);
    fprintf(1,'Loading final file %s\n',final_file);
    res = load_keep_trying(final_file);
    betas = res.betas;
    return;
  end
end

for i = 1:length(models)
  if ~isfield(models{i},'curid')
    models{i}.curid = '-1';
  end
end

model_ids = cellfun2(@(x)x.curid,models);
targets = 1:length(models);

cls = models{1}.cls;

%if isfield(params.dataset_params,'classes')
%  targetc = find(ismember(params.dataset_params.classes, ...
%                          models{1}.cls));
%else
targetc = models{1}.cls;
%end

%fprintf(1,'Preparing boxes for calibration\n');
for i = 1:length(grid)
  if mod(i,100)==0
    fprintf(1,'.');
  end
  cur = grid{i};

  %do not process grids with no bboxes
  if size(cur.bboxes,1) == 0
    continue;
  end

  if size(cur.bboxes,1) >= 1
    cur.bboxes(:,5) = 1:size(cur.bboxes,1);
    cur.coarse_boxes(:,5) = 1:size(cur.bboxes,1);
    if DO_NMS == 1
      cur.bboxes = esvm_nms_within_exemplars(cur.bboxes,.5);
      cur.coarse_boxes = cur.coarse_boxes(cur.bboxes(:,5),:);
    end

    if length(cur.extras)>0
      cur.extras.os = cur.extras.maxos(cur.bboxes(:,5));
      try
      cur.extras.os = cur.extras.os.* ...
          reshape(double(ismember(cur.extras.maxclass,targetc)),...
                  size(cur.extras.os));
      catch
        keyboard
      end

      % cur.extras.os = cur.extras.os.* ...
      %     reshape((cur.extras.maxclass(cur.bboxes(:,5)) == ...
      %              targetc),size(cur.extras.os));

    end
  end

  cur.bboxes(:,5) = grid{i}.index;
  cur.coarse_boxes(:,5) = grid{i}.index;

  coarse_boxes{i} = cur.coarse_boxes;
  bboxes{i} = cur.bboxes;

  %if we have overlaps, collect them
  if length(cur.extras) > 0

    %use all objects as ground truth
    %goods = 1:length(cur.extras.cats);

    %% find the ground truth examples of the right category
    %goods = find(ismember(cur.extras.cats,cls));

    exids = cur.bboxes(:,6);

    %if length(goods) == 0
    %  os{i} = zeros(size(bboxes{i},1),1);
    %else
    %  curos = cur.extras.os(:,goods);
    os{i} = cur.extras.maxos; %max(curos,[],2);
    %end
  else
    os{i} = zeros(size(bboxes{i},1),1);
  end

  scores{i} = cur.bboxes(:,7)';
end

ALL_bboxes = cat(1,bboxes{:});
ALL_coarse_boxes = cat(1,coarse_boxes{:});
ALL_os = cat(1,os{:});

curids = cellfun2(@(x)x.curid,grid);
% Pre-processing models for calibration

for exid = 1:length(models)
  fprintf(1,'.');
  sourcegrid = find(ismember(curids,models{exid}.curid));
  if length(sourcegrid) == 0
    sourcegrid = -1;
  end

  hits = find((ALL_bboxes(:,6)==exid));
  all_scores = ALL_bboxes(hits,end);
  all_os = ALL_os(hits,:);

  good_scores = all_scores(all_os>=.5);
  good_os = all_os(all_os>=.5);

  bad_scores = all_scores(all_os<.5);
  bad_os = all_os(all_os<.5);

  %add virtual sample at os=1.0, score=1.0
  %good_os = cat(1,good_os,1.0);
  %good_scores = cat(1,good_scores,1.0);

  if length(good_os) <= 1 || (length(bad_os) ==0)
    beta = [.1 100];
  else

    [aa,bb] = sort(bad_scores,'descend');
    curlen = min(length(bb),10000*length(good_scores));
    bb = bb(round(linspace(1,length(bb),curlen)));

    bad_scores = bad_scores(bb);
    bad_os = bad_os(bb);
    all_scores = [good_scores; bad_scores];
    all_os = [good_os; bad_os];

    [aaa,bbb] = sort(all_scores, 'descend');
    %bbb = bbb(1:min(1000,length(bbb)));
    %all_scores = all_scores(bbb);
    %all_os = all_os(bbb);
    beta = esvm_learn_sigmoid(all_scores, all_os);
  end

  if beta(1)<.001
    fprintf(1,['warning[esvm_perform_platt_calibration.m]: beta(1)' ...
               ' is low']);
    % beta(1) = .001;
  end

  betas(exid,:) = beta;

  if (sum(ismember(exid,targets))==0)
    continue
  end

  if display == 1

    figure(1)
    clf
    subplot(1,2,1)

    xs = linspace(min(all_scores),max(all_scores),1000);
    fx = @(x)(1./(1+exp(-beta(1)*(x-beta(2)))));

    plot(xs,fx(xs),'b','LineWidth',2)
    hold on
    plot(all_scores,all_os,'r.','MarkerSize',14)

    axis([min(xs) max(xs) 0 1])
    xlabel('SVM score')
    ylabel(sprintf('Max Overlap Score with %s',models{exid}.cls))

    title(sprintf('Learned Sigmoid \\beta=[%.3f %.3f]',beta(1), ...
                  beta(2)))

    subplot(1,2,2)
    Iex = convert_to_I(models{exid}.I);
    imagesc(Iex)
    plot_bbox(models{exid}.gt_box)
    axis image
    axis off

    title(sprintf('Exemplar %s.%d.%s',...
                  models{exid}.curid,...
                  models{exid}.objectid, ...
                  models{exid}.cls))
    drawnow
    snapnow

    bbs=ALL_coarse_boxes(hits,:);
    bbs_os = ALL_os(hits,:);
    [aa,bb] = sort(bbs(:,end),'descend');
    bbs_show = bbs(bb,:);

    %models{exid}.model.svids = {};
    %m = try_reshape(models{exid},bbs_show,100);

    %[models{exid}.model.svids,models{exid}.model.nsv] = ...
    %    esvm_reconstruct_features(bbs_show,100);%,'trainval','');

    models{exid}.model.svbbs = bbs_show;
    m2 = models(exid);
    if length(imageset) > 0
      m2{1}.train_set = imageset;
      m2{1}.model.svbbs(:,6) = 1;
      m2{1}.model.svxs = [];
      figure(445)
      clf
      imagesc(esvm_show_det_stack(m2{1},8))
      axis image
      axis off
      drawnow
      title(sprintf('Topdets Ex %s.%d.%s',...
                    models{exid}.curid,...
                    models{exid}.objectid, ...
                    models{exid}.cls))
      drawnow
      snapnow
    end
  end

  if (display == 0)
    continue
  end

  if dump_images == 1
    figure(2)
    filer = sprintf('%s/result.%d.%s.%s.png', DUMPDIR, ...
                    exid,models{exid}.cls,models{exid}.models_name);
    set(gcf,'PaperPosition',[0 0 20 20]);
    print(gcf,filer,'-dpng');

  else
    pause(.01)
  end
end

if CACHE_FILES == 1
  fprintf(1,['\nLoaded calibration parameters "betas", saving to' ...
             ' %s\n'],final_file);
  save(final_file,'betas');
  rmdir(lockfile);
end


function [paramsOut, okay] = MasterGUI(hObject, callbackdata, userData, EEG) %#ok<INUSL>
geometry = {1, [1, 1], [1, 1], [1, 1]};
geomvert = [1,1,1,1];
title = 'PREP pipeline control panel';
inputData = struct('signal', EEG, 'name', title, 'userData', userData);
closeOpenWindows(inputData.name);
uilist= {{'style', 'text', 'string', 'Override default parameters for processing step:'}...
    {'style', 'pushbutton', 'string', 'Boundary', ...
    'Callback', {@boundaryGUI, inputData}} ...
     {'style', 'pushbutton', 'string', 'Reference', ...
    'Callback', {@referenceGUI, inputData}} ...
    {'style', 'pushbutton', 'string', 'Detrend', ...
    'Callback', {@detrendGUI, inputData}} ...
     {'style', 'pushbutton', 'string', 'Report', ...
    'Callback', {@reportGUI, inputData}} ...
    {'style', 'pushbutton', 'string', 'Line noise', ...
    'Callback', {@lineNoiseGUI, inputData}}...
    {'style', 'pushbutton', 'string', 'Post process', ...
    'Callback', {@postProcessGUI, inputData}}};
[~, userData, buttonPressed, ~] = inputgui('geometry', geometry, 'geomvert', geomvert, ...
    'uilist', uilist, 'title', title, ...
    'helpcom', 'pophelp(''pop_prepPipeline'')');

okay = okayPressed(buttonPressed);
paramsOut = struct();
if ~isempty(userData)
    fNames = fieldnames(userData);
    for k = 1:length(fNames)
        nextStruct = userData.(fNames{k});
        nextNames = fieldnames(nextStruct);
        for j = 1:length(nextNames)
            paramsOut.(nextNames{j}) = nextStruct.(nextNames{j});
        end
    end
end

    function okay = okayPressed(buttonPressed)
        % Returns true if the okay button is pressed, false if otherwise
        okay = false;
        if ~isempty(buttonPressed)
            okay = true;
        end % okayPressed
    end

end % MasterGUI


function UID = getIOD_UID(IOD_type)
%getIOD_UID
%   Given a string indicating an IOD type, returns the UID corresponding to
%   that IOD.
%
%   Currently supported UID strings are: CT
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

switch upper(IOD_type)
    case 'CT'
        UID = '1.2.840.10008.5.1.4.1.1.2';
    case 'MR'
        UID = '1.2.840.10008.5.1.4.1.1.4';
    otherwise
        error('Unsupported IOD type.');
end


function minmax(ob)

minmax(struct(ob))


function v = getOr(s, field, default)
%getOr Returns the structure field or a default if either don't exist
%   v = getOr(s, field, [default]) returns the 'field' of the structure 's'
%   or 'default' if the structure is empty of the field does not exist. If
%   default is not specified it defaults to []. 'field' can also be a cell
%   array of fields, in which case it will check for all of them and return
%   the value of the first field that exists, if any (otherwise the default
%   value).

if nargin < 3
  default = [];
end

fieldExists = isfield(s, field);
if any(fieldExists)
  if iscellstr(field)
    v = s.(field{find(fieldExists, 1)});
  else
    v = s.(field);
  end
else
  v = default;
end

end


%XML_PARSEANY  parses XML strings and convert content into Matlab structure
%
% SYNTAX
%           V = xml_parseany( xmlstr )
%
% INPUT
%   xmlstr   xml string, possibly from file with function xml_load.m
%
% OUTPUT
%   v        Matlab variable or cell array.
%
% RELATED
%   xml_format, xml_formatany, xml_parse, xml_load, xml_save, (xmlread, xmlwrite)

% Copyright (C) 2002-2005, University of Southampton
% Author: Dr Marc Molinari <m.molinari@soton.ac.uk>
% $Revision: 1.1 $ $Date: 2005/04/15 17:12:14 $ $Tag$


function ft_write_data(filename, dat, varargin)

% FT_WRITE_DATA exports electrophysiological data such as EEG to a file.
%
% Use as
%   ft_write_data(filename, dat, ...)
%
% The specified filename can contain the filename extension. If it has no filename
% extension not, it will be added automatically.
%
% Additional options should be specified in key-value pairs and can be
%   'header'         header structure that describes the data, see FT_READ_HEADER
%   'event'          event structure that corresponds to the data, see FT_READ_EVENT
%   'chanindx'       1xN array, for selecting a subset of channels from header and data
%   'dataformat'     string, see below
%   'append'         boolean, not supported for all formats
%
% The supported dataformats for writing are
%   edf
%   gdf
%   anywave_ades
%   brainvision_eeg
%   neuralynx_ncs
%   neuralynx_sdma
%   plexon_nex
%   fcdc_matbin
%   fcdc_mysql
%   fcdc_buffer
%   flac, m4a, mp4, oga, ogg, wav (audio formats)
%   matlab
%
% For EEG data formats, the input data is assumed to be scaled in microvolt.
%
% See also FT_READ_HEADER, FT_READ_DATA, FT_READ_EVENT, FT_WRITE_EVENT

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

global data_queue    % for fcdc_global
global header_queue  % for fcdc_global
global db_blob       % for fcdc_mysql
if isempty(db_blob)
  db_blob = 0;
end

% get the options
append        = ft_getopt(varargin, 'append', false);
nbits         = ft_getopt(varargin, 'nbits', 16); % for audio
chanindx      = ft_getopt(varargin, 'chanindx');
hdr           = ft_getopt(varargin, 'header');
evt           = ft_getopt(varargin, 'event');
dataformat    = ft_getopt(varargin, 'dataformat');

if isempty(dataformat)
  % only do the autodetection if the format was not specified
  dataformat = ft_filetype(filename);
end

if startsWith(dataformat, 'audio_')
  % support for  audio formats is implemented in a generic fashion
  dataformat = dataformat(7:end);
end

% convert 'yes' or 'no' string into boolean
append = istrue(append);

% determine the data size
[nchans, nsamples] = size(dat);

% ensure that the directory exists
isdir_or_mkdir(fileparts(filename));

switch dataformat

  case 'empty'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % just pretend that we are writing the data, this is only for debugging
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    [numC, numS] = size(dat);
    fprintf(1,'Pretending to write %i samples from %i channels...\n',numS,numC);
    % Insert a small delay to make this more realitic for testing purposes
    % The time for writing to an actual location will differ and depend on
    % the amount of data
    pause(0.001);

  case 'fcdc_global'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % store it in a global variable, this is only for debugging
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if ~isempty(hdr)
      header_queue = hdr;
    end
    if isempty(data_queue) || ~append
      data_queue = dat;
    else
      data_queue = cat(2, data_queue, dat);
    end

  case 'fcdc_buffer'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % network transparent buffer
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if ~isempty(chanindx)
      % assume that the header corresponds to the original multichannel
      % file and that the data represents a subset of channels
      hdr.label  = hdr.label(chanindx);
      hdr.nChans = length(chanindx);
    end

    [host, port] = filetype_check_uri(filename);

    type = {
      'char'
      'uint8'
      'uint16'
      'uint32'
      'uint64'
      'int8'
      'int16'
      'int32'
      'int64'
      'single'
      'double'
      };

    wordsize = {
      1 % 'char'
      1 % 'uint8'
      2 % 'uint16'
      4 % 'uint32'
      8 % 'uint64'
      1 % 'int8'
      2 % 'int16'
      4 % 'int32'
      8 % 'int64'
      4 % 'single'
      8 % 'double'
      };

    % this should only be done the first time
    if ~append && ~isempty(hdr)
      % reformat the header into a buffer-compatible format
      packet.fsample   = hdr.Fs;
      packet.nchans    = hdr.nChans;
      packet.nsamples  = 0;
      packet.nevents   = 0;
      packet.data_type = find(strcmp(type, class(dat))) - 1; % zero-offset
      if isfield(hdr,'label') && iscell(hdr.label)
        packet.channel_names = hdr.label;
      end
      if isfield(hdr,'siemensap')
        if isa(hdr.siemensap, 'uint8')
          packet.siemensap = hdr.siemensap;
        else
          %          try
          %            packet.siemensap = matlab2sap(hdr.siemensap);
          %          catch
          warning 'Ignoring field "siemensap"';
          %          end
        end
      end
      if isfield(hdr,'nifti_1')
        if isa(hdr.nifti_1, 'uint8')
          packet.nifti_1 = hdr.nifti_1;
        else
          try
            packet.nifti_1 = encode_nifti1(hdr.nifti_1);
          catch
            warning 'Ignoring field "nifti_1"';
          end
        end
      end
      if isfield(hdr,'ctf_res4')
        if isa(hdr.ctf_res4, 'uint8')
          packet.ctf_res4 = hdr.ctf_res4;
        else
          warning 'Ignoring non-uint8 field "ctf_res4"';
        end
      end

      % try to put_hdr and initialize if necessary
      try
        % try writing the packet
        buffer('put_hdr', packet, host, port);

      catch
        if contains(lasterr, 'Buffer size N must be an integer-valued scalar double.')
          % this happens if the MATLAB75/toolbox/signal/signal/buffer
          % function is used instead of the FieldTrip buffer
          ft_error('the FieldTrip buffer mex file was not found on your path, it should be in fieldtrip/fileio/private');

        elseif contains(lasterr, 'failed to create socket') && (strcmp(host, 'localhost') || strcmp(host, '127.0.0.1'))

          % start a local instance of the TCP server
          ft_warning('starting FieldTrip buffer on %s:%d', host, port);
          buffer('tcpserver', 'init', host, port);
          pause(1);

          % rewrite the packet until success
          success = false;
          while ~success
            try
              % it may take some time before the TCP server is fully initialized
              % try writing the packet again
              buffer('put_hdr', packet, host, port);
              success = true;
            catch
              success = false;
            end
          end
        end % if strfind...

      end % try

    end % writing header

    if ~isempty(dat)
      max_nsamples = 32556;
      if size(dat,2)>max_nsamples
        % FIXME this is a hack to split large writes into multiple smaller writes
        % this is to work around a problem observed in the neuralynx proxy
        % when sampling 32 channels at 32KHz
        begsample = 1;
        while begsample<=size(dat,2)
          endsample = begsample - 1 + max_nsamples;
          endsample = min(endsample, size(dat,2));
          % if append is already one of the arguments, remove it from varargin
          indx = find(strcmp(varargin, 'append')); % find the "append" key
          if ~isempty(indx)
            indx = [indx indx+1];                  % remove the key and the value
            varargin(indx) = [];
          end
          ft_write_data(filename, dat(:,begsample:endsample), varargin{:}, 'append', false);
          begsample = endsample + 1;
        end
      else
        % FIXME this is the normal code, which will also be used recursively
        % reformat the data into a buffer-compatible format
        packet.nchans    = size(dat,1);
        packet.nsamples  = size(dat,2);
        packet.data_type = find(strcmp(type, class(dat))) - 1; % zero-offset
        packet.bufsize   = numel(dat) * wordsize{strcmp(type, class(dat))};
        packet.buf       = dat;
        buffer('put_dat', packet, host, port);
      end % if data larger than chuncksize
    end

  case {'brainvision_eeg', 'brainvision_vhdr'}
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % combination of *.eeg and *.vhdr file
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if append
      ft_error('appending data is not yet supported for this data format');
    end

    if nchans~=hdr.nChans && length(chanindx)==nchans
      % assume that the header corresponds to the original multichannel
      % file and that the data represents a subset of channels
      hdr.label  = hdr.label(chanindx);
      hdr.nChans = length(chanindx);
    end
    % the header should at least contain the following fields
    %   hdr.label
    %   hdr.nChans
    %   hdr.Fs
    write_brainvision_eeg(filename, hdr, dat, evt);

  case 'fcdc_matbin'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % multiplexed data in a *.bin file (ieee-le, 64 bit floating point values),
    % accompanied by a MATLAB V6 file containing the header
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    [path, file, ext] = fileparts(filename);
    headerfile = fullfile(path, [file '.mat']);
    datafile   = fullfile(path, [file '.bin']);

    if append && exist(headerfile, 'file') && exist(datafile, 'file')
      % read the existing header and perform a sanity check
      old = load(headerfile);
      assert(old.hdr.nChans==size(dat,1));

      % update the existing header
      hdr          = old.hdr;
      hdr.nSamples = hdr.nSamples + nsamples;

      % there are no new events
      if isfield(old, 'event')
        event = old.event;
      else
        event = [];
      end

      save(headerfile, 'hdr', 'event', '-v6');

      % update the data file
      fid = fopen_or_error(datafile,'ab','ieee-le');
      fwrite(fid, dat, hdr.precision);
      fclose(fid);

    else
      hdr.nSamples = nsamples;
      hdr.nTrials  = 1;
      if nchans~=hdr.nChans && length(chanindx)==nchans
        % assume that the header corresponds to the original multichannel
        % file and that the data represents a subset of channels
        hdr.label     = hdr.label(chanindx);
        hdr.nChans    = length(chanindx);
      end
      if ~isfield(hdr, 'precision')
        hdr.precision = 'double';
      end
      % there are no events
      event = [];
      % write the header file
      save(headerfile, 'hdr', 'event', '-v6');

      % write the data file
      fid = fopen_or_error(datafile,'wb','ieee-le');
      fwrite(fid, dat, hdr.precision);
      fclose(fid);
    end

  case 'fcdc_mysql'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % write to a MySQL server listening somewhere else on the network
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % check that the required low-level toolbox is available
    ft_hastoolbox('mysql', 1);
    db_open(filename);
    if ~isempty(hdr) && isempty(dat)
      % insert the header information into the database
      if db_blob
        % insert the structure into the database table as a binary blob
        db_insert_blob('fieldtrip.header', 'msg', hdr);
      else
        % make a structure with the same elements as the fields in the database table
        s             = struct;
        s.Fs          = hdr.Fs;           % sampling frequency
        s.nChans      = hdr.nChans;       % number of channels
        s.nSamples    = hdr.nSamples;     % number of samples per trial
        s.nSamplesPre = hdr.nSamplesPre;  % number of pre-trigger samples in each trial
        s.nTrials     = hdr.nTrials;      % number of trials
        s.label       = mxSerialize(hdr.label);
        try
          s.msg = mxSerialize(hdr);
        catch
          ft_warning(lasterr);
        end
        db_insert('fieldtrip.header', s);
      end

    elseif isempty(hdr) && ~isempty(dat)
      dim = size(dat);
      if numel(dim)==2
        % ensure that the data dimensions correspond to ntrials X nchans X samples
        dim = [1 dim];
        dat = reshape(dat, dim);
      end
      ntrials = dim(1);
      for i=1:ntrials
        if db_blob
          % insert the data into the database table as a binary blob
          db_insert_blob('fieldtrip.data', 'msg', reshape(dat(i,:,:), dim(2:end)));
        else
          % create a structure with the same fields as the database table
          s = struct;
          s.nChans   = dim(2);
          s.nSamples = dim(3);
          try
            s.data = mxSerialize(reshape(dat(i,:,:), dim(2:end)));
          catch
            ft_warning(lasterr);
          end
          % insert the structure into the database
          db_insert('fieldtrip.data', s);
        end
      end

    else
      ft_error('you should specify either the header or the data when writing to a MySQL database');
    end

  case 'matlab'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % plain MATLAB file
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    [path, file, ext] = fileparts(filename);
    filename = fullfile(path, [file '.mat']);
    if      append &&  exist(filename, 'file')
      % read the previous header and data from MATLAB file
      prev = load(filename);
      if ~isempty(hdr) && ~isequal(hdr, prev.hdr)
        ft_error('inconsistent header');
      else
        % append the new data to that from the MATLAB file
        dat = cat(2, prev.dat, dat);
      end
    elseif  append && ~exist(filename, 'file')
      % file does not yet exist, which is not a problem
    elseif ~append &&  exist(filename, 'file')
      ft_warning('deleting existing file ''%s''', filename);
      delete(filename);
    elseif ~append && ~exist(filename, 'file')
      % file does not yet exist, which is not a problem
    end
    save(filename, 'dat', 'hdr');

  case 'mff'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % MFF files using Phillips plugin
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    ft_hastoolbox('mffmatlabio', 1);
    mff_fileio_write(filename, hdr, dat, evt);

  case 'neuralynx_sdma'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % The first version of this file format contained in the first 8 bytes the
    % channel label as string. Subsequently it contained 32 bit integer values.
    %
    % The second version of this file format starts with 8 bytes describing (as
    % a space-padded string) the data type. The channel label is contained in
    % the filename as dataset.chanlabel.bin.
    %
    % The third version of this file format starts with 7 bytes describing (as
    % a zero-padded string) the data type, followed by the 8th byte which
    % describes the downscaling for the 8 and 16 bit integer representations.
    % The downscaling itself is represented as uint8 and should be interpreted as
    % the number of bits to shift. The channel label is contained in the
    % filename as dataset.chanlabel.bin.
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    statuschannel = {
      'stx'
      'pid'
      'siz'
      'tsh'
      'tsl'
      'cpu'
      'ttl'
      'x01'
      'x02'
      'x03'
      'x04'
      'x05'
      'x06'
      'x07'
      'x08'
      'x09'
      'x10'
      'crc'
      };

    dirname = filename;
    clear filename
    [path, file] = fileparts(dirname);
    for i=1:hdr.nChans
      downscale(i) = 0;
      if ~isempty(strmatch(hdr.label{i}, statuschannel))
        format{i} = 'uint32';
      else
        format{i} = 'int32';
      end
      filename{i} = fullfile(dirname, [file '.' hdr.label{i} '.bin']);
    end

    if ~isfolder(dirname)
      mkdir(dirname);
    end

    % open and write to the output files, one for each selected channel
    fid = zeros(hdr.nChans,1);
    for j=1:hdr.nChans

      if append==false
        fid(j) = fopen_or_error(filename{j}, 'wb', 'ieee-le'); % open the file
        magic = format{j};                               % this used to be the channel name
        magic((end+1):8) = 0;                            % pad with zeros
        magic(8) = downscale(j);                         % number of bits to shift
        fwrite(fid(j), magic(1:8));                      % write the 8-byte file header
      else
        fid(j) = fopen_or_error(filename{j}, 'ab', 'ieee-le');    % open the file for appending
      end % if append

      % convert the data into the correct class
      buf = dat(j,:);
      if ~strcmp(class(buf), format{j})
        switch format{j}
          case 'int16'
            buf = int16(buf);
          case 'int32'
            buf = int32(buf);
          case 'single'
            buf = single(buf);
          case 'double'
            buf = double(buf);
          case 'uint32'
            buf = uint32(buf);
          otherwise
            ft_error('unsupported format conversion');
        end
      end

      % apply the scaling, this corresponds to bit shifting
      buf = buf ./ (2^downscale(j));

      % write the segment of data to the output file
      fwrite(fid(j), buf, format{j}, 'ieee-le');

      fclose(fid(j));
    end % for each channel

  case {'flac' 'm4a' 'mp4' 'oga' 'ogg' 'wav'}
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % This writes data Y to a Windows WAVE file specified by the file name
    % WAVEFILE, with a sample rate of FS Hz and with NBITS number of bits.
    % NBITS must be 8, 16, 24, or 32.  For NBITS < 32, amplitude values
    % outside the range [-1,+1] are clipped
    %
    % Supported extensions for AUDIOWRITE are:
    %   .flac
    % 	.m4a
    % 	.mp4
    % 	.oga
    % 	.ogg
    % 	.wav
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if append
      ft_error('appending data is not supported for this data format');
    end

    if nchans~=hdr.nChans && length(chanindx)==nchans
      % assume that the header corresponds to the original multichannel
      % file and that the data represents a subset of channels
      hdr.label  = hdr.label(chanindx);
      hdr.nChans = length(chanindx);
    end

    if nchans~=1
      ft_error('this format only supports single channel continuous data');
    end

    [p, f, x] = fileparts(filename);
    if isempty(x)
      % append the format as extension
      filename = [filename '.' dataformat];
    end

    audiowrite(filename, dat, hdr.Fs, 'BitsPerSample', nbits);

  case 'plexon_nex'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % single or mulitple channel Plexon NEX file
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if append
      ft_error('appending data is not yet supported for this data format');
    end

    [path, file] = fileparts(filename);
    filename = fullfile(path, [file, '.nex']);
    if nchans~=1
      ft_error('only supported for single-channel data');
    end
    % construct a NEX structure with  the required parts of the header
    nex.hdr.VarHeader.Type       = 5; % continuous
    nex.hdr.VarHeader.Name       = hdr.label{1};
    nex.hdr.VarHeader.WFrequency = hdr.Fs;
    if isfield(hdr, 'FirstTimeStamp')
      nex.hdr.FileHeader.Frequency = hdr.Fs * hdr.TimeStampPerSample;
      nex.var.ts = hdr.FirstTimeStamp;
    else
      ft_warning('no timestamp information available');
      nex.hdr.FileHeader.Frequency  = nan;
      nex.var.ts = nan;
    end
    nex.var.indx = 0;
    nex.var.dat  = dat;

    write_plexon_nex(filename, nex);

    if 0
      % the following code snippet can be used for testing
      [nex2.var, nex2.hdr] = read_plexon_nex(filename, 'channel', 1);
    end

  case 'neuralynx_ncs'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % single channel Neuralynx NCS file
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if append
      ft_error('appending data is not yet supported for this data format');
    end

    if nchans>1
      ft_error('only supported for single-channel data');
    end

    [path, file, ext] = fileparts(filename);
    filename = fullfile(path, [file, '.ncs']);

    if nchans~=hdr.nChans && length(chanindx)==nchans
      % assume that the header corresponds to the original multichannel
      % file and that the data represents a subset of channels
      % WARNING the AD channel index assumes that the data was read from a DMA or SDMA file
      % the first 17 channels contain status info, this number is zero-offset
      ADCHANNEL  = chanindx - 17 - 1;
      LABEL      = hdr.label{chanindx};
    elseif hdr.nChans==1
      ADCHANNEL  = -1;            % unknown
      LABEL      = hdr.label{1};  % single channel
    else
      ft_error('cannot determine channel label');
    end

    FSAMPLE    = hdr.Fs;
    RECORDNSMP = 512;
    RECORDSIZE = 1044;

    % cut the downsampled LFP data into record-size pieces
    nrecords = ceil(nsamples/RECORDNSMP);
    fprintf('construct ncs with %d records\n', nrecords);

    % construct a ncs structure with all header details and the data in it
    ncs                = [];
    ncs.NumValidSamp   = ones(1,nrecords) * RECORDNSMP;   % except for the last block
    ncs.ChanNumber     = ones(1,nrecords) * ADCHANNEL;
    ncs.SampFreq       = ones(1,nrecords) * FSAMPLE;
    ncs.TimeStamp      = zeros(1,nrecords,'uint64');

    if rem(nsamples, RECORDNSMP)>0
      % the data length is not an integer number of records, pad the last record with zeros
      dat = cat(2, dat, zeros(nchans, nrecords*RECORDNSMP-nsamples));
      ncs.NumValidSamp(end) = rem(nsamples, RECORDNSMP);
    end

    ncs.dat = reshape(dat, RECORDNSMP, nrecords);

    for i=1:nrecords
      % timestamps should be 64 bit unsigned integers
      ncs.TimeStamp(i) = uint64(hdr.FirstTimeStamp) + uint64((i-1)*RECORDNSMP*hdr.TimeStampPerSample);
    end

    % add the elements that will go into the ascii header
    ncs.hdr.CheetahRev            = '4.23.0';
    ncs.hdr.NLX_Base_Class_Type   = 'CscAcqEnt';
    ncs.hdr.NLX_Base_Class_Name   = LABEL;
    ncs.hdr.RecordSize            = RECORDSIZE;
    ncs.hdr.ADChannel             = ADCHANNEL;
    ncs.hdr.SamplingFrequency     = FSAMPLE;

    % write it to a file
    fprintf('writing to %s\n', filename);
    write_neuralynx_ncs(filename, ncs);

    if 0
      % the following code snippet can be used for testing
      ncs2 = read_neuralynx_ncs(filename, 1, inf);
    end

  case 'gdf'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % multiple channel GDF file
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if append
      ft_error('appending data is not yet supported for this data format');
    end
    if ~isempty(chanindx)
      % assume that the header corresponds to the original multichannel
      % file and that the data represents a subset of channels
      hdr.label  = hdr.label(chanindx);
      hdr.nChans = length(chanindx);
    end
    write_gdf(filename, hdr, dat);

  case 'edf'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % multiple channel European Data Format file
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if append
      ft_error('appending data is not yet supported for this data format');
    end
    if ~isempty(chanindx)
      % assume that the header corresponds to the original multichannel
      % file and that the data represents a subset of channels
      hdr.label  = hdr.label(chanindx);
      hdr.nChans = length(chanindx);
    end
    write_edf(filename, hdr, dat);

  case 'anywave_ades'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % see http://meg.univ-amu.fr/wiki/AnyWave:ADES
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if append
      ft_error('appending data is not yet supported for this data format');
    end
    if ~isempty(chanindx)
      % assume that the header corresponds to the original multichannel
      % file and that the data represents a subset of channels
      hdr.label     = hdr.label(chanindx);
      hdr.chantype  = hdr.chantype(chanindx);
      hdr.chanunit  = hdr.chanunit(chanindx);
      hdr.nChans    = length(chanindx);
    end

    dattype = unique(hdr.chantype);
    datunit = cell(size(dattype));
    for i=1:numel(dattype)
      unit = hdr.chanunit(strcmp(hdr.chantype, dattype{i}));
      if ~all(strcmp(unit, unit{1}))
        ft_error('channels of the same type with different units are not supported');
      end
      datunit{i} = unit{1};
    end

    % only change these after checking channel types and units
    chantype = adestype(hdr.chantype);
    dattype  = adestype(dattype);

    % ensure that all channels have the right scaling
    for i=1:size(dat,1)
      switch chantype{i}
        case 'MEG'
          dat(i,:) = dat(i,:) * ft_scalingfactor(hdr.chanunit{i}, 'T');
        case 'Reference'
          dat(i,:) = dat(i,:) * ft_scalingfactor(hdr.chanunit{i}, 'T');
        case 'GRAD'
          dat(i,:) = dat(i,:) * ft_scalingfactor(hdr.chanunit{i}, 'T/m');
        case 'EEG'
          dat(i,:) = dat(i,:) * ft_scalingfactor(hdr.chanunit{i}, 'V');
        case 'SEEG'
          dat(i,:) = dat(i,:) * ft_scalingfactor(hdr.chanunit{i}, 'V');
        case 'EMG'
          dat(i,:) = dat(i,:) * ft_scalingfactor(hdr.chanunit{i}, 'V');
        case 'ECG'
          dat(i,:) = dat(i,:) * ft_scalingfactor(hdr.chanunit{i}, 'V');
        otherwise
          % FIXME I am not sure what scaling to apply
      end
    end

    [p, f, x] = fileparts(filename);
    filename = fullfile(p, f); % without extension
    mat2ades(dat, filename, hdr.Fs, hdr.label, chantype, dattype, datunit);

  otherwise
    ft_error('unsupported data format');
end % switch dataformat

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function type = adestype(type)
for i=1:numel(type)
  switch lower(type{i})
    case 'meggrad'
      type{i} = 'MEG'; % this is for CTF and BTi/4D
    case 'megmag'
      type{i} = 'MEG'; % this is for Neuromag and BTi/4D
    case 'megplanar'
      type{i} = 'GRAD'; % this is for Neuromag
    case {'refmag' 'refgrad'}
      type{i} = 'Reference';
    case 'eeg'
      type{i} = 'EEG';
    case {'seeg' 'ecog' 'ieeg'}
      type{i} = 'SEEG'; % all intracranial channels
    case 'ecg'
      type{i} = 'ECG';
    case 'emg'
      type{i} = 'EMG';
    case 'trigger'
      type{i} = 'Trigger';
    case 'source'
      type{i} = 'Source'; % virtual channel
    otherwise
      type{i} = 'Other';
  end
end


function y = lt( x, y )

if isa(x,'cvxin')||~isa(y,'cvxin')||y.active,
    error( 'CVX error: improper use of the <in> pseudo-operator.' );
end
y.active = true;
y.value  = x;

% Copyright 2010 Michael C. Grant and Stephen P. Boyd.
% See the file COPYING.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function test_pull1248

% MEM 2gb
% WALLTIME 00:10:00
% DEPENDENCY ft_read_header ft_read_data ft_read_event dataset2files

filename = dccnpath('/home/common/matlab/fieldtrip/data/test/pull1248/1106miedo.vhdr');

%%

hdr = ft_read_header(filename);
dat = ft_read_data(filename);
evt = ft_read_event(filename); % this used to crash due to there not being a vmrk file


classdef TestImageTemplates < CoreTest
    % TestImageTemplates. Tests for the MimImageTemplates class.
    %
    %
    %     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.
    %

    methods
        function obj = TestImageTemplates

            mock_reporting = CoreMockReporting;
            mock_datset_disk_cache = MockDatasetDiskCache;
            mock_dataset_results = MockDatasetResults;
            context_def = PTKContextDef;
            image_templates = MimImageTemplates(PTKFrameworkAppDef, mock_dataset_results, context_def, mock_datset_disk_cache, mock_reporting);
            mock_dataset_results.ImageTemplates = image_templates;
            null_dataset_stack = [];

            % By default, all contexts should be enabled
            obj.Assert(image_templates.IsContextEnabled(PTKContext.OriginalImage), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.LungROI), 'ROI context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.LeftLung), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.RightLung), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.RightUpperLobe), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.RightMiddleLobe), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.RightLowerLobe), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.LeftUpperLobe), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.LeftLowerLobe), 'Context is enabled');

            % Check that code fails where template could not be generated
            % When asking for a template, the code should fail if the template
            % could not be generated
            mock_dataset_results.AddMockResult('PTKOriginalImage', PTKContext.OriginalImage, [], [], [], true);
            mock_reporting.AddExpectation('CoreMockReporting.Error', 'MimImageTemplates:NoContext');
            try
                template_image = image_templates.GetTemplateImage(PTKContext.OriginalImage, null_dataset_stack, mock_reporting);
            catch ex
                if ~isa(ex, 'CoreTestException')
                    CoreErrorUtilities.ThrowException('TestImageTemplates:WrongException', 'Test failure: test exception expected');

                end
            end

            % Due to the failure, the original image context should now be
            % disabled
            obj.Assert(~image_templates.IsContextEnabled(PTKContext.OriginalImage), 'Context is disabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.LungROI), 'ROI context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.LeftLung), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.RightLung), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.RightUpperLobe), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.RightMiddleLobe), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.RightLowerLobe), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.LeftUpperLobe), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.LeftLowerLobe), 'Context is enabled');

            % Now force a failure for two more contexts (LungROI and LeftLung,
            % leaving RightLung enabled)

            mock_dataset_results.AddMockResult('PTKLungROI', PTKContext.LungROI, [], [], [], true);
            mock_reporting.AddExpectation('CoreMockReporting.Error', 'MimImageTemplates:NoContext');
            try
                template_image = image_templates.GetTemplateImage(PTKContext.LungROI, null_dataset_stack, mock_reporting);
            catch ex
                if ~isa(ex, 'CoreTestException')
                    CoreErrorUtilities.ThrowException('TestImageTemplates:WrongException', 'Test failure: test exception expected');

                end
            end
            mock_dataset_results.AddMockResult('PTKGetContextForSingleLung', PTKContext.LeftLung, [], [], [], true);
            mock_reporting.AddExpectation('CoreMockReporting.Error', 'MimImageTemplates:NoContext');
            try
                template_image = image_templates.GetTemplateImage(PTKContext.LeftLung, null_dataset_stack, mock_reporting);
            catch ex
                if ~isa(ex, 'CoreTestException')
                    CoreErrorUtilities.ThrowException('TestImageTemplates:WrongException', 'Test failure: test exception expected');

                end
            end

            % Now three of the contexts should be disbaled
            obj.Assert(~image_templates.IsContextEnabled(PTKContext.OriginalImage), 'Context is disabled');
            obj.Assert(~image_templates.IsContextEnabled(PTKContext.LungROI), 'ROI context is enabled');
            obj.Assert(~image_templates.IsContextEnabled(PTKContext.LeftLung), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.RightLung), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.RightUpperLobe), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.RightMiddleLobe), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.RightLowerLobe), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.LeftUpperLobe), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.LeftLowerLobe), 'Context is enabled');

            % Check normal accessing of templates

            % Add template image results
            mock_roi_image = PTKImage;
            mock_roi_image.Title = 'roi';
            mock_full_image = PTKImage;
            mock_full_image.Title = 'full';
            mock_left_image = PTKImage;
            mock_left_image.Title = 'left';
            mock_right_image = PTKImage;
            mock_right_image.Title = 'right';
            mock_ru_image = PTKImage;
            mock_ru_image.Title = 'ru';
            mock_rm_image = PTKImage;
            mock_rm_image.Title = 'rm';
            mock_rl_image = PTKImage;
            mock_rl_image.Title = 'rl';
            mock_lu_image = PTKImage;
            mock_lu_image.Title = 'lu';
            mock_ll_image = PTKImage;
            mock_ll_image.Title = 'll';

            lung_roi_cache_item = MimDatasetStackItem(MimDependency('PTKLungROI', PTKContext.LungROI, '1.2.3.4.5', '1', []), MimDependencyList, false, false, mock_reporting);
            oi_cache_item = MimDatasetStackItem(MimDependency('PTKOriginalImage', PTKContext.OriginalImage, '1.2.3.4.6', '1', []), MimDependencyList, false, false, mock_reporting);
            ll_cache_item = MimDatasetStackItem(MimDependency('PTKGetContextForSingleLung', PTKContext.LeftLung, '1.2.3.4.7', '1', []), MimDependencyList, false, false, mock_reporting);
            rl_cache_item = MimDatasetStackItem(MimDependency('PTKGetContextForSingleLung', PTKContext.RightLung, '1.2.3.4.8', '1', []), MimDependencyList, false, false, mock_reporting);
            rul_cache_item = MimDatasetStackItem(MimDependency('PTKGetContextForLobe', PTKContext.RightUpperLobe, '1.2.3.4.9', '1', []), MimDependencyList, false, false, mock_reporting);
            rml_cache_item = MimDatasetStackItem(MimDependency('PTKGetContextForLobe', PTKContext.RightMiddleLobe, '1.2.3.4.10', '1', []), MimDependencyList, false, false, mock_reporting);
            rll_cache_item = MimDatasetStackItem(MimDependency('PTKGetContextForLobe', PTKContext.RightLowerLobe, '1.2.3.4.11', '1', []), MimDependencyList, false, false, mock_reporting);
            lul_cache_item = MimDatasetStackItem(MimDependency('PTKGetContextForLobe', PTKContext.LeftUpperLobe, '1.2.3.4.12', '1', []), MimDependencyList, false, false, mock_reporting);
            lll_cache_item = MimDatasetStackItem(MimDependency('PTKGetContextForLobe', PTKContext.LeftLowerLobe, '1.2.3.4.13', '1', []), MimDependencyList, false, false, mock_reporting);

            % Check fetching the template images
            mock_dataset_results.AddMockResult('PTKLungROI', PTKContext.LungROI, mock_roi_image, lung_roi_cache_item, [], true);
            mock_dataset_results.AddMockResult('PTKOriginalImage', PTKContext.OriginalImage, mock_full_image, oi_cache_item, [], true);
            mock_dataset_results.AddMockResult('PTKGetContextForSingleLung', PTKContext.LeftLung, mock_left_image, ll_cache_item, [], true);
            mock_dataset_results.AddMockResult('PTKGetContextForSingleLung', PTKContext.RightLung, mock_right_image, rl_cache_item, [], true);
            mock_dataset_results.AddMockResult('PTKGetContextForLobe', PTKContext.RightUpperLobe, mock_ru_image, rul_cache_item, [], true);
            mock_dataset_results.AddMockResult('PTKGetContextForLobe', PTKContext.RightMiddleLobe, mock_rm_image, rml_cache_item, [], true);
            mock_dataset_results.AddMockResult('PTKGetContextForLobe', PTKContext.RightLowerLobe, mock_rl_image, rll_cache_item, [], true);
            mock_dataset_results.AddMockResult('PTKGetContextForLobe', PTKContext.LeftUpperLobe, mock_lu_image, lul_cache_item, [], true);
            mock_dataset_results.AddMockResult('PTKGetContextForLobe', PTKContext.LeftLowerLobe, mock_ll_image, lll_cache_item, [], true);

            roi_template_image = image_templates.GetTemplateImage(PTKContext.LungROI, null_dataset_stack, mock_reporting);
            obj.Assert(strcmp(roi_template_image.Title, 'roi'), 'Correct template image returned');

            original_template_image = image_templates.GetTemplateImage(PTKContext.OriginalImage, null_dataset_stack, mock_reporting);
            obj.Assert(strcmp(original_template_image.Title, 'full'), 'Correct template image returned');

            left_template_image = image_templates.GetTemplateImage(PTKContext.LeftLung, null_dataset_stack, mock_reporting);
            obj.Assert(strcmp(left_template_image.Title, 'left'), 'Correct template image returned');

            right_template_image = image_templates.GetTemplateImage(PTKContext.RightLung, null_dataset_stack, mock_reporting);
            obj.Assert(strcmp(right_template_image.Title, 'right'), 'Correct template image returned');

            ru_template_image = image_templates.GetTemplateImage(PTKContext.RightUpperLobe, null_dataset_stack, mock_reporting);
            obj.Assert(strcmp(ru_template_image.Title, 'ru'), 'Correct template image returned');

            rm_template_image = image_templates.GetTemplateImage(PTKContext.RightMiddleLobe, null_dataset_stack, mock_reporting);
            obj.Assert(strcmp(rm_template_image.Title, 'rm'), 'Correct template image returned');

            rl_template_image = image_templates.GetTemplateImage(PTKContext.RightLowerLobe, null_dataset_stack, mock_reporting);
            obj.Assert(strcmp(rl_template_image.Title, 'rl'), 'Correct template image returned');

            lu_template_image = image_templates.GetTemplateImage(PTKContext.LeftUpperLobe, null_dataset_stack, mock_reporting);
            obj.Assert(strcmp(lu_template_image.Title, 'lu'), 'Correct template image returned');

            ll_template_image = image_templates.GetTemplateImage(PTKContext.LeftLowerLobe, null_dataset_stack, mock_reporting);
            obj.Assert(strcmp(ll_template_image.Title, 'll'), 'Correct template image returned');

            % Contexts should now all be enabled again
            obj.Assert(image_templates.IsContextEnabled(PTKContext.OriginalImage), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.LungROI), 'ROI context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.LeftLung), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.RightLung), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.RightUpperLobe), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.RightMiddleLobe), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.RightLowerLobe), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.LeftUpperLobe), 'Context is enabled');
            obj.Assert(image_templates.IsContextEnabled(PTKContext.LeftLowerLobe), 'Context is enabled');
        end
    end
end


%{
 * Copyright (C) 2020-2030, The Regents of The University of Michigan.
 * All rights reserved.
 * This software was developed in the Biped Lab (https://www.biped.solutions/)
 * under the direction of Jessy Grizzle, grizzle@umich.edu. This software may
 * be available under alternative licensing terms; contact the address above.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * The views and conclusions contained in the software and documentation are those
 * of the authors and should not be interpreted as representing official policies,
 * either expressed or implied, of the Regents of The University of Michigan.
 *
 * AUTHOR: Bruce JK Huang (bjhuang[at]umich.edu)
 * WEBSITE: https://www.brucerobot.com/
%}

function point_cloud = loadPointCloud(path, name)
    if nargin == 1
        file = path;
    else
        file = path + name;
    end

    if ~isfile(file)
        disp('Invalid path when loading dataset')
        fprintf("path: %s\n", file);
        return
    else
        pc = load(file);
        point_cloud = pc.point_cloud; % [scan, point, [X, Y, Z, I, R]]
    end
end


function updateTaxonomyInfoAGORA
% This function retrieves the newest taxonomy information for each AGORA
% strain from NCBI Taxonomy to facilitate mapping taxonomic assignments
% from metagenomic sequencing data to AGORA. An updated version of the
% AGORA information table is saved in spreadsheet format.
%
% .. Author: Almut Heinken, 04/2022

% AGORA information table
infoFile = readInputTableForPipeline('AGORA_infoFile.xlsx');

ncbiCol = find(strcmp(infoFile(1,:),'NCBI Taxonomy ID'));
strainCol = find(strcmp(infoFile(1,:),'Strain'));
speciesCol = find(strcmp(infoFile(1,:),'Species'));
genusCol = find(strcmp(infoFile(1,:),'Genus'));
familyCol = find(strcmp(infoFile(1,:),'Family'));
orderCol = find(strcmp(infoFile(1,:),'Order'));
classCol = find(strcmp(infoFile(1,:),'Class'));
phylumCol = find(strcmp(infoFile(1,:),'Phylum'));
kingdomCol = find(strcmp(infoFile(1,:),'Kingdom'));

taxa = {
    strainCol 'strain'
    speciesCol 'species'
    genusCol 'genus'
    familyCol 'family'
    orderCol 'order'
    classCol 'class'
    phylumCol 'phylum'
    kingdomCol 'superkingdom'
    };

for i=2:size(infoFile,1)
    i
    taxonomy = parseNCBItaxonomy(infoFile{i,ncbiCol});
    for j=1:size(taxa,1)
        if isfield(taxonomy,taxa{j,2})
            if j==1
                if ~strcmp(taxonomy.('strain'),'root')
                    if isfield(taxonomy,'species')
                        if ~strcmp(taxonomy.('strain'),taxonomy.('species'))
                            if ~isempty(taxonomy.(taxa{j,2}))
                                infoFile{i,taxa{j,1}} = taxonomy.(taxa{j,2});
                            end
                        end
                    end
                end
            else
                if ~isempty(taxonomy.(taxa{j,2}))
                    infoFile{i,taxa{j,1}} = taxonomy.(taxa{j,2});
                end
            end
        end
    end
end
writetable(cell2table(infoFile),'AGORA_infoFile.xlsx','FileType','spreadsheet','writeVariableNames',false);

% AGORA2 information table
infoFile = readInputTableForPipeline('AGORA2_infoFile.xlsx');

ncbiCol = find(strcmp(infoFile(1,:),'NCBI Taxonomy ID'));
strainCol = find(strcmp(infoFile(1,:),'Strain'));
speciesCol = find(strcmp(infoFile(1,:),'Species'));
genusCol = find(strcmp(infoFile(1,:),'Genus'));
familyCol = find(strcmp(infoFile(1,:),'Family'));
orderCol = find(strcmp(infoFile(1,:),'Order'));
classCol = find(strcmp(infoFile(1,:),'Class'));
phylumCol = find(strcmp(infoFile(1,:),'Phylum'));
kingdomCol = find(strcmp(infoFile(1,:),'Kingdom'));

taxa = {
    strainCol 'strain'
    speciesCol 'species'
    genusCol 'genus'
    familyCol 'family'
    orderCol 'order'
    classCol 'class'
    phylumCol 'phylum'
    kingdomCol 'superkingdom'
    };

for i=2:size(infoFile,1)
    i
    taxonomy = parseNCBItaxonomy(infoFile{i,ncbiCol});
    for j=1:size(taxa,1)
        if isfield(taxonomy,taxa{j,2})
            if j==1
                if ~strcmp(taxonomy.('strain'),'root')
                    if isfield(taxonomy,'species')
                        if ~strcmp(taxonomy.('strain'),taxonomy.('species'))
                            if ~isempty(taxonomy.(taxa{j,2}))
                                infoFile{i,taxa{j,1}} = taxonomy.(taxa{j,2});
                            end
                        end
                    end
                end
            else
                if ~isempty(taxonomy.(taxa{j,2}))
                    infoFile{i,taxa{j,1}} = taxonomy.(taxa{j,2});
                end
            end
        end
    end
end
writetable(cell2table(infoFile),'AGORA2_infoFile.xlsx','FileType','spreadsheet','writeVariableNames',false );

end


function gui_cg()
%
% This function is needed by FASTICAG

% This file just removes the global variables
% that are used in FASTICAG from the memory

% @(#)$Id: gui_cg.m,v 1.2 2003/04/05 14:23:57 jarmo Exp $

clear global c_FastICA_appr_strD;
clear global c_FastICA_appr_strV;
clear global c_FastICA_dMod_strD;
clear global c_FastICA_dMod_strV;
clear global c_FastICA_finetune_strD;
clear global c_FastICA_finetune_strV;
clear global c_FastICA_g1_strD;
clear global c_FastICA_g1_strV;
clear global c_FastICA_g2_strD;
clear global c_FastICA_g2_strV;
clear global c_FastICA_iSta_strD;
clear global c_FastICA_iSta_strV;
clear global c_FastICA_stabili_strD;
clear global c_FastICA_stabili_strV;
clear global c_FastICA_verb_strD;
clear global c_FastICA_verb_strV;
clear global g_FastICA_a1;
clear global g_FastICA_a2;
clear global g_FastICA_approach;
clear global g_FastICA_displayIn;
clear global g_FastICA_displayMo;
clear global g_FastICA_epsilon;
clear global g_FastICA_finetune;
clear global g_FastICA_g;
clear global g_FastICA_ica_A;
clear global g_FastICA_ica_W;
clear global g_FastICA_ica_sig;
clear global g_FastICA_initGuess;
clear global g_FastICA_initState;
clear global g_FastICA_interrupt;
clear global g_FastICA_loadType;
clear global g_FastICA_maxFinetune;
clear global g_FastICA_maxNumIte;
clear global g_FastICA_mixedmean;
clear global g_FastICA_mixedsig;
clear global g_FastICA_myy;
clear global g_FastICA_numOfIC;
clear global g_FastICA_pca_D;
clear global g_FastICA_pca_E;
clear global g_FastICA_sampleSize;
clear global g_FastICA_stabilization;
clear global g_FastICA_verbose;
clear global g_FastICA_white_dwm;
clear global g_FastICA_white_sig;
clear global g_FastICA_white_wm;
clear global hb_FastICA_initGuess;
clear global he_FastICA_a1;
clear global he_FastICA_a2;
clear global he_FastICA_displayInterval;
clear global he_FastICA_epsilon;
clear global he_FastICA_file;
clear global he_FastICA_suffix;
clear global he_FastICA_maxFinetune;
clear global he_FastICA_maxIterations;
clear global he_FastICA_myy;
clear global he_FastICA_numOfIC;
clear global he_FastICA_sampleSize;
clear global hf_FastICA_MAIN;
clear global hf_FastICA_AdvOpt;
clear global hf_FastICA_Load;
clear global hf_FastICA_Save;
clear global hpm_FastICA_approach;
clear global hpm_FastICA_displayMode;
clear global hpm_FastICA_finetune;
clear global hpm_FastICA_g;
clear global hpm_FastICA_initState;
clear global hpm_FastICA_stabilization;
clear global hpm_FastICA_verbose;
clear global ht_FastICA_dim;
clear global ht_FastICA_icaStatus;
clear global ht_FastICA_initGuess;
clear global ht_FastICA_mixedStatus;
clear global ht_FastICA_newDim;
clear global ht_FastICA_numOfSamp;
clear global ht_FastICA_whiteStatus;


function SetJointVelocities(idx, dq)
global uLINK

for n=1:length(idx)
    j = idx(n);
    uLINK(j).dq = dq(n);
end


function [KMZFullFile] = kml2kmz(varargin)
%kml2kmz converts .kml file types into self-contained .kmz filetypes.
%   kml2kmz(KMLFullFile) copies all the support documents used by the kml
%   into a single 'files' folder, and updates the file path in the kml to
%   the new relative path accordingly.  The kml is also copied, then zipped
%   up with the new copies of supporting files.  The zip file is then
%   renamed with a .kmz extension, and put in the same folder as the
%   original kml.  The new copies of supporting documents are then deleted
%   by default.  Supporting documents referenced by KML attributes are not yet
%   supported.
%
%   kml2kmz(KMLFullFile,'keepsupportfiles') keeps the extra copies of the
%   supporting documents.
%
%   kml2kmz(KMLFullFile, 'deleteoriginalkml') deletes the original kml.
%
%   Both 'keepsupportfiles' and 'deleteoriginalkml' can be used at the same time.
%
%%%%%%%%%%%%%%%%%%%%
%
%   Still to be Considered: Please contact me if you can help me solve these
%   questions/points.
%       1:  Currently checks for addresses in kml elements, but we need to deal with
%       the kml attribute case too.  I don't have an example to work with.
%       2:  Haven't checked fucntionality on Linux or Mac, but should work
%       as far as I know
%       3:  Haven't checked if ".." notation is handled properly
%       4:  I haven't worked with Alias' before.  Are Targethref and
%       Sourcehref handled properly?
%       5:  Are there other element types I've missed?
%
%
%   Author(s): Ryan Bell, ryan.bell@viu.ca
%   Vancouver Island University
%   Version 2.1, December 05, 2012
%
%
%   version 1.0  - intial coding
%   version 2.0  - added internet file download
%                - added check to prevent downloading same file twice
%                - added check to ensure file names don't conflict
%                - removed platform check
%                - added <a href> to catch description text
%                - improved description text and added a todo list
%   version 2.1  - added conditional check for existing, but empty, elements

%% Setup Inputs

%     % Defaults;
    keep_support = 0;
    delete_original = 0;
    KMLFullFile = varargin{1};
    % holds a list of files accessed, so we don't copy the same one more than once
    FileList={'source files','destination files'};
    nin = length(varargin);

%% check for incorrect arguments
    % if the input args is more than 1 - it should be either
    % 'keeplimits' or 'keepticks' or both.
    if nin > 1
        for i = nin:-1:2
            if ~(strcmpi(varargin{i},'keepsupportfiles') || strcmpi(varargin{i},'deleteoriginalkml'))
                error('Incorrect input arguments');
            end
        end
    end

    % Look for 'keeplimits'
    for i=2:nin
        if strcmpi(varargin{i},'keepsupportfiles')
            keep_support = 1;
        elseif strcmpi(varargin{i},'deleteoriginalkml')
            delete_original = 1;
        end
    end

%% Setup support file/folder names
   % Decide where to keep the temporary support files
    if keep_support
        %put the support files where they can be found
        parentfolder = fileparts(KMLFullFile);
    else
        %put the temporary support files where they won't be noticed
        parentfolder = tempname;
    end

    %location of the temporary support documents
    filesPath = fullfile(parentfolder,'files');
    %location of the temporary kml
    tempKMLFullFile = fullfile(parentfolder,'doc.kml');
    %location of the new kmz
    KMZFullFile = [KMLFullFile(1:end-3) 'kmz'];
    %make sure folder exists
    if ~isdir(filesPath)
        mkdir(filesPath);
    end

%% Open file and look for references to local and internet addresses

    %open the original kml as an xDocument
    xDoc = xmlread(KMLFullFile);

    % Go through the kml and find all the referenced files, copy them in to
    % support folder, and update the file names in the kml to relative paths

    % checks for address in elements, but
    for tag = {'href','targetHref','sourceHref','description'}  %others?  https://developers.google.com/kml/documentation/kmzarchives
        allListitems = xDoc.getElementsByTagName(tag);  %find all the references to external files
        for k = 0:allListitems.getLength-1 %go through each refence (Java index starts at 0)
            thisListitem = allListitems.item(k);
            %make sure xml element isn't empty
            if ~isempty(thisListitem.getFirstChild)
                Contents = char(thisListitem.getFirstChild.getData);  %this is the location of support file
                if strcmp(tag,'description')
                    Description = Contents; %Contents are the description html text
                    [Description, FileList] = handle_description(Description, filesPath,FileList);
                    thisListitem.getFirstChild.setData(Description);
                else
                    SourceFile = Contents; %Contents are the source file
                    [DestinationFile_GE, FileList] = handle_link(SourceFile, filesPath,FileList);
                    thisListitem.getFirstChild.setData(DestinationFile_GE);
                end
            end
        end
    end

%% Save the work and Tidy up

    % Rewrite the kml with its new file paths
    write_XML_no_extra_lines(tempKMLFullFile,xDoc) %bug fix see:http://www.mathworks.com/matlabcentral/newsreader/view_thread/245555
    % xmlwrite(tempKMLFullFile,xDoc);  %write the updated xml file into out temp directory

    % This creates a zipped file named 'myKmz.kmz.zip'
    zip(KMZFullFile,{filesPath tempKMLFullFile});
    %renames the zipped file to 'mykmz.kmz'.
    movefile([KMZFullFile '.zip'], KMZFullFile);

    if keep_support == 0
        % Delete supporting files
        delete(tempKMLFullFile) %Delete the temp kml
        rmdir(filesPath,'s');  %delete the files folder
    end
    if delete_original == 1
        delete(KMLFullFile);  %delete original kml
    end

end

%% Functions...

%% Check description text for instances of images of
function [Description, FileList] = handle_description(Description, filesPath,FileList)
    addresses = [strfind(Description,'img src'),...
                 strfind(Description,'a href')];
    for i = addresses
        j = strfind(Description(i:end),'"')+i;
        SourceFile = Description(j(1):j(2)-2);
        DestinationFile_GE = handle_link(SourceFile, filesPath,FileList);
        Description = [Description(1:j(1)-1) DestinationFile_GE Description(j(2)-1:end)];
    end
end

% Move support file into 'files' folder and convert address relative
function [DestinationFile_GE, FileList] = handle_link(SourceFile, filesPath,FileList)

    if ~any(strcmp(SourceFile,FileList(:,1)))  %Check if we've copied or download this file already
        [~,FileName,FileExt] = fileparts(SourceFile);
        DestinationFile_GE = ['files/' FileName FileExt]; %relative GE filepath, using GE file separator (/)
        n=1;
        while any(strcmp(DestinationFile_GE,FileList(:,2)))  %Check if this path is already used (eg the file shares a file name, but was in a different folder from a previous support file)
            FileNameOld = FileName;
            FileName = [FileNameOld ' ' num2str(n,'%.0f')];
            DestinationFile_GE = ['files/' FileName FileExt]; %add a numeric extension to this file that shared the same name as a previous support file
            n=n+1;
        end
        DestinationFile_Local = fullfile(filesPath,[FileName FileExt]);  %destination file path using local file separator

        if strcmp(SourceFile(1:4),'http') || strcmp(SourceFile(1:3),'ftp')  %file is on the internet
            [~,status] = urlwrite(SourceFile,DestinationFile_Local); %download the file this can be painfully slow for some reason...
            if status == 0
                error(['Problem downloading ' SourceFile]);
            end

        else  %file is local
            if ~strcmp(SourceFile(2),':')  %file path relative, add the current folder to the filepath
                SourceFile = fullfile(currentFolder, SourceFile); %change file path from relative to absolute
            end

            if exist(SourceFile,'file') %check if file to be copied exists
                status = copyfile(SourceFile,DestinationFile_Local);  % copyfile into the 'files' folders
                if status == 0
                    error(['Problem copying ' SourceFile]);
                end
            else
                error(['Can not find file:' SourceFile]);
            end
        end
        FileList{size(FileList(:,1),2)+1,1} = SourceFile;                %Store the source file for later checking
        FileList{size(FileList(:,1),2)+1,2} = DestinationFile_GE;        %Store the GE relative path for possible, this path may be reused later
    else
        DestinationFile_GE = FileList{strcmp(SourceFile,FileList(:,1)),2}; % This file is being used again, get the GE relative path
    end
%     save('kmldata')  %for debug
end

%% bug fix.  See: http://www.mathworks.com/matlabcentral/newsreader/view_thread/245555
function write_XML_no_extra_lines(save_name,XDOC)

    XML_string = xmlwrite(XDOC); %open KML as string
    XML_string = regexprep(XML_string,'\n[ \t\n]*\n','\n'); %removes extra tabs, spaces and extra lines

    %Write to file
    fid = fopen(save_name,'w');
    fprintf(fid,'%s\n',XML_string);
    fclose(fid);
end


function SetDefaultValue(position, argName, defaultValue)
%SETDEFAULTVALUE Initialise a missing or empty value in the caller.
%
% SETDEFAULTVALUE(POSITION, ARGNAME, DEFAULTVALUE) checks to see if the
% argument named ARGNAME in position POSITION of the caller function is
% missing or empty, and if so, assigns it the value DEFAULTVALUE.
%
% Example:
% function x = TheCaller(x)
% SetDefaultValue(1, 'x', 10);
% end
% TheCaller()    % 10
% TheCaller([])  % 10
% TheCaller(99)  % 99

% $Author: rcotton $  $Date: 2010/10/01 13:58:35 $ $Revision: 1.1 $
% Copyright: Health and Safety Laboratory 2010

if evalin('caller', 'nargin') < position || ...
      isempty(evalin('caller', argName))
   assignin('caller', argName, defaultValue);
end
end


% Copyright 2010-2013 The MathWorks, Inc.
example_sel2html('wave_list.txt')


classdef DebugLevel
    properties
        possibleValues
        value
    end

    methods

        % ----------------------------------------------------------------------------------
        function obj = DebugLevel(value) %#ok<*INUSD>
            obj.possibleValues = struct('none',0,'simulateBadData',1);
            switch(lower(value))
                case 'none'
                    obj.value = obj.possibleValues.none;
                case 'simulatebaddata'
                    obj.value = obj.possibleValues.simulateBadData;
                otherwise
                    obj.value = obj.possibleValues.none;
            end
        end

        % ----------------------------------------------------------------------------------
        function value = Get(obj)
            value = obj.value;
        end

        % ----------------------------------------------------------------------------------
        function value = SimulateBadData(obj)
            value = obj.possibleValues.simulateBadData;
        end

        % ----------------------------------------------------------------------------------
        function value = None(obj)
            value = obj.possibleValues.None;
        end

    end
end


function test_suite = test_survival_aft

%   Run specific demo, save values and compare the results to the expected.
%   Works for both xUnit Test Framework package by Steve Eddins and for
%   the built-in Unit Testing Framework (as of Matlab version 2013b).
%
%   See also
%     TEST_ALL, DEMO_SURVIVAL_AFT
%
% Copyright (c) 2011-2012 Ville Tolvanen
% Copyright (c) 2014 Tuomas Sivula

% This software is distributed under the GNU General Public
% License (version 3 or later); please refer to the file
% License.txt, included with the software, for details.

  % Check which package to use
  if exist('initTestSuite', 'file')
    initTestSuite_path = which('initTestSuite');
  else
    initTestSuite_path = '';
  end
  if ~isempty(initTestSuite_path) && ...
     exist([initTestSuite_path(1:end-15) 'runtests'], 'file')
    % xUnit package
    initTestSuite;
  else
    % Built-in package
    % Use all functions except the @setup
    tests = localfunctions;
    tests = tests(~cellfun(@(x)strcmp(func2str(x),'setup'),tests));
    test_suite = functiontests(tests);
  end
end

% -------------
%     Tests
% -------------

function testRunDemo(testCase)
  % Run the correspondin demo and save the values. Note this test has to
  % be run at lest once before the other test may succeed.
  rundemo(getName())
end

function testPredictions(testCase)
  verifyVarsEqual(testCase, getName(), {'pmu'}, {@(x)x(:,1)}, ...
    'RelTolElement', 0.05, 'RelTolRange', 0.01)
  verifyVarsEqual(testCase, getName(), {'pmu'}, {@(x)x(:,2)}, ...
    'RelTolElement', 0.05, 'RelTolRange', 0.01)
  verifyVarsEqual(testCase, getName(), {'pmu'}, {@(x)x(:,3)}, ...
    'RelTolElement', 0.05, 'RelTolRange', 0.01)
end

% ------------------------
%     Helper functions
% ------------------------

function testCase = setup
  % Helper function to suply empty array into variable testCase as an
  % argument for each test function, if using xUnit package. Not to be
  % used with built-in test framework.
  testCase = [];
end

function name = getName
  % Helperfunction that returns the name of the demo, e.g. 'binomial1'.
  name = mfilename;
  name = name(6:end);
end