% parse all fields of a solver proto
% transfer all FC layers in the existing model to CONV layers (equvelent)
function [ Solver ] = SolverParser( solver_def_file, resume_file )
if ~exist(solver_def_file,'file')||isempty(solver_def_file)
    error('Solver definition file %s is not found.',solver_def_file);
end
if ~exist('resume_file','var')
    fprintf('Creating a face lmk solver structure based on %s.', solver_def_file);
    Solver = [];
else
    load(resume_file);
end
fout = fopen(solver_def_file,'r');
tline = fgetl(fout);
while ischar(tline)
    disp(tline)
    pos = 1;
    while tline(pos)==' '
       pos = pos + 1;
    end
    if tline(pos) == '#'
            tline = fgetl(fout);
            continue;
    end
    ind = find(tline == '"',1);
    if  ~isempty(ind)
        field = tline(ind + 1 : end - 1);
        ind2 = find(tline == ':',1);
        name = tline(1:ind2-1);
    else
        ind2 = find(tline == ':',1);
        if isempty(ind2)
            error('incorrect format.')
        end
        ctr = tline(ind2+2:end);
        if isempty(str2num(ctr))
            ctr(isspace(ctr)) = [];
            field = ctr;
        else
            field = str2double(ctr);
        end
        name = tline(1:ind2-1);
    end
    Solver = setfield(Solver, name, field);
    tline = fgetl(fout);
end
fclose(fout);
if ~isfield(Solver, 'solver_mode')
    Solver.solver_mode = 'GPU';
end
if ~isfield(Solver, 'device_id') && strcmp(Solver.solver_mode, 'GPU')
        Solver.device_id = 0;
end
if isfield(Solver,'model')
    lnum = length(Solver.model);
    for ind = 1:lnum
        if strcmp(Solver.model(ind).layer_names,sprintf('fc%d',ind))
            Solver.model(ind).layer_names = sprintf('conv%d',ind);
            weights = Solver.model(ind).weights{1};
            [s1,s2] = size(weights);
            [~,~,~,ch] = size(Solver.model(ind-1).weights{1});
            filtersize = sqrt(s1/ch);
            weights = reshape(weights,[filtersize,filtersize,ch,s2]);
            Solver.model(ind).weights{1} = weights;
        end
    end
end
end


function gui_check_range(edithandle,resetstr)
% check whether the the given edit field contains a range; warn and reset if not
if ~exist('resetstr','var')
    resetstr = ''; end

str = get(edithandle,'String');
if ~isempty(str) && numel(str2num(str)) ~= 2
    errordlg2('This field must be of the form [number, number]');
    set(edithandle,'String',resetstr);
end


function obj2off(objFname, offFname)

if ~exist('objFname','var')
    objFname = 'example/model.obj';
end

if ~exist('offFname','var')
    offFname = 'example/model.off';
end

OBJ=read_wobj(objFname);

faces = [];
for i=1:length(OBJ.objects)
    if strcmp(OBJ.objects(i).type,'f')
        faces = [faces; OBJ.objects(i).data.vertices];
    end
end

% check duplicates
for i=1:size(faces,1)
    faces(i,:) = sort(faces(i,:));
end
faces = unique(faces,'rows');

vertices = OBJ.vertices;

%mesh2off(offFname, faces,vertices);
mesh2offbinary(offFname, faces,vertices);


function [nse] = read_neuralynx_nse(filename, begrecord, endrecord)

% READ_NEURALYNX_NSE reads a single electrode waveform file
%
% Use as
%   [nse] = read_neuralynx_nse(filename)
%   [nse] = read_neuralynx_nse(filename, begrecord, endrecord)

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

if nargin<2
  begrecord = 1;
end
if nargin<3
  endrecord = inf;
end

% the file starts with a 16*1024 bytes header in ascii, followed by a number of records
hdr = neuralynx_getheader(filename);
fid = fopen_or_error(filename, 'rb', 'ieee-le');

% determine the length of the file
fseek(fid, 0, 'eof');
headersize = 16384;
if isfield(hdr, 'RecordSize')
  recordsize = hdr.RecordSize;
else
  % this is the default, resulting in 32 samples per spike snippet
  recordsize = 112;
end
NSamples = (recordsize-48)/2;
NRecords = floor((ftell(fid) - headersize)/recordsize);

if NRecords>0
  if (ispc), fclose(fid); end
  % read the timestamp from the first and last record
  hdr.FirstTimeStamp = neuralynx_timestamp(filename, 1);
  hdr.LastTimeStamp  = neuralynx_timestamp(filename, inf);
  if (ispc), fid = fopen_or_error(filename, 'rb', 'ieee-le'); end
else
  hdr.FirstTimeStamp = nan;
  hdr.LastTimeStamp  = nan;
end

if begrecord==0 && endrecord==0
  % only read the header
elseif begrecord<1
  ft_error('cannot read before the first record');
elseif begrecord>NRecords
  ft_error('cannot read beyond the last record')
elseif endrecord>NRecords
  endrecord = NRecords;
end

if begrecord>=1 && endrecord>=begrecord
  % rewind to the first record to be read
  fseek(fid, headersize + (begrecord-1)*recordsize, 'bof');

  numrecord    = (endrecord-begrecord+1);
  TimeStamp    = zeros(1,numrecord,'uint64');
  ScNumber     = zeros(1,numrecord);
  CellNumber   = zeros(1,numrecord);
  Param        = zeros(8,numrecord);
  Samp         = zeros(1,NSamples,numrecord);

  k = 1;
  while (begrecord+k-1)<=endrecord
    % read a single electrode record
    TimeStamp(k)   = fread(fid,  1, 'uint64=>uint64');
    ScNumber(k)    = fread(fid,  1, 'int32');
    CellNumber(k)  = fread(fid,  1, 'int32');
    Param(:,k)     = fread(fid,  8, 'int32');
    Samp(1,:,k)    = fread(fid, NSamples, 'int16');
    k = k + 1;
  end

  nse.TimeStamp   = TimeStamp;
  nse.ScNumber    = ScNumber;
  nse.CellNumber  = CellNumber;
  nse.Param       = Param;
  % apply the scaling factor from ADBitVolts and convert to uV
  nse.dat         = Samp * hdr.ADBitVolts * 1e6;
end
fclose(fid);

nse.NRecords = NRecords;
nse.hdr      = hdr;


function ex_ssc_omp(md, num_samples_per_digit)
    if nargin < 1
        error('database must be loaded.');
    end
    if nargin < 2
        num_samples_per_digit = 50;
    end
    close all;
    clc;
    check_digits(md, num_samples_per_digit, @ssc_omp, 'ssc_omp');
end


addpath([cd '\ballistics_problem_files\']);
ballist_prob;


function b = isany(list, func)
% BOOL = ISANY(ARRAY)
% BOOL = ISANY(ARRAY, FUNC)
%   Without FUNC, ISANY returns true if any element of ARRAY is logically
%   true.  With FUNC, every element first has FUNC applied to it, and this
%   result is used instead - thus if any application of FUNC across ARRAY
%   is true, then ISANY(ARRAY, FUNC) is true.
%

  if nargin < 2, func = @(x) x; end
  % We don't use foldl so as to incur better performance via short circuit.
  b = 0;
  if iscell(list)
    for i = 1:numel(list)
      if func(list{i})
        b = 1;
        return;
      end
    end
  else
    for i = 1:numel(list)
      if func(list(i))
        b = 1;
        return;
      end
    end
  end
end


function varargout = size(X,d)
% SIZE (overloaded)

if nargin == 1 && nargout > 1 && nargout == length(X.dim)
    for i = 1:length(X.dim);
        varargout{i} = X.dim(i);
    end
    return
elseif nargin == 1 && nargout > 1 && nargout < length(X.dim)
    % Weird but this is MATLAB standard
    for i = 1:nargout-1
        varargout{i} = X.dim(i);
    end
    varargout{end+1} = prod(X.dim(nargout:end));
    return
end

if nargin == 1
    varargout{1} = X.dim;
else
    if (d < 1) || d~=round(d)
        error('Dimension argument must be a positive integer scalar in the range 1 to 2^31.');
    end
    if d <= length(X.dim)
        varargout{1} = X.dim(d);
    else
        varargout{1} = 1;
    end
end


function [TorF, vstr, rdate] = have_feature_optimoptions()
%HAVE_FEATURE_OPTIMOPTIONS  Detect availability/version info for OPTIMOPTIONS
%
%   Feature detection function implementing 'optimoptions' tag for HAVE_FEATURE
%   to detect support for OPTIMOPTIONS, option setting function for MATLAB
%   Optimization Toolbox 6.3 and later.
%
%   See also HAVE_FEATURE, HAVE_FEATURE_OPTIM, OPTIMOPTIONS.

%   MP-Opt-Model
%   Copyright (c) 2004-2020, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MP-Opt-Model.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://github.com/MATPOWER/mp-opt-model for more info.

TorF = 0;
vstr = '';
rdate = '';
if have_feature('matlab')
    v = have_feature('optim', 'all');
    if v.av && v.vnum >= 6.003      %% Opt Tbx 6.3+ (R2013a+, MATLAB 8.1+)
        TorF = 1;
        vstr = v.vstr;
        rdate = v.date;
    end
end


function varargout = isempty(varargin)
%ISEMPTY   True for empty SPHEREFUN.
%   ISEMPTY(F) returns 1 if F is an empty SPHEREFUN object and 0 otherwise.

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

[varargout{1:nargout}] = isempty@separableApprox(varargin{:});

end


function ind = get_index(description,pattern)
M=length(description);
N=length(pattern);
ind=[];
for i=1:M
    for j=1:N
        if strcmp(description{i},pattern{j})
            ind(end+1)=i;
        end
    end
end
end


% DYNAMICPLOT
%   obj = dynamicplot(genFcn, T)
%    creates a figure that is automatically updated (by calling a
%    generator function genFcn) every T seconds. genFcn does not take
%    any arguments, and returns a vector of values to be plotted.
%    obj is a handle to the created object.
%
% Example:
%    d = dynamicplot(@() randn(1,100), 0.5);
%    methods(d)  % shows all the methods
%    help dynamicplot/delete % shows help on an individual method
%
% -------------------------------------------------------------------
%
% The DYNAMICPLOT class demonstrates how to get reference (aka. handle)
% semantics using MATLAB classes. Typically when one modifies a MATLAB
% object, it needs be returned to the caller:
%       obj = set(obj, 'myParameter', 10.0);
% But with handle semantics, you can simply do this:
%      set(obj, 'myParameter', 10.0);
% This is especially useful with objects that need to be updated
% autonomously (e.g., acquiring data from a data aquisition device
% or an instrument).
%
% The handle semantics were accomplished as follows. (1) the constructor
% defines the instance variables and (2) returns a set of function handles
% to access these instance variables. Other methods (e.g., set(obj, ...);
% get(obj, ...)), use the function handles to access and modify the data.
% This technique also enforces data-hiding with the object.
%
% Detailed example of handle semantics:
%
%   d = dynamicplot(@() randn(1,100), 0.5);
%   struct(d)
%   ans =
%          getLineHandle: @dynamicplot/getLineHandle
%        setUpdatePeriod: @dynamicplot/setUpdatePeriod
%        getUpdatePeriod: @dynamicplot/getUpdatePeriod
%      getMostRecentData: @dynamicplot/getMostRecentData
%         getTimerObject: @dynamicplot/getTimerObject
%     getNumAcquisitions: @dynamicplot/getNumAcquisitions
%        getFigureHandle: @dynamicplot/getFigureHandle
%          checkValidity: @dynamicplot/checkValidity
%            setValidity: @dynamicplot/setValidity
%
%
%   getdata(d) % issue this command several times
%   setUpdatePeriod(d, 0.2)
%   getNumUpdates(d) % issue this several times
%   setLineStyle(d,'color','r');
%
%   % Object assignment respects the handle semantics
%   d2 = d;  % both d and d2 refer to the same objects
%   pauseDisplay(d);
%   resumeDisplay(d2);
%
%   % Validity checks can be built into the object itself
%   delete(d);
%   getdata(d) % will generate an error
%   getdata(d2) % this generates error also
%
%   % It is possible to have multiple objects without any clashes
%   d1 = dynamicplot(@() randn(1,100), 0.1);
%   d2 = dynamicplot(@() rand(1,100), 0.1);
%   pauseDisplay(d1);
%   getNumUpdates(d1) % issue these a few times
%   getNumUpdates(d2)
%   resumeDisplay(d1);
%   delete(d1);
%
%
%  Gautam Vallabha, Oct-30-2007, Gautam.Vallabha@mathworks.com

%  Revision 1.0, Oct-30-2007
%    - File created

function s = dynamicplot(genFcn, period)

% class variables
isValid = true;

hFigure = figure('name', 'Dynamic Plot');
hAxes = axes('position', [0.13 0.11 0.775 0.815]);
hLine = plot(0,0, 'parent', hAxes);

generatorFcn = genFcn;
mostRecentData = [];
numberOfAcquisitions = 0;
updatePeriod = period;

timerObj = timer('period', updatePeriod, ...
                 'executionMode', 'fixedRate', ...
                 'timerFcn', @timerCallback);
start(timerObj);

% The class struct contains only function handles

s.getLineHandle = @getLineHandle;
s.setUpdatePeriod = @setUpdatePeriod;
s.getUpdatePeriod = @getUpdatePeriod;
s.getMostRecentData = @getMostRecentData;
s.getTimerObject = @getTimerObject;
s.getNumAcquisitions = @getNumAcquisitions;
s.getFigureHandle = @getFigureHandle;
s.checkValidity = @checkValidity;
s.setValidity = @setValidity;

s = class(s, 'dynamicplot');

%% -------------------
% These are essentially private get/set methods

    function out = checkValidity()
        out = isValid;
        if ~isValid
            error('Invalid DYNAMICPLOT object');
        end
    end

    function setValidity(newState)
        isValid = logical(newState);
    end

    function out = getFigureHandle()
       out = hFigure;
    end

    function out = getNumAcquisitions()
        out = numberOfAcquisitions;
    end

    function out = getTimerObject()
        out = timerObj;
    end

    function out = getLineHandle()
        out = hLine;
    end

    function setUpdatePeriod(newPeriod)
        updatePeriod = newPeriod;
    end

    function out = getUpdatePeriod()
        out = updatePeriod;
    end

    function out = getMostRecentData()
        out = mostRecentData;
    end

%% -------------------
    function timerCallback(hobj, eventinfo) %#ok<INUSD>
        mostRecentData = generatorFcn();
        if ~ishandle(hLine)
           % someone deleted the figure, create a new one
           hFigure = figure('name', 'Dynamic Plot');
           hAxes = axes('position', [0.13 0.11 0.775 0.815]);
           hLine = plot(0,0, 'parent', hAxes);
        end

        set(hLine, 'xdata', 1:length(mostRecentData), 'ydata', mostRecentData);
        drawnow;
        numberOfAcquisitions = numberOfAcquisitions + 1;
    end
end


function asa147_test ( )

%*****************************************************************************80
%
%% ASA147_TEST tests ASA147.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'ASA147_TEST\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Test the ASA147 library.\n' );

  asa147_test01 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'ASA147_TEST\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


function minc = spm_cfg_minc
% SPM Configuration file for MINC Import
%__________________________________________________________________________
% Copyright (C) 2005-2011 Wellcome Trust Centre for Neuroimaging

% $Id: spm_cfg_minc.m 6952 2016-11-25 16:03:13Z guillaume $

%--------------------------------------------------------------------------
% data MINC files
%--------------------------------------------------------------------------
data         = cfg_files;
data.tag     = 'data';
data.name    = 'MINC files';
data.help    = {'Select the MINC files to convert.'};
data.filter  = 'mnc';
data.ufilter = '.*';
data.num     = [1 Inf];

%--------------------------------------------------------------------------
% dtype Data Type
%--------------------------------------------------------------------------
dtype         = cfg_menu;
dtype.tag     = 'dtype';
dtype.name    = 'Data Type';
dtype.help    = {'Data-type of output images. Note that the number of bits used determines the accuracy, and the amount of disk space needed.'};
dtype.labels  = {
                'UINT8   - unsigned char'
                'INT16   - signed short'
                'INT32   - signed int'
                'FLOAT32 - single prec. float'
                'FLOAT64 - double prec. float'
}';
dtype.values = {spm_type('uint8') spm_type('int16') spm_type('int32') ...
                spm_type('float32') spm_type('float64')};
dtype.val    = {spm_type('int16')};

%--------------------------------------------------------------------------
% ext Output image format
%--------------------------------------------------------------------------
ext         = cfg_menu;
ext.tag     = 'ext';
ext.name    = 'Output image format';
ext.help    = {'Output files can be written as .img + .hdr, or the two can be combined into a .nii file.'};
ext.labels = {
              'Two file (img+hdr) NIfTI'
              'Single file (nii) NIfTI'
}';
ext.values = { 'img', 'nii' };
ext.def    = @(val)spm_get_defaults('images.format', val{:});

%--------------------------------------------------------------------------
% opts Options
%--------------------------------------------------------------------------
opts         = cfg_branch;
opts.tag     = 'opts';
opts.name    = 'Options';
opts.val     = {dtype ext};
opts.help    = {'Conversion options'};

%--------------------------------------------------------------------------
% minc MINC Import
%--------------------------------------------------------------------------
minc         = cfg_exbranch;
minc.tag     = 'minc';
minc.name    = 'MINC Import';
minc.val     = {data opts};
minc.help    = {
    'MINC Conversion.'
    'MINC is the image data format used for exchanging data within the ICBM community, and the format used by the MNI software tools. It is based on NetCDF. MINC is no longer supported for reading images into SPM, so MINC files need to be converted to NIFTI format in order to use them. See http://www.bic.mni.mcgill.ca/software/ for more information.'
    }';
minc.prog    = @spm_run_minc;
minc.vout    = @vout;

%==========================================================================
function out = spm_run_minc(job)
for i=1:numel(job.data)
    spm_mnc2nifti(job.data{i},job.opts);
end

out.files = cell(size(job.data));
for i=1:numel(job.data)
    out.files{i} = spm_file(job.data{i}, 'path',pwd, 'ext',job.opts.ext);
end

%==========================================================================
function dep = vout(job)
dep            = cfg_dep;
dep.sname      = 'Converted Images';
dep.src_output = substruct('.','files');
dep.tgt_spec   = cfg_findspec({{'filter','image','strtype','e'}});


function demprior(action);
%DEMPRIOR Demonstrate sampling from a multi-parameter Gaussian prior.
%
%	Description
%	This function plots the functions represented by a multi-layer
%	perceptron network when the weights are set to values drawn from a
%	Gaussian prior distribution. The parameters AW1, AB1 AW2 and AB2
%	control the inverse variances of the first-layer weights, the hidden
%	unit  biases, the second-layer weights and the output unit biases
%	respectively.  Their values can be adjusted on a logarithmic scale
%	using the sliders, or  by typing values into the text boxes and
%	pressing the return key.
%
%	See also
%	MLP
%

%	Copyright (c) Ian T Nabney (1996-2001)

if nargin<1,
    action='initialize';
end;

if strcmp(action,'initialize')

  aw1 = 0.01;
  ab1 = 0.1;
  aw2 = 1.0;
  ab2 = 1.0;

  % Create FIGURE
  fig=figure( ...
    'Name','Sampling from a Gaussian prior', ...
    'Position', [50 50 480 380], ...
    'NumberTitle','off', ...
    'Color', [0.8 0.8 0.8], ...
    'Visible','on');

  % The TITLE BAR frame
  uicontrol(fig,  ...
    'Style','frame', ...
    'Units','normalized', ...
    'HorizontalAlignment', 'center', ...
    'Position', [0.5 0.82 0.45 0.1], ...
    'BackgroundColor',[0.60 0.60 0.60]);

  % The TITLE BAR text
  uicontrol(fig, ...
    'Style', 'text', ...
    'Units', 'normalized', ...
    'BackgroundColor', [0.6 0.6 0.6], ...
    'Position', [0.54 0.85 0.40 0.05], ...
    'HorizontalAlignment', 'left', ...
    'String', 'Sampling from a Gaussian prior');

  % Frames to enclose sliders
  uicontrol(fig, ...
    'Style', 'frame', ...
    'Units', 'normalized', ...
    'BackgroundColor', [0.6 0.6 0.6], ...
    'Position', [0.05 0.08 0.35 0.18]);

  uicontrol(fig, ...
    'Style', 'frame', ...
    'Units', 'normalized', ...
    'BackgroundColor', [0.6 0.6 0.6], ...
    'Position', [0.05 0.3 0.35 0.18]);

  uicontrol(fig, ...
    'Style', 'frame', ...
    'Units', 'normalized', ...
    'BackgroundColor', [0.6 0.6 0.6], ...
    'Position', [0.05 0.52 0.35 0.18]);

  uicontrol(fig, ...
    'Style', 'frame', ...
    'Units', 'normalized', ...
    'BackgroundColor', [0.6 0.6 0.6], ...
    'Position', [0.05 0.74 0.35 0.18]);

  % Frame text
  uicontrol(fig, ...
    'Style', 'text', ...
    'Units', 'normalized', ...
    'HorizontalAlignment', 'left', ...
    'BackgroundColor', [0.6 0.6 0.6], ...
    'Position', [0.07 0.17 0.06 0.07], ...
    'String', 'aw1');

  % Frame text
  uicontrol(fig, ...
    'Style', 'text', ...
    'Units', 'normalized', ...
    'HorizontalAlignment', 'left', ...
    'BackgroundColor', [0.6 0.6 0.6], ...
    'Position', [0.07 0.39 0.06 0.07], ...
    'String', 'ab1');

  % Frame text
  uicontrol(fig, ...
    'Style', 'text', ...
    'Units', 'normalized', ...
    'HorizontalAlignment', 'left', ...
    'BackgroundColor', [0.6 0.6 0.6], ...
    'Position', [0.07 0.61 0.06 0.07], ...
    'String', 'aw2');

  % Frame text
  uicontrol(fig, ...
    'Style', 'text', ...
    'Units', 'normalized', ...
    'HorizontalAlignment', 'left', ...
    'BackgroundColor', [0.6 0.6 0.6], ...
    'Position', [0.07 0.83 0.06 0.07], ...
    'String', 'ab2');

  % Slider
  minval = -5; maxval = 5;
  aw1slide = uicontrol(fig, ...
    'Style', 'slider', ...
    'Units', 'normalized', ...
    'Value', log10(aw1), ...
    'BackgroundColor', [0.8 0.8 0.8], ...
    'Position', [0.07 0.1 0.31 0.05], ...
    'Min', minval, 'Max', maxval, ...
    'Callback', 'demprior update');

  % Slider
  ab1slide = uicontrol(fig, ...
    'Style', 'slider', ...
    'Units', 'normalized', ...
    'Value', log10(ab1), ...
    'BackgroundColor', [0.8 0.8 0.8], ...
    'Position', [0.07 0.32 0.31 0.05], ...
    'Min', minval, 'Max', maxval, ...
    'Callback', 'demprior update');

  % Slider
  aw2slide = uicontrol(fig, ...
    'Style', 'slider', ...
    'Units', 'normalized', ...
    'Value', log10(aw2), ...
    'BackgroundColor', [0.8 0.8 0.8], ...
    'Position', [0.07 0.54 0.31 0.05], ...
    'Min', minval, 'Max', maxval, ...
    'Callback', 'demprior update');

  % Slider
  ab2slide = uicontrol(fig, ...
    'Style', 'slider', ...
    'Units', 'normalized', ...
    'Value', log10(ab2), ...
    'BackgroundColor', [0.8 0.8 0.8], ...
    'Position', [0.07 0.76 0.31 0.05], ...
    'Min', minval, 'Max', maxval, ...
    'Callback', 'demprior update');

  % The graph box
  haxes = axes('Position', [0.5 0.28 0.45 0.45], ...
    'Units', 'normalized', ...
    'Visible', 'on');

  % Text display of hyper-parameter values

  format = '%8f';

  aw1val = uicontrol(fig, ...
    'Style', 'edit', ...
    'Units', 'normalized', ...
    'Position', [0.15 0.17 0.23 0.07], ...
    'String', sprintf(format, aw1), ...
    'Callback', 'demprior newval');

  ab1val = uicontrol(fig, ...
    'Style', 'edit', ...
    'Units', 'normalized', ...
    'Position', [0.15 0.39 0.23 0.07], ...
    'String', sprintf(format, ab1), ...
    'Callback', 'demprior newval');

  aw2val = uicontrol(fig, ...
    'Style', 'edit', ...
    'Units', 'normalized', ...
    'Position', [0.15 0.61 0.23 0.07], ...
    'String', sprintf(format, aw2), ...
    'Callback', 'demprior newval');

  ab2val = uicontrol(fig, ...
    'Style', 'edit', ...
    'Units', 'normalized', ...
    'Position', [0.15 0.83 0.23 0.07], ...
    'String', sprintf(format, ab2), ...
    'Callback', 'demprior newval');

  % The SAMPLE button
  uicontrol(fig, ...
    'Style','push', ...
    'Units','normalized', ...
    'BackgroundColor', [0.6 0.6 0.6], ...
    'Position',[0.5 0.08 0.13 0.1], ...
    'String','Sample', ...
    'Callback','demprior replot');

  % The CLOSE button
  uicontrol(fig, ...
    'Style','push', ...
    'Units','normalized', ...
    'BackgroundColor', [0.6 0.6 0.6], ...
    'Position',[0.82 0.08 0.13 0.1], ...
    'String','Close', ...
    'Callback','close(gcf)');

  % The HELP button
  uicontrol(fig, ...
    'Style','push', ...
    'Units','normalized', ...
    'BackgroundColor', [0.6 0.6 0.6], ...
    'Position',[0.66 0.08 0.13 0.1], ...
    'String','Help', ...
    'Callback','demprior help');

   % Save handles to objects

  hndlList=[fig aw1slide ab1slide aw2slide ab2slide aw1val ab1val aw2val ...
      ab2val haxes];
  set(fig, 'UserData', hndlList);

  demprior('replot')

elseif strcmp(action, 'update'),

  % Update when a slider is moved.

  hndlList   = get(gcf, 'UserData');
  aw1slide   = hndlList(2);
  ab1slide = hndlList(3);
  aw2slide  = hndlList(4);
  ab2slide = hndlList(5);
  aw1val = hndlList(6);
  ab1val = hndlList(7);
  aw2val = hndlList(8);
  ab2val = hndlList(9);
  haxes = hndlList(10);

  aw1 = 10^get(aw1slide, 'Value');
  ab1 = 10^get(ab1slide, 'Value');
  aw2 = 10^get(aw2slide, 'Value');
  ab2 = 10^get(ab2slide, 'Value');

  format = '%8f';
  set(aw1val, 'String', sprintf(format, aw1));
  set(ab1val, 'String', sprintf(format, ab1));
  set(aw2val, 'String', sprintf(format, aw2));
  set(ab2val, 'String', sprintf(format, ab2));

  demprior('replot');

elseif strcmp(action, 'newval'),

  % Update when text is changed.

  hndlList   = get(gcf, 'UserData');
  aw1slide   = hndlList(2);
  ab1slide = hndlList(3);
  aw2slide  = hndlList(4);
  ab2slide = hndlList(5);
  aw1val = hndlList(6);
  ab1val = hndlList(7);
  aw2val = hndlList(8);
  ab2val = hndlList(9);
  haxes = hndlList(10);

  aw1 = sscanf(get(aw1val, 'String'), '%f');
  ab1 = sscanf(get(ab1val, 'String'), '%f');
  aw2 = sscanf(get(aw2val, 'String'), '%f');
  ab2 = sscanf(get(ab2val, 'String'), '%f');

  set(aw1slide, 'Value', log10(aw1));
  set(ab1slide, 'Value', log10(ab1));
  set(aw2slide, 'Value', log10(aw2));
  set(ab2slide, 'Value', log10(ab2));

  demprior('replot');

elseif strcmp(action, 'replot'),

  % Re-sample from the prior and plot graphs.

  oldFigNumber=watchon;

  hndlList   = get(gcf, 'UserData');
  aw1slide   = hndlList(2);
  ab1slide = hndlList(3);
  aw2slide  = hndlList(4);
  ab2slide = hndlList(5);
  haxes = hndlList(10);

  aw1 = 10^get(aw1slide, 'Value');
  ab1 = 10^get(ab1slide, 'Value');
  aw2 = 10^get(aw2slide, 'Value');
  ab2 = 10^get(ab2slide, 'Value');

  axes(haxes);
  cla
  set(gca, ...
    'Box', 'on', ...
    'Color', [0 0 0], ...
    'XColor', [0 0 0], ...
    'YColor', [0 0 0], ...
    'FontSize', 14);
  axis([-1 1 -10 10]);
  set(gca,'DefaultLineLineWidth', 2);

  nhidden = 12;
  prior = mlpprior(1, nhidden, 1, aw1, ab1, aw2, ab2);
  xvals = -1:0.005:1;
  nsample = 10;    % Number of samples from prior.
  hold on
  plot([-1 0; 1 0], [0 -10; 0 10], 'b--');
  net = mlp(1, nhidden, 1, 'linear', prior);
  for i = 1:nsample
    net = mlpinit(net, prior);
    yvals = mlpfwd(net, xvals');
    plot(xvals', yvals, 'y');
  end

  watchoff(oldFigNumber);

elseif strcmp(action, 'help'),

  % Provide help to user.

  oldFigNumber=watchon;

  helpfig = figure('Position', [100 100 480 400], ...
    'Name', 'Help', ...
    'NumberTitle', 'off', ...
    'Color', [0.8 0.8 0.8], ...
    'Visible','on');

    % The HELP TITLE BAR frame
  uicontrol(helpfig,  ...
    'Style','frame', ...
    'Units','normalized', ...
    'HorizontalAlignment', 'center', ...
    'Position', [0.05 0.82 0.9 0.1], ...
    'BackgroundColor',[0.60 0.60 0.60]);

  % The HELP TITLE BAR text
  uicontrol(helpfig, ...
    'Style', 'text', ...
    'Units', 'normalized', ...
    'BackgroundColor', [0.6 0.6 0.6], ...
    'Position', [0.26 0.85 0.6 0.05], ...
    'HorizontalAlignment', 'left', ...
    'String', 'Help: Sampling from a Gaussian Prior');

  helpstr1 = strcat( ...
    'This demonstration shows the effects of sampling from a Gaussian', ...
     ' prior over weights for a two-layer feed-forward network. The', ...
     ' parameters aw1, ab1, aw2 and ab2 control the inverse variances of', ...
     ' the first-layer weights, the hidden unit biases, the second-layer', ...
     ' weights and the output unit biases respectively. Their values can', ...
     ' be adjusted on a logarithmic scale using the sliders, or by', ...
     ' typing values into the text boxes and pressing the return key.', ...
     '  After setting these values, press the ''Sample'' button to see a', ...
     ' new sample from the prior. ');
   helpstr2 = strcat( ...
     'Observe how aw1 controls the horizontal length-scale of the', ...
     ' variation in the functions, ab1 controls the input range over', ...
     ' such variations occur, aw2 sets the vertical scale of the output', ...
     ' and ab2 sets the vertical off-set of the output. The network has', ...
     ' 12 hidden units. ');
   hstr(1) = {helpstr1};
   hstr(2) = {''};
   hstr(3) = {helpstr2};

  % The HELP text
  helpui = uicontrol(helpfig, ...
    'Style', 'edit', ...
    'Units', 'normalized', ...
    'ForegroundColor', [0 0 0], ...
    'HorizontalAlignment', 'left', ...
    'BackgroundColor', [1 1 1], ...
    'Min', 0, ...
    'Max', 2, ...
    'Position', [0.05 0.2 0.9 0.8]);

   [hstrw , newpos] = textwrap(helpui, hstr, 70);
   set(helpui, 'String', hstrw, 'Position', [0.05, 0.2, 0.9, newpos(4)]);

  % The CLOSE button
  uicontrol(helpfig, ...
    'Style','push', ...
    'Units','normalized', ...
    'BackgroundColor', [0.6 0.6 0.6], ...
    'Position',[0.4 0.05 0.2 0.1], ...
    'String','Close', ...
    'Callback','close(gcf)');

   watchoff(oldFigNumber);

end;


function [y,fs,wmode,fidx]=readaif(filename,mode,nmax,nskip)
%READAIF  Read a .AIF format sound file [Y,FS,WMODE,FIDX]=(FILENAME,MODE,NMAX,NSKIP)
%
% Input Parameters:
%
%	FILENAME gives the name of the file (with optional .AIF extension) or alternatively
%                 can be the FIDX output from a previous call to READAIF
%	MODE		specifies the following (*=default):
%
%    Scaling: 's'    Auto scale to make data peak = +-1
%             'r'    Raw unscaled data (integer values)
%             'q'    Scaled to make 0dBm0 be unity mean square
%             'p' *	Scaled to make +-1 equal full scale
%             'o'    Scale to bin centre rather than bin edge (e.g. 127 rather than 127.5 for 8 bit values)
%                     (can be combined with n+p,r,s modes)
%             'n'    Scale to negative peak rather than positive peak (e.g. 128.5 rather than 127.5 for 8 bit values)
%                     (can be combined with o+p,r,s modes)
%   File I/O: 'f'    Do not close file on exit
%             'd'    Look in data directory: voicebox('dir_data')
%
%	NMAX     maximum number of samples to read (or -1 for unlimited [default])
%	NSKIP    number of samples to skip from start of file
%               (or -1 to continue from previous read when FIDX is given instead of FILENAME [default])
%
% Output Parameters:
%
%	Y        data matrix of dimension (samples,channels)
%	FS       sample frequency in Hz
%	WMODE    mode string needed to recreate the data file
%	FIDX     Information row vector containing the element listed below.
%
%           (1)  file id
%				(2)  current position in file
%           (3)  dataoff	byte offset in file to start of data
%           (4)  nsamp	number of samples
%           (5)  nchan	number of channels
%           (6)  nbyte	bytes per data value
%           (7)  bits	number of bits of precision
%           (8)  code	Data format: 1=PCM, 2=ADPCM, 6=A-law, 7=Mu-law (always 1 for AIFF)
%           (9)  fs	sample frequency
%           (10) offset
%           (11) block size
%
%   If no output parameters are specified, header information will be printed.
%
%   For stereo data, y(:,1) is the left channel and y(:,2) the right

%  future enhancements: (1) handle LIST and CAT files as well
%                       (2) deal with offset and blocksize properly
%                       (3) handle other chunk types sensibly

%	   Copyright (C) Mike Brookes 1998
%      Version: $Id: readaif.m 713 2011-10-16 14:45:43Z dmb $
%
%   VOICEBOX is a MATLAB toolbox for speech processing.
%   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   This program is free software; you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation; either version 2 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You can obtain a copy of the GNU General Public License from
%   http://www.gnu.org/copyleft/gpl.html or by writing to
%   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if nargin<1 error('Usage: [y,fs,wmode,fidx]=READAIFF(filename,mode,nmax,nskip)'); end

if nargin<2 mode='p';
else mode = [mode(:).' 'p'];
end
k=find((mode>='p') & (mode<='s'));
mno=all(mode~='o');                      % scale to input limits not output limits
sc=mode(k(1));

info=zeros(1,11);
if ischar(filename)
    if any(mode=='d')
        filename=fullfile(voicebox('dir_data'),filename);
    end
    fid=fopen(filename,'rb','b');
    if fid == -1
        fn=[filename,'.aif'];
        fid=fopen(fn,'rb','b');
        if fid ~= -1 filename=fn; end
    end
    if fid == -1 error(sprintf('Can''t open %s for input',filename)); end
    info(1)=fid;
else
    info=filename;
    fid=info(1);
end

if ~info(3)
    fseek(fid,0,-1);						% read file header
    header=fread(fid,4,'uchar');
    if header' ~= 'FORM' fclose(fid); error(sprintf('File %s does not begin with a FORM group ID',filename)); end
    filen=fread(fid,1,'ulong')-4;
    header=fread(fid,4,'uchar');
    if header' ~= 'AIFF' fclose(fid); error(sprintf('File %s does not begin with a AIFF type ID',filename)); end

    fmt=0;
    data=0;
    while filen>=8						% loop to read all chunks
        header=fread(fid,4,'char');
        len=fread(fid,1,'ulong');
        lenx=len+rem(len,2);    % round up to an even number
        filen=filen-lenx-8;
        %fprintf(1,'%s chunk, %d bytes, %d bytes remaining\n',char(header'),len,filen);
        if header' == 'COMM'					% ******* found COMM chunk *********
            fmt=1;
            info(5)=fread(fid,1,'ushort');			%number of channels
            info(4)=fread(fid,1,'ulong');			%number of samples
            info(7)=fread(fid,1,'ushort');				% bits per sample
            info(6)=ceil(info(7)/8);            % bytes per sample
            info(8)=1;
            ieeex=fread(fid,5,'ushort');               % read a 10-byte extended ieee format number
            fsign=ieeex(1)>32767;
            ieeex(1)=ieeex(1)-32768*fsign;
            if ~ieeex info(9)=0;
            elseif ieeex(1)==32767 info(9)=nan;
            else
                info(9)=(1-2*fsign)*sum(pow2(ieeex(2:5)',ieeex(1)-(16398:16:16446)));
            end
            fseek(fid,lenx-18,0);				% skip to end of header
        elseif header' == 'SSND'				% ******* found DATA chunk *********
            info(10)=fread(fid,1,'ulong');			%number of channels
            info(11)=fread(fid,1,'ulong');			%number of channels
            info(3)=ftell(fid);
            data=1;
            fseek(fid,lenx-8,0);				% skip to end of chunk
        else							% ******* found unwanted chunk *********
            fseek(fid,lenx,0);
        end
    end
    if filen~=0
        fprintf(2,'READAIF warning: Inconsistent file length - %d extra bytes\n',filen);
    end
end
fs=info(9);
if ~fmt | ~data fclose(fid); error(sprintf('File %s does not contain COMM and SSND chunks',filename)); end

if nargin<4 nskip=info(2);
elseif nskip<0 nskip=info(2);
end

ksamples=info(4)-nskip;
if nargin>2
    if nmax>=0
        ksamples=min(nmax,ksamples);
    end
elseif ~nargout
    ksamples=min(5,ksamples);
end
if ksamples>0
    info(2)=nskip+ksamples;
    pk=pow2(0.5,8*info(6))*(1+(mno/2-all(mode~='n'))/pow2(0.5,info(7)));  % use modes o and n to determine effective peak
    fseek(fid,info(3)+info(6)*info(5)*nskip,-1);
    nsamples=info(5)*ksamples;
    if info(6)<3
        if info(6)<2
            y=fread(fid,nsamples,'schar');
        else
            y=fread(fid,nsamples,'short');
        end
    else
        if info(6)<4
            y=fread(fid,3*nsamples,'uchar');
            y=reshape(y,3,nsamples);
            y=[1 256 65536]*y-pow2(fix(pow2(y(3,:),-7)),24);
        else
            y=fread(fid,nsamples,'long');
        end
    end
    if sc ~= 'r'
        if sc=='s' sf=1/max(max(abs(y)),1);
        elseif sc=='p' sf=1/pk;
        else   sf=2.03033976/pk;
        end
        y=sf*y;
    else
        y=y*pow2(1,info(7)-8*info(6)); % shift to get the data into the LSB end
    end

    if info(5)>1 y = reshape(y,info(5),ksamples).'; end
else
    y=[];
end

if all(mode~='f') fclose(fid); end

if nargout>2
    if ~mno wmode=[wmode 'o']; end
    if any(mode=='n') wmode=[wmode 'n']; end
    wmode=[sc num2str(info(7))];
    fidx=info;
elseif ~nargout
    fprintf(1,'\n%d Hz sample rate\n%d channel x %d samples x %d bit = %.3g seconds\n',info([9 5 4]), info(7),info(4)/info(9));
end


function test_example_nirs_fingertapping

% MEM 4gb
% WALLTIME 00:10:00

%
%% Analyzing NIRS data recorded during unilateral finger- and foot-tapping
%
% This example script demonstrates the analysis of data that is shared by Sujin Bak, Jinwoo Park, Jaeyoung Shin, and Jichai Jeong: _[Open Access fNIRS Dataset for Classification of Unilateral Finger- and Foot-Tapping](https://doi.org/10.6084/m9.figshare.9783755.v2)_.
%
% The following links point to the shared data, to the PDF manuscript that explains the shared data, and to a GitHub repository from one of the authors that contains some example analyses on the data.
%
%* <https://doi.org/10.6084/m9.figshare.9783755.v2>
%* <https://doi.org/10.3390/electronics8121486>
%* <https://github.com/JaeyoungShin/fNIRS-dataset>
%
% The data includes the concentration changes of oxygenated/reduced hemoglobin ∆HbO/HbR, trigger information, and fNIRS channel information. The recordings were done for 30 subjects that were performing a finger- and foot-tapping task.
%
% The data were recorded by a three-wavelength continuous-time multi-channel fNIRS system (LIGHTNIRS, Shimadzu, Kyoto, Japan) consisting of eight light sources (Tx) and eight detectors (Rx). Four each of Tx and Rx were placed around C3 on the left hemisphere, and the rest were placed around C4 on the right hemisphere.
%
% The temporal structure of each trial is
%
%* instruction for 2s
%* fixation cross, this indicates that the task has to be executed, for 10s
%* "stop" for 2s
%* fixation cross indicating rest period, for 15-17 seconds
%
% The total duration of a trial, including the instruction, ranges from 2+10+2+15=29 to 2+10+2+17=31 seconds.
%
%% # Building a MATLAB analysis script
%

% for now, getting the data from the below URL and unzipping it, works (JM added 20211201)
t = tempdir;
filenames = unzip('https://figshare.com/ndownloader/files/18069143', t);

% filenames = {
%   'v2/fNIRS 01.mat'
%   'v2/fNIRS 02.mat'
%   'v2/fNIRS 03.mat'
%   'v2/fNIRS 04.mat'
%   'v2/fNIRS 05.mat'
%   'v2/fNIRS 06.mat'
%   'v2/fNIRS 07.mat'
%   'v2/fNIRS 08.mat'
%   'v2/fNIRS 09.mat'
%   'v2/fNIRS 10.mat'
%   'v2/fNIRS 11.mat'
%   'v2/fNIRS 12.mat'
%   'v2/fNIRS 13.mat'
%   'v2/fNIRS 14.mat'
%   'v2/fNIRS 15.mat'
%   'v2/fNIRS 16.mat'
%   'v2/fNIRS 17.mat'
%   'v2/fNIRS 18.mat'
%   'v2/fNIRS 19.mat'
%   'v2/fNIRS 20.mat'
%   'v2/fNIRS 21.mat'
%   'v2/fNIRS 22.mat'
%   'v2/fNIRS 23.mat'
%   'v2/fNIRS 24.mat'
%   'v2/fNIRS 25.mat'
%   'v2/fNIRS 26.mat'
%   'v2/fNIRS 27.mat'
%   'v2/fNIRS 28.mat'
%   'v2/fNIRS 29.mat'
%   'v2/fNIRS 30.mat'
%   };

% this allows switching easily between subjects, and eventually looping over all 30 subjects
filename = filenames{1};

%% # Exploring the MATLAB files that hold the NIRS data
%
% The data is shared by the authors in the form of MATLAB files. Each file contains a bunch of separate variables, you can load it like this to represent it as a structure:
%
nirs = load(filename);

% >> nirs
% nirs =
%   struct with fields:
%      mrk: [1x1 struct]
%      mnt: [1x1 struct]
%      nfo: [1x1 struct]
%      ch1: [30003x1 double]
%      ch2: [30003x1 double]
%      ch3: [30003x1 double]
%      ch4: [30003x1 double]
%      ch5: [30003x1 double]
%      ch6: [30003x1 double]
%      ch7: [30003x1 double]
%      ch8: [30003x1 double]
%      ch9: [30003x1 double]
%     ch10: [30003x1 double]
%     ch11: [30003x1 double]
%     ch12: [30003x1 double]
%     ch13: [30003x1 double]
%     ch14: [30003x1 double]
%     ch15: [30003x1 double]
%     ch16: [30003x1 double]
%     ch17: [30003x1 double]
%     ch18: [30003x1 double]
%     ch19: [30003x1 double]
%     ch20: [30003x1 double]
%     ch21: [30003x1 double]
%     ch22: [30003x1 double]
%     ch23: [30003x1 double]
%     ch24: [30003x1 double]
%     ch25: [30003x1 double]
%     ch26: [30003x1 double]
%     ch27: [30003x1 double]
%     ch28: [30003x1 double]
%     ch29: [30003x1 double]
%     ch30: [30003x1 double]
%     ch31: [30003x1 double]
%     ch32: [30003x1 double]
%     ch33: [30003x1 double]
%     ch34: [30003x1 double]
%     ch35: [30003x1 double]
%     ch36: [30003x1 double]
%     ch37: [30003x1 double]
%     ch38: [30003x1 double]
%     ch39: [30003x1 double]
%     ch40: [30003x1 double]
%      dat: [1x1 struct]

% Contrary to the description in the accompanying publication (see table 1 in the PDF manuscript) and in the GitHub repository, the MATLAB files do _not_ contain the variables |cntHb|, |clab|, etc. However, it is not so hard to make sense of the data: each channel is represented as a vector, there is header information, there is information about the optode montage, and there is information about the events.
%
% >> nirs.nfo
% ans =
%   struct with fields:
%             fs: 13.3333
%           clab: {1x40 cell}
%              T: 30003
%        nEpochs: 1
%         length: 2.2502e+03
%         format: 'DOUBLE'
%     resolution: [1x40 double]
%           file: 'D:\Experimental data\NIRS motor imagery\matdata\fNIRS 01'
%        nEvents: 75
%       nClasses: 3
%      className: {'RIGHT'  'LEFT'  'FOOT'}

%
% >> nirs.mnt
% ans =
%  struct with fields:
%               x: [40x1 double]
%               y: [40x1 double]
%          pos_3d: [3x40 double]
%            clab: {1x40 cell}
%             box: [2x41 double]
%          box_sz: [2x41 double]
%       scale_box: [2x1 double]
%    scale_box_sz: [2x1 double]

%
% >> nirs.mrk
% ans =
%  struct with fields:
%        event: [1x1 struct]
%         time: [1x75 double]
%            y: [3x75 double]
%    className: {'RIGHT'  'LEFT'  'FOOT'}

%% Convering the MATLAB structure to a FieldTrip raw data structure
%
% Since the data is not stored on disk in a [dataformat](/faq/dataformat/) that FieldTrip can directly read, we will circumvent the FieldTrip reading functions as outlined in [this frequenly asked question](/faq/how_can_i_import_my_own_dataformat/#circumvent-the-fieldtrip-reading-functions).
%
% We start with constructing a MATLAB data structure according to **[ft_datatype_raw](https://github.com/fieldtrip/fieldtrip/blob/release/utilities/ft_datatype_raw.m)**, as if it were produced by **[ft_preprocessing](https://github.com/fieldtrip/fieldtrip/blob/release/ft_preprocessing.m)**.
%
data_raw = [];
data_raw.label = nirs.nfo.clab(:);
data_raw.trial{1} = [
  % transpose each channel, we want the data matrix to be Nchans * Nsamples
  nirs.ch1'
  nirs.ch2'
  nirs.ch3'
  nirs.ch4'
  nirs.ch5'
  nirs.ch6'
  nirs.ch7'
  nirs.ch8'
  nirs.ch9'
  nirs.ch10'
  nirs.ch11'
  nirs.ch12'
  nirs.ch13'
  nirs.ch14'
  nirs.ch15'
  nirs.ch16'
  nirs.ch17'
  nirs.ch18'
  nirs.ch19'
  nirs.ch20'
  nirs.ch21'
  nirs.ch22'
  nirs.ch23'
  nirs.ch24'
  nirs.ch25'
  nirs.ch26'
  nirs.ch27'
  nirs.ch28'
  nirs.ch29'
  nirs.ch30'
  nirs.ch31'
  nirs.ch32'
  nirs.ch33'
  nirs.ch34'
  nirs.ch35'
  nirs.ch36'
  nirs.ch37'
  nirs.ch38'
  nirs.ch39'
  nirs.ch40'
  ];
data_raw.fsample = nirs.nfo.fs;
data_raw.time{1} = ((1:nirs.nfo.T)-1)/nirs.nfo.fs;

%% # Convert the optode montage to a layout for plotting
%
% In FieldTrip we can have a [detailled description](/faq/how_are_electrodes_magnetometers_or_gradiometers_described/#the-definition-of-nirs-sensors) of the NIRS optode placement and how optodes are combined to form channels. However, in this dataset this information is not complete and we cannot make a complete |opto| structure.
%
% This is how far we can get
%
opto = [];
opto.label = nirs.mnt.clab(:);
opto.chanpos = nirs.mnt.pos_3d'; % these are all nan

% But this is not a complete description of the channel and sensor information according to **[ft_dataype_sens](https://github.com/fieldtrip/fieldtrip/blob/release/utilities/ft_datatype_sens.m)**. However, a full sensor definitioon is also not required: the opical densities have already been converted in HbO and HbR prior to sharing, so we only care about channel positions for plotting.
%
% For the plotting of channel level data (see also [this tutorial](/tutorial/plotting/)) we need a 2D layout. That is explained in detail in [this tutorial](/tutorial/layout/). If the |opto| definition had included 2D or 3D channel positions, then we could have used **[ft_prepare_layout](https://github.com/fieldtrip/fieldtrip/blob/release/ft_prepare_layout.m)** but now we will manually construct the layout structure.
%
layout = [];
layout.label = nirs.mnt.clab(:);
layout.pos = [nirs.mnt.x(:) nirs.mnt.y(:)]; % these are all nan
layout.pos = nirs.mnt.box';
layout.width = nirs.mnt.box_sz(1,:)';
layout.height = nirs.mnt.box_sz(2,:)';
layout.outline = {};
layout.mask = {};

% I don't think that the 41st position refers to an actual channel, so let's remove that.
%
layout.pos(41, :) = [];
layout.width(41)  = [];
layout.height(41) = [];

% We can plot the layout using **[ft_plot_layout](https://github.com/fieldtrip/fieldtrip/blob/release/plotting/ft_plot_layout.m)** and inspect it in detail. That is something I have done multiple times, going back and forth in the script to ensure that my interpretation of the |mnt| field matches the data.
%
figure
ft_plot_layout(layout, 'label', true)

%
% This shows four groups, with two groups of oxy channels on the left of the figure (for the left and right hemisphere), and the corresponding deoxy channels on the right of the figure. This matches with the schepatic display in figure 1 of the PDF manuscript, and with the displayed data in figure 3 of the PDF manuscript.
%
% To improve the plotting of topographies, we can also make an outline and mask. The outline comproses extra lines that are added to the figure, often we include a circle (representing the head) with a triangle at the top (representing the nose). The mask comprises a series of polygons that are used in topographic interpolation and masking the interpolated data that is outside the head, but also by masking the interpolated data that is in between the grid on the left and right hemisphere. This will become more clear at the end of this example script.
%
pad = 0.2;
section = {1:10 11:20 21:30 31:40};
for i=1:4
  sel = section{i};
  % upper left
  corner1x = min(layout.pos(sel,1)-layout.width (sel)/2) - pad;
  corner1y = max(layout.pos(sel,2)+layout.height(sel)/2) + pad;

  % upper right
  corner2x = max(layout.pos(sel,1)+layout.width (sel)/2) + pad;
  corner2y = max(layout.pos(sel,2)+layout.height(sel)/2) + pad;

  % lower right
  corner3x = max(layout.pos(sel,1)+layout.width (sel)/2) + pad;
  corner3y = min(layout.pos(sel,2)-layout.height(sel)/2) - pad;

  % lower left
  corner4x = min(layout.pos(sel,1)-layout.width (sel)/2) - pad;
  corner4y = min(layout.pos(sel,2)-layout.height(sel)/2) - pad;

  layout.outline{i} = [
    corner1x corner1y
    corner2x corner2y
    corner3x corner3y
    corner4x corner4y
    corner1x corner1y % this closes the outline
    ];

  layout.mask{i} = [
    corner1x corner1y
    corner2x corner2y
    corner3x corner3y
    corner4x corner4y
    corner1x corner1y % this closes the outline
    ];
end

figure
ft_plot_layout(layout, 'label', true, 'outline', true, 'mask', true)

%
% The layout now also shows the outline, as thick black lines. If you disable the outline, you can also see the mask as dotted lines.
%
%% # Parsing the events and segmenting the data in trials
%
% In general in FieldTrip events have to be aligned with samples. The first sample of a recording on disk is referred to as sample 1.
%
% The |mrk| field contains times
%
% >> nirs.mrk.time
% ans =
%   Columns 1 through 9
%         1950    30975    60975    91950    ...

% These numbers are larger than the total number of samples, so they do not directly map onto samples. I started off assuming that the marker time is expressed in milliseconds, but that turned out not to be correct. Therefore I experimented with the following piece of code until I had something that made sense.
%
% This timestamp to sample ratio results in the events being nicely spaced over the whole experiment
%
ratio = 75;

% Note that `1/data.fsample = 0.075`, i.e., with the 13.333 Hz sampling rate each sample happens to be 75 ms. When working with unknown data it is not uncommon to have to deal with a puzzle like this, it reminds me of [Kabbalah](https://en.wikipedia.org/wiki/Kabbalah).
%
event = [];
for i=1:nirs.nfo.nEvents
  event(i).type = 'marker';
  event(i).value = nirs.mrk.className{nirs.mrk.event.desc(i)};
  event(i).sample = round(nirs.mrk.time(i)/ratio) + 1;
  event(i).duration = nan;
  event(i).offset = nan;
end

cfg = [];
cfg.event = event; % store the events in the configuration to have them displayed
cfg.viewmode = 'vertical';
cfg.preproc.demean = 'yes';
cfg.blocksize = nirs.nfo.length; % show the data over the whole length
ft_databrowser(cfg, data_raw);

%
%% # Apply a band-pass filter on the continuous data
%
cfg = [];
cfg.bpfilter = 'yes';
cfg.bpfreq = [0.02 0.8];
cfg.bpfilford = 2;
data_filt = ft_preprocessing(cfg, data_raw);

%% # Segment the continuous data into trials
%
% To segment the data we have to create a so-called "trial definition". This would normally be done using **[ft_definetrial](https://github.com/fieldtrip/fieldtrip/blob/release/ft_definetrials.m)** and using the events that were read from the data on disk (had it been a supported file format). The trial definition specifies the begin and end sample of each trial, and the offset, i.e., how many samples the time defined as t=0 is shifted relative to the data segment. Furthermore, it can contain additional columns with trial specific information, such as condition codes.
%
% The temporal structure of each trial is
%
%* instruction for 2s
%* fixation cross, this indicates that the task has to be executed, for 10s
%* "stop" for 2s
%* fixation cross indicating rest period, for 15-17 seconds
%
% The total duration of a trial, including the instruction, ranges from 2+10+2+15=29 to 2+10+2+17=31 seconds.
%
% We will use the standard FieldTrip |event| structure to make the trials, this is also what **[ft_read_event](https://github.com/fieldtrip/fieldtrip/blob/release/fileio/ft_read_event.m)** returns for supported data formats.
%
taskonset = [event.sample];  % let's assume that the marker is at task onset
begsample = taskonset - 2*data_raw.fsample;
endsample = taskonset + (10+2+15)*data_raw.fsample;
offset = - 2*data_raw.fsample * ones(size(begsample)); % each trial has the same 2 seconds offset

% The begin sample, end sample and offset should be integers:
%
begsample = round(begsample);
endsample = round(endsample);
offset = round(offset);

% and we map the right, left, and foot condition onto condition codes 1, 2, and 3.
%
[dummy, condition] = ismember({event.value}, {'RIGHT'  'LEFT'  'FOOT'});

trl = [begsample(:) endsample(:) offset(:) condition(:)];

cfg = [];
cfg.trl = trl;
data_segmented = ft_redefinetrial(cfg, data_filt);

%% # Visualize the segmented data
%
cfg = [];
cfg.event = event;
cfg.viewmode = 'vertical';
cfg.preproc.demean = 'no'; % it is filtered by now
ft_databrowser(cfg, data_segmented);

%
%% # Average the segmented data, conditional on each condition
%
cfg = [];
cfg.trials = data_segmented.trialinfo==1;
timelockRight = ft_timelockanalysis(cfg, data_segmented);
cfg.trials = data_segmented.trialinfo==2;
timelockLeft = ft_timelockanalysis(cfg, data_segmented);
cfg.trials = data_segmented.trialinfo==3;
timelockFoot = ft_timelockanalysis(cfg, data_segmented);

%% # Plot the averaged responses
%
%
cfg = [];
cfg.layout = layout;
cfg.showoutline = 'yes';
cfg.baseline = [-2 0];
cfg.showlabels = 'yes';
cfg.interactive = 'no'; % use MATLAB for zooming in
ft_multiplotER(cfg, timelockRight, timelockLeft, timelockFoot);

%
% Although some of the more noisy channels dominate the figure due to the automatic vertical scaling, if you zoom in and pay attention to |Ch4oxy|, |Ch5oxy|, and |Ch6oxy| over the left hemisphere, and |Ch14oxy| and |Ch16oxy| over the right hemisphere, you can see that the left hemisphere shows more activity during the right fingertapping task (blue) and the right hemisphere shows more activity following the left fingertapping task (red).
%
% This [example script](/example/nirs_layout/) explains in more detail how for a NIRS dataset the oxy and deoxy channels can either be plotted on top of each other (which is spatially consistent with how the data is recorded) or side-by-side. Plotting them side-by-side makes the results easier to interpret, especially if you have multiple responses (like we have here for left, right and foot conditions). For plotting topographic distributions you also have to ensure that your 2D channel layout does not have overlapping channels that have bvery different numbers.
%
%% # Plot the topography of the averaged responses
%
% This step benefits from the layout having an outline and especially a mask, otherwise the interpolation will cause the whole image to be color coded, including the pieces in between the hemispheres and in between the oxy (on the left) and deoxy channels (on the right).
%
cfg = [];
cfg.layout = layout;
cfg.interactive = 'yes';
cfg.xlim = [7 15];
cfg.ylim = [-0.004 0.004];
figure; ft_topoplotER(cfg, timelockRight);
figure; ft_topoplotER(cfg, timelockLeft);
figure; ft_topoplotER(cfg, timelockFoot);

%
%
% From the topographic arrangements it is clear that the left hemisphere responds with an increase in HbO to the right fingertapping task and the right hemisphere to the left fingertapping task; the HbR (on the right side of the figure) shows the opposite pattern. Also interesting is that both left and right hemisphere show a decrease in HbO and an increase in HbR during the tapping of the foot.


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

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

% Last Modified by GUIDE v2.5 13-Feb-2013 04:22:47

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

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

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

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

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes FUN_PLOTTER wait for user response (see UIRESUME)
% uiwait(handles.figure1);

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

% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global z thta
cla(handles.axes1)
reset(handles.axes1)
set(handles.axes1,'box','on')
set(handles.axes1,'xtick',[])
set(handles.axes1,'ytick',[])
z = 'sin(x)';
v = get(handles.checkbox2,'value');
if v == 1
    thta = 0:3*360;
    axes(handles.axes1)
    plot(thta,sind(thta),'linewidth',3)
    set(handles.text1,'string','SINE PLOT FROM 0 TO 6*PI')
    grid on
else
    msgbox('PLZ SET RANGE...TRY AGAIN','WARNING','warn','modal')
    set(handles.text1,'string','')
    cla(handles.axes1)
    reset(handles.axes1)
    set(handles.axes1,'box','on')
    set(handles.axes1,'xtick',[])
    set(handles.axes1,'ytick',[])
    return
end

% --- Executes on button press in pushbutton2.
function pushbutton2_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global z thta
cla(handles.axes1)
reset(handles.axes1)
set(handles.axes1,'box','on')
set(handles.axes1,'xtick',[])
set(handles.axes1,'ytick',[])
z = 'cos(x)';
v = get(handles.checkbox2,'value');
if v == 1
    thta = 0:3*360;
    axes(handles.axes1)
    plot(thta,cosd(thta),'linewidth',3)
    set(handles.text1,'string','COSINE PLOT FROM 0 TO 6*PI')
    grid on
else
    msgbox('PLZ SET RANGE...TRY AGAIN','WARNING','warn','modal')
    set(handles.text1,'string','')
    cla(handles.axes1)
    reset(handles.axes1)
    set(handles.axes1,'box','on')
    set(handles.axes1,'xtick',[])
    set(handles.axes1,'ytick',[])
    return
end

% --- Executes on button press in pushbutton3.
function pushbutton3_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton3 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global z thta
cla(handles.axes1)
reset(handles.axes1)
set(handles.axes1,'box','on')
set(handles.axes1,'xtick',[])
set(handles.axes1,'ytick',[])
z = 'tan(x)';
v = get(handles.checkbox2,'value');
if v == 1
    thta = 0:3*360;
    axes(handles.axes1)
    plot(thta,tand(thta),'linewidth',3)
    set(handles.text1,'string','TANGENT PLOT FROM 0 TO 6*PI')
    grid on
else
    msgbox('PLZ SET RANGE...TRY AGAIN','WARNING','warn','modal')
    set(handles.text1,'string','')
    cla(handles.axes1)
    reset(handles.axes1)
    set(handles.axes1,'box','on')
    set(handles.axes1,'xtick',[])
    set(handles.axes1,'ytick',[])
    return
end

% --- Executes on button press in pushbutton4.
function pushbutton4_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton4 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global z thta
cla(handles.axes1)
reset(handles.axes1)
set(handles.axes1,'box','on')
set(handles.axes1,'xtick',[])
set(handles.axes1,'ytick',[])
z = 'cot(x)';
v = get(handles.checkbox2,'value');
if v == 1
    thta = 0:3*360;
    axes(handles.axes1)
    plot(thta,cotd(thta),'linewidth',3)
    set(handles.text1,'string','COTANGENT PLOT FROM 0 TO 6*PI')
    grid on
else
    msgbox('PLZ SET RANGE...TRY AGAIN','WARNING','warn','modal')
    set(handles.text1,'string','')
    cla(handles.axes1)
    reset(handles.axes1)
    set(handles.axes1,'box','on')
    set(handles.axes1,'xtick',[])
    set(handles.axes1,'ytick',[])
    return
end

% --- Executes on button press in pushbutton5.
function pushbutton5_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton5 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global z thta
cla(handles.axes1)
reset(handles.axes1)
set(handles.axes1,'box','on')
set(handles.axes1,'xtick',[])
set(handles.axes1,'ytick',[])
z = 'sec(x)';
v = get(handles.checkbox2,'value');
if v == 1
    thta = 0:3*360;
    axes(handles.axes1)
    plot(thta,secd(thta),'linewidth',3)
    set(handles.text1,'string','SECANT PLOT FROM 0 TO 6*PI')
    grid on
else
    msgbox('PLZ SET RANGE...TRY AGAIN','WARNING','warn','modal')
    set(handles.text1,'string','')
    cla(handles.axes1)
    reset(handles.axes1)
    set(handles.axes1,'box','on')
    set(handles.axes1,'xtick',[])
    set(handles.axes1,'ytick',[])
    return
end

% --- Executes on button press in pushbutton6.
function pushbutton6_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton6 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global z thta
cla(handles.axes1)
reset(handles.axes1)
set(handles.axes1,'box','on')
set(handles.axes1,'xtick',[])
set(handles.axes1,'ytick',[])
z = 'csc(x)';
v = get(handles.checkbox2,'value');
if v == 1
    thta = 0:3*360;
    axes(handles.axes1)
    plot(thta,cscd(thta),'linewidth',3)
    set(handles.text1,'string','COSECANT PLOT FROM 0 TO 6*PI')
    grid on
else
    msgbox('PLZ SET RANGE...TRY AGAIN','WARNING','warn','modal')
    set(handles.text1,'string','')
    cla(handles.axes1)
    reset(handles.axes1)
    set(handles.axes1,'box','on')
    set(handles.axes1,'xtick',[])
    set(handles.axes1,'ytick',[])
    return
end

% --- Executes on button press in pushbutton7.
function pushbutton7_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton7 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global z x
cla(handles.axes1)
reset(handles.axes1)
set(handles.axes1,'box','on')
set(handles.axes1,'xtick',[])
set(handles.axes1,'ytick',[])
z = 'log(t)';
v = get(handles.checkbox2,'value');
if v == 1
    x = 0:0.25:10;
    axes(handles.axes1)
    plot(x,log(x),'linewidth',3)
    set(handles.text1,'string','LOGRITHMIC PLOT FROM 0 TO 10')
    grid on
else
    msgbox('PLZ SET RANGE...TRY AGAIN','WARNING','warn','modal')
    set(handles.text1,'string','')
    cla(handles.axes1)
    reset(handles.axes1)
    set(handles.axes1,'box','on')
    set(handles.axes1,'xtick',[])
    set(handles.axes1,'ytick',[])
    return
end

% --- Executes on button press in pushbutton8.
function pushbutton8_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton8 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global z x
cla(handles.axes1)
reset(handles.axes1)
set(handles.axes1,'box','on')
set(handles.axes1,'xtick',[])
set(handles.axes1,'ytick',[])
z = 'exp(t)';
v = get(handles.checkbox2,'value');
if v == 1
    x = 0:0.25:10;
    axes(handles.axes1)
    plot(x,exp(x),'linewidth',3)
    set(handles.text1,'string','EXPONENTIAL PLOT FROM 0 TO 10')
    grid on
else
    msgbox('PLZ SET RANGE...TRY AGAIN','WARNING','warn','modal')
    set(handles.text1,'string','')
    cla(handles.axes1)
    reset(handles.axes1)
    set(handles.axes1,'box','on')
    set(handles.axes1,'xtick',[])
    set(handles.axes1,'ytick',[])
    return
end

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

% Hint: get(hObject,'Value') returns toggle state of checkbox2
set(handles.checkbox3,'value',0)
set(handles.edit1,'enable','inactive')
set(handles.edit2,'enable','inactive')
% --- Executes on button press in checkbox3.
function checkbox3_Callback(hObject, eventdata, handles)
% hObject    handle to checkbox3 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of checkbox3
set(handles.checkbox2,'value',0)
set(handles.edit1,'enable','on')
set(handles.edit2,'enable','on')

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

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

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

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

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

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

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

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

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

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

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

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

% --- Executes on button press in pushbutton10.
function pushbutton10_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton10 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global z p1
v = get(handles.checkbox2,'value');
if v == 1
    msgbox('CAN NOT WORK ON DEFAULT RANGE','WARNING','warn','modal')
    return
end
v1 = get(handles.checkbox3,'value');
if v1 == 0
    msgbox('FIRST SET RANGE','WARNING','warn','modal')
    return
end
a = str2double(get(handles.edit1,'string'));
b = str2double(get(handles.edit2,'string'));
if a > b
    msgbox('MIN IS GR8ER THAN MAX','WARNING','warn','modal')
    set(handles.edit1,'string','')
    set(handles.edit2,'string','')
    return
end
fx2 = get(handles.edit3,'string');
z = fx2;
if isempty(fx2) || isempty(a) || isempty(b)
    msgbox('EITHER MAX OR MIN OR FUNCTION FIELD IS EMPTY OR INVALID','WARNING...','modal')
    set(handles.edit1,'string','')
    set(handles.edit2,'string','')
    set(handles.edit3,'string','')
    return
end
fx3 = inline(fx2);
p1 = a:0.25:b;
p2 = p1;
for l = 1:length(p2)
    mag(l) = fx3(p2(l));
end
axes(handles.axes1)
plot(p2,mag,'linewidth',3)
grid on
set(handles.text1,'string',strcat('PLOT OF ',fx2,' FROM RANGE ',num2str(a),' TO ',num2str(b)))

% --- Executes on button press in pushbutton11.
function pushbutton11_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton11 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global z thta x p1
d = z;
k = z;
switch k
    case 'sin(x)'
        fx = sym(k);
        n = str2double(inputdlg('INPUT ORDER OF DIFFRENTIATION','DY/DX'));
        if isnan(n)
            return
        end
        fx1 = diff(fx,n);
        for l = 1:length(thta)
            mag(l) = subs(fx1,deg2rad(thta(l)));
        end
        axes(handles.axes1)
        hold on
        plot(thta,mag,'r','linewidth',3)
        grid on
        %legend('sin\theta','d(sin\theta)/dx')
        set(handles.text1,'string','DIFFRENTIATION OF SIN(X) AND SIN(X)')
    case 'cos(x)'
        fx = sym(k);
        n = str2double(inputdlg('INPUT ORDER OF DIFFRENTIATION','DY/DX'));
        if isnan(n)
            return
        end
        fx1 = diff(fx,n);
        for l = 1:length(thta)
            mag(l) = subs(fx1,deg2rad(thta(l)));
        end
        axes(handles.axes1)
        hold on
        plot(thta,mag,'r','linewidth',3)
        grid on
        %legend('cos\theta','d(cos\theta)/dx')
        set(handles.text1,'string','DIFFRENTIATION OF COS(X) AND COS(X)')
    case 'tan(x)'
        fx = sym(k);
        fx1 = diff(fx);
        for l = 1:length(thta)
            mag(l) = subs(fx1,deg2rad(thta(l)));
        end
        axes(handles.axes1)
        hold on
        plot(thta,mag,'r','linewidth',3)
        grid on
        %legend('tan\theta','d(tan\theta)/dx')
        set(handles.text1,'string','DIFFRENTIATION OF TAN(X) AND TAN(X)')
    case 'cot(x)'
        fx = sym(k);
        fx1 = diff(fx);
        for l = 1:length(thta)
            mag(l) = subs(fx1,deg2rad(thta(l)));
        end
        axes(handles.axes1)
        hold on
        plot(thta,mag,'r','linewidth',3)
        grid on
        %legend('cot\theta','d(cot\theta)/dx')
        set(handles.text1,'string','DIFFRENTIATION OF COT(X) AND COT(X)')
    case 'sec(x)'
        fx = sym(k);
        fx1 = diff(fx);
        for l = 1:length(thta)
            mag(l) = subs(fx1,deg2rad(thta(l)));
        end
        axes(handles.axes1)
        hold on
        plot(thta,mag,'r','linewidth',3)
        grid on
        %legend('sec\theta','d(sec\theta)/dx')
        set(handles.text1,'string','DIFFRENTIATION OF SEC(X) AND SEC(X)')
    case 'csc(x)'
        fx = sym(k);
        fx1 = diff(fx);
        for l = 1:length(thta)
            mag(l) = subs(fx1,deg2rad(thta(l)));
        end
        axes(handles.axes1)
        hold on
        plot(thta,mag,'r','linewidth',3)
        grid on
        %legend('csc\theta','d(csc\theta)/dx')
        set(handles.text1,'string','DIFFRENTIATION OF CSC(X) AND CSC(X)')
    case 'log(t)'
        fx = sym(k);
        fx1 = diff(fx);
        r = x;
        for l = 1:length(r)
            mag(l) = subs(fx1,r(l));
        end
        axes(handles.axes1)
        hold on
        plot(r,mag,'r','linewidth',3)
        grid on
        %legend('log(x)','d(log(x))/dx')
        set(handles.text1,'string','DIFFRENTIATION OF LOG(X) AND LOG(X)')
    case 'exp(t)'
        fx = sym(k);
        fx1 = diff(fx);
        r = x;
        for l = 1:length(r)
            mag(l) = subs(fx1,r(l));
        end
        axes(handles.axes1)
        hold on
        plot(r,mag,'r','linewidth',1.5)
        grid on
        %legend('e^x','d(e^x)/dx')
        set(handles.text1,'string','DIFFRENTIATION OF EXP(X) AND EXP(X)')
    case d
        fx = sym(k);
        fx1 = diff(fx);
        r = p1;
        for l = 1:length(r)
            mag(l) = subs(fx1,r(l));
        end
        axes(handles.axes1)
        hold on
        plot(r,mag,'r','linewidth',1.8)
        grid on
        %legend(d,strcat('d(',d,')/dx'))
        set(handles.text1,'string',strcat('DIFFRENTIATION OF ',d,' AND ',d))
end

% --- Executes on button press in pushbutton12.
function pushbutton12_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton12 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global z thta x p1
d = z;
k = z;
switch k
    case 'sin(x)'
        fx = sym(k);
        fx1 = int(fx);
        for l = 1:length(thta)
            mag(l) = subs(fx1,deg2rad(thta(l)));
        end
        axes(handles.axes1)
        hold on
        plot(thta,mag,'g','linewidth',3)
        grid on
        %legend('sin\theta','d(sin\theta)/dx')
        set(handles.text1,'string','INTEGRATION OF SIN(X) AND SIN(X)')
    case 'cos(x)'
        fx = sym(k);
        fx1 = int(fx);
        for l = 1:length(thta)
            mag(l) = subs(fx1,deg2rad(thta(l)));
        end
        axes(handles.axes1)
        hold on
        plot(thta,mag,'g','linewidth',3)
        grid on
        %legend('cos\theta','d(cos\theta)/dx')
        set(handles.text1,'string','INTEGRATION OF COS(X) AND COS(X)')
    case 'tan(x)'
        fx = sym(k);
        fx1 = int(fx);
        for l = 1:length(thta)
            mag(l) = subs(fx1,deg2rad(thta(l)));
        end
        axes(handles.axes1)
        hold on
        plot(thta,mag,'g','linewidth',3)
        grid on
        %legend('tan\theta','d(tan\theta)/dx')
        set(handles.text1,'string','INTEGRATION OF TAN(X) AND TAN(X)')
    case 'cot(x)'
        fx = sym(k);
        fx1 = int(fx);
        for l = 1:length(thta)
            mag(l) = subs(fx1,deg2rad(thta(l)));
        end
        axes(handles.axes1)
        hold on
        plot(thta,mag,'g','linewidth',3)
        grid on
        %legend('cot\theta','d(cot\theta)/dx')
        set(handles.text1,'string','INTEGRATION OF COT(X) AND COT(X)')
    case 'sec(x)'
        fx = sym(k);
        fx1 = int(fx);
        for l = 1:length(thta)
            mag(l) = subs(fx1,deg2rad(thta(l)));
        end
        axes(handles.axes1)
        hold on
        plot(thta,mag,'g','linewidth',3)
        grid on
        %legend('sec\theta','d(sec\theta)/dx')
        set(handles.text1,'string','INTEGRATION OF SEC(X) AND SEC(X)')
    case 'csc(x)'
        fx = sym(k);
        fx1 = int(fx);
        for l = 1:length(thta)
            mag(l) = subs(fx1,deg2rad(thta(l)));
        end
        axes(handles.axes1)
        hold on
        plot(thta,mag,'g','linewidth',3)
        grid on
        %legend('csc\theta','d(csc\theta)/dx')
        set(handles.text1,'string','INTEGRATION OF CSC(X) AND CSC(X)')
    case 'log(t)'
        fx = sym(k);
        fx1 = int(fx);
        r = x;
        for l = 1:length(r)
            mag(l) = subs(fx1,r(l));
        end
        axes(handles.axes1)
        hold on
        plot(r,mag,'g','linewidth',3)
        grid on
        %legend('log(x)','d(log(x))/dx')
        set(handles.text1,'string','INTEGRATION OF LOG(X) AND LOG(X)')
    case 'exp(t)'
        fx = sym(k);
        fx1 = int(fx);
        r = x;
        for l = 1:length(r)
            mag(l) = subs(fx1,r(l));
        end
        axes(handles.axes1)
        hold on
        plot(r,mag,'g','linewidth',1.5)
        grid on
        %legend('e^x','d(e^x)/dx')
        set(handles.text1,'string','INTEGRATION OF EXP(X) AND EXP(X)')

     case d
        fx = sym(k);
        fx1 = int(fx);
        r = p1;
        for l = 1:length(r)
            mag(l) = subs(fx1,r(l));
        end
        axes(handles.axes1)
        hold on
        plot(r,mag,'g','linewidth',2.3)
        grid on
        %legend(d,strcat('d(',d,')/dx'))
        set(handles.text1,'string',strcat('INTEGRATION OF ',d,' AND ',d))
end

% --------------------------------------------------------------------
function CL_EAR_Callback(hObject, eventdata, handles)
% hObject    handle to CL_EAR (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
cla(handles.axes1)
reset(handles.axes1)
set(handles.axes1,'box','on')
set(handles.axes1,'xtick',[])
set(handles.axes1,'ytick',[])
set(handles.edit1,'string','')
set(handles.edit2,'string','')
set(handles.edit3,'string','')
set(handles.checkbox2,'value',0)
set(handles.checkbox3,'value',0)

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

% --------------------------------------------------------------------
function CLEAR_AXES_Callback(hObject, eventdata, handles)
% hObject    handle to CLEAR_AXES (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
cla(handles.axes1)
reset(handles.axes1)
set(handles.axes1,'box','on')
set(handles.axes1,'xtick',[])
set(handles.axes1,'ytick',[])


function s = n2str(n)
% num2str with exact zero

s = num2str(setNull(n));


function [minr, maxr, minc, maxc, slcV, modelMask3M, planC] = ...
    getCropLimits(planC,mask3M,scanNum,cropS)
% getCropLimits.m
% Get limits of bounding box for various cropping options.
%
% AI 5/2/19
%--------------------------------------------------------------------------
%INPUTS:
% planC
% scan3M       : Scan array
% mask3M       : Mask
% cropS        : Dictionary of parameters for cropping
%                Supported methods: 'crop_fixed_amt','crop_to_bounding_box',
%                'crop_to_str', 'crop_around_center', 'none'
%--------------------------------------------------------------------------
% AI 5/2/19
% AI 7/23/19

%Get mask for model config
[modelMask3M, planC] = getMaskForModelConfig(planC,mask3M,scanNum,cropS);

%Compute bounding box
methodC = lower({cropS.method});
crop2DMethodsC = {'crop_to_bounding_box_2d','crop_to_str_2d',...
    'crop_pt_outline_2d'};%Suported 2D crop options
if length(methodC) == 1 && strcmp(methodC{1},'none')
    scanSizeV = size(getScanArray(scanNum,planC));
    minr = 1;
    maxr = scanSizeV(1);
    minc = 1;
    maxc = scanSizeV(2);
    slcV = 1:scanSizeV(3);

elseif any(ismember(methodC,crop2DMethodsC))

    slcV = find(sum(sum(modelMask3M))>0);
    numSlcs = length(slcV);
    minr = nan(numSlcs,1);
    minc = nan(numSlcs,1);
    maxr = nan(numSlcs,1);
    maxc = nan(numSlcs,1);
    for n = 1:numSlcs
        [minr(n), maxr(n), minc(n), maxc(n)] = compute_boundingbox(modelMask3M(:,:,slcV(n)));
    end
else
    [minr, maxr, minc, maxc] = compute_boundingbox(modelMask3M);
    slcV = find(sum(sum(modelMask3M))>0);
end

end


function [obs,nobs,obss]=searchobsr(obss)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%search rover observations
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
global gls

if obss.idx>=obss.n
    obs=NaN;nobs=-1;return
end

obss.idx=obss.idx+1;
obs_tmp=obss.data(obss.idx,:);

time0=obss.data(:,1)+obss.data(:,2);
time1=obs_tmp(1)+obs_tmp(2);
idx=time0==time1;  pos=find(time0==time1);
if any(idx)
    obs0=obss.data(idx,:);  nobs=size(obs0,1); obss.idx=pos(end);
else
    nobs=0;obs=NaN;return;
end

obs=repmat(gls.obs_tmp,nobs,1);
for i=1:nobs
    obs(i).time.time=obs0(i,1);
    obs(i).time.sec=obs0(i,2);
    obs(i).sat=obs0(i,3);
    obs(i).P=obs0(i,4:6);
    obs(i).L=obs0(i,7:9);
    obs(i).D=obs0(i,10:12);
    obs(i).S=obs0(i,13:15);
    obs(i).LLI=obs0(i,16:18);
    obs(i).code=obs0(i,19:21);
end

return


function [epoch_std, year] = mydatestd (epoch)
    temp = mydatevec(epoch);
    year = temp(:,1);
    [year_len, year_start] = mydatestd_aux(year);

    std_year_len = mydatestd_aux();

    epoch_std = (epoch - year_start) ./ year_len .* std_year_len;
end

%!test
%! % mydatestd()
%! test('mydatestd_aux')


function T_plotting = CalculatePlottingMatrix(T_new,x_intervals,y_intervals)

a = 1;

for x_index = 2:1:(x_intervals-1)
    b = 1;
    for y_index = 2:1:(y_intervals-1)
         T_plotting(a,b) = T_new(x_index,y_index);
         b = b+1;
    end

    a = a+1;
end

end


function [flowftrs,hogftrs,info] = genFeatures(varargin)

%%

wsize = 5;
psize = 40;
nbins = 8;
halfpsize = round(psize*10/2);
hsz = round( (wsize - 1)/2);
debug = false;

% * Video: either readframeFcns or vidfile should be specified.
% * Interest pts: If interest points are desired, specify either ips or
% trxfile. If interest points are not desired (side only), leave both ips
% and trxfile empty.
[ts,readframeFcns,vidfile,trxfile,ips,face,framechunksize,frontside,...
  dopatchprint] = myparse(varargin,...
  'ts',[],...
  'readframeFcns',[],...
  'vidfile','',...
  'trxfile','',...
  'ips',[],...
  'face','',...
  'framechunksize',[],...
  'frontside',false,...
  'dopatchprint',true);

if isempty(framechunksize),

  framechunksize = 100;

end

if isempty(face)
  error('Face direction of the mice is not specified');
end

if strcmpi(face,'left')
  do_fliplr = true;
else
  do_fliplr = false;
end

if isempty(readframeFcns) && isempty(vidfile)
  error('Both arguments are empty');
end

tfvidfile = false;
if isempty(readframeFcns)
  if frontside
    assert(isstruct(vidfile) && all(isfield(vidfile,{'front' 'side'})),...
      'vidfile must be a struct with fields .front, .side.');
    [readFrameFcns.front.readframe,readFrameFcns.front.nframes,readFrameFcns.front.fid,readFrameFcns.front.headerinfo] = get_readframe_fcn(vidfile.front);
    [readFrameFcns.side.readframe,readFrameFcns.side.nframes,readFrameFcns.side.fid,readFrameFcns.side.headerinfo] = get_readframe_fcn(vidfile.side);
  else
    [readFrameFcns.side.readframe,readFrameFcns.side.nframes,readFrameFcns.side.fid,readFrameFcns.side.headerinfo] = get_readframe_fcn(vidfile);
  end
  tfvidfile = true;
else
  if ~frontside
    readFrameFcns.side = readframeFcns;
  end
end

% offside = 0;
% offfront = 0;
if frontside
  if readFrameFcns.front.nframes~=readFrameFcns.side.nframes
    warning('genFeatures:nframe',...
      'Number of frames in front video (%d) and side video (%d) do not match. Using minimum.',...
      readFrameFcns.front.nframes,readFrameFcns.side.nframes);
  end
  nframes = min(readFrameFcns.front.nframes,readFrameFcns.side.nframes);
  % turns out we should cut from the end
  %offfront = readFrameFcns.front.nframes-nframes;
  %offside = readFrameFcns.side.nframes-nframes;
else
  nframes = readFrameFcns.side.nframes;
end

if isempty(ts)
  ts = 1:nframes;
  if any(diff(ts)~=1),
    error('ts must be starframe:endframe');
  end
end

if ~isempty(ips) && ~isempty(trxfile)
  error('Both ips and trxfile specified.');
elseif ~isempty(ips) && isempty(trxfile)
  if frontside
    assert(all(isfield(ips,{'front' 'side'})),'Expected fields missing from ips.');
  elseif ~isstruct(ips)
    ips = struct('side',ips);
  end
elseif isempty(ips) && ~isempty(trxfile)
  T = load(trxfile);
  ips.side(1,:) = T.trx(1).arena.food;
  ips.side(2,:) = T.trx(1).arena.mouth;
  ips.side(3,:) = T.trx(1).arena.perch;
  ips.side = round(ips.side);
  if frontside
    ips.front(1,:) = T.trx(1).arena.foodfront;
    ips.front(2,:) = T.trx(1).arena.mouthfront;
    ips.front = round(ips.front);
  end
  assert(strcmp(face,T.trx(1).arena.face),'Specified ''face'' does not match ''face'' in specified trxfile');
else
  % isempty(ips) && isempty(trxfile)
  % no-op; handled below
end

if do_fliplr
  imw = readframeFcns.side.headerinfo.Width;
  ips.side(:,1) = imw - ips.side(:,1);
  if frontside
    imw = readframeFcns.front.headerinfo.Width;
    ips.front(:,1) = imw - ips.front(:,1);
  end
end

if isempty(ips),
  assert(~frontside,'Frontside currently requires interest point specification');
  patchsz = [headerinfo.Height,headerinfo.Width];
else
  Npatch = size(ips.side,1);
  if frontside
    Npatch = Npatch + size(ips.front,1);
  end
  patchsz1 = halfpsize*2+1;
  patchsz = [patchsz1,patchsz1*Npatch];
end

% initialize
flowftrs = [];
hogftrs = [];

% buffer of the past wsize frames
Fall = {};
Hall = {};
buffert0 = -1;
buffert1 = -2;
first = true;
% Fallslow = {};
% Hallslow = {};

% previous and current patch
patchPrev = zeros(patchsz,'single');
patchCurr = zeros(patchsz,'single');

% which frames to read
ts2readstart = max(ts(1)-hsz,1);
ts2readend = min(ts(end)+hsz,nframes);

s = warning('error','MATLAB:audiovideo:VideoReader:incompleteRead');

% initialize buffer

if dopatchprint && tfvidfile && ~isdeployed && numel(ts) >= 2+hsz,
  randomframe = randsample(ts(2+hsz:end),1);
else
  randomframe = nan;
end

tic;
for ndx = 1:numel(ts),

  t = ts(ndx);

  % window considered during this frame
  wstart = max(1,t-hsz);
  wend = min(nframes,t+hsz);
  curn = wend - wstart +1;

  % reuse the previously computed features.
  if numel(Hall)>=curn,
    Fall(1:end-1) = Fall(2:end);
    Hall(1:end-1) = Hall(2:end);
    buffert0 = buffert0+1;
  end

  % initialize HOG, HOF buffer
  if first,

    for wndx = 1:curn,

      patchPrev = patchCurr;
      patchCurr = lclGrabPatch(readFrameFcns,wstart+wndx-1,do_fliplr,tfvidfile,frontside,ips,halfpsize,patchCurr);

      % HOG
      % step size is two for gradient computation
      % approx equiv Matlab code, ignoring borders
      % gx = patchCurr(2:end-1,3:end)-patchCurr(2:end-1,1:end-2);
      % gy = patchCurr(3:end,2:end-1)-patchCurr(1:end-2,2:end-1);
      % M = sqrt(gx.^2+gy.^2)/2;
      % O = modrange(atan2(gy,gx),0,pi);
      % will match M(2:end-1,2:end-1) and O(2:end-1,2:end-1)
      [M,O] = gradientMag(patchCurr/255);
      H=gradientHist(M,O,psize,nbins,1);
      Hall{wndx} = H;

      if wndx > 1,

        % HOF
        [Vx,Vy,~] = optFlowLk(patchPrev,patchCurr,[],3);
        M = sqrt(Vx.^2 + Vy.^2);
        O = mod(atan2(Vy,Vx)/2,pi);
        O = min(O,pi-1e-6);
        H = gradientHist(single(M),single(O),psize,nbins,1);
        Fall{wndx-1} = H;

      end

    end
    buffert0 = wstart;
    buffert1 = wend;

  else

    % add to the buffer
    if buffert1 < wend,

      patchPrev = patchCurr;
      patchCurr = lclGrabPatch(readFrameFcns,wend,do_fliplr,tfvidfile,frontside,ips,halfpsize,patchCurr);

      % HOG feature for frame wend
      [M,O] = gradientMag(patchCurr/255);
      H=gradientHist(M,O,psize,nbins,1);
      Hall{curn} = H; %#ok<AGROW>

      [Vx,Vy,~] = optFlowLk(patchPrev,patchCurr,[],3);
      % Gradient hist requires orientation to be between 0 and pi. Makes sense for
      % image gradients. But for flow pi/2 is different than -pi/2. So adjust for
      % that.

      M = sqrt(Vx.^2 + Vy.^2);
      O = mod(atan2(Vy,Vx)/2,pi);
      O = min(O,pi-1e-6);
      H = gradientHist(single(M),single(O),psize,nbins,1);
      Fall{curn-1} = H; %#ok<AGROW>
      buffert1 = buffert1 + 1;
    end

  end

  curFall = Fall{1};
  curHall = Hall{1};
  for ii = 2:curn-1
    curFall = curFall + Fall{ii};
    curHall = curHall + Hall{ii};
  end
  curHall = curHall + Hall{curn};

  curFall = curFall/(curn-1);
  curHall = curHall/curn;

  if first,
    flowftrs = zeros([size(curFall),numel(ts)],'single');
    hogftrs = zeros([size(curFall),numel(ts)],'single');
  end

  flowftrs(:,:,:,ndx) = curFall;
  hogftrs(:,:,:,ndx) = curHall;

  if mod(ndx,10)==0,
    fprintf('Processed frame %d / %d\n',ndx,numel(ts));
  end
  first = false;

  if buffert1 == randomframe,
    hFig = figure;
    imshow(patchCurr,[0 256]);
    fname = sprintf('patch_%d.jpg',randomframe);
    if ischar(vidfile)
      pth = fileparts(vidfile);
    else
      pth = fileparts(vidfile.side);
    end
    fname = fullfile(pth,fname);
    print(hFig,'-djpeg',fname);
    delete(hFig);
  end

end
warning(s);

fprintf('\n');
fprintf('Generating features for %d frames took %f seconds.\n',numel(ts),toc);

info = struct();
info.nframes = nframes;

function imMat = lclReadFrame(rff,i0,i1,do_fliplr,tfvidfile)
try
  tt = rff.readframe([i0 i1]);
catch ME,
  if strcmp(ME.identifier,'MATLAB:audiovideo:VideoReader:incompleteRead')
    fprintf('Reading Frames individually\n');
    tt = [];
    for ndx = i0:i1
      tt(:,:,:,end+1) = rff.readframe(ndx); %#ok<AGROW>
    end
  else
    rethrow(ME);
  end
end

iscolor = size(tt,3) > 1;

nfrm = i1-i0+1;
imMat = zeros(rff.headerinfo.Height,rff.headerinfo.Width,nfrm,'single');

for ndx = 1:nfrm,
  if iscolor,
    ttgraycurr = rgb2gray(tt(:,:,:,ndx));
  else
    ttgraycurr = tt(:,:,:,ndx);
  end
  if do_fliplr,
    qq = fliplr(ttgraycurr);
  else
    qq = ttgraycurr;
  end
  imMat(:,:,ndx) = single(qq);
end

if tfvidfile && rff.fid>0
  fclose(rff.fid);
end

function patchMat = lclGrabPatch(readFrameFcns,f,do_fliplr,tfvidfile,frontside,ips,halfpsize,patchMat)

imMat.side = lclReadFrame(readFrameFcns.side,f,f,do_fliplr,tfvidfile);
if frontside
  imMat.front = lclReadFrame(readFrameFcns.front,f,f,do_fliplr,tfvidfile);
end

patchsz1 = size(patchMat,1);
if ~isempty(ips)
  Nipsside = size(ips.side,1);
  for pndx = 1:Nipsside
    pp = padgrab(imMat.side,0,...
      ips.side(pndx,2)-halfpsize,ips.side(pndx,2)+halfpsize,...
      ips.side(pndx,1)-halfpsize,ips.side(pndx,1)+halfpsize,...
      1,size(imMat.side,3));
    patchMat(:,(pndx-1)*patchsz1+1:pndx*patchsz1) = pp;
  end
  if frontside
    for pndx = 1:size(ips.front,1)
      pp = padgrab(imMat.front,0,...
        ips.front(pndx,2)-halfpsize,ips.front(pndx,2)+halfpsize,...
        ips.front(pndx,1)-halfpsize,ips.front(pndx,1)+halfpsize,...
        1,size(imMat.front,3));
      patchMat(:,(pndx-1+Nipsside)*patchsz1+1:(pndx+Nipsside)*patchsz1) = pp;
    end
  end
else
  assert(~frontside);
  patchMat = imMat.side;
end


function checkSpatialFT(MRSIStruct)
    if(~getFlags(MRSIStruct, 'spatialFT'))
        error('Please fourier transform along the spatial dimension')
    end
end


function obj = updateImage(obj, imageIndex)

% HEATMAPS
% z: ...[DONE]
% x: ...[DONE]
% y: ...[DONE]
% name: ...[DONE]
% zauto: ...[DONE]
% zmin: ...[DONE]
% zmax: ...[DONE]
% colorscale: ...[DONE]
% reversescale: ...[DONE]
% showscale: ...[DONE]
% colorbar: ...[HANDLED BY COLORBAR]
% zsmooth: ...[NOT SUPPORTED BY MATLAB]
% opacity: ---[TODO]
% xaxis: ...[DONE]
% yaxis: ...[DONE]
% showlegend: ...[DONE]
% stream: ...[HANDLED BY PLOTLYSTREAM]
% visible: ...[DONE]
% x0: ...[NOT SUPPORTED IN MATLAB]
% dx: ...[NOT SUPPORTED IN MATLAB]
% y0: ...[NOT SUPPORTED IN MATLAB]
% dy: ...[NOT SUPPORTED IN MATLAB]
% xtype: ...[NOT SUPPORTED IN MATLAB]
% ytype: ...[NOT SUPPORTED IN MATLAB]
% type: ...[DONE]

%-FIGURE STRUCTURE-%
figure_data = get(obj.State.Figure.Handle);

%-AXIS STRUCTURE-%
axis_data = get(obj.State.Plot(imageIndex).AssociatedAxis);

%-AXIS INDEX-%
axIndex = obj.getAxisIndex(obj.State.Plot(imageIndex).AssociatedAxis);

%-CHECK FOR MULTIPLE AXES-%
[xsource, ysource] = findSourceAxis(obj,axIndex);

%-IMAGE DATA STRUCTURE- %
image_data = get(obj.State.Plot(imageIndex).Handle);

%-AXIS DATA-%
eval(['xaxis = obj.layout.xaxis' num2str(xsource) ';']);
eval(['yaxis = obj.layout.yaxis' num2str(ysource) ';']);

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

%-image xaxis-%
obj.data{imageIndex}.xaxis = ['x' num2str(xsource)];

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

%-image yaxis-%
obj.data{imageIndex}.yaxis = ['y' num2str(ysource)];

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

%-image type-%
obj.data{imageIndex}.type = 'heatmap';

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

%-image x-%
if (size(image_data.XData,2) == 2)
    obj.data{imageIndex}.x = image_data.XData(1):image_data.XData(2);
else
    obj.data{imageIndex}.x = image_data.XData;
end

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

%-image y-%
if (size(image_data.YData,2) == 2)
    obj.data{imageIndex}.y = image_data.YData(1):image_data.YData(2);
else
    obj.data{imageIndex}.y = image_data.YData;
end

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

%-image z-%
if(size(image_data.CData,3) > 1)
    % TODO: ALLOW FOR TRUE COLOUR SPECS.
    obj.data{imageIndex}.z = image_data.CData(:,:,1);
else
    obj.data{imageIndex}.z = image_data.CData;
end

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

%-image name-%
obj.data{imageIndex}.name = image_data.DisplayName;

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

%-image visible-%
obj.data{imageIndex}.visible = strcmp(image_data.Visible,'on');

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

%-image showscale-%
obj.data{imageIndex}.showscale = false;

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

%-image zauto-%
obj.data{imageIndex}.zauto = false;

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

%-image zmin-%
obj.data{imageIndex}.zmin = axis_data.CLim(1);

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

%-image zmax-%
obj.data{imageIndex}.zmax = axis_data.CLim(2);

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

%-COLORSCALE (ASSUMES IMAGE CDATAMAP IS 'SCALED')-%

%-image colorscale-%
colormap = figure_data.Colormap;

for c = 1:length(colormap)
    col =  255*(colormap(c,:));
    obj.data{imageIndex}.colorscale{c} = {(c-1)/length(colormap), ['rgb(' num2str(col(1)) ',' num2str(col(2)) ',' num2str(col(3)) ')']};
end

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

%-image showlegend-%
leg = get(image_data.Annotation);
legInfo = get(leg.LegendInformation);

switch legInfo.IconDisplayStyle
    case 'on'
        showleg = true;
    case 'off'
        showleg = false;
end

obj.data{imageIndex}.showlegend = showleg;

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

end


function W = Unfold(W, dim, i)
    W = reshape(shiftdim(W,i-1), dim(i), []);
end


% Find the number of frames in a tiff file
%
% This function reports number of frames in a tiff file by
% jumping over seekInterval frames until the end of the file.
% This is in general faster than Matlab's imfinfo function.
%
%  USAGE
%   n = nFrames(tiff, seekInterval)
%   tiff            Path to tiff file or a handler of an already opened file.
%   seekInterval    Optional number of frames to jump over.
%                   Default is 1000.
%   n               Number of frames
%
function n = nFrames(tiff, seekInterval)
    if nargin < 2
        seekInterval = 1000;
    end
    %keep guessing until we seek too far
    guess = seekInterval;
    overSeeked = false;
    n = 0;

    if ischar(tiff) || isstring(tiff)
        tiff = Tiff(tiff, 'r');
        closeTiff = onCleanup(@() close(tiff));
    end

    while ~overSeeked
      try
        tiff.setDirectory(guess);
        guess = 2*guess; %double the guess
      catch ex
        overSeeked = true; %we tried to seek past the last directory
      end
    end
    %when overseeking occurs, the current directory/frame will be the last one
    n = tiff.currentDirectory;
end


%  logistic 1st-order logistic function
%
%  ::
%
%
%  Args:
%
%  Returns:
%     :
%
%  Note:
%
%  Example:
%
%     See also:
%