function varargout = ssofm(varargin)
% SSOFM M-file for ssofm.fig
%      SSOFM, by itself, creates a new SSOFM or raises the existing
%      singleton*.
%
%      H = SSOFM returns the handle to a new SSOFM or the handle to
%      the existing singleton*.
%
%      SSOFM('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in SSOFM.M with the given input arguments.
%
%      SSOFM('Property','Value',...) creates a new SSOFM or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before ssofm_OpeningFunction gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to ssofm_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Copyright 2002-2003 The MathWorks, Inc.

% Edit the above text to modify the response to help ssofm

% Last Modified by GUIDE v2.5 10-Jun-2006 02:13:27

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @ssofm_OpeningFcn, ...
                   'gui_OutputFcn',  @ssofm_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before ssofm is made visible.
function ssofm_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to ssofm (see VARARGIN)

% Choose default command line output for ssofm
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes ssofm wait for user response (see UIRESUME)
% uiwait(handles.ssofmFigure);

% --- Outputs from this function are returned to the command line.
function varargout = ssofm_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;

% --------------------------------------------------------------------
function exit_Callback(hObject, eventdata, handles)
% hObject    handle to exit (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
close;

% --------------------------------------------------------------------
function file_Callback(hObject, eventdata, handles)
% hObject    handle to file (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% --------------------------------------------------------------------
function loaddata_Callback(hObject, eventdata, handles)
% hObject    handle to load (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
[filenameData, pathnameData]=uigetfile('*.mat','Load data...','MultiSelect', 'off');
set(handles.data2Text,'String',filenameData);
handles.Data = [pathnameData filenameData];
guidata(ssofm,handles)
a = get(handles.data2Text,'String');
b = get(handles.ssofm2Text,'String');
if a(1:3)~='...' & b(1:3)~='...'
    set(handles.trainButton,'Enable','on')
end

function epochsEdit_Callback(hObject, eventdata, handles)
% hObject    handle to epochsEdit (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of epochsEdit as text
%        str2double(get(hObject,'String')) returns contents of epochsEdit as a double

% --- Executes during object creation, after setting all properties.
function epochsEdit_CreateFcn(hObject, eventdata, handles)
% hObject    handle to epochsEdit (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc
    set(hObject,'BackgroundColor','white');
else
    set(hObject,'BackgroundColor',get(0,'defaultUicontrolBackgroundColor'));
end

% --- Executes on button press in trainButton.
function trainButton_Callback(hObject, eventdata, handles)
% hObject    handle to trainButton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
set(hObject,'Enable','off');
set(handles.plotglyphButton,'Enable','off');
set(handles.retrainButton,'Enable','off');
s = str2num(get(handles.sizeEdit,'String'));
epochs = str2num(get(handles.epochsEdit,'String'));
if get(handles.plotRadio,'Value') == 1
    showglyph = 'plot';
end
if get(handles.glyphRadio,'Value') == 1
    showglyph = 'glyph';
end
if get(handles.aviRadio,'Value') == 1
    showglyph = get(handles.aviText,'String');
    if isempty(showglyph)
        showglyph = 'test.avi';
    else
        showglyph = [get(handles.aviText,'String') '.avi'];
    end
end
load(handles.Data);
load(handles.Ssofm);
[w,g,r,c,freq]=trainGlyph(P,X,C,s,epochs,showglyph);
handles.w = w;
handles.g = g;
handles.r = r;
handles.c = c;
handles.freq = freq;
handles.X = X;
guidata(ssofm,handles);
set(hObject,'Enable','on');
set(handles.plotglyphButton,'Enable','on');
set(handles.retrainButton,'Enable','on');

function sizeEdit_Callback(hObject, eventdata, handles)
% hObject    handle to sizeEdit (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of sizeEdit as text
%        str2double(get(hObject,'String')) returns contents of sizeEdit as a double

% --- Executes during object creation, after setting all properties.
function sizeEdit_CreateFcn(hObject, eventdata, handles)
% hObject    handle to sizeEdit (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc
    set(hObject,'BackgroundColor','white');
else
    set(hObject,'BackgroundColor',get(0,'defaultUicontrolBackgroundColor'));
end

% --------------------------------------------------------------------
function loadssofm_Callback(hObject, eventdata, handles)
% hObject    handle to loadssofm (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
[filenameSsofm, pathnameSsofm]=uigetfile('*.mat','Load S-SOFM...','MultiSelect', 'off');
set(handles.ssofm2Text,'String',filenameSsofm);
handles.Ssofm = [pathnameSsofm filenameSsofm];
guidata(ssofm,handles);
a = get(handles.data2Text,'String');
b = get(handles.ssofm2Text,'String');
if a(1:3)~='...' & b(1:3)~='...'
    set(handles.trainButton,'Enable','on')
end

% --------------------------------------------------------------------
function about_Callback(hObject, eventdata, handles)
% hObject    handle to about (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
ssofmAbout;

% --------------------------------------------------------------------
function help_Callback(hObject, eventdata, handles)
% hObject    handle to help (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

function aviText_Callback(hObject, eventdata, handles)
% hObject    handle to aviText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of aviText as text
%        str2double(get(hObject,'String')) returns contents of aviText as a double

% --- Executes during object creation, after setting all properties.
function aviText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to aviText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc
    set(hObject,'BackgroundColor','white');
else
    set(hObject,'BackgroundColor',get(0,'defaultUicontrolBackgroundColor'));
end

% --- Executes on button press in plotglyphButton.
function plotglyphButton_Callback(hObject, eventdata, handles)
% hObject    handle to plotglyphButton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
figure;
glyph(handles.X,handles.r);

% --- Executes on button press in aviRadio.
function aviRadio_Callback(hObject, eventdata, handles)
% hObject    handle to aviRadio (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of aviRadio
if get(hObject,'Value')==1
    set(handles.aviText,'Enable','on');
else
    set(handles.aviText,'Enable','off');
end

% --- Executes on button press in retrainButton.
function retrainButton_Callback(hObject, eventdata, handles)
% hObject    handle to retrainButton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

w = handles.w;
freq = handles.freq;
X = handles.X;
load(handles.Data);
load(handles.Ssofm);
s = str2num(get(handles.sizeEdit,'String'));
if get(handles.plotRadio,'Value') == 1
    showglyph = 'plot';
end
if get(handles.glyphRadio,'Value') == 1
    showglyph = 'glyph';
end
if get(handles.aviRadio,'Value') == 1
    showglyph = get(handles.aviText,'String');
    if isempty(showglyph)
        showglyph = 'test.avi';
    else
        showglyph = [get(handles.aviText,'String') '.avi'];
    end
end

j=1;
% For each epoch
epochs = str2num(get(handles.epochsEdit,'String'));
for i=1:max(epochs)
    % Define the learning rate
    a=0.1*exp(-i/max(epochs));
    % Update the weights
    [w,freq]=updateGlyph(P,X,C,w,a,s,freq);
    % Update g
    g(i+1,:)=[mean(stdrc(w)) 1.96*std(stdrc(w))/sqrt(size(X,1))];
    if strcmp(showglyph,{'none','plot'})==0
        % Standardize the range
        r=stdrc(w);
        % Draw the glyph
        glyph(X,r);
        drawnow
        if strcmp(showglyph,'glyph')==0
            % Add another frame
            aviobj = addframe(aviobj,getframe(gcf));
        end
    elseif showglyph=='plot'
        %plot(0:i,g(1:i+1),'.-','LineWidth',2);
        errorbar(0:i,g(1:i+1,1),g(1:i+1,2),'.-','LineWidth',2);
        axis([0 max(1,i) 1 1.2])
        xlabel('epoch #');
        ylabel('convergence');
        if i<=10
            if i==1
                set(gca,'XTick',0:2);
            else
                set(gca,'XTick',1:i);
            end
        else
            set(gca,'XTickMode','auto');
        end
        drawnow
    else
        % Show progress
        if i==epochs(j)
            fprintf('Epoch %4.0f, log10(convergence) %9.4f\n',i,log10(g(i)));
            j=j+1;
        end
    end
end

[r,c]=stdrc(w);

if strcmp(showglyph,{'none','plot','glyph'})==0
    % Close the avi file
    aviobj = close(aviobj);
end

handles.w = w;
handles.freq = freq;
handles.X = X;


run = true;
last_mrk = '';

state_acquire= bbci_acquire_lsl('init');
cnt = zeros(64, 100);
mrk = zeros(1, 100);

step = 1;

while state_acquire.running
    [cnt_new, cntTime, mrkTime, mrkDesc, state_acquire]= bbci_acquire_lsl(state_acquire);

    if not(isempty(mrkDesc))
        fprintf('RECEIVED %s\n',  mrkDesc{1});
        fprintf('TIME %f \n',  mrkTime);
    end

    %   fprintf('Data %s at %f \n', cnt_new, cntTime);
%     fprintf('step %f \n', step)
%     last_mrk = mrkDesc;
%     last_mrkTime = mrkTime;
%
%     cnt(:,step) = cnt_new;
    step = step + 1;
end
display('Streams broke off')


function A = set(A, varargin)
%
% Set psfMatrix properties and return the updated object.
%
%     A = set(A, ...)
%
%  This funtion accepts an psfMatrix object, A, and a variable list of
%  property name/value pairs and returns the modified object.
%  Valid properties are:
%    'psf', 'matdata', 'type', 'boundary', 'transpose'
%

%  J. Nagy  5/2/01

property_argin = varargin;

while length( property_argin ) >= 2
  prop = property_argin{1};
  val = property_argin{2};
  property_argin = property_argin(3:end);

  switch prop
  case 'psf'
    A.psf = val;
  case 'matdata'
    A.matdata = val;
  case 'type'
    A.type = val;
  case 'boundary'
    A.boundary = val;
  case 'transpose'
    A.transpose = val;
  otherwise
    error('Valid psfMatrix properties: psf, matdata, type, boundary, transpose')
  end
end


%run this test case with the command
%results = runtests('hmmerTests.m')
function tests = hmmerTests
tests = functiontests(localfunctions);
end

function testHmmer(testCase)
%This unit test comprises the functionality test for HMMER in RAVEN:
% 1. Check of parsed HMMER results against the expected.
%
% NOTE: as hmm and HMMER results files are time-specific, no checks for
% these files existence are done. Also, due to the way HMMER is utilized in
% getKEGGModelForOrganism (HMMER result files can be parsed only once all
% required hmm files are generated), the code segment involving HMMER
% results parsing is pasted in this test function. Should the parsing problems
% occur in the results processing, the code modifications shall be done in
% this function and getKEGGModelForOrganism respectively.

%%
%Get the directory for RAVEN Toolbox
[ST, I]=dbstack('-completenames');
ravenPath=fileparts(fileparts(fileparts(ST(I).file)));

%Identify the operating system
if isunix
    if ismac
        binEnd='.mac';
    else
        binEnd='';
    end
elseif ispc
    binEnd='.exe';
else
    dispEM('Unknown OS, exiting.')
    return
end

%Create empty structures needed for HMMER results
actHmmResult.genes = {};
actHmmResult.scores = [];

%Create structures that contain expected HMMER results
expHmmResult.genes = {'sp|P41947|MEL6_YEASX','sp|P41946|MEL5_YEASX', 'sp|P41945|MEL2_YEASX', 'sp|P04824|MEL1_YEASX'};
expHmmResult.scores = [10^-250, 10^-250, 10^-250, 10^-250];

%Generate temporary names for working directory and outFile
tmpDIR=tempname;
outFile=tempname;

%Run HMMER multi-threaded to use all logical cores assigned to MATLAB
cores = evalc('feature(''numcores'')');
cores = strsplit(cores, 'MATLAB was assigned: ');
cores = regexp(cores{2},'^\d*','match');
cores = cores{1};

%Create a temporary folder and copy multi-FASTA file there
[~, ~]=system(['mkdir "' tmpDIR '"']);

sourceDir = fileparts(which(mfilename));
copyfile(fullfile(sourceDir,'test_data','yeast_galactosidases.fa'),tmpDIR);
copyfile(fullfile(sourceDir,'test_data','human_galactosidases.fa'),tmpDIR);

%%
%Train a hidden Markov model
[~, ~]=system(['"' fullfile(ravenPath,'software','hmmer',['hmmbuild' binEnd]) '" --cpu "' num2str(cores) '" "' fullfile(tmpDIR,'human_galactosidases.hmm') '" "' fullfile(tmpDIR,'yeast_galactosidases.fa') '"']);

%Run a homology search against the newly-trained HMM
[~, output]=system(['"' fullfile(ravenPath,'software','hmmer',['hmmsearch' binEnd]) '" --cpu "' num2str(cores) '" "' fullfile(tmpDIR,'human_galactosidases.hmm') '" "' fullfile(tmpDIR,'yeast_galactosidases.fa') '"']);

%Save the output to a file
fid=fopen(outFile,'w');
fwrite(fid,output);
fclose(fid);

%%
%Parse the results
geneCounter=0;
fid=fopen(outFile,'r');
beginMatches=false;
while 1
    %Get the next line
    tline = fgetl(fid);

    %Abort at end of file
    if ~ischar(tline)
        break;
    end

    if and(beginMatches,strcmp(tline,'  ------ inclusion threshold ------'))
        break;
    end

    if beginMatches==false
        %This is how the listing of matches begins
        if any(strfind(tline,'E-value '))
            %Read one more line that is only padding
            tline = fgetl(fid);
            beginMatches=true;
        end
    else
        %If matches should be read
        if ~strcmp(tline,'   [No hits detected that satisfy reporting thresholds]') && ~isempty(tline)
            elements=regexp(tline,' ','split');
            elements=elements(cellfun(@any,elements));

            %Check if the match is below the treshhold
            score=str2double(elements{1});
            gene=elements{9};
            if score<=10^-50
                %If the score is exactly 0, change it to a very
                %small value to avoid NaN
                if score==0
                    score=10^-250;
                end
                %Check if the gene is added already and, is so, get
                %the best score for it
                geneCounter=geneCounter+1;
                actHmmResult.genes{geneCounter}=gene;
                actHmmResult.scores(geneCounter)=score;
            end
        else
            break;
        end
    end
end
fclose(fid);

%Remove the old tempfiles
delete([outFile '*']);

%Remove temporary folder, since testing is finished
[~, ~]=system(['rm "' tmpDIR '" -r']);

%%
%Test 1a: Check if HMMER results match the expected ones
verifyEqual(testCase,actHmmResult,expHmmResult);

%Test 1b: Modify actual HMMER results structure and check if test fails
actHmmResult.score(2)=1;
verifyNotEqual(testCase,actHmmResult,expHmmResult);
end


function mesh = ft_defacemesh(cfg, mesh)

% FT_DEFACEMESH allows you to de-identify a scalp surface mesh by erasing specific
% regions, such as the face and ears. The interactive graphical user interface allows
% you to position a box over the anatomical data inside which all vertices will be
% removed. You might have to call this function multiple times when both face and
% ears need to be removed. Following defacing, you should check the result with
% FT_PLOT_MESH.
%
% Use as
%   mesh = ft_defacevolume(cfg, mesh)
%
% The configuration can contain the following options
%   cfg.translate  = initial position of the center of the box (default = [0 0 0])
%   cfg.scale      = initial size of the box along each dimension (default is automatic)
%   cfg.rotate     = initial rotation of the box (default = [0 0 0])
%   cfg.selection  = which vertices to keep, can be 'inside' or 'outside' (default = 'outside')
%
% See also FT_ANONYMIZEDATA, FT_DEFACEVCOLUME, FT_ANALYSISPIPELINE, FT_PLOT_MESH

% Copyright (C) 2015-2022, 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$

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

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

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

% the actual work is done by FT_DEFACEVOLUME
tmpcfg = cfg;
tmpcfg.showcallinfo = 'no';
tmpcfg.method = 'interactive';
mesh = ft_defacevolume(tmpcfg, mesh);
% remember the output rotate, scale and translate
rotate    = mesh.cfg.rotate;
scale     = mesh.cfg.scale;
translate = mesh.cfg.translate;
% restore provenance information and put back cfg.callinfo
tmpcallinfo = cfg.showcallinfo;
[cfg, mesh] = rollback_provenance(cfg, mesh);
% store these in the output configuration
cfg.showcallinfo = tmpcallinfo;
cfg.rotate       = rotate;
cfg.scale        = scale;
cfg.translate    = translate;

% do the general cleanup and bookkeeping at the end of the function
ft_postamble debug
ft_postamble previous mesh
ft_postamble provenance mesh
ft_postamble history mesh
ft_postamble savevar mesh


% Struct Utility functions
%
% Author: Jonathan Karr
% Affilitation: Covert Lab, Department of Bioengineering, Stanford University
% Last updated: 7/14/2010
classdef StructUtil
    methods (Static=true)
        function A = catstruct(varargin)
            % CATSTRUCT - concatenate structures
            %
            %   X = CATSTRUCT(S1,S2,S3,...) concates the structures S1, S2, ... into one
            %   structure X.
            %
            %   Example:
            %     A.name = 'Me' ;
            %     B.income = 99999 ;
            %     X = catstruct(A,B)
            %     % -> X.name = 'Me' ;
            %     %    X.income = 99999 ;
            %
            %   CATSTRUCT(S1,S2,'sorted') will sort the fieldnames alphabetically.
            %
            %   If a fieldname occurs more than once in the argument list, only the last
            %   occurence is used, and the fields are alphabetically sorted.
            %
            %   To sort the fieldnames of a structure A use:
            %     A = CATSTRUCT(A,'sorted') ;
            %
            %   To concatenate two similar array of structs use simple concatenation:
            %     A = dir('*.mat') ; B = dir('*.m') ; C = [A ; B] ;
            %
            %   When there is nothing to concatenate, the result will be an empty
            %   struct (0x0 struct array with no fields).
            %
            %   See also CAT, STRUCT, FIELDNAMES, STRUCT2CELL

            % for Matlab R13 and up
            % version 2.2 (oct 2008)
            % (c) Jos van der Geest
            % email: jos@jasen.nl

            % History
            % Created:  2005
            % Revisions
            %   2.0 (sep 2007) removed bug when dealing with fields containing cell
            %                  arrays (Thanks to Rene Willemink)
            %   2.1 (sep 2008) added warning and error identifiers
            %   2.2 (oct 2008) fixed error when dealing with empty structs (Thanks to
            %                  Lars Barring)

            N = nargin ;

            error(nargchk(1,Inf,N)) ;

            if ~isstruct(varargin{end}),
                if isequal(varargin{end},'sorted'),
                    sorted = 1 ;
                    N = N-1 ;
                    if N < 1,
                        A = struct([]) ;
                        return
                    end
                else
                    error('catstruct:InvalidArgument','Last argument should be a structure, or the string "sorted".') ;
                end
            else
                sorted = 0 ;
            end

            FN = cell(N,1) ;
            VAL = cell(N,1) ;

            for ii=1:N,
                X = varargin{ii} ;
                if ~isstruct(X),
                    error('catstruct:InvalidArgument',['Argument #' num2str(ii) ' is not a structure.']) ;
                end
                if ~isempty(X),
                    % empty structs are ignored
                    FN{ii} = fieldnames(X) ;
                    VAL{ii} = struct2cell(X) ;
                end
            end

            FN = cat(1,FN{:}) ;
            VAL = cat(1,VAL{:}) ;
            [UFN,ind] = unique(FN) ;

            %BEGIN added by jkarr
            UVAL = {VAL{ind}}';
            for i=1:length(UFN)
                idxs = find(strcmp(FN,UFN{i}));
                if(length(idxs)==1)
                    continue;
                end

                recurse=true;
                for j=1:length(idxs)
                    if(~isstruct(VAL{idxs(j)}))
                        recurse=false;
                        break;
                    end
                end

                if(recurse)
                    UVAL{i} = edu.stanford.covert.util.StructUtil.catstruct(VAL{idxs});
                end
            end
            VAL=UVAL;
            FN=UFN;
            %END added by jkarr

            %BEGIN removed by jkarr
            %if numel(UFN) ~= numel(FN),
            %    warning('catstruct:DuplicatesFound','Duplicate fieldnames found. Last value is used and fields are sorted') ;
            %    sorted = 1 ;
            %end
            %
            %if sorted,
            %    VAL = VAL(ind) ;
            %    FN = FN(ind) ;
            %end
            %END removed by jkarr

            if ~isempty(FN),
                % This deals correctly with cell arrays
                A = cell2struct(VAL, FN);
            else
                A = struct([]) ;
            end
        end

        function diff(struct1, struct2, indent)
            if ~exist('indent', 'var')
                indent = 0;
            end

            fieldNames1 = fieldnames(struct1);
            fieldNames2 = fieldnames(struct2);

            fieldsNotIn2 = setdiff(fieldNames1, fieldNames2);
            fieldsNotIn1 = setdiff(fieldNames2, fieldNames1);

            if ~isempty(fieldsNotIn2)
                fprintf([repmat('\t', 1, indent) 'Fields in struct1 not in struct2:\n' repmat('- %s\n', 1, numel(fieldsNotIn2))], fieldsNotIn2{:});
            end
            if ~isempty(fieldsNotIn1)
                fprintf([repmat('\t', 1, indent) 'Fields in struct2 not in struct1:\n' repmat('- %s\n', 1, numel(fieldsNotIn1))], fieldsNotIn2{:});
            end

            commonFieldNames = intersect(fieldNames1, fieldNames2);
            for i = 1:numel(commonFieldNames)
                val1 = struct1.(commonFieldNames{i});
                val2 = struct2.(commonFieldNames{i});
                class1 = class(val1);
                class2 = class(val2);
                if ~isequal(class1, class2)
                    fprintf([repmat('\t', 1, indent) 'Types of %s''s fields differ (%s v. %s)\n'], commonFieldNames{i}, class1, class2);
                    continue;
                end

                size1 = size(val1);
                size2 = size(val2);
                if ~isequal(size1, size2)
                    fprintf([repmat('\t', 1, indent) 'Sizes of %s''s fields differ (%s v. %s)\n'], commonFieldNames{i}, ...
                        sprintf(['%d' repmat(' x %d', 1, numel(size1)-1)], size1), ...
                        sprintf(['%d' repmat(' x %d', 1, numel(size2)-1)], size2));
                    continue;
                end

                switch class1
                    case 'cell'
                        idxs = find(cellfun(@(x, y) ~isequal(x, y), val1, val2));
                        if isempty(idxs); continue; end;

                        fprintf([repmat('\t', 1, indent) 'Comparing %s fields\n'], commonFieldNames{i});
                        subs = cell(1, ndims(val1));
                        [subs{:}] = ind2sub(size1, idxs);
                        subs = cell2mat(subs);
                        val1 = val1(idxs);
                        for j = 1:numel(idxs)
                            fprintf([repmat('\t', 1, indent+1) '%s\t%s\n'], ...
                                sprintf(['(%d' repmat(', %d', 1, ndims(val1)-1)  ')'], subs(j, :)), ...
                                'differs');
                        end
                    case {'logical', 'int8', 'int16' ,'int32 ','int64', 'uint8', 'uint16', 'uint32', 'uint64', 'double', 'single', 'char'}
                        idxs = find(val1 ~= val2);
                        if isempty(idxs); continue; end;

                        fprintf([repmat('\t', 1, indent) 'Comparing %s fields\n'], commonFieldNames{i});
                        subs = cell(1, ndims(val1));
                        [subs{:}] = ind2sub(size1, idxs);
                        subs = cell2mat(subs);
                        val1 = val1(idxs);
                        val2 = val2(idxs);
                        for j = 1:numel(idxs)
                            fprintf([repmat('\t', 1, indent+1) '%s\t%e\t%e\n'], ...
                                sprintf(['(%d' repmat(', %d', 1, ndims(val1)-1)  ')'], subs(j, :)), ...
                                val1(j), val2(j));
                        end
                    case {'edu.stanford.covert.util.SparseMat', 'edu.stanford.covert.util.CircularSparseMat'}
                        subs = find(val1 ~= val2);
                        if isempty(subs); continue; end;

                        fprintf([repmat('\t', 1, indent) 'Comparing %s fields\n'], commonFieldNames{i});
                        val1 = val1(subs);
                        val2 = val2(subs);
                        for j = 1:numel(idxs)
                            fprintf([repmat('\t', 1, indent+1) '%s\t%e\t%e\n'], ...
                                sprintf(['(%d' repmat(', %d', 1, ndims(val1)-1)  ')'], subs(j, :)), ...
                                val1(j), val2(j));
                        end
                    otherwise
                        fprintf([repmat('\t', 1, indent) 'Comparing %s fields\n'], commonFieldNames{i});
                        edu.stanford.covert.util.StructUtil.diff(val1, val2, indent+1);
                end
            end
        end
    end
end


function  numTSeries = countTSeries(view)
%numTSeries = countTSeries(view)
%
%Counts the tSeries
%
% 12.22.98 RFD: changed countFiles to work with new tSeries format ('.dat')
%				It should still work with old-style '.mat' tSeries files too.

if exist('view','var')
    subdir = view.subdir;
else
    subdir = 'Inplane';
end

[numScans,scanDirList] = countDirs('Scan*',tSeriesDir(view));
for scan=1:numScans
    dirPathStr = fullfile(tSeriesDir(view),scanDirList{scan});
    numTSeries(scan) = countFiles('tSeries*',dirPathStr);
end


%* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
%*                                                                           *
%*                  This file is part of the program and library             *
%*         SCIP --- Solving Constraint Integer Programs                      *
%*                                                                           *
%*    Copyright (C) 2002-2012 Konrad-Zuse-Zentrum                            *
%*                            fuer Informationstechnik Berlin                *
%*                                                                           *
%*  SCIP is distributed under the terms of the ZIB Academic Licence.         *
%*                                                                           *
%*  You should have received a copy of the ZIB Academic License              *
%*  along with SCIP; see the file COPYING. If not email to scip@zib.de.      *
%*                                                                           *
%* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

%@file    scip.m
%@brief   SCIP installation file for MATLAB interface
%@author  Ambros Gleixner
%@author  Timo Berthold

function[bestsol, objval] = scip(matrix, lhs, rhs, obj, lb, ub, vartype, objsense)

% copyright %
fprintf('SCIP-MATLAB interface\n');
fprintf('Copyright (c) 2002-2012 Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB)\n\n');

% syntax description %
usage = '\n';
usage = [usage 'syntax: [bestsol, objval] = scip(matrix, lhs, rhs, obj, lb, ub, vartype, objsense)\n'];
usage = [usage 'input parameters are\n'];
usage = [usage '   matrix   : real matrix with constraint nonzeros\n'];
usage = [usage '   lhs      : real vector with left-hand sides of constraints\n'];
usage = [usage '   rhs      : real vector with right-hand sides of constraints\n'];
usage = [usage '   obj      : real vector with objective coefficient of variables\n'];
usage = [usage '   lb       : real vector with lower bounds of variables\n'];
usage = [usage '   ub       : real vector with upper bounds of variables\n'];
usage = [usage '   vartype  : character vector with types of variables (b: binary, i: general integer, c: continuous)\n'];
usage = [usage '   objsense : value indicating optimization sense (+1: minimize, -1: maximize)\n'];
usage = [usage 'output parameters are\n'];
usage = [usage '   bestsol  : real vector containing best solution found\n'];
usage = [usage '   objval   : objective function value of best solution found\n'];
usage = [usage '\n'];

% output is undefined for an invalid call %
bestsol = NaN;
objval = NaN;

% we do not define default values for input parameters %
if( nargin ~= 8 )
   fprintf('\ninvalid call: provide all input parameters\n');
   fprintf(usage);
   return;
end

% display input parameters %
matrix
lhs
rhs
obj
lb
ub
vartype
objsense

% matrix must be two-dimensional %
if( ndims(matrix) ~= 2 )
   fprintf('\ninvalid call: ndims(matrix) ~= 2\n');
   fprintf(usage);
   return;
end

% get number of variables and constraints %
[nconss,nvars] = size(matrix);

% check that vectors are one-dimensional %
if( ~isvector(lhs) )
   fprintf('\ninvalid call: ~isvector(lhs)\n');
   fprintf(usage);
   return;
elseif( ~isvector(rhs) )
   fprintf('\ninvalid call: ~isvector(rhs)\n');
   fprintf(usage);
   return;
elseif( ~isvector(obj) )
   fprintf('\ninvalid call: ~isvector(obj)\n');
   fprintf(usage);
   return;
elseif( ~isvector(lb) )
   fprintf('\ninvalid call: ~isvector(lb)\n');
   fprintf(usage);
   return;
elseif( ~isvector(ub) )
   fprintf('\ninvalid call: ~isvector(ub)\n');
   fprintf(usage);
   return;
elseif( ~isvector(vartype) )
   fprintf('\ninvalid call: ~isvector(vartype)\n');
   fprintf(usage);
   return;
end

% check that vectors have consistent length %
if( length(lhs) ~= nconss )
   fprintf('\ninvalid call: length(lhs) ~= size(matrix,1)\n');
   fprintf(usage);
   return;
elseif( length(rhs) ~= nconss )
   fprintf('\ninvalid call: length(rhs) ~= size(matrix,1)\n');
   fprintf(usage);
   return;
elseif( length(obj) ~= nvars )
   fprintf('\ninvalid call: length(obj) ~= size(matrix,2)\n');
   fprintf(usage);
   return;
elseif( length(lb) ~= nvars )
   fprintf('\ninvalid call: length(lb) ~= size(matrix,2)\n');
   fprintf(usage);
   return;
elseif( length(ub) ~= nvars )
   fprintf('\ninvalid call: length(ub) ~= size(matrix,2)\n');
   fprintf(usage);
   return;
elseif( length(vartype) ~= nvars )
   fprintf('\ninvalid call: length(vartype) ~= size(matrix,2)\n');
   fprintf(usage);
   return;
end

% check that input values have correct type %
if( ~isreal(matrix) )
   fprintf('\ninvalid call: ~isreal(matrix)\n');
   fprintf(usage);
   return;
elseif( ~isreal(lhs) )
   fprintf('\ninvalid call: ~isreal(lhs)\n');
   fprintf(usage);
   return;
elseif( ~isreal(rhs) )
   fprintf('\ninvalid call: ~isreal(rhs)\n');
   fprintf(usage);
   return;
elseif( ~isreal(obj) )
   fprintf('\ninvalid call: ~isreal(obj)\n');
   fprintf(usage);
   return;
elseif( ~isreal(lb) )
   fprintf('\ninvalid call: ~isreal(lb)\n');
   fprintf(usage);
   return;
elseif( ~isreal(ub) )
   fprintf('\ninvalid call: ~isreal(ub)\n');
   fprintf(usage);
   return;
elseif( ~ischar(vartype) )
   fprintf('\ninvalid call: ~ischar(vartype)\n');
   fprintf(usage);
   return;
elseif( ~strcmp(objsense,'min') && ~strcmp(objsense,'max') )
   fprintf('\ninvalid call: objsense must be min or max\n');
   fprintf(usage);
   return;
else
   for v = 1:length(vartype)
      if( vartype(v) ~= 'b' && vartype(v) ~= 'i' && vartype(v) ~= 'c' )
         fprintf('\ninvalid call: vartype(%d) must be one of {b,i,c}\n', v);
         fprintf(usage);
         return;
      end
   end
end

% call SCIP %
[bestsol, objval] = matscip(matrix, lhs, rhs, obj, lb, ub, vartype, objsense);

bestsol
objval


function var = loadgenericdata(varfile, vartype, fields, varname, args)
%LOADGENERICDATA Loads data of a specified type from file or data structure.
%
%   VAR = LOADGENERICDATA(VARFILE, VARTYPE)
%   VAR = LOADGENERICDATA(VARFILE, VARTYPE, FIELDS)
%   VAR = LOADGENERICDATA(VARFILE, VARTYPE, FIELDS, VARNAME)
%   VAR = LOADGENERICDATA(VARFILE, VARTYPE, FIELDS, VARNAME, ARGS)
%
%   Loads data from a variable or M-file or MAT-file and checks that it
%   matches a specified type.
%
%   Inputs:
%       VARFILE : Variable containing the data structure or a string
%                 containing the name of a function M-file or a MAT-file
%                 on the MATLAB/Octave path. If no file extension is provided
%                 it will attempt to load a MAT-file with that name and,
%                 if not found, will call a function by that name to
%                 get the data. The function M-file should return a
%                 single argument containing the data. A MAT-file should
%                 either contain a single variable with the desired data
%                 or provide the variable name in VARNAME.
%       VARTYPE : String or cell array of strings with, in order of
%                 priority, the data structure type to be returned.
%                 Valid values are 'struct', 'cell' and 'array'.
%       FIELDS :  (optional) String or cell array of strings containing
%                 a list of required fields in case the VARTYPE is struct.
%                 If a required field is missing it will throw an error.
%       VARNAME   (optional) String containing the name of the variable to
%                 extract when loading a MAT-file. If not provided, the
%                 default is to extract the 1st variable, regardless of name.
%       ARGS :    (optional) Scalar or cell array of values that are passed
%                 as input function arguments to VARFILE if it is an M-file.
%
%   Output:
%       VAR : Returned data structure of the first matching VARTYPE.

%   MOST
%   Copyright (c) 2013-2016, Power Systems Engineering Research Center (PSERC)
%   by Daniel Munoz-Alvarez and Ray Zimmerman, PSERC Cornell
%
%   This file is part of MOST.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://github.com/MATPOWER/most for more info.

if isempty(varfile)
    var = [];
    return;
end
if nargin < 5
    args = [];
    if nargin < 4
        varname = '';
        if nargin < 3
            fields = {};
        end
    end
end

if ischar(varfile)      %% it's a file name
    %% check for explicit extension
    l = length(varfile);
    if l > 2
        if strcmp(varfile(l-1:l), '.m')
            rootname = varfile(1:l-2);
            extension = '.m';
        elseif l > 4
            if strcmp(varfile(l-3:l), '.mat')
                rootname = varfile(1:l-4);
                extension = '.mat';
            end
        end
    end

    %% set extension if not specified explicitly
    if ~exist('rootname', 'var')
        rootname = varfile;
        if exist([rootname '.mat'], 'file') == 2
            extension = '.mat';
        elseif exist([rootname '.m'], 'file') == 2
            extension = '.m';
        else
            error('loadgenericdata: No file named ''%s.mat'' or ''%s.m'' found in MATLAB/Octave path.', rootname, rootname);
        end
    end

    %% attempt to read file
    if strcmp(extension,'.mat')         %% from MAT file
        s = load(rootname);
        if isempty(varname)
            f = fieldnames(s);
            var = s.(f{1});             %% use first variable if not specified
        elseif isfield(s, varname)
            var = s.(varname);          %% use specified variable
        else
            error('loadgenericdata: No variable named ''%s'' in ''%s.mat''', varname, rootname);
        end
    elseif strcmp(extension,'.m')       %% from M file
        if isempty(args)
            var = feval(rootname);
        elseif iscell(args)
            var = feval(rootname, args{:});
        else
            var = feval(rootname, args);
        end
    end
else                    %% it's a data structure, not a file name
    var = varfile;
end

%% check the provided types
if ~iscell(vartype)
    vartype = {vartype};    %% convert string to single element cell array
end
if ~iscell(fields) && ~isempty(fields)
    fields = {fields};      %% convert string to single element cell array
end
done = false;
for i = length(vartype)
    switch vartype{i}
        case 'struct'
            if isstruct(var)
                for j = 1:length(fields)
                    if ~ischar(fields{j})
                        error('loadgenericdata: FIELDS input must be a string or cell array of strings.')
                    end
                    if ~isfield(var, fields{j})
                        error('loadgenericdata:missingfield', 'loadgenericdata: field ''%s'' missing from struct data.', fields{j});
                    end
                end
                done = true; break;     %% struct OK
            end

        case 'cell'
            if iscell(var)
                done = true; break;     %% cell array OK
            end

        case 'array'
            if isnumeric(var)
                done = true; break;     %% array OK
            end
        otherwise
            error('loadgenericdata: ''%s'' is not a valid value for VARTYPE', vartype{i});
    end
end
if ~done
    error('loadgenericdata: data not found in any of the specified formats');
end


function C = mtimes(A, B)
%*   CHEBOP composition, multiplication, or application.
%   C = A*B, where either A or B is a scalar, returns a CHEBOP C representing
%   scalar multiplication of the original operator.  Boundary conditions
%   are copied from A or B to C.
%
%   If N is a CHEBOP and U a CHEBFUN or CHEBMATRIX of dimension compatible
%   with N.op, then N*U is equivalent to FEVAL(N, U).
%
%   C = A*B, where A and B are CHEBOP objects, should return a CHEBOP C
%   representing the composition of the operators of A and B. Boundary
%   conditions on A or B are destroyed by this process. Note this is not yet
%   supported.
%
% See also CHEBOP/PLUS, CHEBOP/MINUS, CHEBOP/MLDIVIDE, CHEBOP/FEVAL

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

if ( isa(A, 'chebfun') )
    error('CHEBFUN:CHEBOP:mtimes:invalid', 'Operation is undefined.');

elseif ( isa(B, 'chebfun') || isa(B, 'chebmatrix') )
    % Let A operate on B:
    C = feval(A, B);

elseif ( isnumeric(B) )
    % Switch argument to make sure A is numeric:
    C = mtimes(B, A);

elseif ( isnumeric(A) )

    if ( ~isscalar(A) )
        error('CHEBFUN:CHEBOP:mtimes:nonScalar', ...
            'CHEBOP * DOUBLE multiplication is defined only for scalars.');
    end

    % Initialize C as a CHEBOP
    C = B;

    % Make the pretty string:
    funArgs = getFunArgs(C);
    argStr = ['@(',funArgs,')'];
    if ( ~isempty(C.opShow) )
        op = C.opShow;
    else
        op = func2str(C.op);
    end
    C.opShow = strrep(op, argStr, [argStr num2str(A) '*']);

    % Multiplication of anonymous functions is not supported in Matlab. Need to
    % work around that.
    C.op = eval(['@(', funArgs, ') A*C.op(', funArgs, ')']);

elseif ( isa(A,'chebop') && isa(B,'chebop') )
    % CHEBOP composition is not yet supported. It will probably be a mess once
    % we start getting systems involved, as the inputs need to be shuffled
    % correctly. A remedy might be through a nested function in this file.
    error('CHEBFUN:CHEBOP:mtimes:notSupported1',...
        'CHEBOP composition is not supported.');

else
    error('CHEBFUN:CHEBOP:mtimes:notSupported2', ...
        '%s * %s multiplication is not supported.', class(A), class(B));

end

end


%kImageIcon 'ImageIcon Object Menuform'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros ImageIcon.pane file
%
% Parameters:
% Integer: imageiconSize 'Image Icon Size', default: 1: ' '
% InputFile: imageImagefile ' InputFile', required: 'input file'
%
% Example: kImageIcon(imageImagefile, {'imageiconSize',1;'imageImagefile',''})
%
% Khoros helpfile follows below:
% .begin tagged
%
% .item "The Image Icon Visual Object"
% The image icon visual object displays the image as an icon, or "miniature"
% version of the image.
%
% .item "Image Icon Size"
% This integer value specifies the size of the icon in pixels.
% The image icon size should always be used rather than setting width and
% height separately; otherwise, the image may not be proportionally correct.
%
% .item "Input File"
% The file containing the image to be dsiplayed as an image icon.
%
% .end tagged

function varargout = kImageIcon(varargin)
if nargin ==0
  Inputs={};arglist={'',''};
elseif nargin ==1
  Inputs=varargin{1};arglist={'',''};
elseif nargin ==2
  Inputs=varargin{1}; arglist=varargin{2};
else error('Usage: [out1,..] = kImageIcon(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'imageiconSize', 1;'imageImagefile', '__input'};
maxval={512,0};
minval={-1,0};
istoggle=[0,0];
was_set=istoggle * 0;
paramtype={'Integer','InputFile'};
% identify the input arrays and assign them to the arguments as stated by the user
if ~iscell(Inputs)
Inputs = {Inputs};
end
NumReqOutputs=0; nextinput=1; nextoutput=1;
  for ii=1:size(arglist,1)
  wasmatched=0;
  for jj=1:size(narglist,1)
   if strcmp(arglist{ii,1},narglist{jj,1})  % a given argument was matched to the possible arguments
     wasmatched = 1;
     was_set(jj) = 1;
     if strcmp(narglist{jj,2}, '__input')
      if (nextinput > length(Inputs))
        error(['Input ' narglist{jj,1} ' has no corresponding input!']);
      end
      narglist{jj,2} = 'OK_in';
      nextinput = nextinput + 1;
     elseif strcmp(narglist{jj,2}, '__output')
      if (nextoutput > nargout)
        error(['Output nr. ' narglist{jj,1} ' is not present in the assignment list of outputs !']);
      end
      if (isempty(arglist{ii,2}))
        narglist{jj,2} = 'OK_out';
      else
        narglist{jj,2} = arglist{ii,2};
      end

      nextoutput = nextoutput + 1;
      if (minval{jj} == 0)
         NumReqOutputs = NumReqOutputs - 1;
      end
     elseif isstr(arglist{ii,2})
      narglist{jj,2} = arglist{ii,2};
     else
        if strcmp(paramtype{jj}, 'Integer') & (round(arglist{ii,2}) ~= arglist{ii,2})
            error(['Argument ' arglist{ii,1} ' is of integer type but non-integer number ' arglist{ii,2} ' was supplied']);
        end
        if (minval{jj} ~= 0 | maxval{jj} ~= 0)
          if (minval{jj} == 1 & maxval{jj} == 1 & arglist{ii,2} < 0)
            error(['Argument ' arglist{ii,1} ' must be bigger or equal to zero!']);
          elseif (minval{jj} == -1 & maxval{jj} == -1 & arglist{ii,2} > 0)
            error(['Argument ' arglist{ii,1} ' must be smaller or equal to zero!']);
          elseif (minval{jj} == 2 & maxval{jj} == 2 & arglist{ii,2} <= 0)
            error(['Argument ' arglist{ii,1} ' must be bigger than zero!']);
          elseif (minval{jj} == -2 & maxval{jj} == -2 & arglist{ii,2} >= 0)
            error(['Argument ' arglist{ii,1} ' must be smaller than zero!']);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} < minval{jj})
            error(['Argument ' arglist{ii,1} ' must be bigger than ' num2str(minval{jj})]);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} > maxval{jj})
            error(['Argument ' arglist{ii,1} ' must be smaller than ' num2str(maxval{jj})]);
          end
        end
     end
     if ~strcmp(narglist{jj,2},'OK_out') &  ~strcmp(narglist{jj,2},'OK_in')
       narglist{jj,2} = arglist{ii,2};
     end
   end
   end
   if (wasmatched == 0 & ~strcmp(arglist{ii,1},''))
        error(['Argument ' arglist{ii,1} ' is not a valid argument for this function']);
   end
end
% match the remaining inputs/outputs to the unused arguments and test for missing required inputs
 for jj=1:size(narglist,1)
     if  strcmp(paramtype{jj}, 'Toggle')
        if (narglist{jj,2} ==0)
          narglist{jj,1} = '';
        end;
        narglist{jj,2} = '';
     end;
     if  ~strcmp(narglist{jj,2},'__input') && ~strcmp(narglist{jj,2},'__output') && istoggle(jj) && ~ was_set(jj)
          narglist{jj,1} = '';
          narglist{jj,2} = '';
     end;
     if strcmp(narglist{jj,2}, '__input')
      if (minval{jj} == 0)  % meaning this input is required
        if (nextinput > size(Inputs))
           error(['Required input ' narglist{jj,1} ' has no corresponding input in the list!']);
        else
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        end
      else  % this is an optional input
        if (nextinput <= length(Inputs))
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end;
     else
     if strcmp(narglist{jj,2}, '__output')
      if (minval{jj} == 0) % this is a required output
        if (nextoutput > nargout & nargout > 1)
           error(['Required output ' narglist{jj,1} ' is not stated in the assignment list!']);
        else
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
          NumReqOutputs = NumReqOutputs-1;
        end
      else % this is an optional output
        if (nargout - nextoutput >= NumReqOutputs)
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end
     end
  end
end
if nargout
   varargout = cell(1,nargout);
else
  varargout = cell(0);
end
global KhorosRoot
if exist('KhorosRoot') && ~isempty(KhorosRoot)
w=['"' KhorosRoot];
else
if ispc
  w='"C:\Program Files\dip\khorosBin\';
else
[s,w] = system('which cantata');
w=['"' w(1:end-8)];
end
end
callKhoros([w 'ImageIcon" '],Inputs,narglist);


function im = text_to_image(str,varargin)
  % TEXT_TO_IMAGE  Create an grayscale image the given text
  %
  % im = text_to_image(str)
  % im = text_to_image(str,'ParameterName',ParameterValue, ...)
  %
  % Inputs:
  %   str  string of text
  %   Optional:
  %     'FontName  followed by name of font. List available fonts using
  %       `/usr/local/bin/convert -list font | sed -n "s/^ *Font: //p"`
  %       {'CourierNewB'}
  %     'PointSize'  followed by height of font (in pixels) {200}
  % Outputs:
  %   im  h by w image of text
  %
  % Example:
  %   im = text_to_image('Zapfino','FontName','Zapfino');imshow(im)
  %

  % Defaults
  fontname = [];
  pointsize = 200;
  filename = 'text_to_image-tmp.png';
  % Map of parameter names to variable names
  params_to_variables = containers.Map( ...
    {'FontName','PointSize'}, ...
    {'fontname','pointsize'});
  v = 1;
  while v <= numel(varargin)
    param_name = varargin{v};
    if isKey(params_to_variables,param_name)
      assert(v+1<=numel(varargin));
      v = v+1;
      % Trick: use feval on anonymous function to use assignin to this workspace
      feval(@()assignin('caller',params_to_variables(param_name),varargin{v}));
    else
      error('Unsupported parameter: %s',varargin{v});
    end
    v=v+1;
  end
  if isempty(fontname)
    fontname = 'CourierNewB';
  end

  cmd = sprintf( ...
    ['%s -size %dx%d xc:white -font "%s" -pointsize %d ' ...
     '-fill black -annotate +%d+%d "%s" -trim -bordercolor "#FFF" ' ...
     '-border 0 %s'], ...
   path_to_convert,pointsize*2*numel(str),pointsize*4,fontname,pointsize, ...
   0,2*pointsize,str, ...
   filename);
  [status,result] = system(cmd);
  if status ~= 0
    warning(cmd);
    error(result);
  end
  im = imread(filename);
  delete(filename);
end


function x0 = addfixparameters(x0,x,fixedparam)
x0(~fixedparam) = x;
end


% Assigns the given value to the named property of an object or structure.
% This function can deal with nested properties.
%
% Input arguments:
% obj:
%    the structure, handle or value object the value should be assigned to
% name:
%    a property name with dot (.) separating property names at
%    different hierarchy levels
% value:
%    the value to assign to the property at the deepest hierarchy
%    level
%
% Output arguments:
% obj:
%    the updated object or structure, optional for handle objects
%
% Example:
%    obj = struct('surface', struct('nested', 10));
%    obj = nestedassign(obj, 'surface.nested', 23);
%    disp(obj.surface.nested);  % prints 23
%
% See also: nestedfetch

% Copyright 2010 Levente Hunyadi
function obj = nestedassign(obj, name, value)
    if ~iscell(name)
        nameparts = strsplit2(name, '.');
    else
        nameparts = name;
    end
    obj = nestedassign_recurse(obj, nameparts, value);
end

function obj = nestedassign_recurse(obj, name, value)
% Assigns the given value to the named property of an object.
%
% Input arguments:
% obj:
%    the handle or value object the value should be assigned to
% name:
%    a cell array of the composite property name
% value:
%    the value to assign to the property at the deepest hierarchy
%    level
    if numel(name) > 1
        obj.(name{1}) = nestedassign_recurse(obj.(name{1}), name(2:end), value);
    else
        obj.(name{1}) = value;
    end
end


% clc - clear command window.
%
% USAGE
%  c
%
% INPUTS
%
% OUTPUTS
%
% EXAMPLE
%
% See also CLC, CC, CCC
%
% Piotr's Image&Video Toolbox      Version 1.5
% Copyright 2012 Piotr Dollar.  [pdollar-at-caltech.edu]
% Please email me if you find bugs, or have suggestions or questions!
% Licensed under the Simplified BSD License [see external/bsd.txt]

clc


function [hFig, iDS, iFig] = view_timeseries(DataFile, Modality, RowNames, hFig)
% VIEW_TIMESERIES: Display times series in a new figure.
%
% USAGE: [hFig, iDS, iFig] = view_timeseries(DataFile, Modality=[], RowNames=[], hFig=[])
%        [hFig, iDS, iFig] = view_timeseries(DataFile, Modality=[], RowNames=[], 'NewFigure')
%        [hFig, iDS, iFig] = view_timeseries(DataFiles, ...)
%
% INPUT:
%     - DataFile  : Path to data file to visualize
%     - DataFiles : Cell-array of file paths (simply calls this function recursively for each file)
%     - Modality  : Modality to display with the input Data file
%     - RowNames  : Cell array of channel names to plot in this figure
%     - "NewFigure" : force new figure creation (do not re-use a previously created figure)
%     - hFig        : Specify the figure in which to display the MRI
%
% OUTPUT :
%     - hFig : Matlab handle to the 3DViz figure that was created or updated
%     - iDS  : DataSet index in the GlobalData variable
%     - iFig : Indice of returned figure in the GlobalData(iDS).Figure array

% @=============================================================================
% 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-2023

%% ===== INITIALIZATION =====
global GlobalData;
% Parse inputs
if (nargin < 3) || isempty(RowNames)
    RowNames = {};
elseif ischar(RowNames)
    RowNames = {RowNames};
end
if (nargin < 2) || isempty(Modality)
    % Get default modality
    [AllMod,DispMod,Modality] = bst_get('ChannelModalities', DataFile);
    % Replace SEEG and ECOG with SEEG+ECOG
    if ~isempty(DispMod) && all(ismember({'SEEG','ECOG'}, DispMod))
        DispMod = cat(2, {'ECOG+SEEG'}, setdiff(DispMod, {'SEEG','ECOG'}));
        if ismember(Modality, {'SEEG','ECOG'})
            Modality = 'ECOG+SEEG';
        end
    elseif ~isempty(AllMod) && ismember(Modality, {'SEEG','ECOG'}) && all(ismember({'SEEG','ECOG'}, AllMod))
        Modality = 'ECOG+SEEG';
        DispMod = union(DispMod, {'ECOG+SEEG','SEEG','ECOG'});
    end
else
    DispMod = [];
end
% Get target figure
if (nargin < 4) || isempty(hFig)
    hFig = [];
    iFig = [];
    NewFigure = 0;
elseif ischar(hFig) && strcmpi(hFig, 'NewFigure')
    hFig = [];
    iFig = [];
    NewFigure = 1;
elseif ishandle(hFig)
    [hFig,iFig,iDS] = bst_figures('GetFigure', hFig);
    NewFigure = 0;
else
    error('Invalid figure handle.');
end
% Multiple files in input: call function recursively
if iscell(DataFile)
    hFigInput = hFig;
    hFig = zeros(1,length(DataFile));
    iDS = zeros(1,length(DataFile));
    iFig = zeros(1,length(DataFile));
    for iFile = 1:length(DataFile)
        [hFig(iFile), iDS(iFile), iFig(iFile)] = view_timeseries(DataFile{iFile}, Modality, RowNames, hFigInput);
        % Remove the borders in the figure
        hAxes = findobj(hFig(iFile), '-depth', 1, 'tag', 'AxesGraph');
        set(hFig(iFile), bst_get('ResizeFunction'), []);
        set(hAxes, 'Units', 'normalized', 'Position', [0 0 1 1]);
    end
    return;
end

%% ===== GET A DATASET AND LOAD DATA =====
% Get DataFile information
[sStudy, iData, ChannelFile] = bst_memory('GetFileInfo', DataFile);
% If Channel is not defined
if isempty(ChannelFile)
    Modality = 'EEG';
end
% If not loaded yet
if isempty(hFig)
    % Load file
    iDS = bst_memory('LoadDataFile', DataFile);
    % If no DataSet is accessible : error
    if isempty(iDS)
        return
    end
end
% Check that the selected modality can be displayed, if not select another one
if ~isempty(DispMod)
    % List of expected modalities, in order of preference
    AllMod = {'MEG', 'MEG MAG', 'MEG GRAD', 'EEG', 'ECOG', 'SEEG', 'ECOG+SEEG'};
    % Get the list of good modalities
    GoodMod = unique({GlobalData.DataSet(iDS).Channel(GlobalData.DataSet(iDS).Measures.ChannelFlag == 1).Type});
    GoodMod = intersect(GoodMod, DispMod);
    % Add MEG for Elekta systems
    if any(ismember({'MEG MAG', 'MEG GRAD'}, GoodMod))
        GoodMod{end+1} = 'MEG';
    end
    % Add combined ECOG+SEEG
    if all(ismember({'ECOG', 'SEEG'}, GoodMod))
        GoodMod{end+1} = 'ECOG+SEEG';
    end
    % Get the preferred modalities
    iMod = find(ismember(AllMod, GoodMod));
    GoodMod = AllMod(iMod);
    % If the selected modality is not in the list of the good ones: select the first of the good ones.
    if ~isempty(iMod) && ~ismember(Modality, GoodMod)
        Modality = GoodMod{1};
    end
end

%% ===== CREATE A NEW FIGURE =====
bst_progress('start', 'View time series', 'Loading data...');
if isempty(hFig)
    % Prepare FigureId structure
    FigureId.Type     = 'DataTimeSeries';
    FigureId.SubType  = '';
    FigureId.Modality = Modality;
    % Create TimeSeries figure
    if NewFigure
        [hFig, iFig, isNewFig] = bst_figures('CreateFigure', iDS, FigureId, 'AlwaysCreate', RowNames);
    else
        [hFig, iFig, isNewFig] = bst_figures('CreateFigure', iDS, FigureId, [], RowNames);
    end
    if isempty(hFig)
        bst_error('Could not create figure', 'View time series', 0);
        return;
    end
else
    isNewFig = 0;
end
% Add DataFile to figure appdata
setappdata(hFig, 'DataFile', DataFile);
setappdata(hFig, 'StudyFile', GlobalData.DataSet(iDS).StudyFile);
setappdata(hFig, 'SubjectFile', GlobalData.DataSet(iDS).SubjectFile);

%% ===== SELECT ROWS =====
LinesColor = {};
% Select only the channels that we need to plot
if ~isempty(RowNames)
    % Get the channels normally displayed in this figure
    iSelChanMod = GlobalData.DataSet(iDS).Figure(iFig).SelectedChannels;
    AllChannels = {GlobalData.DataSet(iDS).Channel.Name};
    % Remove all spaces
    AllChannels = cellfun(@(c)strrep(c,' ',''), AllChannels, 'UniformOutput', 0);
    RowNames    = cellfun(@(c)strrep(c,' ',''), RowNames,    'UniformOutput', 0);
    % Get the channels that are requested from the command line call (RowNames argument)
    iSelChanCall = [];
    for i = 1:length(RowNames)
        iSelChanCall = [iSelChanCall, find(strcmpi(RowNames{i}, AllChannels))];
        % NIRS: color based on the name
        if isequal(Modality, 'NIRS') && (length(iSelChanCall) == i)
            if ~isempty(strfind(lower(RowNames{i}), 'hbo'))
                LinesColor{i} = [1,0,0];
            elseif ~isempty(strfind(lower(RowNames{i}), 'hbr'))
                LinesColor{i} = [0,0,1];
            elseif ~isempty(strfind(lower(RowNames{i}), 'hbt'))
                LinesColor{i} = [0,1,0];
            end
        else
            LinesColor = {};
        end
    end
    % Keep only the intersection of the two selections (if non-empty)
    if ~isempty(iSelChanCall) && ~isempty(intersect(iSelChanMod, iSelChanCall))
        GlobalData.DataSet(iDS).Figure(iFig).SelectedChannels = intersect(iSelChanMod, iSelChanCall);
    end
    % Redraw position of figures
    if (iFig > 1)
        gui_layout('Update');
    end
end

%% ===== CONFIGURE FIGURE =====
% Static dataset ?
setappdata(hFig, 'isStatic', (GlobalData.DataSet(iDS).Measures.NumberOfSamples <= 2));
% Raw file
isRaw = strcmpi(GlobalData.DataSet(iDS).Measures.DataType, 'raw');
% Statistics?
% isStat = strcmpi(GlobalData.DataSet(iDS).Measures.DataType, 'stat');
isStat = ~ismember(GlobalData.DataSet(iDS).Measures.DataType, {'recordings', 'raw'});

% Create time-series information structure
if isNewFig
    % Create figure structure
    TsInfo = db_template('TsInfo');
    TsInfo.FileName      = DataFile;
    TsInfo.Modality      = Modality;
    TsInfo.DisplayMode   = bst_get('TSDisplayMode');
    TsInfo.LinesLabels   = {};
    TsInfo.AxesLabels    = {};
    TsInfo.LinesColor    = LinesColor;
    TsInfo.RowNames      = RowNames;
    TsInfo.MontageName   = [];
    TsInfo.DefaultFactor = figure_timeseries('GetDefaultFactor', Modality);
    TsInfo.DisplayUnits  = GlobalData.DataSet(iDS).Measures.DisplayUnits;
    TsInfo.FlipYAxis     = ~isempty(Modality) && ismember(Modality, {'EEG','MEG','MEG GRAD','MEG MAG','SEEG','ECOG','NIRS'}) && ~isStat && bst_get('FlipYAxis');
    TsInfo.AutoScaleY    = bst_get('AutoScaleY');
    TsInfo.NormalizeAmp  = 0;
    TsInfo.Resolution    = [0 0];
    TsInfo.ShowXGrid     = bst_get('ShowXGrid');
    TsInfo.ShowYGrid     = bst_get('ShowYGrid');
    TsInfo.ShowZeroLines = bst_get('ShowZeroLines');
    TsInfo.ShowEventsMode = bst_get('ShowEventsMode');
    % Hide events only for multiple RAW figures
    allId = [GlobalData.DataSet(iDS).Figure(1:iFig-1).Id];
    TsInfo.ShowEvents = ~isRaw || ((iFig == 1) || ~any(strcmpi({allId.Type}, 'DataTimeSeries')));
else
    TsInfo = getappdata(hFig, 'TsInfo');
    TsInfo.FileName = DataFile;
end
setappdata(hFig, 'TsInfo', TsInfo);
% Get default montage
if isNewFig
    sMontage = panel_montage('GetCurrentMontage', Modality);
    % If displaying a SEEG for which a bipolar montage has already been applied: ignore current montage
    if ~isempty(sMontage) && isempty(RowNames) && strcmpi(Modality, 'SEEG') && all(cellfun(@(c)any(c=='-'), {GlobalData.DataSet(iDS).Channel.Name}))
        TsInfo.MontageName = [];
    % Use previous montage
    elseif ~isempty(sMontage) && isempty(RowNames) && (~isStat || strcmpi(sMontage.Type, 'selection')) && ~ismember(sMontage.Name, {'ICA components[tmp]', 'SSP components[tmp]'})
        TsInfo.MontageName = sMontage.Name;
    else
        TsInfo.MontageName = [];
    end
    setappdata(hFig, 'TsInfo', TsInfo);
end
% If no bad channels are available: do not accept bad channels montage
if isequal(TsInfo.MontageName, 'Bad channels') && ~any(GlobalData.DataSet(iDS).Measures.ChannelFlag == -1)
    TsInfo.MontageName = [];
    setappdata(hFig, 'TsInfo', TsInfo);
end
% Default display mode: Force to 'butterfly' if there is only one channel to display
if isequal(TsInfo.MontageName, 'Bad channels')
    nChan = nnz(GlobalData.DataSet(iDS).Measures.ChannelFlag == -1);
else
    nChan = length(GlobalData.DataSet(iDS).Figure(iFig).SelectedChannels);
end
if (nChan == 1) && strcmpi(TsInfo.DisplayMode, 'column')
    TsInfo.DisplayMode = 'butterfly';
    setappdata(hFig, 'TsInfo', TsInfo);
end

%% ===== PLOT TIME SERIES =====
% Update figure selection
bst_figures('SetCurrentFigure', hFig, '2D');
% Plot figure
isOk = figure_timeseries('PlotFigure', iDS, iFig);
% Some error occured during the display procedure: close the window and stop process
if ~isOk
    close(hFig);
    return;
end

%% ===== UPDATE ENVIRONMENT =====
% Uniformize time series scales if required
isUniform = bst_get('UniformizeTimeSeriesScales');
if ~isempty(isUniform) && (isUniform == 1)
    figure_timeseries('UniformizeTimeSeriesScales', 1);
end
% Set the Y scale factor if necessary
if isRaw && ~isempty(Modality) && (Modality(1) ~= '$')
    newScale = bst_get('FixedScaleY', [Modality, TsInfo.DisplayMode]);
    if ~isempty(newScale)
        figure_timeseries('SetScaleY', iDS, iFig, newScale);
    end
end
% Set figure visible
if strcmpi(get(hFig,'Visible'), 'off')
    set(hFig, 'Visible', 'on');
end
% Set the time label visible
figure_timeseries('SetTimeVisible', hFig, 1);
% Last updates
if isNewFig
    % Update record tab
    panel_record('UpdateDisplayOptions', hFig);
    % Update stat tab
    if isStat
        panel_stat('CurrentFigureChanged_Callback', hFig);
    % Select Record tab
    else
        gui_brainstorm('SetSelectedTab', 'Record');
    end
else
    % Update figure name
    bst_figures('UpdateFigureName', hFig);
end
% Open Cluster tab
if ~isempty(GlobalData.DataSet(iDS).Clusters)
    gui_brainstorm('ShowToolTab', 'Cluster');
end
% Close progress bar
drawnow;
bst_progress('stop');


function w=antelope2waveform_test()
    %dbpath = '/aerun/sum/db/archive/archive_2011/archive_2011_11_16';
    gismopath = fileparts(which('startup_GISMO'));
    dbpath = fullfile(gismopath, 'tests', 'test_data', 'antelope2waveform_testdb')
    sta = '.*';
    sta = 'AKT';
    sta = '.*';
    %sta = 'AKT|CRAP|VIB';
    chan = 'HHZ.*';
    %chan = 'HH.*';
    starttime = datenum2epoch(datenum('16-Nov-2011 16:29:00'));
    endtime = datenum2epoch(datenum('16-Nov-2011 16:43:24'));
%     dbexample_get_demodb_path;
%     dbpath = demodb_path;
%     sta = '.*';
%     chan = '.*';
%     starttime = [];
%     endtime = [];
     w=antelope.antelope2waveform(dbpath, sta, chan, starttime, endtime);
end


function [ output_args ] = vVecA2vVecB( vxA, vyA, pxA, pxB )
%UNTITLED Summary of this function goes here
%   Detailed explanation goes here

end


function warpedScanNumV = getAssocWarpedScanNum(scanNumV,planC)
% Return warped scan created from input (moving) scanNum.
% ------------------------------------------------------------------------
% scanNumV   : Vector of scan nos.
% planC
% ------------------------------------------------------------------------
% AI 12/09/21

indexS = planC{end};

assocMovScanUIDc = {planC{indexS.scan}.assocMovingScanUID};

warpedScanNumV = nan(1,length(scanNumV)); % Initialize
for nScan = 1:length(scanNumV)
    movScanUID = {planC{indexS.scan}(scanNumV(nScan)).scanUID};
    assocIdxV = strcmpi(movScanUID,assocMovScanUIDc);
    if any(assocIdxV)
        warpedScanNumV(nScan) = find(assocIdxV);
    end
end
warpedScanNumV = warpedScanNumV(~isnan(warpedScanNumV));

end


function [tightInset,figTightInset] = calcTightInset(mtexFig)
% determine tight inset for each axis

tightInset = zeros(1,4);
figTightInset = mtexFig.outerPlotSpacing * [1,1,1,1];

%return

if isempty(mtexFig.children), return; end
ax = mtexFig.children(1);

if strcmpi(get(ax,'visible'),'off') || strcmpi(get(ax,'XColor'),'none')

  xtl = get(ax,'xTickLabel');
  ytl = get(ax,'yTickLabel');
  %xl = get(ax,'xLabel');
  %yl = get(ax,'yLabel');
  set(ax,'xTickLabel',[],'yTickLabel',[],'units','pixel');
  tightInset = get(ax,'tightInset');
  %set(ax,'xTickLabel',xtl,'yTickLabel',ytl,'xlabel',xl,'ylabel',yl);
  set(ax,'xTickLabel',xtl,'yTickLabel',ytl);

  % consider text labels
  txt = findall(ax,'type','text','unit','data');
  s = get(txt,'string');
  if ~iscell(s), s = {s}; end
  ind = cellfun(@isempty,s);
  txt = txt(~ind);
  if ~isempty(txt)
    pos = ensurecell(get(txt,'position'));
    set(txt,'unit','pixel')
    ext = cell2mat(ensurecell(get(txt,'extent')));
    %set(txt,'units','data');
    for i=1:length(txt), set(txt(i),'units','data','position',pos{i}); end
    pos = get(ax,'position');
    tightInset(1:2) = max([tightInset(1:2);-ext(:,1:2)]);
    tightInset(3:4) = max([tightInset(3:4);ext(:,1:2)+ext(:,3:4)-repmat(pos(3:4),size(ext,1),1)]);
  end

elseif all(get(ax,'ticklength') == 0)

  xt = get(ax,'xtick');
  yt = get(ax,'ytick');
  set(ax,'xtick',[],'ytick',[]);
  %axis(ax,'normal');
  tightInset = get(ax,'tightInset');
  %axis(ax,'equal','tight');
  set(ax,'xtick',xt,'ytick',yt);

else %if strcmpi(get(ax,'PlotBoxAspectRatioMode'),'auto')

  tightInset = get(ax,'tightInset');

end

 % consider colorbar
 if ~isempty(mtexFig.cBarAxis)

   pos = get(mtexFig.cBarAxis(1),'position');
   pos = pos(3:4);
   pos(pos==max(pos)) = 0;
   fs = get(mtexFig.cBarAxis(1),'FontSize');

   try
     tiPos = get(mtexFig.cBarAxis(1),'tightInset');
     tiPos = tiPos(1:2) + tiPos(3:4);

   catch
     l = get(mtexFig.cBarAxis(1),'Label');
     s = get(l,'String');
     if isempty(s)
       tiPos = [3.5,1.5] * fs;
     elseif get(l,'Rotation') == 0
       tiPos = [3.5,3.5] * fs;
     else
       tiPos = [5.5,1.5] * fs;
     end
   end
   mtexFig.cBarShift = tiPos(pos>0) + fs / 2;

   pos(pos>0) = pos(pos>0) + mtexFig.cBarShift + fs / 2;

   if numel(mtexFig.cBarAxis) == numel(mtexFig.children)
     tightInset = tightInset + [0,pos(2),pos(1),0];
   else
     figTightInset = figTightInset + [0,pos(2),pos(1),0];
   end
 end

 % consider sgtitle
 h = findobj(gcf,'Type','subplottext');
 if ~isempty(h)
   figTightInset(4) = figTightInset(4) + 2.5*h(1).FontSize;
 end

end


%% subplotPPT _ Demo script
% Demonstrates different ways in which the function subplotPPT can work
%
% Copyright 2008, The MathWorks, Inc. MATLAB and Simulink are registered
% trademarks of The MathWorks, Inc. See www.mathworks.com/trademarks for a
% list of additional trademarks. Other product or brand names may be
% trademarks or registered trademarks of their respective holders.

%% Individual usage
% Here we plot successive windows to the third  slide in a  presentation

close all
clear
h(1) = figure;
peaks;
h(2) = figure;
membrane;
h(3) = figure;
spy;
h(4) = figure;
image;

for ii = 1:numel(h)
    subplotPPT(2,2,ii,h(ii),[pwd,filesep,'test.ppt'],1);
end

%% Call together
% Instead of calling the function in a for loop we can group the figures
% and call the function once
close all
clear
h(1) = figure;
peaks;
h(2) = figure;
membrane;
h(3) = figure;
spy;
h(4) = figure;
image;

subplotPPT(2,2,[4:-1:1],h,[pwd,filesep,'test.ppt'],[]);

%% Try merging plots (Similar to subplot)
close all
clear
h(1) = figure;
peaks;
h(2) = figure;
membrane;
h(3) = figure;
spy;
h(4) = figure;
image;
h(5) = figure;
tori4;

subplotPPT(3,3,[1 4; 2 3; 5 5; 6 9; 7 8],h,[pwd,filesep,'test.ppt'],3,...
    'region',[.1 .1 .8 .8],'hgap',10,'vgap',10);

%% Try different way of specifying region
close all
clear
h(1) = figure;
peaks;
h(2) = figure;
membrane;
h(3) = figure;
spy;
h(4) = figure;
image;
h(5) = figure;
tori4;

subplotPPT(3,3,[1 4; 2 3; 5 5; 6 9; 7 8],h,[pwd,filesep,'TestImage.gif'],4,...
    'region',[200 100 500 340],'hgap',10,'vgap',10,'units','pixels');

%% Create image files
% rather than save to clipboard now create image files in a separate
% directory akin to the puiblish command

subplotPPT(3,3,[1 4; 2 3; 5 5; 6 9; 7 8],h,[pwd,filesep,'test.ppt'],7,...
    'region',[200 100 500 340],'hgap',.1,'vgap',.1,'gapunits','norm','units','pixels',...
    'ImageFormat','emf');

%% Create image files
% rather than save to clipboard now create image files in a separate
% directory akin to the puiblish command
close all
clear
h(1) = figure;
peaks;
h(2) = figure;
membrane;
h(3) = figure;
spy;
h(4) = figure;
image;
h(5) = figure;
tori4;
%%
subplotPPT(3,3,[1 4; 2 3; 5 5; 6 9; 7 8],h,[],5,...
    'region',[200 100 500 340],'hgap',.1,'vgap',.1,'gapunits','norm','units','pixels',...
    'ImageFormat','emf');

%% Create image files
% rather than save to clipboard now create image files in a separate
% directory akin to the puiblish command
close all
clear
h(1) = figure;
peaks;
h(2) = figure;
membrane;
h(3) = figure;
spy;
h(4) = figure;
image;
h(5) = figure;
tori4;

ext = {'.ppt','.bmp','.emf','.gif','.jpg','.png','.tif'};
Idx = 3;

subplotPPT(3,3,[1 4; 2 3; 5 5; 6 9; 7 8],h,['test',ext{Idx}],3,...
    'region',[200 100 500 340],'hgap',.1,'vgap',.1,'gapunits','norm','units','pixels',...
    'ImageFormat','emf');


%  internal function

%  - Jimmy Shen (jimmy@rotman-baycrest.on.ca)

function save_nii_hdr(hdr, fid)

   if ~isequal(hdr.hk.sizeof_hdr,348),
      error('hdr.hk.sizeof_hdr must be 348.');
   end

   write_header(hdr, fid);

   return;					% save_nii_hdr

%---------------------------------------------------------------------
function write_header(hdr, fid)

        %  Original header structures
	%  struct dsr				/* dsr = hdr */
	%       {
	%       struct header_key hk;            /*   0 +  40       */
	%       struct image_dimension dime;     /*  40 + 108       */
	%       struct data_history hist;        /* 148 + 200       */
	%       };                               /* total= 348 bytes*/

   header_key(fid, hdr.hk);
   image_dimension(fid, hdr.dime);
   data_history(fid, hdr.hist);

   %  check the file size is 348 bytes
   %
   fbytes = ftell(fid);

   if ~isequal(fbytes,348),
      msg = sprintf('Header size is not 348 bytes.');
      warning(msg);
   end

   return;					% write_header

%---------------------------------------------------------------------
function header_key(fid, hk)

   fseek(fid,0,'bof');

	%  Original header structures
	%  struct header_key                      /* header key      */
	%       {                                /* off + size      */
	%       int sizeof_hdr                   /*  0 +  4         */
	%       char data_type[10];              /*  4 + 10         */
	%       char db_name[18];                /* 14 + 18         */
	%       int extents;                     /* 32 +  4         */
	%       short int session_error;         /* 36 +  2         */
	%       char regular;                    /* 38 +  1         */
	%       char hkey_un0;                   /* 39 +  1 */
	%       };                               /* total=40 bytes  */

   fwrite(fid, hk.sizeof_hdr(1),    'int32');	% must be 348.

   % data_type = sprintf('%-10s',hk.data_type);	% ensure it is 10 chars from left
   % fwrite(fid, data_type(1:10), 'uchar');
   pad = zeros(1, 10-length(hk.data_type));
   hk.data_type = [hk.data_type  char(pad)];
   fwrite(fid, hk.data_type(1:10), 'uchar');

   % db_name   = sprintf('%-18s', hk.db_name);	% ensure it is 18 chars from left
   % fwrite(fid, db_name(1:18), 'uchar');
   pad = zeros(1, 18-length(hk.db_name));
   hk.db_name = [hk.db_name  char(pad)];
   fwrite(fid, hk.db_name(1:18), 'uchar');

   fwrite(fid, hk.extents(1),       'int32');
   fwrite(fid, hk.session_error(1), 'int16');
   fwrite(fid, hk.regular(1),       'uchar');

   fwrite(fid, hk.hkey_un0(1),    'uchar');

   return;					% header_key

%---------------------------------------------------------------------
function image_dimension(fid, dime)

	%struct image_dimension
	%       {                                /* off + size      */
	%       short int dim[8];                /* 0 + 16          */
	%       char vox_units[4];               /* 16 + 4          */
	%       char cal_units[8];               /* 20 + 8          */
	%       short int unused1;               /* 28 + 2          */
	%       short int datatype;              /* 30 + 2          */
	%       short int bitpix;                /* 32 + 2          */
	%       short int dim_un0;               /* 34 + 2          */
	%       float pixdim[8];                 /* 36 + 32         */
	%			/*
	%				pixdim[] specifies the voxel dimensions:
	%				pixdim[1] - voxel width
	%				pixdim[2] - voxel height
	%				pixdim[3] - interslice distance
	%					..etc
	%			*/
	%       float vox_offset;                /* 68 + 4          */
	%       float roi_scale;                 /* 72 + 4          */
	%       float funused1;                  /* 76 + 4          */
	%       float funused2;                  /* 80 + 4          */
	%       float cal_max;                   /* 84 + 4          */
	%       float cal_min;                   /* 88 + 4          */
	%       int compressed;                  /* 92 + 4          */
	%       int verified;                    /* 96 + 4          */
	%       int glmax;                       /* 100 + 4         */
	%       int glmin;                       /* 104 + 4         */
	%       };                               /* total=108 bytes */

   fwrite(fid, dime.dim(1:8),      'int16');

   pad = zeros(1, 4-length(dime.vox_units));
   dime.vox_units = [dime.vox_units  char(pad)];
   fwrite(fid, dime.vox_units(1:4),  'uchar');

   pad = zeros(1, 8-length(dime.cal_units));
   dime.cal_units = [dime.cal_units  char(pad)];
   fwrite(fid, dime.cal_units(1:8),  'uchar');

   fwrite(fid, dime.unused1(1),    'int16');
   fwrite(fid, dime.datatype(1),   'int16');
   fwrite(fid, dime.bitpix(1),     'int16');
   fwrite(fid, dime.dim_un0(1),    'int16');
   fwrite(fid, dime.pixdim(1:8),   'float32');
   fwrite(fid, dime.vox_offset(1), 'float32');
   fwrite(fid, dime.roi_scale(1),  'float32');
   fwrite(fid, dime.funused1(1),   'float32');
   fwrite(fid, dime.funused2(1),   'float32');
   fwrite(fid, dime.cal_max(1),    'float32');
   fwrite(fid, dime.cal_min(1),    'float32');
   fwrite(fid, dime.compressed(1), 'int32');
   fwrite(fid, dime.verified(1),   'int32');
   fwrite(fid, dime.glmax(1),      'int32');
   fwrite(fid, dime.glmin(1),      'int32');

   return;					% image_dimension

%---------------------------------------------------------------------
function data_history(fid, hist)

	% Original header structures - ANALYZE 7.5
	%struct data_history
	%       {                                /* off + size      */
	%       char descrip[80];                /* 0 + 80          */
	%       char aux_file[24];               /* 80 + 24         */
	%       char orient;                     /* 104 + 1         */
	%       char originator[10];             /* 105 + 10        */
	%       char generated[10];              /* 115 + 10        */
	%       char scannum[10];                /* 125 + 10        */
	%       char patient_id[10];             /* 135 + 10        */
	%       char exp_date[10];               /* 145 + 10        */
	%       char exp_time[10];               /* 155 + 10        */
	%       char hist_un0[3];                /* 165 + 3         */
	%       int views                        /* 168 + 4         */
	%       int vols_added;                  /* 172 + 4         */
	%       int start_field;                 /* 176 + 4         */
	%       int field_skip;                  /* 180 + 4         */
	%       int omax;                        /* 184 + 4         */
	%       int omin;                        /* 188 + 4         */
	%       int smax;                        /* 192 + 4         */
	%       int smin;                        /* 196 + 4         */
	%       };                               /* total=200 bytes */

   % descrip     = sprintf('%-80s', hist.descrip);     % 80 chars from left
   % fwrite(fid, descrip(1:80),    'uchar');
   pad = zeros(1, 80-length(hist.descrip));
   hist.descrip = [hist.descrip  char(pad)];
   fwrite(fid, hist.descrip(1:80), 'uchar');

   % aux_file    = sprintf('%-24s', hist.aux_file);    % 24 chars from left
   % fwrite(fid, aux_file(1:24),   'uchar');
   pad = zeros(1, 24-length(hist.aux_file));
   hist.aux_file = [hist.aux_file  char(pad)];
   fwrite(fid, hist.aux_file(1:24), 'uchar');

   fwrite(fid, hist.orient(1),      'uchar');
   fwrite(fid, hist.originator(1:5), 'int16');

   pad = zeros(1, 10-length(hist.generated));
   hist.generated = [hist.generated  char(pad)];
   fwrite(fid, hist.generated(1:10),  'uchar');

   pad = zeros(1, 10-length(hist.scannum));
   hist.scannum = [hist.scannum  char(pad)];
   fwrite(fid, hist.scannum(1:10),  'uchar');

   pad = zeros(1, 10-length(hist.patient_id));
   hist.patient_id = [hist.patient_id  char(pad)];
   fwrite(fid, hist.patient_id(1:10),  'uchar');

   pad = zeros(1, 10-length(hist.exp_date));
   hist.exp_date = [hist.exp_date  char(pad)];
   fwrite(fid, hist.exp_date(1:10),  'uchar');

   pad = zeros(1, 10-length(hist.exp_time));
   hist.exp_time = [hist.exp_time  char(pad)];
   fwrite(fid, hist.exp_time(1:10),  'uchar');

   pad = zeros(1, 3-length(hist.hist_un0));
   hist.hist_un0 = [hist.hist_un0  char(pad)];
   fwrite(fid, hist.hist_un0(1:3),  'uchar');

   fwrite(fid, hist.views(1),      'int32');
   fwrite(fid, hist.vols_added(1), 'int32');
   fwrite(fid, hist.start_field(1),'int32');
   fwrite(fid, hist.field_skip(1), 'int32');
   fwrite(fid, hist.omax(1),       'int32');
   fwrite(fid, hist.omin(1),       'int32');
   fwrite(fid, hist.smax(1),       'int32');
   fwrite(fid, hist.smin(1),       'int32');

   return;					% data_history


function [exitflag, message] = lvd_executeOptimProblem(celBodyData, writeOutput, problem, recorder, callOutputFcn)
    global options_gravParamType;
    initX = []; %#ok<NASGU>

    try
        useParallel = problem.options.UseParallel;
    catch ME %#ok<NASGU>
        if(isprop(problem.options,'UseParallel') || isfield(struct(problem.options),'UseParallel'))
            useParallel = problem.options.UseParallel;
        else
            useParallel = problem.UseParallel;
        end
    end

    if(useParallel)
        pp=gcp('nocreate');

        if(not(isempty(pp)))
            fnc3 = @() setGravParamTypeForWorker(options_gravParamType);
            pp.parfevalOnAll(fnc3, 0);
        end
    end

    lvdData = problem.lvdData;
    initX = lvdData.optimizer.vars.getTotalScaledXVector();

    writeOutput('Beginning mission script optimization...','append');
    tt = tic;
    if(strcmpi(problem.solver,'fmincon'))
        [x,fval,exitflag,output,lambda,grad,hessian] = fmincon(problem);
        message = output.message;

    elseif(strcmpi(problem.solver,'patternsearch'))
        [x,fval,exitflag,output] = patternsearch(problem);
        message = output.message;

    elseif(strcmpi(problem.solver,'nomad'))
        [x,fval,exitflag,iter,nfval] = nomad(problem.objective, problem.x0, problem.lb, problem.ub, problem.options);
        message = nomadExitFlagMessageLookup(exitflag);
%         [x,fval,exitflag,iter,nfval] = nomadOpt(problem.objective, problem.x0, problem.lb, problem.ub, problem.options);

    elseif(strcmpi(problem.solver,'ipopt'))
        [x,info] = ipopt(problem.x0, problem.funcs, problem.options);
        exitflag = info.status;
        message = ipoptExitFlagMessageLookup(exitflag);

    elseif(strcmpi(problem.solver,'surrogateopt'))
        [x,fval,exitflag,output,trials] = surrogateopt(problem);
        message = output.message;

    else
        error('Unknown optimizer function: %s', problem.solver);
    end

    execTime = toc(tt);
    writeOutput(sprintf('Mission script optimization finished in %0.3f sec with exit flag "%i".', execTime, exitflag),'append');

    %%%%%%%
    % Ask if the user wants to keep the current solution or not.
    %%%%%%%
    if(callOutputFcn)
%         [~, x] = ma_OptimResultsScorecardGUI(recorder);
        out = AppDesignerGUIOutput({[],[]});
        ma_OptimResultsScorecardGUI_App(recorder, out);
        x = out.output{2};
    end

    if(~isempty(x))
        writeOutput(sprintf('Optimization results accepted: merging with mission script.'),'append');

        %%%%%%%
        % Update existing script, reprocess
        %%%%%%%
        lvdData.optimizer.vars.updateObjsWithScaledVarValues(x);
    else
        writeOutput(sprintf('Optimization results discarded: reverting to previous script.'),'append');

        lvdData.optimizer.vars.updateObjsWithScaledVarValues(initX);
    end
end


function res4=writeRes4(res4File,res4,MAX_COILS);
%  Write the new .res4 file.  Use ieee-be (big endian) format
%  Character-string output is done using function writeCTFstring which
%  checks that strings are the correct length for the .res4 file format.

%  Function calls: - writeCTFstring (included in this listing).

fid_res4=fopen(res4File,'w','ieee-be');
if fid_res4<0
  fprintf('writeCTFds (writeRes4): Could not open file %s\n',res4File);
  return
end

fwrite(fid_res4,[res4.header(1:7),char(0)],'uint8');   % 8-byte header

%  meg41GeneralResRec
res4.appName=writeCTFstring(res4.appName,-256,fid_res4);
res4.dataOrigin=writeCTFstring(res4.dataOrigin,-256,fid_res4);
res4.dataDescription=writeCTFstring(res4.dataDescription,-256,fid_res4);
fwrite(fid_res4,res4.no_trials_avgd,'int16');
res4.data_time=writeCTFstring(res4.data_time,255,fid_res4);
res4.data_date=writeCTFstring(res4.data_date,255,fid_res4);

% new_general_setup_rec_ext part of meg41GeneralResRec

fwrite(fid_res4,res4.no_samples,'int32');        % 4
fwrite(fid_res4,[res4.no_channels 0],'int16');   % 2*2
fwrite(fid_res4,res4.sample_rate,'double');      % 8
fwrite(fid_res4,res4.epoch_time,'double');       % 8
fwrite(fid_res4,[res4.no_trials 0],'int16');     % 2*2
fwrite(fid_res4,res4.preTrigPts,'int32');        % 4
fwrite(fid_res4,res4.no_trials_done,'int16');    % 2
fwrite(fid_res4,res4.no_trials_display,'int16'); % 2
fwrite(fid_res4,res4.save_trials,'int32');       % 4 CTFBoolean

% meg41TriggerData part of new_general_setup_rec_ext   10 bytes total
fwrite(fid_res4,res4.primaryTrigger,'int32');      % 4
fwrite(fid_res4,res4.triggerPolarityMask,'int32'); % 4
fwrite(fid_res4,[0 0],'uint8');                    % 2 bytes
% end of meg41TriggerData part of new_general_setup_rec_ext

fwrite(fid_res4,[0 0],'uint8');                    % 2 bytes padding
fwrite(fid_res4,[res4.trigger_mode 0],'int16');    % 2*2
fwrite(fid_res4,res4.accept_reject_Flag,'int32');  % 4 CTFBoolean
fwrite(fid_res4,[res4.run_time_display 0],'int16'); % 2*2

fwrite(fid_res4,res4.zero_Head_Flag,'int32');      % 4 CTFBoolean
fwrite(fid_res4,res4.artifact_mode,'int32');       % 4 CTFBoolean
%  end of new_general_setup_rec_ext part of meg41GeneralResRec

% meg4FileSetup part of meg41GeneralResRec
res4.nf_run_name=writeCTFstring(res4.nf_run_name,32,fid_res4);
res4.nf_run_title=writeCTFstring(res4.nf_run_title,-256,fid_res4);
res4.nf_instruments=writeCTFstring(res4.nf_instruments,32,fid_res4);
res4.nf_collect_descriptor=writeCTFstring(res4.nf_collect_descriptor,32,fid_res4);
res4.nf_subject_id=writeCTFstring(res4.nf_subject_id,-32,fid_res4);
res4.nf_operator=writeCTFstring(res4.nf_operator,32,fid_res4);
res4.nf_sensorFileName=writeCTFstring(res4.nf_sensorFileName,56,fid_res4);
res4.rdlen=length(res4.run_description);      % Run_description may have been changed.
fwrite(fid_res4,[0 res4.rdlen 0],'int32');    %  12-byte structure of the .res4 file.
res4.run_description=writeCTFstring(res4.run_description,res4.rdlen,fid_res4);
%  end of meg4FileSetup part of meg41GeneralResRec

%  filter descriptions

fwrite(fid_res4,res4.num_filters,'int16');
for kfilt=1:res4.num_filters
  fwrite(fid_res4,res4.filters(kfilt).freq,'double');
  fwrite(fid_res4,res4.filters(kfilt).fClass,'int32');
  fwrite(fid_res4,res4.filters(kfilt).fType,'int32');
  fwrite(fid_res4,res4.filters(kfilt).numParam,'int16');
  for kparm=1:res4.filters(kfilt).numParam
    fwrite(fid_res4,res4.filters(kfilt).Param(kparm),'double');
  end
end

%  Write channel names.   Must have size(res4.chanNames)=[nChan 32]
[no_chanNames len_chanNames]=size(res4.chanNames);
for kchan=1:res4.no_channels
  res4.chanNames(kchan,:)=writeCTFstring(res4.chanNames(kchan,:),len_chanNames,fid_res4);
end

%  Write sensor resource table
for kchan=1:res4.no_channels
  fwrite(fid_res4,res4.senres(kchan).sensorTypeIndex,'int16');
  fwrite(fid_res4,res4.senres(kchan).originalRunNum,'int16');
  fwrite(fid_res4,res4.senres(kchan).coilShape,'int32');
  fwrite(fid_res4,res4.senres(kchan).properGain,'double');
  fwrite(fid_res4,res4.senres(kchan).qGain,'double');
  fwrite(fid_res4,res4.senres(kchan).ioGain,'double');
  fwrite(fid_res4,res4.senres(kchan).ioOffset,'double');
  fwrite(fid_res4,res4.senres(kchan).numCoils,'int16');
  numCoils=res4.senres(kchan).numCoils;
  fwrite(fid_res4,res4.senres(kchan).grad_order_no,'int16');
  fwrite(fid_res4,0,'int32');  % Padding to 8-byte boundary

  % coilTbl
  for qx=1:numCoils
    fwrite(fid_res4,[res4.senres(kchan).pos0(:,qx)' 0],'double');
    fwrite(fid_res4,[res4.senres(kchan).ori0(:,qx)' 0],'double');
    fwrite(fid_res4,[res4.senres(kchan).numturns(qx) 0 0 0],'int16');
    fwrite(fid_res4,res4.senres(kchan).area(qx),'double');
  end
  if numCoils<MAX_COILS
    fwrite(fid_res4,zeros(10*(MAX_COILS-numCoils),1),'double');
  end

  %HdcoilTbl
  for qx=1:numCoils
    fwrite(fid_res4,[res4.senres(kchan).pos(:,qx)' 0],'double');
    fwrite(fid_res4,[res4.senres(kchan).ori(:,qx)' 0],'double');
    fwrite(fid_res4,[res4.senres(kchan).numturns(qx) 0 0 0],'int16');
    fwrite(fid_res4,res4.senres(kchan).area(qx),'double');
  end
  if numCoils<MAX_COILS
    fwrite(fid_res4,zeros(10*(MAX_COILS-numCoils),1),'double');
  end
end
%  End writing sensor resource table

%  Write the table of balance coefficients.
if res4.numcoef<=0
  fwrite(fid_res4,res4.numcoef,'int16');  % Number of coefficient records
elseif res4.numcoef>0
  scrx_out=[];
  for kx=1:res4.numcoef
    sName=strtok(char(res4.scrr(kx).sensorName),['- ',char(0)]);
    if ~isempty(strmatch(sName,res4.chanNames))
      scrx_out=[scrx_out kx];
    end
  end
  %  Remove the extra coefficient records
  res4.scrr=res4.scrr(scrx_out);
  res4.numcoef=size(res4.scrr,2);
  fwrite(fid_res4,res4.numcoef,'int16');  % Number of coefficient records
  %  Convert res4.scrr to double before writing to output file.  In MATLAB 5.3.1,
  %  when the 'ieee-be' option is applied, fwrite cannot write anything except
  %  doubles and character strings, even if fwrite does allow you to specify short
  %  integer formats in the output file.
  for nx=1:res4.numcoef
    fwrite(fid_res4,double(res4.scrr(nx).sensorName),'uint8');
    fwrite(fid_res4,[double(res4.scrr(nx).coefType) 0 0 0 0],'uint8');
    fwrite(fid_res4,double(res4.scrr(nx).numcoefs),'int16');
    fwrite(fid_res4,double(res4.scrr(nx).sensor),'uint8');
    fwrite(fid_res4,res4.scrr(nx).coefs,'double');
  end
end
fclose(fid_res4);
return

% *************************************************************************************
%*************** Function writeCTFstring ************************************************
function strng=writeCTFstring(instrng,strlen,fid)

%  Writes a character string to output unit fid.  Append nulls to get the correct length.
%  instrng : Character string.  size(instrng)=[nLine nPerLine].  strng is reformulated as a
%            long string of size [1 nChar].  Multiple lines are allowed so the user can
%            easily append text.  If necessary, characters are removed from
%            instrng(1:nLine-1,:) so all of strng(nLine,:) can be accomodated.
%    strlen: Number of characters to write.  strlen<0 means remove leading characters.
%        If abs(strlen)>length(strng) pad with nulls (char(0))
%        If 0<strlen<length(strng), truncate strng and terminate with a null.
%        If -length(string)<strlen<0, remove leading characters and terminate with a null.

%  Form a single long string
nLine=size(instrng,1);
strng=deblank(instrng(1,:));

if nLine>1
  %  Concatenate lines 1:nLine-1
  for k=2:nLine-1
    if length(strng)>0
      if ~strcmp(strng(length(strng)),'.') & ~strcmp(strng(length(strng)),',')
        strng=[strng '.'];   % Force a period at the end of the string.
      end
    end
    strng=[strng '  ' deblank(instrng(k,:))];
  end

  if length(strng)>0
    if ~strcmp(strng(length(strng)),'.')  % Force a period at the end of the string.
      strng=[strng '.'];
    end
  end
  %  Add all of the last line.
  nChar=length(strng);
  nLast=length(deblank(instrng(nLine,:)));
  strng=[strng(1:min(nChar,abs(strlen)-nLast-4)) '  ' deblank(instrng(nLine,:))];
end

if length(strng)<abs(strlen)
  strng=[strng char(zeros(1,abs(strlen)-length(strng)))];
elseif length(strng)>=strlen & strlen>0
  strng=[strng(1:strlen-1) char(0)];
else
   strng=[strng(nLast+[strlen+2:0]) char(0)];
end

fwrite(fid,strng,'char');
return
%  ************* End of function writeCTFstring ***************************************
% ************************************************************************************


function opt=varargin2struct(varargin)
%
% opt=varargin2struct('param1',value1,'param2',value2,...)
%   or
% opt=varargin2struct(...,optstruct,...)
%
% convert a series of input parameters into a structure
%
% author: Qianqian Fang, <q.fang at neu.edu>
% date: 2012/12/22
%
% input:
%      'param', value: the input parameters should be pairs of a string and a value
%       optstruct: if a parameter is a struct, the fields will be merged to the output struct
%
% output:
%      opt: a struct where opt.param1=value1, opt.param2=value2 ...
%
% license:
%     BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details
%
% -- this function is part of JSONlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%

len=length(varargin);
opt=struct;
if(len==0) return; end
i=1;
while(i<=len)
    if(isstruct(varargin{i}))
        opt=mergestruct(opt,varargin{i});
    elseif(ischar(varargin{i}) && i<len)
        opt=setfield(opt,lower(varargin{i}),varargin{i+1});
        i=i+1;
    else
        error('input must be in the form of ...,''name'',value,... pairs or structs');
    end
    i=i+1;
end


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

%%
clear; close all; clc;

%% Syntax
% |[S]=cellPair2struct(fieldNameCell,fieldDataCell,convertOption,optionStruct);|

%% Description
% Converts a cell array pair to a structure. The cell |fieldNameCell|
% contains field names and the cell |fieldDataCell| contains the data. The
% data may be anything a structure can hold. The option parameter
% |convertOption| can be used to convert numeric data to text. The optional
% |optionStruct| structure can be used to control this conversion (see
% |mat2strIntDouble|).

%% Examples
%

fieldNameCell={'bob','mary','banana','qwerty_yuiop'};
fieldDataCell={5,'sure',[pi 1 3.5],[1 2 3]};

%%
% Convert all numerical data
convertOption=1;
[S]=cellPair2struct(fieldNameCell,fieldDataCell,convertOption)

%%
% No conversion
convertOption=0;
[S]=cellPair2struct(fieldNameCell,fieldDataCell,convertOption)

%%
% Convert some of the entries
convertOption=[1 0 0 1];
[S]=cellPair2struct(fieldNameCell,fieldDataCell,convertOption)

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