function vw = contrastGUI(vw, flag)
%
% vw = contrastGUI([vw=cur view])
%
% Dialog to set parameters for a contrast map.
%
% Inputs:
%  stim: stim ('stim') structure from er_concatParfiles.
%  initParams: initial params structure specifying initial values for the
%       relevant fields (same format as output p struct below).
%
% Outputs: parameters structure p with fields:
%   active: initial list of active conditions, or weights of active conditions.
%   control:  initial list of control conditions, or weights.
%   name: contrast name.
%   options: [to be added]
%
%
% ras, 01/2007.

% first, check if this is a callback from one of the uicontrols --
% if it is, it will have a flag as the third argument, describing what to
% do next:
if exist('flag','var')
    s = get(gcf,'UserData'); % this struct will be useful for the callbacks

    switch flag
        case 1,     num = get(gcbo,'UserData');  setControlCond(s, num);
        case 2,     num = get(gcbo,'UserData');  setActiveCond(s, num);
        case 3,     setSaveNameUI(s);
        case 4,     vw = callComputeContrastMap(s, vw);
        otherwise,  error('Illegal flag entered as third param.')
    end

    return
end

if notDefined('vw'),  vw = getCurView;  end

%% open the figure
s = openFig(vw);

%% append an 'Advanced Options' params
advancedOptionsPanel(s);

return
% /---------------------------------------------------------------------/ %

%% /---------------------------------------------------------------------/ %
function s = openFig(vw)
% s = openFig(stim);
% creates the interface window and returns the GUI structure s.

stim = er_concatParfiles(vw);
nConds = length(stim.condNums);
winHeight = (30 * nConds) + 180; % do this in pixels, 30 pix per condition row
winWidth = 450;
bgColor = [.8 .8 .8];
fgColor = [0 0 0];
s.h(1) = figure('Name', 'Statistical Contrast Map', 'Color', bgColor, ...
    'Position', [300 300 winWidth winHeight],...
    'NumberTitle', 'off', 'MenuBar','none');

% add title text fields
tittxt = sprintf('Compute a Contrast Map');
uicontrol('Style','text','String',tittxt,...
    'FontName','Helvetica','FontSize',18,'FontWeight','bold',...
    'HorizontalAlignment','center',...
    'ForegroundColor', fgColor, 'BackgroundColor', bgColor, ...
    'Units','Normalized', ...
    'Position',[10/winWidth (winHeight-30)/winHeight 430/winWidth 30/winHeight]);

uicontrol('Style', 'text', 'String', viewGet(vw, 'annotation'),...
    'FontName','Helvetica','FontSize',16,'FontWeight','bold',...
    'HorizontalAlignment','center',...
    'ForegroundColor', fgColor, 'BackgroundColor', bgColor,...
    'Units','Normalized','Position',[10/winWidth (winHeight-60)/winHeight 430/winWidth 30/winHeight]);

% make a top row of labels
uicontrol('Style', 'text', 'String', 'Cond #', ...
    'ForegroundColor', fgColor, 'BackgroundColor', bgColor, ...
    'FontName', 'Helvetica', 'FontSize', 12, 'FontWeight', 'bold', ...
    'Units', 'Normalized', ...
    'Position', [30/winWidth (winHeight-90)/winHeight 60/winWidth 30/winHeight]);

uicontrol('Style','text','String','Control?', ...
    'FontName', 'Helvetica', 'FontSize', 12, 'FontWeight', 'bold', ...
    'ForegroundColor', 'w', 'BackgroundColor', [1 0 0],...
    'Units','Normalized','Position',[360/winWidth (winHeight-90)/winHeight 60/winWidth 30/winHeight]);

uicontrol('Style','text','String','Condition Name',...
    'FontName', 'Helvetica', 'FontSize', 12, 'FontWeight', 'bold', ...
    'ForegroundColor', fgColor, 'BackgroundColor', bgColor, ...
    'Units','Normalized','Position',[210/winWidth (winHeight-90)/winHeight 120/winWidth 30/winHeight]);

uicontrol('Style','text','String','Active?', ...
    'FontName', 'Helvetica', 'FontSize', 12, 'FontWeight', 'bold', ...
    'ForegroundColor', 'w', 'BackgroundColor', [0 0 1],...
    'Units','Normalized','Position',[120/winWidth (winHeight-90)/winHeight 60/winWidth 30/winHeight]);

% make labels for each cond num
for i = 1:nConds
    ypos = (winHeight - 90 -  30*i)/winHeight;
    s.condNumHandles(i) = uicontrol('Style', 'text', ...
        'String', num2str(stim.condNums(i)), ...
        'FontName', 'Helvetica', 'FontSize', 12, ...
        'ForegroundColor', fgColor, 'BackgroundColor', bgColor,...
        'Units', 'Normalized', ...
        'Position', [30/winWidth ypos 60/winWidth 30/winHeight]);
end

% make control checkboxes for each cond
cbstr = sprintf('contrastGUI(%s, 1);', vw.name);
for i = 1:nConds
    ypos = (winHeight - 90 -  30*i)/winHeight;
    s.controlHandles(i) = uicontrol('Style','checkbox','Value',0,...
        'FontName','Helvetica','FontSize',12,...
        'ForegroundColor',fgColor,'BackgroundColor',bgColor,...
        'UserData',i,'Callback',cbstr,...
        'Units','Normalized','Position',[360/winWidth ypos 60/winWidth 30/winHeight]);

    % add a weights control
    s.controlWeightEdits(i) = uicontrol('Style', 'edit', 'String','',...
        'FontName', 'Helvetica', 'FontSize', 8,...
        'ForegroundColor', [0 0 0], 'BackgroundColor', [1 1 1],...
        'UserData', i, 'Callback', cbstr, 'Enable', 'off', ...
        'Visible', 'off', 'Units', 'Normalized', ...
        'Position', [(380/winWidth) (ypos + 8/winWidth) 40/winWidth 20/winHeight]);

end

% make text fields for each cond name
for i = 1:nConds
    ypos = (winHeight - 90 -  30*i)/winHeight;
    s.condNameHandles(i) = uicontrol('Style', 'text', ...
        'String', stim.condNames{i},...
        'FontName', 'Helvetica', 'FontSize', 12,...
        'ForegroundColor', fgColor, 'BackgroundColor', [1 1 1],...
        'Units', 'Normalized', ...
        'Position',[210/winWidth ypos 120/winWidth 30/winHeight]);
end

% make active checkboxes for each cond
cbstr = sprintf('contrastGUI(%s, 2);', vw.name);
for i = 1:nConds
    ypos = (winHeight - 90 -  30*i)/winHeight;
    s.activeHandles(i) = uicontrol('Style','check','Value',0,...
        'FontName','Helvetica','FontSize',12,'FontWeight','bold',...
        'ForegroundColor', fgColor, 'BackgroundColor',bgColor,...
        'UserData',i,'Callback',cbstr,...
        'Units', 'Normalized', ...
        'Position', [120/winWidth ypos 60/winWidth 30/winHeight]);

    s.activeWeightEdits(i) = uicontrol('Style', 'edit', 'String', '', ...
        'FontName', 'Helvetica', 'FontSize', 8, ...
        'ForegroundColor', fgColor, 'BackgroundColor', [1 1 1],...
        'UserData', i, 'Callback', cbstr, 'Enable', 'off', ...
        'Visible', 'off', 'Units', 'Normalized', ...
        'Position', [(140/winWidth) (ypos + 8/winWidth) 40/winWidth 20/winHeight]);

end

% make button to set save file path
cbstr = sprintf('contrastGUI(%s, 3);', vw.name);
s.setPathHandle = uicontrol('Style', 'pushbutton', 'String', 'Name:',...
    'FontName', 'Helvetica', 'FontSize',12,...
    'ForegroundColor', 'k', 'BackgroundColor', [.8 .8 .8],...
    'Callback', cbstr, 'Enable', 'off', ...
    'Units', 'Normalized', ...
    'Position', [120/winWidth 50/winHeight 60/winWidth 30/winHeight]);

% make field with save filename
s.saveHandle = uicontrol('Style', 'edit', 'String', 'V ',...
    'FontName', 'Helvetica', 'FontSize',12, 'FontWeight', 'bold', ...
    'ForegroundColor', [0 0 0], 'BackgroundColor', [1 1 1], ...
    'Enable','off',...
    'Units', 'Normalized', ...
    'Position', [120/winWidth 20/winHeight 210/winWidth 30/winHeight]);

% make 'GO' button
cbstr = sprintf('%s = contrastGUI(%s, 4);',vw.name, vw.name);
s.goHandle = uicontrol('Style','pushbutton', 'String', 'GO',...
    'FontName', 'Helvetica', 'FontSize', 24, 'FontWeight', 'bold',...
    'ForegroundColor',[1 1 1],'BackgroundColor',[.1 .7 .1],...
    'UserData', stim.condNums,...
    'Callback', cbstr, 'Enable', 'off', ...
    'Units', 'Normalized', ...
    'Position', [360/winWidth 20/winHeight 60/winWidth 60/winHeight]);

% put the s struct, containing important info, in the figure UserData
s.condNames = stim.condNames;
s.condNums = stim.condNums;
set(gcf, 'UserData', s);

return
% /---------------------------------------------------------------------/ %

% /---------------------------------------------------------------------/ %
function s = advancedOptionsPanel(s)
% Add a uipanel containing advanced controls for a contrast map,
% such as setting the type of statistical test (F or T), the
% units of the resulting map (-log(p), T, F, p, ces, etc), and
% whether to activate the weights edit controls.

s.optsPanel = mrvPanel('below', .25);

% popup menu to set test type
s.testPopup = uicontrol('Parent', s.optsPanel, 'Style', 'popup', ...
    'Units', 'normalized', 'Position', [.1 .4 .2 .15], ...
    'FontName', 'Arial', 'FontSize', 12, ...
	'BackgroundColor', get(gcf, 'Color'), ...
    'String', {'T test' 'F test'}, 'Value', 1);

uicontrol('Parent', s.optsPanel, 'Style', 'text', ...
    'Units', 'normalized', 'Position', [.1 .6 .2 .1], ...
    'String', 'Test Type', 'FontName', 'Helvetica', ...
	'BackgroundColor', get(gcf, 'Color'), ...
    'FontSize', 10, 'FontWeight', 'bold', 'FontAngle', 'italic');

% popup menu to set units of map
vals = {'-log(p)' 'p' 'T' 'F' 'Contrast Effect Size'};
s.unitPopup = uicontrol('Parent', s.optsPanel, 'Style', 'popup', ...
    'Units', 'normalized', 'Position', [.4 .4 .2 .15], ...
    'FontName', 'Arial', 'FontSize', 12, ...
	'BackgroundColor', get(gcf, 'Color'), ...
    'String', vals, 'Value', 1);

uicontrol('Parent', s.optsPanel, 'Style', 'text', ...
    'Units', 'normalized', 'Position', [.4 .6 .2 .1], ...
    'String', 'Units For Map?', 'FontName', 'Helvetica', ...
	'BackgroundColor', get(gcf, 'Color'), ...
    'FontSize', 10, 'FontWeight', 'bold', 'FontAngle', 'italic');

% checkbox to toggle visibility of edit fields for condition weights
cb = ['TMP = get(gcf, ''UserData''); ' ...
      'vis = get(gcbo, ''Value'') + 1; ' ...
      'onoff = {''off'' ''on''}; ' ...
      'set(TMP.activeWeightEdits, ''Visible'', onoff{vis}); ' ...
      'set(TMP.controlWeightEdits, ''Visible'', onoff{vis}); ' ...
      'clear TMP vis onoff '];
uicontrol('Parent', s.optsPanel, 'Style', 'checkbox', ...
    'Units', 'normalized', 'Position', [.1 .1 .5 .15], ...
    'String', 'Set Condition Weights', 'FontName', 'Helvetica', ...
	'BackgroundColor', get(gcf, 'Color'), ...
    'FontSize', 10, 'Callback', cb);

% initialize panel to invisible
mrvPanelToggle(s.optsPanel, 'off');

% add a button to the main GUI to toggle this panel
cb = ['TMP = get(gcf, ''UserData''); ' ...
      'mrvPanelToggle(TMP.optsPanel); ' ...
      'clear TMP '];
s.panelToggle = uicontrol('Style', 'pushbutton', ...
    'String', 'More...', 'Units', 'norm', 'Position', [.1 .03 .15 .06], ...
    'BackgroundColor', [.9 .9 .9], 'ForegroundColor', 'k', ...
    'Callback', cb);

% update userdata of GUI to include this info
set(gcf, 'UserData', s);

return
% /---------------------------------------------------------------------/ %

% /---------------------------------------------------------------------/ %
function setControlCond(s,num)
% set the specified num condition as a control condition,
% highlighting the selected condition number and checking if ready to
% proceed

[active control w] = loadActiveControl(s);

bgColor = get(gcf, 'Color');

if get(s.controlHandles(num),'Value')==1
	set(s.controlHandles(num),'BackgroundColor',[1 0 0]);
	set(s.activeHandles(num),'Value',0,'BackgroundColor',bgColor);
    set(s.condNameHandles(num),'ForegroundColor','w','BackgroundColor',[1 0 0]);
    set(s.condNumHandles(num),'ForegroundColor','w','BackgroundColor',[1 0 0]);
    set(s.controlWeightEdits(num),'Enable','On');
    set(s.activeWeightEdits(num),'Enable','Off','String','');

    if isempty(get(s.controlWeightEdits(num),'String'))
        set(s.controlWeightEdits(num),'String','1');
    end

else
	set(s.controlHandles(num),'BackgroundColor',bgColor);
    set(s.condNameHandles(num),'ForegroundColor','k','BackgroundColor',[1 1 1]);
    set(s.condNumHandles(num),'ForegroundColor','k','BackgroundColor',bgColor);
    set(s.controlWeightEdits(num),'Enable','Off','String','');

end

setEvenWeights(s);

checkIfReady(s);

return
% /---------------------------------------------------------------------/ %

% /---------------------------------------------------------------------/ %
function setActiveCond(s,num)
% set the specified num condition as an active condition,
% highlighting the selected condition number and checking if ready to
% proceed

[active control w] = loadActiveControl(s);

bgColor = get(gcf, 'Color');

if get(s.activeHandles(num),'Value')==1
	set(s.activeHandles(num),'BackgroundColor',[0 0 1]);
    set(s.controlHandles(num),'Value',0,'BackgroundColor',bgColor);
    set(s.condNameHandles(num),'ForegroundColor','w','BackgroundColor',[0 0 1]);
    set(s.condNumHandles(num),'ForegroundColor','w','BackgroundColor',[0 0 1]);
    set(s.activeWeightEdits(num),'Enable','On');
    set(s.controlWeightEdits(num),'Enable','Off','String','');

    if isempty(get(s.activeWeightEdits(num), 'String'))
        set(s.activeWeightEdits(num), 'String', '1');
    end

else
	set(s.activeHandles(num),'BackgroundColor',bgColor);
    set(s.condNameHandles(num),'ForegroundColor','k','BackgroundColor',[1 1 1]);
    set(s.condNumHandles(num),'ForegroundColor','k','BackgroundColor',bgColor);
    set(s.activeWeightEdits(num),'Enable','Off','String','');

end

setEvenWeights(s);

checkIfReady(s);

return
% /---------------------------------------------------------------------/ %

% /---------------------------------------------------------------------/ %
function checkIfReady(s)
% update the name of the save file based on the highlighted conditions, and
% check if at least one control and one active condition are selected -- if
% so, enable the GO button.
atLeast1C = 0; atLeast1A = 0;

for i = 1:length(s.condNameHandles)
    s.condNames{i} = get(s.condNameHandles(i),'String');
end

saveName = '';
for i = 1:length(s.activeHandles)
    if get(s.activeHandles(i),'Value')==1
        saveName = [saveName rmBlanks(s.condNames{i})];
        atLeast1C = 1;
    end
end

saveName = [saveName 'V'];

for i = 1:length(s.controlHandles)
    if get(s.controlHandles(i),'Value')==1
        saveName = [saveName rmBlanks(s.condNames{i})];
        atLeast1A = 1;
    end
end

set(s.saveHandle,'String',saveName);

if atLeast1C && atLeast1A
    set(s.setPathHandle,'Enable','on');
    set(s.saveHandle,'Enable','on');
    set(s.goHandle,'Enable','on');
else
    set(s.setPathHandle,'Enable','off');
    set(s.saveHandle,'Enable','off');
    set(s.goHandle,'Enable','off');
end

return
% /---------------------------------------------------------------------/ %

% /---------------------------------------------------------------------/ %
function str = rmBlanks(str)
% removes all the blanks from str.
ok = ones(size(str));
loc = findstr(' ',str);
ok(loc) = 0;
str = str(find(ok));
return
% /---------------------------------------------------------------------/ %

% /---------------------------------------------------------------------/ %
function setSaveNameUI(s,num)
[fname,pth] = myUIPutFile('Inplane/Original/','*.mat','Select a save file name / path: ' );
saveName = fullfile(pth,fname);
set(s.saveHandle,'String',saveName);
return
% /---------------------------------------------------------------------/ %

% /---------------------------------------------------------------------/ %
function setEvenWeights(s)
% make the weights for all selected active and control conditions
% equal. (sum of active weights = 1; sum of control weights = -1).

[active control w] = loadActiveControl(s);

if sum(w) ~= 0
    if ~isempty(active)
        w(active) = 1 / length(active);
    end

    if ~isempty(control)
        w(control) = -1 / length(control);
    end
end

for i = 1:length(s.activeHandles)
    if get(s.activeHandles(i),'Value')==1
        set(s.activeWeightEdits(i), 'String', num2str(w(i)));

    elseif get(s.controlHandles(i),'Value')==1
        set(s.controlWeightEdits(i), 'String', num2str(w(i)));

    end
end

return
% /---------------------------------------------------------------------/ %

% /---------------------------------------------------------------------/ %
function [active, control, w] = loadActiveControl(s)
% [active, control, w] = loadActiveControl(s)
% get the active and control conditions based on the GUI settings.
% active: list of active conditions.
% control: list of control conditions.
% w: weights vector, where graded weights can be used for
% each condition. (+ weight = active, -weight = control).

active = zeros(1,length(s.activeHandles));
control = zeros(1,length(s.activeHandles));
w = zeros(1, length(s.activeHandles));

for i = 1:length(s.activeHandles)
    if get(s.activeHandles(i),'Value')==1
        active(i) = 1;

        if ~isempty( get(s.activeWeightEdits(i), 'String') )
            w(i) = str2num(get(s.activeWeightEdits(i),'String'));
        end
    elseif get(s.controlHandles(i),'Value')==1
        control(i) = 1;

        if ~isempty( get(s.controlWeightEdits(i), 'String') )
            w(i) = -str2double(get(s.controlWeightEdits(i),'String'));
        end
    end
end

active = find(active);
control = find(control);

return
% /---------------------------------------------------------------------/ %

% /---------------------------------------------------------------------/ %
function vw = callComputeContrastMap(s, vw)
% callback for the big 'GO' button; this takes the UI info
% contained in the s struct, and calls the computeContrastMap
% function:
hgui = gcf;

[active control w] = loadActiveControl(s);

% account for null condition: -1 offset to get to condNums
active = active - 1;
control = control - 1;

% get advanced options (test type, units)
testList = {'T' 'F'};
test = testList{ get(s.testPopup, 'Value') };
unitList = {'log10p' 'p' 't' 'f' 'ces'};
units = unitList{ get(s.unitPopup, 'Value') };

saveName = get(s.saveHandle,'String');
if isempty(findstr(filesep,saveName)) % check that absolute path not specified
    %     savePath = fullfile(dataDir(vw),['contrastMap_' saveName]);
    savePath = fullfile(dataDir(vw),saveName);
else
    savePath = saveName;
end

condNums = get(gcbo,'UserData');

% to do: use weights vector
vw = computeContrastMap2(vw, active, control, saveName, ...
                           'test', test, 'mapUnits', units);

close(hgui);

return
% /---------------------------------------------------------------------/ %


function runningOctave = isOctave()

% Returns whether this code has been run using Octave or MATLAB

try
    OCTAVE_VERSION;
    runningOctave = 1;
catch
    runningOctave = 0;
end


classdef CelestialBodyData < matlab.mixin.SetGet & dynamicprops
    %CelestialBodyData Summary of this class goes here
    %   Detailed explanation goes here

    properties(Access=private)
        bodies(1,:) KSPTOT_BodyInfo

        bodyIdCacheArr(1,:) double = [];

        ci CelestialBodyIntegration
    end

    properties(Transient,Access=private)
        topLvlBodyCache KSPTOT_BodyInfo
    end

    properties(Constant)
        emptyBodyInfo KSPTOT_BodyInfo = KSPTOT_BodyInfo.empty(1,0);
        globalBaseFrame GlobalBaseInertialFrame = GlobalBaseInertialFrame();
        numIntBlockSize(1,1) double = 1000*86400;
    end

    methods
        function obj = CelestialBodyData(celBodyData)
            if(isstruct(celBodyData))
                bodyNameFields = fields(celBodyData);

                for(i=1:length(bodyNameFields)) %#ok<*NO4LP>
                    bodyName = bodyNameFields{i};

                    if(not(isprop(obj,bodyName)))
                        addprop(obj,bodyName);
                        bodyInfo = celBodyData.(bodyName);

                        obj.(bodyName) = bodyInfo;
                        obj.bodies(end+1) = bodyInfo;
                    else
                        error('The following body already exists in CelestialBodyData when trying to instantiate the class from the celestial body data structure: %s', bodyName);
                    end
                end

            elseif(isa(celBodyData,'CelestialBodyData'))
                obj = celBodyData;

            else
                error('Input to CelestialBodyData must be the structure representation of celestial body data.');
            end

            for(i=1:length(obj.bodies))
                if(isstruct(obj.bodies(i).celBodyData) || isempty(obj.bodies(i).celBodyData))
                    obj.bodies(i).celBodyData = obj;
                end
            end

            obj.bodyIdCacheArr = [obj.bodies.id];

            obj.ci = CelestialBodyIntegration(obj);
            obj.ci.integrateCelestialBodies(0, obj.numIntBlockSize);
        end

        function resetAllParentNeedsUpdateFlags(obj)
            for(i=1:length(obj.bodies))
                obj.bodies(i).parentBodyInfoNeedsUpdate = true;
            end
        end

        function bodyInfo = getBodyInfoById(obj, bodyId)
%             arr = [obj.bodies.id];
            bodyInfo = obj.bodies(obj.bodyIdCacheArr == bodyId);

            if(numel(bodyInfo) > 1)
                bodyInfo = bodyInfo(1);
            end
        end

        function [minUt, maxUt] = getStateCacheMinUtMaxUt(obj)
            bool = [obj.bodies.propTypeEnum] == BodyPropagationTypeEnum.Numerical;
            numericBodies = obj.bodies(bool);

            if(numel(numericBodies) >= 1)
                numericBody = numericBodies(1);
                times = numericBody.numIntStateCache.times;
                minUt = min(times);
                maxUt = max(times);
            else
                minUt = 0;
                maxUt = 0;
            end
        end

        function updateCelestialBodyStateCache(obj, minUT, maxUT, hWaitbar)
            arguments
                obj(1,1) CelestialBodyData
                minUT(1,1) double
                maxUT(1,1) double
                hWaitbar = [];
            end

            obj.ci.integrateCelestialBodies(minUT, maxUT, hWaitbar);
        end

        %Override the following structure methods for backwards
        %compatibility with structure celBodyData
        function f = fields(obj)
            f = {};

            for(i=1:length(obj.bodies))
                f{end+1} = lower(obj.bodies(i).name); %#ok<AGROW>
            end

            f = f(:);
        end

        function f = fieldnames(obj)
            f = obj.fields();
        end

        function tf = isfield(obj,field)
            tf = isprop(obj,field);
        end

        function allBodyInfo = getAllBodyInfo(obj)
            allBodyInfo = obj.bodies;
        end

        function [listBoxStr, bodyInfos] = getListboxStr(obj)
            listBoxStr = {};

            for(i=1:length(obj.bodies))
                listBoxStr{end+1} = obj.bodies(i).name; %#ok<AGROW>
            end

            bodyInfos = obj.bodies;
        end

        function topLvlBody = getTopLevelBody(obj)
            if(isempty(obj.topLvlBodyCache))
                obj.topLvlBodyCache = getTopLevelCentralBody(obj);
            end

            topLvlBody = obj.topLvlBodyCache;
        end

        function bodies = getAllBodiesWithChildren(obj)
            bodies = KSPTOT_BodyInfo.empty(1,0);
            for(i=1:length(obj.bodies))
                bodyInfo = obj.bodies(i);

                cBodies = bodyInfo.getChildrenBodyInfo(obj);
                if(not(isempty(cBodies)))
                    bodies(end+1) = bodyInfo;
                end
            end
        end
    end

    methods(Static)
        function obj = loadobj(obj)
            obj.bodyIdCacheArr = [obj.bodies.id];

            if(isprop(obj,'sun'))
                obj.topLvlBodyCache = getTopLevelCentralBody(obj);
            end

            if(isempty(obj.ci))
                obj.ci = CelestialBodyIntegration(obj);
                obj.ci.integrateCelestialBodies(0, obj.numIntBlockSize);
            end
        end
    end
end


classdef SliderCheckboxChangedData < event.EventData & dynamicprops
    % Event data for widget property value changes
    %
    % Syntax:
    %           obj = wt.eventdata.SliderCheckboxChangedData(name,index,prop,state,value)
    %

    % Copyright 2020-2021 The MathWorks, Inc.

    %% Properties
    properties (SetAccess = protected)
        Name (1,1) string
        Index (1,1) double
        Property (1,1) string
        State (1,1) logical
        Value (1,1) double
    end %properties

    %% Constructor / destructor
    methods
        function obj = SliderCheckboxChangedData(name,index,prop,state,value)

            % Set the changed properties
            obj.Name = name;
            obj.Index = index;
            obj.Property = prop;
            obj.State = state;
            obj.Value = value;

        end %constructor
    end %methods

end % classdef


%% (Internal) Display a message framed to a string
%
%     This function format a string for fprintf like functions in order to
%     present a message string2display framed with # characters
%
%   str_out = disp_string_framed(style, string2display )
%
% Arguments:
%
%      + style: if numeric, could be the stream identifier for fprintf
%      function. If char, can be the "style" argument for cprintf function.
%
%      + string2display: The string to frame.
%
% Output:
%
%      + str_out: resulting string
%
% Example:
%
%
% See also disp_option_enumeration, disp_string_title
%
% Author: Mariano Llamedo Soria llamedom@electron.frba.utn.edu.ar
% Version: 0.1 beta
% Last update: 14/5/2014
% Birthdate  : 21/4/2015
% Copyright 2008-2015
%
function str_out = disp_string_framed(style, string2display )

    str_out = [];

    if( nargin == 1 || isempty(string2display) )
        string2display = style;
        style = 'text';
        fid = 1;
    end

    if( isempty(style) )
        style = 'text';
        fid = 1;
    elseif( isnumeric(style) )
        fid = style;
        style = 'text';
    else
        if( ischar(style) )
            fid = 1;
        else
            style = 'text';
            fid = 1;
        end
    end

    str_aux = sprintf('# %s #', string2display);
    str_aux1 = repmat('#', 1, length(str_aux));
    if( fid == 0)
        string2display = strrep(string2display, '\', '\\');
        str_out = sprintf('\n%s\n# %s #\n%s\n\n', str_aux1, string2display, str_aux1);
    elseif( fid == 1)
        fprintf(fid, '\n%s\n# ', str_aux1);
        string2display = strrep(string2display, '\', '\\');
        cprintf(style, [string2display ' ']);
        fprintf(fid, '#\n%s\n\n', str_aux1);
    else
        fprintf(fid, '\n%s\n# %s #\n%s\n\n', str_aux1, string2display, str_aux1);
    end

end


% -------------------------------------------------------------------------------------------------------------------------
function net = remove_layers_from_prefix(net, prefix)
% -------------------------------------------------------------------------------------------------------------------------
    L = net.layers;
    num_layers = numel(L);
    to_remove = {};
    for i = 1:num_layers
        if strfind(L(i).name, prefix)
            to_remove{end+1} = L(i).name;
        end
    end
    net.removeLayer(to_remove);
end


function addcopyright(organization,folder,copyright_year,update,copyright_string)
%ADDCOPYRIGHT Add copyright info to M-file.
%   ADDCOPYRIGHT(ORGANIZATION) adds the copyright info to all M-files in
%   the current folder as well as subfolders.  The copyright year is the
%   current year as a default.  The organization is set to ORGANIZATION.
%
%   The copyright line that is built up looks like the following:
%
%         %   Copyright <YEAR> <ORGANIZATION>
%
%   For example:
%
%         %   Copyright 2003 The MathWorks, Inc.
%
%   The copyright info is place directly above the Revision line.
%   Specifically is it looking for the following substring:
%
%          %   $Revision
%
%   Where the comment character is placed in the first column.  If it
%   can't find the $Revision keyword (Typically this is right after the
%   help section of the M-file.  See this file as an example), it doesn't
%   know where to insert it.  When it is finished, it will look like the
%   following example:
%
%          %   Copyright 2003 The MathWorks, Inc.
%          %   $Revision...
%
%   ADDCOPYRIGHT(ORGANIZTIONS,FOLDER) adds the copyright info to all
%   M-files in the folder FOLDER and its subfolders.  The copyright year
%   is the current year as a default.  The organization is set to
%   ORGANIZATION.
%
%   ADDCOPYRIGHT(ORGANIZATION,FOLDER,COPYRIGHT_YEAR) adds the copyright
%   info to all M-files in the folder FOLDER and its subfolders.  If
%   FOLDER is [], the default value, the current folder (pwd), is used.
%   The copyright year is set to COPYRIGHT_YEAR.  COPYRIGHT_YEAR may
%   either be a character string (for example, '2003' or '2001-2003') or
%   a numeric.  The organization is set to ORGANIZATION.
%
%   ADDCOPYRIGHT(...,UPDATE) updates the copyright info if UPDATE is set
%   to true (false by default).  If FOLDER is [], the default value, the
%   current folder, is used.  If COPYRIGHT_YEAR is [], the default value,
%   the current year, is used.
%
%   When replacing the copyright info line, it looks for the following string:
%
%          %   Copyright
%
%   Where the comment character is placed in the first column.
%
%   ADDCOPYRIGHT([],FOLDER,[],UPDATE,COPYRIGHT_STRING) ignore the
%   organization and the copyright year to build up a copyright string
%   and use COPYRIGHT_STRING instead.
%
%   Examples:
%   ---------
%   % Supply just the organization name, starting from the current
%   % folder, and use the current year but don't overwrite it if the
%   % copyright info is already there.
%   addcopyright('My Organization')
%
%   % Supply the organization name starting from the "src" folder (found
%   % in the current folder), and use the current year but don't
%   % overwrite it if the copyright info is already there.
%   addcopyright('My Organization','src')
%
%   % Supply the organization name starting from the "src" folder (found
%   % in the current folder), and use the supplied year but don't
%   % overwrite it if the copyright info is already there.
%   addcopyright('My Organization','private',2001)
%   addcopyright('My Organization','src','2001-2003')
%
%   % Supply the organization name starting from the "src" folder (found
%   % in the current folder), and use the supplied year.  If the
%   % copyright info is already in the M-file, replace it with the new
%   % copyright line.
%   % overwrite it if the copyright info is already there.
%   addcopyright('My Organization','src',2004,true)
%
%   % Replace all instances of the copyright info or add it if it's not
%   % there.  Use the supplied copyright info.
%   addcopyright([],[],[],true, ...
%        'Copyright 1984-2003 MathWorks, makers of MATLAB(R)')

%   Copyright 2003 The MathWorks, Inc.
%   $Revision: 1.2 $ $Date: 2003/09/11 21:25:11 $

%   Author: Raymond Norris (rayn@mathworks.com)

% Parse input arguments
error(nargchk(1,5,nargin))

if nargin<4
    update = false;
end
if nargin<3
    copyright_year = num2str(datestr(date,10));
end
if nargin<2
    folder = pwd;
end

if isempty(folder)
    folder = pwd;
end

if isempty(copyright_year)
    copyright_year = datestr(date,10);
end

if isempty(update)
    update = false;
end

if isnumeric(copyright_year)
    copyright_year = num2str(copyright_year);
end

if nargin<5
    copyright_string = ['%   Copyright ' copyright_year ' ' organization];
else
    copyright_string = ['%   ' copyright_string];
end

dlist = dir(folder);

% Order the listing so that all of the files are first, then the subfolders.
idx = [dlist.isdir];
newdlist = [dlist(~idx); dlist(idx)];

for didx = 1:length(newdlist)
    token_name = newdlist(didx);
    if strcmp(token_name.name,'.') || strcmp(token_name.name,'..') || strcmp(token_name.name,'CVS')
        continue
    end

    if token_name.isdir==true
        addcopyright([folder filesep token_name.name],copyright_year);
        continue
    end

    if length(token_name.name)>2 && strcmp(token_name.name(end-1:end),'.m')
        lAddCopyrightInfo([folder filesep token_name.name],copyright_string,update)
    end
end

function lAddCopyrightInfo(fname,copyright_string,update)

fprintf(1,'Modifying file: %s...',fname)

fid_1 = fopen(fname,'r+');
if fid_1<3
    disp(['Failed to open ' fname ' for modifying.'])
    return
end

[dummy,file,ext] = fileparts(fname);
new_fname = ['new_' file ext];
fid_2 = fopen(new_fname,'w');
if fid_2<3
    disp(['Failed to open ' new_fname ' for writing to.'])
    fclose(fid_1)
    return
end

next_line   = [];
found_token = false;
token_already_embedded = false;
while isempty(next_line) | next_line~=-1
    next_line = fgetl(fid_1);
    if next_line==-1
        break
    elseif strncmp(next_line,'%   Copyright',13)
        token_already_embedded = true;
        found_token = true;
        if update==true
            fprintf(fid_2,'%s\n',copyright_string);
            continue
        end
    end

    if found_token==false
        if strncmp(next_line,'%   $Revision',13)
            fprintf(fid_2,'%s\n',copyright_string);
            found_token = true;
        end
    end
    fprintf(fid_2,'%s\n',next_line);
end

fclose(fid_1);
fclose(fid_2);

if found_token==false
    disp('Could not find Revision token.  Copyright info will NOT be added to the file.')
    delete(new_fname)
elseif token_already_embedded==true && update==false
    disp('Copyright info was found in the file.')
    delete(new_fname)
else
    disp('Done.')
    movefile(new_fname,fname)
end


function [event] = read_brainstorm_event(filename)

% READ_BRAINSTORM_EVENT reads the event information from .EEG files
% that have been generated by the Nihon Kohden system. The function
% constitutes a wrapper around BrainStorm3 functionalities
%
% Use as
%   [event] = read_brainstorm_event(filename)
%
% See also READ_NK1200_HEADER, READ_NK1200_DATA

% Copyright (C) 2018, Arjen Stolk & Sandon Griffin
%
% 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$

% call BrainStorm's in_fopen_nk
[sFile] = in_fopen_nk(filename);

% create the event file by pulling values from the output
event = [];
for e = 1:numel(sFile.events)
  event(e).type      = sFile.events(e).label;
  event(e).sample    = sFile.events(e).samples(1);
  event(e).value     = sFile.events(e).label;
  event(e).offset    = 0;
  if numel(sFile.events(e).samples)>1
    event(e).duration  = sFile.events(e).samples(2)-sFile.events(e).samples(1)+1;
  else
    event(e).duration  = 0;
  end
end


%kkcpfromval 'Copy Value Segment Into One Segment of Output'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros kcpfromval.pane file
%
% Parameters:
% InputFile: i 'Input', required: 'Source input file'
% OutputFile: o 'Output ', required: 'output file'
% Toggle: val 'Value', default: 0: 'If -val flag is selected, operate on Value segment'
% Toggle: map 'Map', default: 0: 'If -map flag is selected, operate on map segment'
% Toggle: mask 'Mask', default: 0: 'If -mask flag is selected, operate on Mask segment'
% Toggle: loc 'Location', default: 0: 'If -loc flag is selected, operate on Location segment'
% Toggle: time 'Time', default: 0: 'If -time flag is selected, operate on Time segment'
%
% Example: o = kkcpfromval(i, {'i','';'o','';'val',0;'map',0;'mask',0;'loc',0;'time',0})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% kcpfromval - Copy Value Segment Into One Segment of Output
%
%  DESCRIPTION
% This routine copies the five dimensional value segment from the source
% object to the specified segment specified in the
% destination_object. The data will be copied into the lowest order
% dimension of the destination segment, then the next order will be
% used, and the next, and so forth, until all the value data is copied.
% If the dimensionality of the destination is less than five, then the
% last dimension of the destination segment will have all the higher
% order dimensions rolled into it.
% If segment is specified to be a polymorphic segment by setting one of
% the toggles (value, location, time, mask, map) then the segment
% dimensionalities and index orders specified by the polymorphic model
% will be used. If the segment is not one of the polymorphic segments,
% then the dimensionality of the value segment will be used, and the
% segment will be given an index order of width, height, depth, time, and
% elements.
% Only the size and data type attribute will be changed, all others will
% not be transferred to the destination segment.  If the segment does
% not exist in the destination and is not a polymorphic segment the
% dimension and index order will be set.  If it is a polymorphic segment
% the default polymorphic dimension and index order will be used.
%
%
%
%  EXAMPLES
%
%  "SEE ALSO"
%
%  RESTRICTIONS
% Results guaranteed only if dimension of destination segment is 5.
% Other dimensions are not tested and may produce poor results.
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993 - 1997, Khoral Research, Inc. ("KRI")  All rights reserved.
%

function varargout = kkcpfromval(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,..] = kkcpfromval(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i', '__input';'o', '__output';'val', 0;'map', 0;'mask', 0;'loc', 0;'time', 0};
maxval={0,0,0,0,0,0,0};
minval={0,0,0,0,0,0,0};
istoggle=[0,0,1,1,1,1,1];
was_set=istoggle * 0;
paramtype={'InputFile','OutputFile','Toggle','Toggle','Toggle','Toggle','Toggle'};
% identify the input arrays and assign them to the arguments as stated by the user
if ~iscell(Inputs)
Inputs = {Inputs};
end
NumReqOutputs=1; 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(1,1);
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
[varargout{:}]=callKhoros([w 'kcpfromval"  '],Inputs,narglist);


%describres the results of a classification for a single file
classdef AssessmentDetailedClassificationResult < handle
    properties (Access = public)
        annotations;
        segments;
        classificationResult ClassificationResult;
        missedEvents;
    end

    properties (Dependent)
        fileName;
    end

    methods
        function fn = get.fileName(obj)
            fn = obj.classificationResult.table.file.fileName;
        end
    end

    methods (Access = public)
        function obj = AssessmentDetailedClassificationResult(annotations, segments,...
                classificationResult, postProcessingAlgorithm)
            if nargin > 0
                obj.annotations = annotations;
                obj.segments = segments;
                obj.classificationResult = classificationResult;
                obj.createMissedEvents(postProcessingAlgorithm);
            end
        end

        function labels = getAllTruthLabels(obj)
            labels = vertcat(obj.classificationResult.truthClasses);
        end

        function labels = getAllPredictedLabels(obj)
            labels = vertcat(obj.classificationResult.predictedClasses);
        end
    end

    methods (Access = private)
        function createMissedEvents(obj,postProcessingAlgorithm)
            if obj.shouldUseEventDetection()
                resultsComputer = DetectionResultsComputer();
                events = obj.createEventsWithEventIdxs(obj.segments);
                detectionResults = resultsComputer.computeDetectionResults({events},obj.annotations);
                obj.missedEvents = detectionResults.missedEvents;
                if isa(postProcessingAlgorithm, 'LabelMapper')
                    obj.mapMissedEvents(postProcessingAlgorithm);
                end
            end
        end

        function shouldUseEventDetection = shouldUseEventDetection(obj)
            shouldUseEventDetection = false;
            if ~isempty(obj.segments)
                firstSegment = obj.segments(1);
                shouldUseEventDetection = ~isempty(firstSegment.eventIdx);
            end
        end

        function events = createEventsWithEventIdxs(~,segments)
            nEvents = length(segments);
            events = repmat(Event,1,nEvents);
            for i = 1 : nEvents
                segment = segments(i);
                events(i) = Event(segment.eventIdx,segment.label);
            end
        end

        function mapMissedEvents(obj,labelMapper)
            for j = 1 : length(obj.missedEvents)
                obj.missedEvents(j).label = labelMapper.mappingForLabel(obj.missedEvents(j).label);
            end
        end
    end
end


function [isSame, nDiff, commonFields] = isSameCobraModel(model1, model2, printLevel)
% Checks if two COBRA models are the same
%
% USAGE:
%
%    [isSame, nDiff, commonFields] = isSameCobraModel(model1, model2, printLevel)
%
% INPUTS:
%    model1:          COBRA model structure 1
%    model2:          COBRA model structure 2
%
% OPTIONAL INPUTS:
%    printLevel:      Whether to provide additional output (0 - no output (default), 1 - output).
%
% OUTPUTS:
%    isSame:          True if all common fields are identical, else false
%    nDiff:           Number of differences between the two models for each field
%    commonFields:    List of common fields
%
% .. Authors:
%     - Markus Herrgard 9/14/07
%     - CI integration: Laurent Heirendt

%TODO this function needs updating to use structeq.m

if ~exist('printLevel','var')
    printLevel = 0;
end

isSame = true;

fields1 = fieldnames(model1);
fields2 = fieldnames(model2);
onlyIn1 = setdiff(fields1, fields2);
onlyIn2 = setdiff(fields2, fields1);
if printLevel > 0
    if ~isempty(onlyIn1)
        fprintf('The following fields are only present in the first input model:\n');
        for i = 1:numel(onlyIn1)
            fprintf('%s\n',onlyIn1{i});
        end
    end
    if ~isempty(onlyIn2)
        fprintf('The following fields are only present in the second input model:\n');
        for i = 1:numel(onlyIn2)
            fprintf('%s\n',onlyIn2{i});
        end
    end
end

commonFields = intersect(fields1, fields2);
commonFields = commonFields(~strcmpi('description', commonFields));

if (~isempty(onlyIn1) || ~isempty(onlyIn2))
    isSame = false;
end

% initialize variables
nFields = length(commonFields);
nDiff = zeros(nFields,1);

% loop through all fields
for i = 1:nFields
    fieldName = commonFields{i};
    value1 = getfield(model1, fieldName);
    value2 = getfield(model2, fieldName);

    if 0 %debugging code
            if strcmp(fieldName,'rxnConfidenceScores')
                pause(0.1);
            end
    end
    % replace all whitespaces
    if iscellstr(value1)
        value1 = regexprep(value1, '[^\w'']', '');
        value2 = regexprep(value2, '[^\w'']', '');
    end

    if isnumeric(value1)
        nDiff(i) = sum(sum(~((value1 == value2) | (isnan(value1) & isnan(value2))) ));
    elseif iscellstr(value1)
        if 0 %debugging code
        for i=1:length(value1)
            if class(value1{i})~=class(value2{i})
                pause(0.1)
            end
            if length(value1{i})~=length(value2{i})
                pause(0.1)
            end
        end
        end
        nDiff(i) = sum(~strcmp(value1, value2));
    elseif ischar(value1)
        nDiff(i) = ~strcmp(value1, value2);
    end

    if (nDiff(i) > 0)
        isSame = false;
    end
    if printLevel > 0
        if nDiff(i) > 0
            fprintf('Field %s differs in %d positions between the models\n',fieldName,nDiff(i));
        end
    end

end


function Dout = spm_eeg_merge(S)
% Concatenate epoched single trial files
% FORMAT Dout = spm_eeg_merge(S)
%
% S           - input structure (optional)
%  fields of S:
%   S.D       - character array containing filename of M/EEG mat-files
%               or cell array of D's
%   S.recode  - this field specifies how the condition labels will be
%               translated from the original files to the merged file.
%               Several options are possible:
%                 'same'        - leave the condition labels unchanged
%                 'addfilename' - add the original file name to condition
%                                 label
%                 old way specification - (for backward compatibility)
%                       a cell array where each cell contains a condition
%                       label. The ordering of these labels must be such
%                       that each row in the cell matrix specifies the
%                       conditionlabels for one of the selected files.
%                 specification via recoding rules - for this S.recode
%                       should be a structure array where each element
%                       specifies a rule using the following fields:
%                            file - can be a cell array of strings with
%                                   file names, a vector of file indices
%                                   or a string with regular expression
%                                   matching the files to which the rule
%                                   will apply.
%                            labelorg - can be a cell array of condition
%                                   labels or a string with regular
%                                   expression matching the condition
%                                   labels to which this rule will apply.
%                            labelnew - new label for the merged file. It
%                                   can contain special tokens #file# and
%                                   #labelorg# that will be replaced by
%                                   the original file name and original
%                                   condition label respectively.
%                       The rule will be applied one after the other so
%                       the last rule takes precedences. Trials not
%                       matched by any of the rules will keep their
%                       original labels.
%                       Example:
%                          S.recode(1).file     = '.*';
%                          S.recode(1).labelorg = '.*';
%                          S.recode(1).labelnew = '#labelorg# #file#';
%                       has the same effect as the 'addfilename' option.
%   S.prefix  - prefix for the output file (default - 'c')
%
%
% Dout        - MEEG object (also written to disk)
%__________________________________________________________________________
%
% This function can be used to merge M/EEG files to one file. This is
% useful whenever the data are distributed over multiple files, but one
% wants to use all information in one file. For example, when displaying
% data (SPM displays data from only one file at a time), or merging
% information that has been measured in multiple sessions.
%__________________________________________________________________________
% Copyright (C) 2008-2017 Wellcome Trust Centre for Neuroimaging

% Stefan Kiebel, Vladimir Litvak, Doris Eckstein, Rik Henson
% $Id: spm_eeg_merge.m 7125 2017-06-23 09:49:29Z guillaume $

SVNrev = '$Rev: 7125 $';

%-Startup
%--------------------------------------------------------------------------
spm('FnBanner', mfilename, SVNrev);
spm('FigName','M/EEG Merge'); spm('Pointer','Watch');

if ~isfield(S,'prefix'), S.prefix = 'c';    end
if ~isfield(S,'recode'), S.recode = 'same'; end

%-Load MEEG data
%--------------------------------------------------------------------------
D = S.D;

if ischar(D)
    F = cell(1,size(D,1));
    try
        for i = 1:size(D, 1)
            F{i} = spm_eeg_load(deblank(D(i, :)));
        end
        D = F;
    catch
        error('Trouble reading files.');
    end
end

Nfiles = length(D);

if Nfiles < 2
    %error('Need at least two files for merging.');
end

%-Check input and determine number of new number of trial types
%--------------------------------------------------------------------------
Ntrials = [];
megsens = [];
eegsens = [];
fid     = [];
isTF    =  strncmpi(D{1}.transformtype,'TF',2); % TF and TFphase

for i = 1:Nfiles
    if ~isequal(D{i}.transformtype, D{1}.transformtype)
        error(['The datasets do not contain the same kind of data.\n'...
               'There is a difference between files\n\t%s\nand\n\t%s.'], ...
               D{1}.fname, D{i}.fname);
    end

    if D{1}.nchannels ~= D{i}.nchannels
        error(['Data don''t have the same number of channels.\n' ...
               'There is a difference between files\n\t%s\nand\n\t%s.'], ...
               D{1}.fname, D{i}.fname);
    end

    if D{1}.nsamples ~= D{i}.nsamples
        error(['Data don''t have the same number of time points.\n' ...
               'There is a difference between files\n\t%s\nand\n\t%s.'], ...
               D{1}.fname, D{i}.fname);
    end

    if D{1}.fsample ~= D{i}.fsample
        error(['Data don''t have the same sampling rate.\n' ...
               'There is a difference between files\n\t%s\nand\n\t%s.'], ...
               D{1}.fname, D{i}.fname);
    end

    if isTF &&  ~isequal(D{1}.frequencies, D{i}.frequencies)
        error(['Data don''t have the same frequencies.\n' ...
               'There is a difference between files\n\t%s\nand\n\t%s.'], ...
               D{1}.fname, D{i}.fname);
    end

    if ~isempty(D{i}.sensors('MEG'))
        megsens = spm_cat_struct(megsens, D{i}.sensors('MEG'));
    end

    if ~isempty(D{i}.sensors('EEG'))
        eegsens = spm_cat_struct(eegsens, D{i}.sensors('EEG'));
    end

    if ~isempty(megsens) || ~isempty(eegsens)
        fid = spm_cat_struct(fid, D{i}.fiducials);
    end

    Ntrials = [Ntrials D{i}.ntrials];
end

%-Prepare some useful lists
%--------------------------------------------------------------------------
F        = {};
Find     = [];
clb      = {};
for i = 1:Nfiles
    F{i} = fname(D{i});
    clb  = [clb D{i}.conditions];
    Find = [Find i*ones(1, D{i}.ntrials)];
end
uclb     = unique(clb);

%-Specify condition labels recoding
%--------------------------------------------------------------------------
if ~isfield(S, 'recode')
    S.recode = spm_input('What to do with condition labels?', 1, 'm',...
        'Leave as they are|Add file name|Specify rules for recoding|Specify recoding the old way', strvcat('same', 'addfilename', 'rules', 'old'));
end

if isequal(S.recode, 'old')
    S.recode = {};
    for i = 1:Nfiles
        for j = 1:nconditions(D{i})
            S.recode{i}{j} = spm_input(sprintf('Labels: %s', spm_file(D{i}.fname, 'basename')),...
                '+1', 's', D{i}.condlist{j});
        end
    end
elseif isequal(S.recode, 'rules')
    S.recode = [];
    stop     = 0;
    ind      = 1;
    while ~stop
        spm_input(['Please define rule ' num2str(ind) ':'], 1, 'd');
        switch spm_input('To which files will this rule apply?', '+1', 'm',...
                'All the files|Specify indices|Select files|Wildcard expression (*,?)|Regular expression',...
                strvcat('all', 'indices', 'select', 'wildcard', 'regexp'))
            case 'all'
                S.recode(ind).file = '.*';
            case 'indices'
                S.recode(ind).file =  spm_input('Input file indices', '+1', 'n', num2str(ind), [1 Inf]);
            case 'select'
                [selection, ok]= listdlg('ListString', F, 'SelectionMode', 'multiple' ,'Name', 'Select files' , 'ListSize', [400 300]);
                if ok
                    S.recode(ind).file = F(selection);
                else
                    continue;
                end
            case 'wildcard'
                S.recode(ind).file = regexptranslate('wildcard' , spm_input('Input wildcard expresssion', '+1', 's',  '*'));
            case 'regexp'
                S.recode(ind).file = spm_input('Input regular expresssion', '+1', 's',  '.*');
        end

        switch spm_input('What conditions will be renamed?', '+1', 'm',...
                'All|Select|Specify by wildcard expression (*,?)|Specify by regular expression',...
                strvcat('all', 'select', 'wildcard', 'regexp'))
            case 'all'
                S.recode(ind).labelorg = '.*';
            case 'select'
                [selection, ok]= listdlg('ListString', uclb, 'SelectionMode', 'multiple' ,'Name', 'Select conditions' , 'ListSize', [400 300]);
                if ok
                    S.recode(ind).labelorg = uclb(selection);
                else
                    continue;
                end
            case 'wildcard'
                S.recode(ind).labelorg = regexptranslate('wildcard' , spm_input('Input wildcard expresssion', '+1', 's',  '*'));
            case 'regexp'
                S.recode(ind).labelorg = spm_input('Input regular expresssion', '+1', 's',  '.*');
        end

        S.recode(ind).labelnew = spm_input('Input the new name?', '+1', 's',  '');

        stop = spm_input('Define another rule?','+1','yes|stop', [0 1], 0);
        ind  = ind+1;
    end
end

%-Generate new meeg object with new filename
%--------------------------------------------------------------------------
Dout = D{1};
newfilename = spm_file(fnamedat(Dout), 'path',pwd, 'prefix',S.prefix);

if ~isTF
    Dout = clone(Dout, newfilename, [Dout.nchannels Dout.nsamples sum(Ntrials)]);
else
    Dout = clone(Dout, newfilename, [Dout.nchannels Dout.nfrequencies Dout.nsamples sum(Ntrials)]);
end

%-Perform condition labels recoding
%--------------------------------------------------------------------------
if isequal(S.recode, 'same')
    Dout = conditions(Dout, ':', clb);
elseif isequal(S.recode, 'addfilename')
    for i = 1:numel(clb)
        clb{i} = [clb{i} ' ' spm_file(F{Find(i)}, 'basename')];
    end
    Dout = conditions(Dout, ':', clb);
elseif iscell(S.recode)
    for i = 1:Nfiles
        ind = find(Find == i);

        for j = 1:D{i}.nconditions
            clb(ind(strmatch(D{i}.condlist{j}, clb(ind), 'exact'))) = S.recode{i}(j);
        end
    end
    Dout = conditions(Dout, ':', clb);
elseif isstruct(S.recode)
    clbnew = clb;

    for i = 1:numel(S.recode)
        if isnumeric(S.recode(i).file)
            ind = S.recode(i).file;
        elseif iscell(S.recode(i).file)
            ind = spm_match_str(F, S.recode(i).file);
        elseif ischar(S.recode(i).file)
            ind = find(~cellfun('isempty', regexp(F, S.recode(i).file)));
        else
            error('Invalid file specification in recoding rule.');
        end

        ind = find(ismember(Find, ind));

        if iscell(S.recode(i).labelorg)
            ind = ind(ismember(clb(ind), S.recode(i).labelorg));
        elseif ischar(S.recode(i).labelorg)
            ind = ind(~cellfun('isempty', regexp(clb(ind), S.recode(i).labelorg)));
        else
            error('Invalid original condition label specification in recoding rule.');
        end

        for j = 1:length(ind)
            labelnew = S.recode(i).labelnew;
            labelnew = strrep(labelnew, '#file#', spm_file(F{Find(ind(j))}, 'basename'));
            labelnew = strrep(labelnew, '#labelorg#', clb(ind(j)));

            clbnew{ind(j)} = labelnew;
        end
    end

    Dout = conditions(Dout, ':', clbnew);
end

%-Average sensor locations
%--------------------------------------------------------------------------
CmdLine = spm('CmdLine');
if CmdLine, h = []; end
if ~isempty(megsens)
    if ~CmdLine, spm_figure('GetWin','Graphics');clf; end
    if ~isempty(eegsens)
        if ~CmdLine, h = subplot(2, 1, 1); end
        aeegsens = ft_average_sens(eegsens, 'weights', Ntrials, 'feedback', h);
        Dout = sensors(Dout, 'EEG', aeegsens);

        if ~CmdLine, h = subplot(2, 1, 2); end
    else
        if ~CmdLine, h = axes; end
    end

    [amegsens,afid] = ft_average_sens(megsens, 'fiducials', fid, 'weights', Ntrials, 'feedback', h);
    Dout = sensors(Dout, 'MEG', amegsens);
    Dout = fiducials(Dout, afid);
elseif ~isempty(eegsens)
    if ~CmdLine, spm_figure('GetWin','Graphics');clf; end
    if ~CmdLine, h = axes; end
    [aeegsens,afid] = ft_average_sens(eegsens, 'fiducials', fid, 'weights', Ntrials, 'feedback', h);
    Dout = sensors(Dout, 'EEG', aeegsens);
    Dout = fiducials(Dout, afid);
end

%-Write files
%--------------------------------------------------------------------------
spm_progress_bar('Init', Nfiles, 'Files merged');

k = 0;

for i = 1:Nfiles

    ind = union(Dout.badchannels, D{i}.badchannels);
    if ~isempty(ind)
        Dout = badchannels(Dout, ind, 1);
    end

    % write trial-wise to avoid memory mapping error
    for j = 1:D{i}.ntrials
        k = k + 1;
        if ~isTF
            Dout(1:Dout.nchannels, 1:Dout.nsamples, k) =  D{i}(:,:,j);
        else
            Dout(1:Dout.nchannels, 1:Dout.nfrequencies, 1:Dout.nsamples, k) =  D{i}(:,:,:,j);
        end
        Dout = badtrials(Dout, k, badtrials(D{i}, j));
    end

    % Propagate some useful information from the original files to the
    % merged file
    Dout = repl(Dout, find(Find == i), D{i}.repl);
    Dout = trialonset(Dout, find(Find == i), D{i}.trialonset);
    Dout = trialtag(Dout, find(Find == i), D{i}.trialtag);
    Dout = events(Dout, find(Find == i), D{i}.events);

    spm_progress_bar('Set', i);

end

%-Save new M/EEG data
%--------------------------------------------------------------------------
Dout = Dout.history('spm_eeg_merge', S, 'reset');
save(Dout);

%-Cleanup
%--------------------------------------------------------------------------
spm_progress_bar('Clear');
fprintf('%-40s: %30s\n','Completed',spm('time'));                       %-#
spm('FigName','M/EEG merge: done'); spm('Pointer','Arrow');


function [depFiles] = lexdepfun(rootFunction,varargin)
%
% lexdepfun.m--Recursively searches for file dependencies for the specified
% mfile. If the mfile name specified by the user does not include any path
% information, which.m will be used to acquire it.
%
% Only user-defined mfiles are returned as dependencies.
%
% If optional, second argument is '-quiet', then progress is not displayed
% as search happens.
%
% Syntax: depFiles = lexdepfun(rootFunction,<quietFlag>)
%
% e.g.,   depFiles = lexdepfun('myplot')

% Developed in Matlab 7.6.0.324 (R2008a) on GLNX86.
% Kevin Bartlett (kpb@uvic.ca), 2008-06-25 13:45
%-------------------------------------------------------------------------

% Development note. Rewritten largely from scratch in June 2008 to work
% with class-definition directories ("@-directories").

isQuiet = false;

if nargin > 1
    if strcmpi(varargin{1},'-quiet')
        isQuiet = true;
    end % if
end % if

recursionLevel = 0;
alreadySearched = {};

% Get list of paths to search and make first recursive call.
[pathName,rootBaseName,ext] = fileparts(rootFunction);

if isempty(pathName)
    % If no path information, use which.m to get path to root function.
    rootFunction = whichfile(rootFunction);

    if isempty(rootFunction)
        error([mfilename '.m--rootFunction must be on Matlab''s path.']);
    end % if

end % if

% Get list of directories to search.
pathStr = path;

if isunix
    pathCell = textscan(pathStr,'%s','delimiter',':');
else
    pathCell = textscan(pathStr,'%s','delimiter',';');
end % if

pathCell = pathCell{1};

% Exlude the current directory and parent directory indicators ('.' and
% '..', respectively) from the list of directories to search.
matchIndex = strmatch('.',pathCell);
pathCell(matchIndex) = [];
matchIndex = strmatch('..',pathCell);
pathCell(matchIndex) = [];

% Only interested in user-defined functions, so exclude Mathworks
% mfiles.
matPath = matlabroot;
matchIndex = strmatch(matPath,pathCell);
pathCell(matchIndex) = [];

% Get list of base names of all mfiles on path. Only the base names are
% collected because these are what are searched for lexically in the
% file whose dependencies are being determined.
onPathBaseNames = {};

for iPath = 1:length(pathCell)

    thisDir = pathCell{iPath};
    dirOut = dir(fullfile(thisDir,'*.m'));
    numFiles = length(dirOut);
    thisPathBaseNames = cell(1,numFiles);

    for iFile = 1:numFiles
        [dummy,thisBaseName] = fileparts(dirOut(iFile).name);
        thisPathBaseNames{iFile} = thisBaseName;
    end % for

    onPathBaseNames = union(onPathBaseNames,thisPathBaseNames);

    % If there are any "@-directories" (class-definition directories) in
    % this directory, then the class-definition files they contain are also
    % on Matlab's search path, although they do not appear in the output
    % from path.m. For example, if a sub-directory named "@dial" exists in
    % this directory, then the file ".../@dial/dial.m" should be included
    % in onPathBaseNames.
    dirOut = dir(fullfile(thisDir,'@*'));
    numFiles = length(dirOut);
    atDirNames = cell(1,numFiles);

    for iFile = 1:numFiles
        [dummy,thisBaseName] = fileparts(dirOut(iFile).name);
        thisBaseName = strrep(thisBaseName,'@','');
        atDirNames{iFile} = thisBaseName;
    end % for

    onPathBaseNames = union(onPathBaseNames,atDirNames);

end % for

% Make recursive call to search routine and return results.
if isQuiet == false
    progressStr = ['RecursionLevel ' num2str(recursionLevel) ' (' rootBaseName ') '];
    fprintf(1,'%s',progressStr);
end % if

[depFiles,recursionLevel] = recursive_search(rootFunction,recursionLevel,onPathBaseNames,alreadySearched,isQuiet);

if isQuiet == false
    fprintf(1,'\n');
end % if

%-------------------------------------------------------------------------
function [depFiles,recursionLevel,alreadySearched] = recursive_search(rootFunction,recursionLevel,onPathBaseNames,alreadySearched,isQuiet)
%
% recursive_search.m--Recursively searches the specified function
% (fully-qualified filename) for dependencies.
%
% Syntax: [depFiles,recursionLevel,alreadySearched] = recursive_search(rootFunction,recursionLevel,onPathBaseNames,alreadySearched,isQuiet)

%-------------------------------------------------------------------------

depFiles = {rootFunction};
candidates = onPathBaseNames;

% If there is a "private" directory under the root function's directory,
% then the mfiles it contains will need to be considered as possible
% dependencies (private directories don't appear in Matlab's path).
[pathName,rootBaseName,ext] = fileparts(rootFunction);
privDirName = fullfile(pathName,'private');
privDirBaseNames = {};

if exist(privDirName,'dir')

    dirOut = dir(fullfile(privDirName,'*.m'));

    numPrivFiles = length(dirOut);
    privDirBaseNames = cell(1,numPrivFiles);

    for iFile = 1:numPrivFiles
        [dummy,thisBaseName] = fileparts(dirOut(iFile).name);
        privDirBaseNames{iFile} = thisBaseName;
    end % for

    candidates = union(candidates,privDirBaseNames);

end % if

% If the root function lives in an "@-directory" (a class-definition
% directory), then any other files in that directory should be considered
% as possible dependencies, just like the contents of a "private" directory
% (parent directories of @-directories appear in Matlab's path, but the
% @-directories themselves do not).
[dummy,parentDirName] = fileparts(pathName);
classDefBaseNames = {};

if strncmp(parentDirName,'@',1)

    dirOut = dir(fullfile(pathName,'*.m'));

    numClassDefFiles = length(dirOut);
    classDefBaseNames = cell(1,numClassDefFiles);

    for iFile = 1:numClassDefFiles
        [dummy,thisBaseName] = fileparts(dirOut(iFile).name);
        classDefBaseNames{iFile} = thisBaseName;
    end % for

    classDefBaseNames = setdiff(classDefBaseNames,rootBaseName);
    candidates = union(candidates,classDefBaseNames);

end % if

% Look in the mfile being searched for strings that match the candidate
% dependencies.
lexicalMatches = lexical_search(rootFunction,candidates);

% Each of the lexical matches is a possible dependency that itself must be
% searched for dependencies.
numMatches = length(lexicalMatches);

if isQuiet == false
    if numMatches == 0
        progressStr = 'no lexical matches found.';
        fprintf(1,'%s',progressStr);
    end % if
end % if

for iMatch = 1:numMatches

    % Show progress.
    if isQuiet == false
        progressStr = ['lexical match ' num2str(iMatch) ' of ' num2str(numMatches) '.'];
        fprintf(1,'%s',progressStr);
    end % if

    thisMatch = lexicalMatches{iMatch};
    recursiveRootFunction = '';

    if ismember(thisMatch,privDirBaseNames)
        recursiveRootFunction = fullfile(privDirName,[thisMatch '.m']);
    elseif ismember(thisMatch,classDefBaseNames)
        recursiveRootFunction = fullfile(pathName,[thisMatch '.m']);
    elseif ismember(thisMatch,onPathBaseNames)
        % Dependency is on Matlab's path, so can use which.m to find it.
        recursiveRootFunction = whichfile(thisMatch);
    end % if

    if ~isempty(recursiveRootFunction)

        if ~ismember(recursiveRootFunction,alreadySearched)

            recursionLevel = recursionLevel + 1;

            if recursionLevel > 0
                progressStr = ['RecursionLevel ' num2str(recursionLevel) ' (' thisMatch ') '];
                leadingBlank = repmat('.',1,recursionLevel*6);
                progressStr = sprintf('%s%s',leadingBlank,progressStr);
            else
                progressStr = ['RecursionLevel ' num2str(recursionLevel) ' (' thisMatch ') '];
                progressStr = sprintf('\n%s',progressStr);
            end % if

            if isQuiet == false
                fprintf(1,'\n%s',progressStr);
            end % if

            alreadySearched = union(alreadySearched,recursiveRootFunction);

            [newDepFiles,recursionLevel,alreadySearched] = ...
                recursive_search(recursiveRootFunction,recursionLevel,candidates,alreadySearched,isQuiet);

            recursionLevel = recursionLevel - 1;

            if recursionLevel > 0
                progressStr = ['RecursionLevel ' num2str(recursionLevel) ' (' thisMatch ') '];
                leadingBlank = repmat('.',1,recursionLevel*6);
                progressStr = sprintf('%s%s',leadingBlank,progressStr);
            else
                progressStr = ['RecursionLevel ' num2str(recursionLevel) ' (' thisMatch ') '];
                progressStr = sprintf('\n%s',progressStr);
            end % if

            if isQuiet == false
                fprintf(1,'\n%s',progressStr);
            end % if

            depFiles = union(depFiles,newDepFiles);

        end % if

    end % if

end % for

%-------------------------------------------------------------------------
function [lexicalMatches] = lexical_search(filename,candidates)
%
% lexical_search.m--Searches the specified function (fully-qualified
% filename) for strings that match candidates for dependencies. The
% basename of the function itself is not returned in the list of lexical
% matches.
%
% Syntax: lexicalMatches = lexical_search(filename,candidates)

%-------------------------------------------------------------------------

% Get list of characters that are not permitted in an mfilename.

% ...The list of permitted characters includes a whitespace. This is so
% that the whitespace separating words in a line of the mfile are not
% removed along with the '(', '}', etc.
goodChars = [ ['a':'z'] ['A':'Z'] ['0':'9'] '_' ' ' ];
badChars = setdiff(char(1:127),goodChars);
tokens = {};

% Read in the mfile and extract string tokens from it. "Tokens" are
% space-delimited strings that conform to our expectations of what an mfile
% basename should look like (no special characters or leading numeric
% characters, etc.)
fullRootMfile = whichfile(filename);

if ~isempty(fullRootMfile)

    fid = fopen(fullRootMfile);

    if fid < 1
        error([mfilename '.m--Could not open mfile ' fullRootMfile '.']);
    end % if

    textLines = textscan(fid,'%s','commentstyle','%','delimiter','\n','whitespace','');
    fclose(fid);
    textLines = strtrim(textLines{1});
    numLines = length(textLines);

    % The 'commentstyle' parameter for textscan isn't smart enough to
    % detect comment lines when preceded by spaces. Now that textLines has
    % been deblanked, seek out comment lines and delete them.
    for lineCount = 1:numLines

        thisLine = textLines{lineCount};

        if ~isempty(thisLine)
            if strcmp(thisLine(1),'%')
                textLines{lineCount} = '';
            end % if
        end % if

    end % for

    % Cycle through the lines and extract the strings from them.
    for lineCount = 1:numLines

        thisLine = textLines{lineCount};

        % Replace any characters that aren't allowed in mfilenames with
        % whitespaces.
        thisLine(ismember(thisLine,badChars)) = ' ';

        if isempty(thisLine)
            thisLineStrs = '';
        else
            thisLineStrs = textscan(thisLine,'%s');
            thisLineStrs = thisLineStrs{1};
        end % if

        % Ignore line if it is empty.
        if ~isempty(thisLineStrs)

            % Ignore line if it starts with 'function'.
            if strcmp(thisLineStrs{1},'function')==0
                [tokens{length(tokens)+1: ...
                    length(tokens)+length(thisLineStrs)}] = ...
                    deal(thisLineStrs{:});
            end % if

        end % if

    end % for

end % if

% Remove duplicate tokens.
tokens = unique(tokens);
numTokens = length(tokens);

% Remove tokens that have leading numeric characters (illegal for
% variable names or mfile names in Matlab). Perform the removal by
% replacing individual elements with blanks (simplifies indexing).
for iToken = 1:numTokens

    thisToken = tokens{iToken};

    if ismember(thisToken(1),'0123456789')
        tokens{iToken} = '';
    end % if

end % for

% Remove known Matlab keywords.
for iToken = 1:numTokens

    thisToken = tokens{iToken};

    if iskeyword(thisToken)
        tokens{iToken} = '';
    end % if

end % for

% Get rid of the blanks introduced by the removal of unwanted elements.
isGoodToken = true(1,numTokens);

for iToken = 1:numTokens

    thisToken = tokens{iToken};

    if isempty(thisToken)
        isGoodToken(iToken) = false;
    end % if

end % for

numTokens = length(isGoodToken(isGoodToken==true));
[tmp{1:numTokens}] = deal(tokens{isGoodToken});
tokens = tmp;

% Match the tokens with the candidate mfile basenames.
lexicalMatches = intersect(tokens,candidates);

% Remove the filename itself from its list of candidate dependencies.
[dummy,baseName] = fileparts(filename);
lexicalMatches = setdiff(lexicalMatches,baseName);

%-------------------------------------------------------------------------
function [whichFile] = whichfile(UNLIKELYFILENAME)
%
% whichfile.m--Like Matlab's which.m, but ignores variable names matching
% the input string.
%
% Matlab's which.m returns the string 'variable' when given an input string
% that matches the name of a variable on the workspace, even if the string
% also matches an m-file on the path. For example,
%   name = which('jump')
% where an m-file named jump.m exists on the Matlab path AND 'jump' is the
% name of a variable results in the variable "name" being assigned the
% value 'variable'.
%
% whichfile.m avoids this counter-intuitive behaviour by ignoring variables
% that match the input string.
%
% Syntax: whichFile = whichfile(fileName)
%
% e.g.,  ls = 99;
%        badOutput = which('ls') % (returns the string 'variable')
%        whichFile = whichfile('ls')

% Developed in Matlab 7.2.0.232 (R2006a) on PCWIN.
% Kevin Bartlett (kpb@uvic.ca), 2008-02-12 23:38
%-------------------------------------------------------------------------

% This program makes use of a variable named "UNLIKELYFILENAME", under the
% assumption that it is extremely unlikely for a user to want to trace a
% file named "UNLIKELYFILENAME.m". Just in case, check to make sure that
% the variable UNLIKELYFILENAME does not contain the string
% 'UNLIKELYFILENAME'.
if strcmp(UNLIKELYFILENAME,'UNLIKELYFILENAME')
    error([mfilename '.m--The string ''UNLIKELYFILENAME'' is the ONLY string that is not allowed! Buy a lottery ticket!']);
end % if

% Because UNLIKELYFILENAME is the only variable in this workspace, can now
% use Matlab's which.m without inadvertently returning the string
% 'variable'.
whichFile = which(UNLIKELYFILENAME);


function Bnew = pollGPS2N(B,x,gpstruct,LB,UB,optimState,options)
%POLLGPS2N Poll 2N fixed basis vectors (Generalized Pattern Search).

nvars = numel(x);

if isempty(B)
    % Axis-oriented poll vector set
    Bnew = [eye(nvars); -eye(nvars)];
else
    Bnew = [];
end

end


% mff_fileio_read_header() - import MFF header
%
% Usage:
%   >> header = read_eeglabheader(filename);
%
% Inputs:
%   filename - [string] file name
%
% Outputs:
%   header   - FILEIO toolbox type structure

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

function header = mff_fileio_read_header(mffFile)

if nargin < 1
    help mff_fileio_read_header;
    return;
end

% import basic information
tmp = mff_import(mffFile);
curPath = pwd;
p = fileparts(which('ft_read_header'));
cd(fullfile(p, 'private'));
header = read_eeglabheader( tmp );
cd(curPath);
header.orig = tmp;


function [] = testLSTM(modelFiles, beamSize, stackSize, batchSize, outputFile,varargin)
% Test a trained LSTM model by generating translations.
% Arguments:
%   modelFiles: single or multiple models to decode. Multiple models are
%     separated by commas.
%   beamSize: number of hypotheses kept at each time step.
%   stackSize: number of translations retrieved.
%   batchSize: number of sentences decoded simultaneously. We only ensure
%     accuracy of batchSize = 1 for now.
%   outputFile: output translation file.
%   varargin: other optional arguments.
%
% Thang Luong @ 2015, <lmthang@stanford.edu>
% Hieu Pham @ 2015, <hyhieu@cs.stanford.edu>

  addpath(genpath(sprintf('%s/..', pwd)));

  %% Argument Parser
  p = inputParser;
  % required
  addRequired(p,'modelFiles',@ischar);
  addRequired(p,'beamSize',@isnumeric);
  addRequired(p,'stackSize',@isnumeric);
  addRequired(p,'batchSize',@isnumeric);
  addRequired(p,'outputFile',@ischar);

  % optional
  addOptional(p,'gpuDevice', 0, @isnumeric); % choose the gpuDevice to use: 0 -- no GPU
  addOptional(p,'align', 0, @isnumeric); % 1 -- output aignment from attention model
  addOptional(p,'assert', 0, @isnumeric); % 1 -- assert
  addOptional(p,'debug', 0, @isnumeric); % 1 -- debug
  addOptional(p,'minLenRatio', 0.5, @isnumeric); % decodeLen >= minLenRatio * srcMaxLen
  addOptional(p,'maxLenRatio', 1.5, @isnumeric); % decodeLen <= maxLenRatio * srcMaxLen
  addOptional(p,'testPrefix', '', @ischar); % to specify a different file for decoding
  addOptional(p,'hasTgt', 1, @isnumeric); % 0 -- no ref translations (groundtruth)
  addOptional(p,'continueId', 0, @isnumeric); % > 0: start decoding from this continueId (base 1) sent and append the results
  addOptional(p,'unkDiscount', 0, @isnumeric); % > 0: to prevent long unk sequences

  % force decoding: always feed the correct words (groundtruth)
  addOptional(p,'forceDecoder', 0, @isnumeric);

  p.KeepUnmatched = true;
  parse(p,modelFiles,beamSize,stackSize,batchSize,outputFile,varargin{:})
  decodeParams = p.Results;
  if decodeParams.batchSize==-1 % decode sents one by one
    decodeParams.batchSize = 1;
  end

  % GPU settings
  decodeParams.isGPU = 0;
  if decodeParams.gpuDevice
    n = gpuDeviceCount;
    if n>0 % GPU exists
      fprintf(2, '# %d GPUs exist. So, we will use GPUs.\n', n);
      decodeParams.isGPU = 1;
      gpuDevice(decodeParams.gpuDevice)
      decodeParams.dataType = 'single';
    else
      decodeParams.dataType = 'double';
    end
  else
    decodeParams.dataType = 'double';
  end
  printParams(2, decodeParams);

  %% load multiple models
  tokens = strsplit(decodeParams.modelFiles, ',');
  numModels = length(tokens);
  models = cell(numModels, 1);
  for mm=1:numModels
    modelFile = tokens{mm};
    [savedData] = load(modelFile);
    models{mm} = savedData.model;
    models{mm}
    models{mm}.params = savedData.params;

    % backward compatible
    if (isfield(models{mm}.params,'softmaxFeedInput')) && (~isfield(models{mm}.params,'feedInput'))
      models{mm}.params.feedInput = models{mm}.params.softmaxFeedInput;
    end
    [models{mm}.params] = backwardCompatible(models{mm}.params, {'charOpt', 'charSrcRep', 'charTgtGen', 'normLocalAttn'}, 0);

    % convert absolute paths to local paths
    fieldNames = fields(models{mm}.params);
    for ii=1:length(fieldNames)
     field = fieldNames{ii};
     if ischar(models{mm}.params.(field))
       if strfind(models{mm}.params.(field), '/afs/ir/users/l/m/lmthang') ==1
         models{mm}.params.(field) = strrep(models{mm}.params.(field), '/afs/ir/users/l/m/lmthang', '~');
       end
       if strfind(models{mm}.params.(field), '/afs/cs.stanford.edu/u/lmthang') ==1
         models{mm}.params.(field) = strrep(models{mm}.params.(field), '/afs/cs.stanford.edu/u/lmthang', '~');
       end
       if strfind(models{mm}.params.(field), '/home/lmthang') ==1
         models{mm}.params.(field) = strrep(models{mm}.params.(field), '/home/lmthang', '~');
       end
     end
    end

    % load vocabs
    [models{mm}.params] = prepareVocabs(models{mm}.params);

    % make sure all models have the same vocab, and the number of layers
    if mm>1
      for ii=1:models{mm}.params.srcVocabSize
        assert(strcmp(models{mm}.params.srcVocab{ii}, models{1}.params.srcVocab{ii}), '! model %d, mismatch src word %d: %s vs. %s\n', mm, ii, models{mm}.params.srcVocab{ii}, models{1}.params.srcVocab{ii});
      end
      for ii=1:models{mm}.params.tgtVocabSize
        assert(strcmp(models{mm}.params.tgtVocab{ii}, models{1}.params.tgtVocab{ii}), '! model %d, mismatch tgt word %d: %s vs. %s\n', mm, ii, models{mm}.params.tgtVocab{ii}, models{1}.params.tgtVocab{ii});
      end
      models{mm}.params = rmfield(models{mm}.params, {'srcVocab', 'tgtVocab'});
    end

    % copy fields
    fieldNames = fields(decodeParams);
    for ii=1:length(fieldNames)
      field = fieldNames{ii};
      if strcmp(field, 'testPrefix')==1 && strcmp(decodeParams.(field), '')==1 % skip empty testPrefix
        continue;
      elseif strcmp(field, 'testPrefix')==1
        fprintf(2, '# Decode a different test file %s\n', decodeParams.(field));
      end
      models{mm}.params.(field) = decodeParams.(field);
    end
  end

  params = models{1}.params;

  % force decode
  if decodeParams.forceDecoder
    params.stackSize = 1;
    params.beamSize = 1;
  end

  if params.continueId > 0 % appending
    fileOpt = 'a';
  else
    fileOpt = 'w';
  end

  params.fid = fopen(params.outputFile, fileOpt);
  if params.charTgtGen
    params.charFid = fopen([params.outputFile '.char'], fileOpt);
  end

  params.logId = fopen([outputFile '.log'], fileOpt);
  % align
  if params.align
    params.alignId = fopen([params.outputFile '.align'], fileOpt);
  end
  printParams(2, params);

  % load test data
  [srcSents, tgtSents, numSents]  = loadBiData(params, params.testPrefix, params.srcVocab, params.tgtVocab, -1, params.hasTgt);

  %%%%%%%%%%%%
  %% decode %%
  %%%%%%%%%%%%
  numBatches = floor((numSents-1)/batchSize) + 1;

  fprintf(2, '# Decoding %d sents, %s\n', numSents, datestr(now));
  fprintf(params.logId, '# Decoding %d sents, %s\n', numSents, datestr(now));
  startTime = clock;
  for batchId = 1 : numBatches
    % prepare batch data
    startId = (batchId-1)*batchSize+1;
    endId = batchId*batchSize;
    if endId > numSents
      endId = numSents;
    end

    % continue training
    if params.continueId > startId
      continue;
    end

    [decodeData] = prepareData(srcSents(startId:endId), tgtSents(startId:endId), 1, params);
    decodeData.startId = startId;

    % call lstmDecoder
    [candidates, candScores, alignInfo, otherInfo] = lstmDecoder(models, decodeData, params);

    % print results
    printDecodeResults(decodeData, candidates, candScores, alignInfo, otherInfo, params, 1);
  end

  endTime = clock;
  timeElapsed = etime(endTime, startTime);
  fprintf(2, '# Complete decoding %d sents, time %.0fs, %s\n', numSents, timeElapsed, datestr(now));
  fprintf(params.logId, '# Complete decoding %d sents, time %.0fs, %s\n', numSents, timeElapsed, datestr(now));

  fclose(params.fid);
  if params.charTgtGen
    fclose(params.charFid);
  end
  fclose(params.logId);
end

%     % convert local paths to absolute paths
%     fieldNames = fields(models{mm}.params);
%     for ii=1:length(fieldNames)
%       field = fieldNames{ii};
%       if ischar(models{mm}.params.(field))
%         if strfind(models{mm}.params.(field), '~lmthang/') ==1
%           models{mm}.params.(field) = strrep(models{mm}.params.(field), '~lmthang/', '/afs/ir/users/l/m/lmthang/');
%         end
%         if strfind(models{mm}.params.(field), '~lmthang/') ==1
%           models{mm}.params.(field) = strrep(models{mm}.params.(field), '~lmthang/', '/afs/cs.stanford.edu/u/lmthang/');
%         end
%         if strfind(models{mm}.params.(field), '~lmthang/') ==1
%           models{mm}.params.(field) = strrep(models{mm}.params.(field), '~lmthang/', '/home/lmthang/');
%         end
%       end
%     end


classdef MimContextMapping < handle
    % MimContextMapping. A class for specifying the relationship between
    % contexts.
    %
    % This class is used by the Framework to store the relationship between
    % a context (the region in the image over which results are calculated),
    % and its context sets (the set of contexts of which it is a member), and
    % alo the hierarchy of contexts. For example, the LeftLung and RightLung
    % contexts are both in the context set SingleLung, and these are both
    % children of the LungROI context.
    %
    %
    %     Licence
    %     -------
    %     Part of the TD MIM Toolkit. https://github.com/tomdoel
    %     Author: Tom Doel, Copyright Tom Doel 2014.  www.tomdoel.com
    %     Distributed under the MIT licence. Please see website for details.
    %

    properties
        Context % The context
        ContextSet % The context type (of type MimContextSet)
        TemplateGenerationFunctions % The name of a function from which this context can be found
        ContextTriggerPlugin % The name of a plugin which, when called, will trigger saving of a template
        Parent %
        Children
    end

    methods
        function obj = MimContextMapping(context_id, context_set, template_generation_function, context_trigger_plugin, parent_context_mapping)
            obj.Context = context_id;
            obj.ContextSet = context_set;
            obj.TemplateGenerationFunctions = template_generation_function;
            obj.ContextTriggerPlugin = context_trigger_plugin;
            obj.Parent = parent_context_mapping;
            obj.Children = {};

            % Add this context to the list of contexts for this context type
            obj.ContextSet.AddContext(obj);

            if ~isempty(parent_context_mapping)
                obj.Parent.AddChild(obj);
            end
        end

        function AddChild(obj, child)
            obj.Children{end + 1} = child;
        end
    end

end


%% Example
% This script is used to initialize the hand guiding functionality on KUKA
% robot remotely

% Mohammad SAFEEA, 9th of June 2017

% TO use this example:
% 1- Start the server on KUKA
% 2- Start the client on Matlab
% 3- Press the white button and hand guide the robot
% 4- To save the coordinates of the robot, long click on the green button
% 5- Repeat three times
% 6- The robot gives you an interval of five seconds, clear the area around
% the robot directly, the robot will reproduce the motion tought.

HandTeachingExample();


function ui = mrViewGrayscalePanel(ui, dockFlag, vis);
%
% ui = mrViewGrayscalePanel(ui, [dockFlag], [vis=0]);
%
% Add a panel for setting the grayscale display
% values of the mr image (underlay). Also initializes
% the panel to be hidden, since it may not be needed
% right away.
%
% dockFlag: if 1, will attach panel to the
% mrViewer figure. Otherwise, will make a
% separate figure for the panel.
%
% vis: if 0, will initialize the panel to be hidden (default when
% starting up mrViewer); otherwise, leave it visible (as when
% docking/undocking the panel).
%
% ras, 07/05.
% ras, 07/15/05 -- now places the panel in a separate figure
% by default.
% ras, 06/07 -- now a horizontal panel; added vis toggle.
if ~exist('ui','var') | isempty(ui), ui = mrViewGet; end
if ~exist('dockFlag','var') | isempty(dockFlag), dockFlag = 0; end
if ~exist('vis', 'var') | isempty(vis),  vis = 0; end

% add the panel
if dockFlag==1
    ui.panels.grayscale = mrvPanel('above', .2, ui.fig, 'normalized');
else
    hfig = figure('Name', sprintf('Grayscale [%s]',ui.tag),...
        'Units', 'normalized', 'Position', [.2 .4 .12 .3],...
        'MenuBar', 'none', 'NumberTitle', 'off', ...
        'UserData', ui.tags);
    ui.panels.grayscale = uipanel('Parent',hfig,'Units','normalized',...
        'Position',[0 0 1 1]);

	% close request function for this figure: just toggle visibility
    crf = 'tmp = findobj(''Parent'', gcf, ''Type'', ''uipanel''); ';
    crf = [crf 'mrvPanelToggle(tmp); clear tmp;'];
    set(hfig, 'CloseRequestFcn', crf);
end

set(ui.panels.grayscale, 'BackgroundColor', [.9 .9 .9],...
    'ShadowColor', [1 1 1], 'Title', 'Grayscale');

% add a slider for brightness
ui.controls.brightness = mrvSlider([.02 .2 .2 .5], 'Brightness', ...
    'Callback', 'mrViewSetGrayscale;', 'Range', [-1 1], 'Val', 0,...
    'Parent', ui.panels.grayscale);

% add a toggle button for manually setting clip values
cb = 'mrViewSetGrayscale(gcf, ''manualclip'', gcbo); ';
ui.controls.manualClip = mrvButtons('Manual Clip Values',...
    [.25 .55 .15 .4], ui.panels.grayscale, cb, 0);

% add a button to guess clip val
cb = 'mrViewSetGrayscale([],''clip'',''guess'');';
ui.controls.guessClip = uicontrol('Parent', ui.panels.grayscale, ...
    'Style', 'pushbutton', ...
    'String', 'Guess Clip Vals', ...
    'Units', 'normalized', ...
    'Position', [.25 .05 .15 .4], ...
    'Callback', cb);

% add sliders for clip min / max
rng = [min(ui.mr.data(:)) max(ui.mr.data(:))];
ui.controls.clipMin = mrvSlider([.45 .55 .2 .4], 'Clip Min Val',...
    'Callback', 'mrViewSetGrayscale;', ...
    'Range', rng, 'Val', rng(1),...
    'Visible', 'off', ...
    'Parent', ui.panels.grayscale);

ui.controls.clipMax = mrvSlider([.45 .05 .2 .4], 'Clip Max Val',...
    'Callback', 'mrViewSetGrayscale;',...
    'Range', rng, 'Val', rng(2),...
    'Visible', 'off',...
    'Parent', ui.panels.grayscale);

% hide the panel
mrvPanelToggle(ui.panels.grayscale,'off');

%%%%%hide the panel
if vis==0
	mrvPanelToggle(ui.panels.grayscale, 'off');
end

return


% ---------------------------------------------------------
% Copyright (c) 2017, Gurkirt Singh
% This code and is available
% under the terms of MIT License provided in LICENSE.
% Please retain this notice and LICENSE if you use
% this file (or any portion of it) in your project.
% ---------------------------------------------------------

function opts = initDatasetOpts(data_root,baseDir,dataset,imgType,model_type,listid,iteration_num,iouthresh,costtype,gap)

opts = struct();
opts.imgType = imgType;
opts.costtype = costtype;
opts.gap = gap;
opts.baseDir = baseDir;
opts.imgType = imgType;
opts.dataset = dataset;
opts.iouThresh = iouthresh;
opts.weight = iteration_num;
opts.listid = listid;

testlist = ['display',listid];
% opts.vidList = sprintf('%s/%s/splitfiles/%s.txt',data_root,dataset,testlist);
opts.vidList = sprintf('%s.txt',testlist);

if strcmp(dataset,'ucf24')
    opts.actions = {'Basketball','BasketballDunk','Biking','CliffDiving','CricketBowling',...
        'Diving','Fencing','FloorGymnastics','GolfSwing','HorseRiding','IceDancing',...
        'LongJump','PoleVault','RopeClimbing','SalsaSpin','SkateBoarding','Skiing',...
        'Skijet','SoccerJuggling','Surfing','TennisSwing','TrampolineJumping',...
        'VolleyballSpiking','WalkingWithDog'};
elseif strcmp(dataset,'JHMDB')
    opts.actions = {'brush_hair','catch','clap','climb_stairs','golf','jump',...
        'kick_ball','pick','pour','pullup','push','run','shoot_ball','shoot_bow',...
        'shoot_gun','sit','stand','swing_baseball','throw','walk','wave'};
elseif strcmp(dataset,'LIRIS')
    opts.actions = {'discussion', 'give_object_to_person','put_take_obj_into_from_box_desk',...
        'enter_leave_room_no_unlocking','try_enter_room_unsuccessfully','unlock_enter_leave_room',...
        'leave_baggage_unattended','handshaking','typing_on_keyboard','telephone_conversation'};
end

opts.imgDir = sprintf('%s/%s/%s-images/',data_root,dataset,imgType);

opts.detDir = sprintf('%s/%s/detections/%s-%s-%s-%06d/',baseDir,dataset,model_type,imgType,listid,iteration_num);
opts.annotFile = sprintf('%s/%s/splitfiles/annots.mat',data_root,dataset);

opts.actPathDir = sprintf('%s/%s/actionPaths/%s-%s-%s-%06d-%s-%d-%04d/',baseDir,dataset,model_type,imgType,listid,iteration_num,costtype,gap,iouthresh*100);
opts.tubeDir = sprintf('%s/%s/actionTubes/%s-%s-%s-%06d-%s-%d-%04d/',baseDir,dataset,model_type,imgType,listid,iteration_num,costtype,gap,iouthresh*100);

if exist(opts.detDir,'dir')
    if ~isdir(opts.actPathDir)
        fprintf('Creating %s\n',opts.actPathDir);
        mkdir(opts.actPathDir)
    end
    if ~isdir(opts.tubeDir)
        mkdir(opts.tubeDir)
    end
    if strcmp(dataset,'ucf24') || strcmp(dataset,'JHMDB')
        createdires({opts.actPathDir},opts.actions)
    end
end