function [net, info] = cnn_train(net, imdb, getBatch, varargin)
%CNN_TRAIN  An example implementation of SGD for training CNNs
%    CNN_TRAIN() is an example learner implementing stochastic
%    gradient descent with momentum to train a CNN. It can be used
%    with different datasets and tasks by providing a suitable
%    getBatch function.
%
%    The function automatically restarts after each training epoch by
%    checkpointing.
%
%    The function supports training on CPU or on one or more GPUs
%    (specify the list of GPU IDs in the `gpus` option). Multi-GPU
%    support is relatively primitive but sufficient to obtain a
%    noticable speedup.

% Copyright (C) 2014-15 Andrea Vedaldi.
% All rights reserved.
%
% This file is part of the VLFeat library and is made available under
% the terms of the BSD license (see the COPYING file).

opts.expDir = fullfile('data','exp') ;
opts.continue = true ;
opts.batchSize = 256 ;
opts.numSubBatches = 1 ;
opts.train = [] ;
opts.val = [] ;
opts.gpus = [] ;
opts.prefetch = false ;
opts.numEpochs = 300 ;
opts.learningRate = 0.001 ;
opts.weightDecay = 0.0005 ;
opts.momentum = 0.9 ;
opts.memoryMapFile = fullfile(tempdir, 'matconvnet.bin') ;
opts.profile = false ;

opts.conserveMemory = true ;
opts.backPropDepth = +inf ;
opts.sync = false ;
opts.cudnn = true ;
opts.errorFunction = 'multiclass' ;
opts.errorLabels = {} ;
opts.plotDiagnostics = false ;
opts.plotStatistics = true;
opts = vl_argparse(opts, varargin) ;

if ~exist(opts.expDir, 'dir'), mkdir(opts.expDir) ; end
if isempty(opts.train), opts.train = find(imdb.images.set==1) ; end
if isempty(opts.val), opts.val = find(imdb.images.set==2) ; end
if isnan(opts.train), opts.train = [] ; end
if isnan(opts.val), opts.val = [] ; end

% -------------------------------------------------------------------------
%                                                    Network initialization
% -------------------------------------------------------------------------

net = vl_simplenn_tidy(net); % fill in some eventually missing values
net.layers{end-1}.precious = 1; % do not remove predictions, used for error
vl_simplenn_display(net, 'batchSize', opts.batchSize) ;

evaluateMode = isempty(opts.train) ;

if ~evaluateMode
  for i=1:numel(net.layers)
    if isfield(net.layers{i}, 'weights')
      J = numel(net.layers{i}.weights) ;
      for j=1:J
        net.layers{i}.momentum{j} = zeros(size(net.layers{i}.weights{j}), 'single') ;
      end
      if ~isfield(net.layers{i}, 'learningRate')
        net.layers{i}.learningRate = ones(1, J, 'single') ;
      end
      if ~isfield(net.layers{i}, 'weightDecay')
        net.layers{i}.weightDecay = ones(1, J, 'single') ;
      end
    end
  end
end

% setup GPUs
numGpus = numel(opts.gpus) ;
if numGpus > 1
  if isempty(gcp('nocreate')),
    parpool('local',numGpus) ;
    spmd, gpuDevice(opts.gpus(labindex)), end
  end
elseif numGpus == 1
  gpuDevice(opts.gpus)
end
if exist(opts.memoryMapFile), delete(opts.memoryMapFile) ; end

% setup error calculation function
hasError = true ;
if isstr(opts.errorFunction)
  switch opts.errorFunction
    case 'none'
      opts.errorFunction = @error_none ;
      hasError = false ;
    case 'multiclass'
      opts.errorFunction = @error_multiclass ;
      if isempty(opts.errorLabels), opts.errorLabels = {'top1err', 'top5err'} ; end
    case 'binary'
      opts.errorFunction = @error_binary ;
      if isempty(opts.errorLabels), opts.errorLabels = {'binerr'} ; end
    otherwise
      error('Unknown error function ''%s''.', opts.errorFunction) ;
  end
end

% -------------------------------------------------------------------------
%                                                        Train and validate
% -------------------------------------------------------------------------

modelPath = @(ep) fullfile(opts.expDir, sprintf('net-epoch-%d.mat', ep));
modelFigPath = fullfile(opts.expDir, 'net-train.pdf') ;

start = opts.continue * findLastCheckpoint(opts.expDir) ;
if start >= 1
  fprintf('%s: resuming by loading epoch %d\n', mfilename, start) ;
  load(modelPath(start), 'net', 'info') ;
  net = vl_simplenn_tidy(net) ; % just in case MatConvNet was updated
end

for epoch=start+1:opts.numEpochs

  % train one epoch and validate
  learningRate = opts.learningRate(min(epoch, numel(opts.learningRate))) ;
  train = opts.train(randperm(numel(opts.train))) ; % shuffle
  val = opts.val ;

  if numGpus <= 1
    [net,stats.train,prof] = process_epoch(opts, getBatch, epoch, train, learningRate, imdb, net) ;
    [~,stats.val] = process_epoch(opts, getBatch, epoch, val, 0, imdb, net) ;
    if opts.profile
      profile('viewer') ;
      keyboard ;
    end
  else
    fprintf('%s: sending model to %d GPUs\n', mfilename, numGpus) ;
    spmd(numGpus)
      [net_, stats_train_,prof_] = process_epoch(opts, getBatch, epoch, train, learningRate, imdb, net) ;
      [~, stats_val_] = process_epoch(opts, getBatch, epoch, val, 0, imdb, net_) ;
    end
    net = net_{1} ;
    stats.train = sum([stats_train_{:}],2) ;
    stats.val = sum([stats_val_{:}],2) ;
    if opts.profile
      mpiprofile('viewer', [prof_{:,1}]) ;
      keyboard ;
    end
    clear net_ stats_train_ stats_val_ ;
  end

  % save
  if evaluateMode, sets = {'val'} ; else sets = {'train', 'val'} ; end
  for f = sets
    f = char(f) ;
    n = numel(eval(f)) ;
    info.(f).speed(epoch) = n / stats.(f)(1) * max(1, numGpus) ;
    info.(f).objective(epoch) = stats.(f)(2) / n ;
    info.(f).error(:,epoch) = stats.(f)(3:end) / n ;
  end
  if ~evaluateMode
    fprintf('%s: saving model for epoch %d\n', mfilename, epoch) ;
    tic ;
    save(modelPath(epoch), 'net', 'info') ;
    fprintf('%s: model saved in %.2g s\n', mfilename, toc) ;
  end

  if opts.plotStatistics
    switchfigure(1) ; clf ;
    subplot(1,1+hasError,1) ;
    if ~evaluateMode
      semilogy(1:epoch, info.train.objective, '.-', 'linewidth', 2) ;
      hold on ;
    end
    semilogy(1:epoch, info.val.objective, '.--') ;
    xlabel('training epoch') ; ylabel('energy') ;
    grid on ;
    h=legend(sets) ;
    set(h,'color','none');
    title('objective') ;
    if hasError
      subplot(1,2,2) ; leg = {} ;
      if ~evaluateMode
        plot(1:epoch, info.train.error', '.-', 'linewidth', 2) ;
        hold on ;
        leg = horzcat(leg, strcat('train ', opts.errorLabels)) ;
      end
      plot(1:epoch, info.val.error', '.--') ;
      leg = horzcat(leg, strcat('val ', opts.errorLabels)) ;
      set(legend(leg{:}),'color','none') ;
      grid on ;
      xlabel('training epoch') ; ylabel('error') ;
      title('error') ;
    end
    drawnow ;
    print(1, modelFigPath, '-dpdf') ;
  end
end

% -------------------------------------------------------------------------
function err = error_multiclass(opts, labels, res)
% -------------------------------------------------------------------------
predictions = gather(res(end-1).x) ;
[~,predictions] = sort(predictions, 3, 'descend') ;

% be resilient to badly formatted labels
if numel(labels) == size(predictions, 4)
  labels = reshape(labels,1,1,1,[]) ;
end

% skip null labels
mass = single(labels(:,:,1,:) > 0) ;
if size(labels,3) == 2
  % if there is a second channel in labels, used it as weights
  mass = mass .* labels(:,:,2,:) ;
  labels(:,:,2,:) = [] ;
end

m = min(5, size(predictions,3)) ;

error = ~bsxfun(@eq, predictions, labels) ;
err(1,1) = sum(sum(sum(mass .* error(:,:,1,:)))) ;
err(2,1) = sum(sum(sum(mass .* min(error(:,:,1:m,:),[],3)))) ;

% -------------------------------------------------------------------------
function err = error_binary(opts, labels, res)
% -------------------------------------------------------------------------
predictions = gather(res(end-1).x) ;
error = bsxfun(@times, predictions, labels) < 0 ;
err = sum(error(:)) ;

% -------------------------------------------------------------------------
function err = error_none(opts, labels, res)
% -------------------------------------------------------------------------
err = zeros(0,1) ;

% -------------------------------------------------------------------------
function  [net_cpu,stats,prof] = process_epoch(opts, getBatch, epoch, subset, learningRate, imdb, net_cpu)
% -------------------------------------------------------------------------

% move the CNN to GPU (if needed)
numGpus = numel(opts.gpus) ;
if numGpus >= 1
  net = vl_simplenn_move(net_cpu, 'gpu') ;
  one = gpuArray(single(1)) ;
else
  net = net_cpu ;
  net_cpu = [] ;
  one = single(1) ;
end

% assume validation mode if the learning rate is zero
training = learningRate > 0 ;
if training
  mode = 'train' ;
  evalMode = 'normal' ;
else
  mode = 'val' ;
  evalMode = 'test' ;
end

% turn on the profiler (if needed)
if opts.profile
  if numGpus <= 1
    prof = profile('info') ;
    profile clear ;
    profile on ;
  else
    prof = mpiprofile('info') ;
    mpiprofile reset ;
    mpiprofile on ;
  end
end

res = [] ;
mmap = [] ;
stats = [] ;
start = tic ;

for t=1:opts.batchSize:numel(subset)
  fprintf('%s: epoch %02d: %3d/%3d: ', mode, epoch, ...
          fix(t/opts.batchSize)+1, ceil(numel(subset)/opts.batchSize)) ;
  batchSize = min(opts.batchSize, numel(subset) - t + 1) ;
  numDone = 0 ;
  error = [] ;
  for s=1:opts.numSubBatches
    % get this image batch and prefetch the next
    batchStart = t + (labindex-1) + (s-1) * numlabs ;
    batchEnd = min(t+opts.batchSize-1, numel(subset)) ;
    batch = subset(batchStart : opts.numSubBatches * numlabs : batchEnd) ;
    [im, labels] = getBatch(imdb, batch) ;

    if opts.prefetch
      if s==opts.numSubBatches
        batchStart = t + (labindex-1) + opts.batchSize ;
        batchEnd = min(t+2*opts.batchSize-1, numel(subset)) ;
      else
        batchStart = batchStart + numlabs ;
      end
      nextBatch = subset(batchStart : opts.numSubBatches * numlabs : batchEnd) ;
      getBatch(imdb, nextBatch) ;
    end

    if numGpus >= 1
      im = gpuArray(im) ;
    end

    % evaluate the CNN
    net.layers{end}.class = labels ;
    if training, dzdy = one; else, dzdy = [] ; end
    res = vl_simplenn(net, im, dzdy, res, ...
                      'accumulate', s ~= 1, ...
                      'mode', evalMode, ...
                      'conserveMemory', opts.conserveMemory, ...
                      'backPropDepth', opts.backPropDepth, ...
                      'sync', opts.sync, ...
                      'cudnn', opts.cudnn) ;

    % accumulate training errors
    error = sum([error, [...
      sum(double(gather(res(end).x))) ;
      reshape(opts.errorFunction(opts, labels, res),[],1) ; ]],2) ;
    numDone = numDone + numel(batch) ;
  end % next sub-batch

  % gather and accumulate gradients across labs
  if training
    if numGpus <= 1
      [net,res] = accumulate_gradients(opts, learningRate, batchSize, net, res) ;
    else
      if isempty(mmap)
        mmap = map_gradients(opts.memoryMapFile, net, res, numGpus) ;
      end
      write_gradients(mmap, net, res) ;
      labBarrier() ;
      [net,res] = accumulate_gradients(opts, learningRate, batchSize, net, res, mmap) ;
    end
  end

  % collect and print learning statistics
  time = toc(start) ;
  stats = sum([stats,[0 ; error]],2); % works even when stats=[]
  stats(1) = time ;
  n = t + batchSize - 1 ; % number of images processed overall
  speed = n/time ;
  fprintf('%.1f Hz%s\n', speed) ;

  m = n / max(1,numlabs) ; % num images processed on this lab only
  fprintf(' obj:%.3g', stats(2)/m) ;
  for i=1:numel(opts.errorLabels)
    fprintf(' %s:%.3g', opts.errorLabels{i}, stats(i+2)/m) ;
  end
  fprintf(' [%d/%d]', numDone, batchSize);
  fprintf('\n') ;

  % collect diagnostic statistics
  if training & opts.plotDiagnostics
    switchfigure(2) ; clf ;
    diag = [res.stats] ;
    barh(horzcat(diag.variation)) ;
    set(gca,'TickLabelInterpreter', 'none', ...
      'YTickLabel',horzcat(diag.label), ...
      'YDir', 'reverse', ...
      'XScale', 'log', ...
      'XLim', [1e-5 1]) ;
    drawnow ;
  end

end

% switch off the profiler
if opts.profile
  if numGpus <= 1
    prof = profile('info') ;
    profile off ;
  else
    prof = mpiprofile('info');
    mpiprofile off ;
  end
else
  prof = [] ;
end

% bring the network back to CPU
if numGpus >= 1
  net_cpu = vl_simplenn_move(net, 'cpu') ;
else
  net_cpu = net ;
end

% -------------------------------------------------------------------------
function [net,res] = accumulate_gradients(opts, lr, batchSize, net, res, mmap)
% -------------------------------------------------------------------------
if nargin >= 6
  numGpus = numel(mmap.Data) ;
else
  numGpus = 1 ;
end

for l=numel(net.layers):-1:1
  for j=1:numel(res(l).dzdw)

    % accumualte gradients from multiple labs (GPUs) if needed
    if numGpus > 1
      tag = sprintf('l%d_%d',l,j) ;
      tmp = zeros(size(mmap.Data(labindex).(tag)), 'single') ;
      for g = setdiff(1:numGpus, labindex)
        tmp = tmp + mmap.Data(g).(tag) ;
      end
      res(l).dzdw{j} = res(l).dzdw{j} + tmp ;
    end

    if j == 3 && strcmp(net.layers{l}.type, 'bnorm')
      % special case for learning bnorm moments
      thisLR = net.layers{l}.learningRate(j) ;
      net.layers{l}.weights{j} = ...
        (1-thisLR) * net.layers{l}.weights{j} + ...
        (thisLR/batchSize) * res(l).dzdw{j} ;
    else
      % standard gradient training
      thisDecay = opts.weightDecay * net.layers{l}.weightDecay(j) ;
      thisLR = lr * net.layers{l}.learningRate(j) ;
      net.layers{l}.momentum{j} = ...
        opts.momentum * net.layers{l}.momentum{j} ...
        - thisDecay * net.layers{l}.weights{j} ...
        - (1 / batchSize) * res(l).dzdw{j} ;
      net.layers{l}.weights{j} = net.layers{l}.weights{j} + ...
        thisLR * net.layers{l}.momentum{j} ;
    end

    % if requested, collect some useful stats for debugging
    if opts.plotDiagnostics
      variation = [] ;
      label = '' ;
      switch net.layers{l}.type
        case {'conv','convt'}
          variation = thisLR * mean(abs(net.layers{l}.momentum{j}(:))) ;
          if j == 1 % fiters
            base = mean(abs(net.layers{l}.weights{j}(:))) ;
            label = 'filters' ;
          else % biases
            base = mean(abs(res(l+1).x(:))) ;
            label = 'biases' ;
          end
          variation = variation / base ;
          label = sprintf('%s_%s', net.layers{l}.name, label) ;
      end
      res(l).stats.variation(j) = variation ;
      res(l).stats.label{j} = label ;
    end
  end
end

% -------------------------------------------------------------------------
function mmap = map_gradients(fname, net, res, numGpus)
% -------------------------------------------------------------------------
format = {} ;
for i=1:numel(net.layers)
  for j=1:numel(res(i).dzdw)
    format(end+1,1:3) = {'single', size(res(i).dzdw{j}), sprintf('l%d_%d',i,j)} ;
  end
end
format(end+1,1:3) = {'double', [3 1], 'errors'} ;
if ~exist(fname) && (labindex == 1)
  f = fopen(fname,'wb') ;
  for g=1:numGpus
    for i=1:size(format,1)
      fwrite(f,zeros(format{i,2},format{i,1}),format{i,1}) ;
    end
  end
  fclose(f) ;
end
labBarrier() ;
mmap = memmapfile(fname, 'Format', format, 'Repeat', numGpus, 'Writable', true) ;

% -------------------------------------------------------------------------
function write_gradients(mmap, net, res)
% -------------------------------------------------------------------------
for i=1:numel(net.layers)
  for j=1:numel(res(i).dzdw)
    mmap.Data(labindex).(sprintf('l%d_%d',i,j)) = gather(res(i).dzdw{j}) ;
  end
end

% -------------------------------------------------------------------------
function epoch = findLastCheckpoint(modelDir)
% -------------------------------------------------------------------------
list = dir(fullfile(modelDir, 'net-epoch-*.mat')) ;
tokens = regexp({list.name}, 'net-epoch-([\d]+).mat', 'tokens') ;
epoch = cellfun(@(x) sscanf(x{1}{1}, '%d'), tokens) ;
epoch = max([epoch 0]) ;

% -------------------------------------------------------------------------
function switchfigure(n)
% -------------------------------------------------------------------------
if get(0,'CurrentFigure') ~= n
  try
    set(0,'CurrentFigure',n) ;
  catch
    figure(n) ;
  end
end


% SUBSASGN Subscripted assignment.
%    A(I) = B assigns the values of B into the elements of A specified by
%    the subscript vector I.  B must have the same number of elements as I
%    or be a scalar.
%
%    A(I,J) = B assigns the values of B into the elements of the rectangular
%    submatrix of A specified by the subscript vectors I and J.  A colon used as
%    a subscript, as in A(I,:) = B, indicates all columns of those rows
%    indicated by vector I. Similarly, A(:,J) = B means all rows of columns J.
%
%    A(I,J,K,...) = B assigns the values of B to the submatrix of A specified
%    by the subscript vectors I, J, K, etc. A colon used as a subscript, as in
%    A(I,:,K) = B, indicates the entire dimension.
%
%    For both A(I,J) = B and the more general multi-dimensional
%    A(I,J,K,...) = B, B must be LENGTH(I)-by-LENGTH(J)-by-LENGTH(K)-... , or
%    be shiftable to that size by adding or removing singleton dimensions, or
%    contain a scalar, in which case its value is replicated to form a matrix
%    of that size.
%
%    A{I} = B when A is a cell array and I is a scalar places a copy of
%    the array B into the specified cell of A.  If I has more than one
%    element, this expression is an error.  Use [A{I}] = DEAL(B) to place
%    copies of B into multiple cells of A.  Multiple subscripts that
%    specify a scalar element, as in A{3,4} = magic(3), also work.
%
%    A(I).field = B when A is a structure array and I is a scalar places
%    a copy of the array B into the field with the name 'field'.  If I
%    has more than one element, this expression is an error. Use
%    [A(I).field] = DEAL(B) to place copies of B into multiple elements
%    of A.  If A is a 1-by-1 structure array, then the subscript can be
%    dropped.  In this case, A.field = B is the same as A(1).field = B.
%
%    A = SUBSASGN(A,S,B) is called for the syntax A(I)=B, A{I}=B, or
%    A.I=B when A is an object.  S is a structure array with the fields:
%        type -- character vector or string containing '()', '{}', or '.'
%                specifying the subscript type.
%        subs -- cell array, character vector, or string containing the
%                actual subscripts.
%
%    For instance, the syntax A(1:2,:)=B calls A=SUBSASGN(A,S,B) where
%    S is a 1-by-1 structure with S.type='()' and S.subs = {1:2,':'}. A
%    colon used as a subscript is passed as the character vector ':'.
%
%    Similarly, the syntax A{1:2}=B invokes A=SUBSASGN(A,S,B) where
%    S.type='{}' and the syntax A.field=B invokes SUBSASGN(A,S,B) where
%    S.type='.' and S.subs='field'.
%
%    These simple calls are combined in a straightforward way for
%    more complicated subscripting expressions.  In such cases
%    length(S) is the number of subscripting levels.  For instance,
%    A(1,2).name(3:5)=B invokes A=SUBSASGN(A,S,B) where S is 3-by-1
%    structure array with the following values:
%        S(1).type='()'       S(2).type='.'        S(3).type='()'
%        S(1).subs={1,2}      S(2).subs='name'     S(3).subs={3:5}
%
%    See also SUBSREF, SUBSTRUCT, PAREN, SUBSINDEX, LISTS,
%             NUMARGUMENTSFROMSUBSCRIPT.
%
%    Reference page in Doc Center
%       doc subsasgn
%
%    Other functions named subsasgn
%
%       axisobj/subsasgn             gbm/subsasgn
%       axistext/subsasgn            gpuArray/subsasgn
%       bm/subsasgn                  graph/subsasgn
%       calendarDuration/subsasgn    heston/subsasgn
%       categorical/subsasgn         hgbin/subsasgn
%       cev/subsasgn                 hwv/subsasgn
%       cir/subsasgn                 instrument/subsasgn
%       classregtree/subsasgn        scribehandle/subsasgn
%       codistributed/subsasgn       scribehgobj/subsasgn
%       Composite/subsasgn           sde/subsasgn
%       dataset/subsasgn             sdeddo/subsasgn
%       datetime/subsasgn            sdeld/subsasgn
%       diffusion/subsasgn           sdemrd/subsasgn
%       digraph/subsasgn             serial/subsasgn
%       distributed/subsasgn         sym/subsasgn
%       drift/subsasgn               tabular/subsasgn
%       duration/subsasgn            tall/subsasgn
%       fighandle/subsasgn           ts/subsasgn
%       figobj/subsasgn              tscollection/subsasgn
%       fints/subsasgn
%


% Routine to display the time for a line for ZNLDetect
%
% Matt Allen, July 2005-Aug 2006

global ZNLD

% Find Extrapolation line and add to plot
lineh = gco;
if isempty(lineh) | isempty(get(get(lineh,'Parent'),'Parent'))
    error('No Line on Figure 102 was selected. Select a line and run the script again.');
end
if get(get(lineh,'Parent'),'Parent') ~= 102;
    error('No Line on Figure 102 was selected. Select a line and run the script again.');
end

disp(['Current line is number: ',num2str(get(gco,'UserData')),', for time response starting at: ',...
    num2str(ZNLD.ts_zc(get(gco,'UserData'))),' seconds.']);


function display(t)
%DISPLAY Command window display of a tenmat.
%
%   See also TENMAT.
%
%MATLAB Tensor Toolbox.
%Copyright 2012, Sandia Corporation.

% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others.
% http://www.sandia.gov/~tgkolda/TensorToolbox.
% Copyright (2012) Sandia Corporation. Under the terms of Contract
% DE-AC04-94AL85000, there is a non-exclusive license for use of this
% work by or on behalf of the U.S. Government. Export of this data may
% require a license from the United States Government.
% The full license terms can be found in the file LICENSE.txt

disp(t,inputname(1));


%  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 should have received a copy of the GNU General Public License
%  along with this program; if not, write to the Free Software
%  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
%function klaudert
%KLAUDERT Unit test for function KLAUDER.

%	O. Lemoine - March 1996.

N=256;

% Admissibility condition
psi=klauder(N);
if abs(sum(psi))>sqrt(eps),
 error('klauder test 1 failed');
end

% Admissibility condition
psi=klauder(N,100,0.04);
if abs(sum(psi))>sqrt(eps),
 error('klauder test 2 failed');
end

% Admissibility condition
psi=klauder(N,1,0.49);
if abs(sum(psi))>sqrt(eps),
 error('klauder test 3 failed');
end

N=227;

% Admissibility condition
psi=klauder(N);
if abs(sum(psi))>sqrt(eps),
 error('klauder test 4 failed');
end

% Admissibility condition
psi=klauder(N,100,0.04);
if abs(sum(psi))>sqrt(eps),
 error('klauder test 5 failed');
end

% Admissibility condition
psi=klauder(N,1,0.49);
if abs(sum(psi))>sqrt(eps),
 error('klauder test 6 failed');
end


function value = ch_is_alpha ( c )

%*****************************************************************************80
%
%% CH_IS_ALPHA returns TRUE if C is an alphabetic character.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    22 February 2010
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, character C, a character to check.
%
%    Output, logical VALUE is TRUE if C is an alphabetic character.
%
  if ( ( 'a' <= c && c <= 'z' ) || ...
       ( 'A' <= c && c <= 'Z' ) )
    value = 1;
  else
    value = 0;
  end

  return
end


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

axes(axis);
oldUnits = get(axis, 'units');
set(axis, 'units', 'pixels');
h = text(1, 1, 1, '||', 'margin', .01, 'interpreter', 'none', 'units', 'pixels');
extent = get(h, 'extent');
delete(h);
baseline = extent(3);

for i=0:255
    h = text(1, 1, 1, ['|' char(i) '|'], 'margin', .01, 'interpreter', 'none', 'units', 'pixels');
    extent = get(h, 'extent');
    output(i+1) = extent(3) - baseline;
    delete(h);
end
chars = output;
set(axis, 'units', oldUnits);


function read_ceos_raw ( output_file_pre, start_line_blk, blk )
%
% -------------------------------------------------------------------------
% This function reads the CEOS format RSAT-1 RAW data from the CD
% This function is called by extract_data.m
% -------------------------------------------------------------------------
% output_file_pre : output file prefix ( path + prefix + block number)
% start_line_blk  : extract data starting from row number 'start_line_blk'
% blk             : the block number
%
% input_path     : Input file path
% length_replica : Length (I & Q) of replica (for Fine Beam -> 2880 bytes)
% tot_Nrg_cells  : Total number of columns available in the dataset
% Nrg_lines_blk  : Number of samples in azimuth
% first_rg_cell  : Extract data starting from column number 'first_rg_cell'
% Nrg_cells      : Number of samples in ranged
% UseMATfiles    : Do you want to write MAT files for the data rather than
%                  binary files for all the data and parameters?
% -------------------------------------------------------------------------

% date created  : May 05, 2004  by  Kaan Ersahin & Millie Sikdar
% date modified : Nov 30, 2004  by  Kaan Ersahin
% Modified:  Dec 17 by Ian Cumming
%             - Added UseMATfiles option
% -------------------------------------------------------------------------

% 'RSI - D4' refers to the document RSI-GS-026, Rev 3.0 - May 8, 2000
%  that describes the detailed format of the RADARSAT-1 raw data CDs.
tic
num_aux            = 50;                        % RSI - D4 Pg.32
num_header         = 192;                       % RSI - D4 Pg.32
file_header_length = 16252;                     % RSI - D4 Pg.103
load CD_run_params

%  Specify input data file path and open to read
file_in  = strcat( input_path, CD_data_file_name );
fid      = fopen( file_in, 'r' );

%  Create output file names and open to write if MAT files not used
if ~UseMATfiles
    file_replica 	 = '_replica.dat';     % one replica per 8-line
    file_data_header = '_data_header.dat'; % header of each line
    file_aux     	 = '_aux.dat';         % auxiliary data from each line
    file_data    	 = '_data.dat';        % radar signal data
    file_file_header = '_file_header.dat'; % header of file 'dat_01.001'

    file_replica     = strcat(output_file_pre, file_replica);
    file_data_header = strcat(output_file_pre, file_data_header);
    file_aux         = strcat(output_file_pre, file_aux);
    file_data        = strcat(output_file_pre, file_data);
    file_file_header = strcat(output_file_pre, file_file_header);

    fod1             = fopen( file_replica    , 'w' );
    fod2             = fopen( file_data_header, 'w' );
    fod3             = fopen( file_aux        , 'w' );
    fod4             = fopen( file_data       , 'w' );
    fod5             = fopen( file_file_header, 'w' );

    %  Read file header
    file_header      = fread( fid, [file_header_length,1], 'uint8' );
    %  Write file header in a binary file as unsigned integers
    fwrite( fod5, file_header, 'uint8');
    fclose( fod5 );
end  % of if ~UseMATfiles

% some useful calculations
num_pixel_data   = 2*tot_Nrg_cells;                               %  18576
h                = num_header;                                    %    192
ha               = num_header + num_aux;                          %    242
hpa              = num_header + num_aux + num_pixel_data;         %  18818

% Define 'rep_block' as the 8-line block of data including one replica
% 'start_rep' and 'end_rep' locates the replica in the 'rep_block'
% 'start_col' and 'end_col' locates the area of interest in the columns
rep_block_length = length_replica + 8*hpa ;

start_rep        = (first_replica-1)*hpa + num_header + num_aux + 1;
end_rep          = start_rep + length_replica - 1 ;

start_col        = ha + 2*(first_rg_cell - 1) + 1 ;
end_col          = start_col + 2*Nrg_cells - 1;

% The number of bytes to skip from the beginning of the file (Nbytes_skip)
Nrep_blks_row1   = ceil(start_line_blk/8) - 1;
Nbytes_blocks    = Nrep_blks_row1 * rep_block_length;
Nbytes_skip      = file_header_length + Nbytes_blocks;

fseek( fid, Nbytes_skip , 'bof' );  % go to start of the 1st data block
data = int8( zeros(Nrg_lines_blk, 2*Nrg_cells) );   % Allocate data array

N_8line_blocks = ceil(Nrg_lines_blk/8);
fprintf('\nReading %1.0f small 8-line blocks from range line %5.0f\n',...
    N_8line_blocks, start_line_blk )

for kb = 1 : N_8line_blocks   %  Read and decode 8 lines at a time

    % read one 8-line block of radar data and replica
    temp = uint8( fread( fid, [rep_block_length,1], 'uint8' ) );

    % separate the replica and 8 lines of [header, aux and data]
    replica = temp(start_rep : end_rep)';
    temp = [ temp(1 : start_rep-1)' temp(end_rep+1 : rep_block_length)' ];
    temp = reshape(temp, hpa, 8)';   % Shape array as 8 rows by all columns

    % Extract the desired set of range cells
    data(1+8*(kb-1):8*kb, :) = temp( : , start_col : end_col );

    if ~UseMATfiles  % Write replica, header, aux and data in a binary file
        header (:,1:8) = temp( : ,         1 : h       )';
        aux    (:,1:8) = temp( : ,       h+1 : ha      )';
        count1 = fwrite( fod1, replica, 'ubit4' ); % 4-bit replica
        count2 = fwrite( fod2, header , 'uint8' ); % 8-bit header
        count3 = fwrite( fod3, aux    , 'uint8' ); % 8-bit aux data
        count4 = fwrite( fod4, data(1+8*(kb-1):8*kb, :)'   , 'ubit4' );
    end  % of if UseMATfiles
end

fclose(fid);           % Close input file
if ~UseMATfiles        % Close output files
    fclose(fod1);   fclose(fod2);   fclose(fod3);   fclose(fod4);
    fprintf('This block written to binary file:\n%s\n', file_data )
end

%--------------------------------------------------------------------------
%  Decode the data, save as MAT file , if UseMATfiles == 1
%--------------------------------------------------------------------------

if UseMATfiles == 1
    disp 'Decode data by subtracting 16 from upper register'
    vv    = version;   vers = str2num(vv(1));  % Find MATLAB version
    seven = int8( 7 );

    if vers == 7
        one     = int8( 1 );
        two     = int8( 2 );
        sixteen = int8( 16 );
        data    = two*(data - sixteen*int8(data > seven)) + one;
    else
        data    = int8( 2*(double(data) - 16*double(data > seven) ) + 1 );
    end

    %  Separate the I and Q channels and form a complex array
    data = complex( data(:, 1:2:2*Nrg_cells), data(:, 2:2:2*Nrg_cells) );

    if SaveV6
       eval(['save -v6 ' output_path 'CDdata' num2str(blk) ' data'])
       disp  'Save int8 data in MAT file in V6 format'
    else
       eval(['save ' output_path 'CDdata' num2str(blk) ' data'])
       fprintf('Save int8 data in file:  CDdata%1.0f.mat\n', blk)
    end
    % somedata = data(1,1:4)  % Check a few data samples
end   % of if UseMATfiles
toc


%% Example
% An example script, it is used to show how to use the arcs
% functions of the KUKA iiwa matlab toolbox
% First start the server on the KUKA iiwa controller
% Then run the following script in Matlab

% Note you have 60 seconds to connect to server after starting the
% application (MatlabToolboxServer) from the smart pad on the robot controller.

% Mohammad SAFEEA, 3rd of May 2017

close all,clear all;clc;
warning('off');
ip='172.31.1.147'; % The IP of the controller
% start a connection with the server
global t_Kuka;
t_Kuka=net_establishConnection( ip );

if ~exist('t_Kuka','var') || isempty(t_Kuka) || strcmp(t_Kuka.Status,'closed')
  warning('Connection could not be establised, script aborted');
  return;
else

      %% Go to initial configuration
      relVel=0.25; % over ride relative joint velocities

      pos={0, -pi / 180 * 10, 0, -pi / 180 * 100, pi / 180 * 90,pi / 180 * 90, 0};   % initial cofiguration

      movePTPJointSpace( t_Kuka , pos, relVel); % go to home position
      %% Move in an arc, the orientation of EEF changes while performing the motion,
      % The function utilized (movePTPCirc1OrintationInter)
      % f2 is the final frame, at which the arc motion ends
      % f1 is an intermidiate frame, through wich the robot passes while
      % performing the motion.

      f1=getEEFPos( t_Kuka );
      f2=f1;
      r=75;
      f1{2}=f1{2}+r;
      f1{3}=f1{3}-r;
      f1{6}=f1{6}+pi/8;

      f2{3}=f2{3}-2*r;
      f2{6}=f2{6}+pi/2;

      vel=150; % linear velocity of end-effector mm/sec
      movePTPCirc1OrintationInter( t_Kuka , f1,f2, vel)

          %% Move robot in joint space to some initial configuration
pinit={0,pi*20/180,0,-pi*70/180,0,pi*90/180,0}; % joint angles of initial confuguration
relVel=0.15; % the relative velocity
movePTPJointSpace( t_Kuka , pinit, relVel); % point to point motion in joint space

%% Move EEF -100 mm in Z direction
deltaX=0.0;deltaY=0;deltaZ=-100.; % relative displacemnets of end-effector
Pos{1}=deltaX;
Pos{2}=deltaY;
Pos{3}=deltaZ;
movePTPLineEefRelBase( t_Kuka , Pos, vel);

%% Store the current position in the memory
Cen=getEEFPos(t_Kuka); % Concider the current position as the center of the arcs

%% Move EEF 50mm in X direction
deltaX=100;deltaY=0;deltaZ=0.;
Pos{1}=deltaX;
Pos{2}=deltaY;
Pos{3}=deltaZ;
movePTPLineEefRelBase( t_Kuka , Pos, vel);
%% Store the current position in the memory
circle_Starting_Point=getEEFPos( t_Kuka ); % Consider the current point as circle starting point

%% Move in an arc, the arc is drawn on an incliend plane
% using the function ((movePTPArc_AC))
theta=pi/2; % the angle subtended by the arc at the center ((c))
k=[1;1;1]; % normal vector of the plane, on which the circle is drawn
c=[Cen{1};Cen{2};Cen{3}]; % the center of the arc
vel=100; % the motion velocity mm/sec
movePTPArc_AC(t_Kuka,theta,c,k,vel)

%% Go back to ((circle_Starting_Point)) coordinates
vel=150;
movePTPLineEEF( t_Kuka , circle_Starting_Point, vel);
%% Move in an arc, the arc is drawn in XY plane
% using the function ((movePTPArcXY_AC))
theta=1.98*pi; % the angle subtended by the arc at the center ((c))
c=[Cen{1};Cen{2}]; % the XY coordinate of the center of the arc
vel=150; % the motion velocity mm/sec
movePTPArcXY_AC(t_Kuka,theta,c,vel)

      %% turn off the server
       net_turnOffServer( t_Kuka );

       fclose(t_Kuka);
end

warning('on');


function kern = rbfhKernExpandParam(kern, params)

% RBFHKERNEXPANDPARAM Create kernel structure from RBFH kernel's parameters.
% FORMAT
% DESC returns a radial basis function HEAT kernel structure filled with
% the parameters in the given vector. This is used as a helper function to
% enable parameters to be optimised in, for example, the NETLAB
% optimisation functions.
% ARG kern : the kernel structure in which the parameters are to be
% placed.
% ARG param : vector of parameters which are to be placed in the
% kernel structure.
% RETURN kern : kernel structure with the given parameters in the
% relevant locations.
%
% SEEALSO : rbfhKernParamInit, rbfhKernExtractParam, kernExpandParam
%
% COPYRIGHT : Mauricio A. Alvarez, 2010

% KERN

kern.inverseWidthTime = params(1);
kern.inverseWidthSpace = params(2);


function mr = mrReadDicomDir(ifileDir)
% Read a directory of GE I-files into an mr struct.
%
% mr = mrReadDicomDir(ifileDir);
%
% ras, 07/05.

% initialize mr struct
[p f ext] = fileparts(ifileDir);
if isequal(ext, '.dcm')
    % oops -- accidentally included an I-file in the path: chop this off:
    ifileDir = p;
    [p f] = fileparts(ifileDir); %#ok<ASGLU>
end

mr = mrCreateEmpty;
mr.pth = ifileDir;
mr.name = f;
mr.format = 'dicom';

[mr.data hdr1 hdr2] = loopOverMRFiles(ifileDir,'*.dcm','mrReadIfile');
mr.hdr = hdr1;

mr.voxelSize = double([mr.hdr.image.pixsize_Y mr.hdr.image.pixsize_X ...
                       mr.hdr.image.slthick]);
mr.dims = size(mr.data);
mr.spaces = mrStandardSpaces(mr);
mr.dimUnits = {'mm' 'mm' 'mm' 'sec'};
mr.dataUnits = 'T1-Weighted Intensity';

mr.info.scanner = char(mr.hdr.exam.hospname');
mr.info.subject = char(mr.hdr.exam.patname');
sex = {'female' 'male'};
mr.info.subjectSex = sex{mr.hdr.exam.patsex+1};
mr.info.subjectAge = mr.hdr.exam.patage;
mr.info.subjectSpecies = 'human'; % may not always be the case, find field
mr.info.date = datestr(parseGEDate(mr.hdr.series.se_datetime));
mr.info.scanStart = datestr(parseGEDate(mr.hdr.image.im_actual_dt));
mr.info.examNum = mr.hdr.exam.ex_no;
mr.info.protocol = char(mr.hdr.series.prtcl');
if checkfields(mr, 'hdr', 'image', 'cname')
    mr.info.coil = mr.hdr.image.cname;
else
    mr.info.coil = 'unknown coil';
end
mr.info.magnetStrength = mr.hdr.exam.magstrength/10000;

% get coordinates of 3 corners of the last image and
% express in R|A|S coords:
tmp = mr.hdr.image;
mr.info.cornerCoords = [tmp.tlhc_R tmp.trhc_R tmp.brhc_R; ...
                        tmp.tlhc_A tmp.trhc_A tmp.brhc_A; ...
                        tmp.tlhc_S tmp.trhc_S tmp.brhc_S];
tmp = hdr2.image;
mr.info.cornerCoords = [mr.info.cornerCoords; ...
                        tmp.tlhc_R tmp.trhc_R tmp.brhc_R; ...
                        tmp.tlhc_A tmp.trhc_A tmp.brhc_A; ...
                        tmp.tlhc_S tmp.trhc_S tmp.brhc_S];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Use the corner coords to estimate transform into  %
% scanner space:                                    %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% % first, get the coordinates of the corners of the last slice
% % in pixel coords: (Using code Bob wrote, below)
% tlhc = [1 1 mr.dims(3)]'; % top left-hand-corner
% trhc = [1 mr.dims(2:3)]'; % top right-hand-corner
% brhc = [mr.dims]';        % bottom right-hand-corner
% pixCorners = [tlhc trhc brhc];

% now build a space defining the scanner coords, where the
% xform maps from the pixCorners to the R|A|S coords of the
% the three corners from the header:
w = dir(fullfile(ifileDir,'*.dcm'));
firstIfile = fullfile(ifileDir,w(1).name);
mr.spaces(end+1).name = 'Scanner';
mr.spaces(end).xform = inv(affineScanner2Pixels(firstIfile));
mr.spaces(end).dirLabels = {'L <--> R' 'P <--> A'  'I <--> S'};
mr.spaces(end).sliceLabels =  {'Sagittal' 'Coronal' 'Axial'};
mr.spaces(end).units = 'mm';
mr.spaces(end).coords = [];
mr.spaces(end).indices = [];

% also update the direction labels on the pixel and L/R flipped spaces,
% using the header info:
dirs = mrIfileDirections(ifileDir);
for i=1:3, mr.spaces(i).dirLabels = dirs; end
mr.spaces(3).dirLabels{2} = dimFlip(mr.spaces(3).dirLabels{2});

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

% /-----------------------------------------------------------------/ %
function dirText = dimFlip(dirText)
% flip direction 'a <--> b' to read 'b <--> a'.
I = strfind(dirText, ' <--> ');
if isempty(I), return; end
lhs = dirText(1:I);
rhs = dirText(I+5:end);
dirText = [rhs '<-->' lhs];
return


function varargout = process_evt_detect_eog( varargin )
% PROCESS_EVT_DETECT_EOG: Detect eye blinks in a continuous file, and create set of events called "blink"
%
% USAGE:  OutputFiles = process_evt_detect_eog('Run', sProcess, sInputs)

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

eval(macro_method);
end

%% ===== GET DESCRIPTION =====
function sProcess = GetDescription() %#ok<DEFNU>
    % Description the process
    sProcess.Comment     = 'Detect eye blinks';
    sProcess.Category    = 'Custom';
    sProcess.SubGroup    = 'Events';
    sProcess.Index       = 44;
    sProcess.Description = 'https://neuroimage.usc.edu/brainstorm/Tutorials/ArtifactsDetect#Detection:_Blinks';
    % Definition of the input accepted by this process
    sProcess.InputTypes  = {'raw', 'data'};
    sProcess.OutputTypes = {'raw', 'data'};
    sProcess.nInputs     = 1;
    sProcess.nMinFiles   = 1;
    % Channel name
    sProcess.options.channelname.Comment = 'Channel name: ';
    sProcess.options.channelname.Type    = 'channelname';
    sProcess.options.channelname.Value   = '';
    % Channel name comment
    sProcess.options.channelhelp.Comment = 'You can use the montage syntax here: "ch1, -ch2"';
    sProcess.options.channelhelp.Type    = 'label';
    % Time window
    sProcess.options.timewindow.Comment = 'Time window:';
    sProcess.options.timewindow.Type    = 'timewindow';
    sProcess.options.timewindow.Value   = [];
    % Event name
    sProcess.options.eventname.Comment = 'Event name: ';
    sProcess.options.eventname.Type    = 'text';
    sProcess.options.eventname.Value   = 'blink';
end

%% ===== FORMAT COMMENT =====
function Comment = FormatComment(sProcess) %#ok<DEFNU>
    Comment = sProcess.Comment;
end

%% ===== RUN =====
function OutputFiles = Run(sProcess, sInputs) %#ok<DEFNU>
    % Pre-defined set of properties
    %sProcess.options.eventname.Value = 'blink';
    sProcess.options.threshold.Value = {2, 'x std', 2};
    sProcess.options.bandpass.Value  = {[1.5 15], 'Hz', 2};
    sProcess.options.blanking.Value  = {0.8, 'ms', []};
    sProcess.options.isnoisecheck.Value = 1;
    sProcess.options.isclassify.Value   = 1;
    % Call the generic version of the event detection
    OutputFiles = process_evt_detect('Run', sProcess, sInputs);
end


function r = foldl(list, identity, func)
% VAL = FOLDL(ARRAY, ID, FUNC)
%   Perform a left fold over ARRAY with FUNC using ID as the identity.
%   FOLDL applies FUNC to the current identity (initially ID) and each item
%   of ARRAY successively.  Thus, FOLDL iterates over ARRAY with FUNC.  ID
%   is updated to be the result of this function.  The final result of ID
%   is returned from the function.
%
%   FOLDL is most simply viewed as the haskell code
%     foldl []   id f = id
%     foldl x:xs id f = foldl xs (f id x) f
%
%   FOLDL and FOLDR are implemented as a loop for optimization purposes in
%   these libraries.  FOLDL is tail recursive and thus more efficient on
%   most platforms that use the above functional definition.
%
%   Examples of Common FOLDL uses:
%     sum(array) == foldl(array, 0, @(a,b) a + b)
%     all(array) == foldl(array, true, @(a,b) a && b)
%     any(array) == foldl(array, false, @(a,b) a || b)
%

  if isempty(list)
    r = identity;
    return;
  end

  if iscell(list)
    for i = 1:numel(list)
      identity = func(identity, list{i});
    end
  else
    for i = 1:numel(list)
      identity = func(identity, list(i));
    end
  end

  r = identity;
end


function out = ndims(fa)
% Number of dimensions
%_______________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

%
% $Id$

out = size(fa);
out = length(out);


%  internal function

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

function save_nii_hdr(hdr, fid)

   if ~exist('hdr','var') || ~exist('fid','var')
      error('Usage: save_nii_hdr(hdr, fid)');
   end

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

   if hdr.hist.qform_code == 0 && hdr.hist.sform_code == 0
      hdr.hist.sform_code = 1;
      hdr.hist.srow_x(1) = hdr.dime.pixdim(2);
      hdr.hist.srow_x(2) = 0;
      hdr.hist.srow_x(3) = 0;
      hdr.hist.srow_y(1) = 0;
      hdr.hist.srow_y(2) = hdr.dime.pixdim(3);
      hdr.hist.srow_y(3) = 0;
      hdr.hist.srow_z(1) = 0;
      hdr.hist.srow_z(2) = 0;
      hdr.hist.srow_z(3) = hdr.dime.pixdim(4);
      hdr.hist.srow_x(4) = (1-hdr.hist.originator(1))*hdr.dime.pixdim(2);
      hdr.hist.srow_y(4) = (1-hdr.hist.originator(2))*hdr.dime.pixdim(3);
      hdr.hist.srow_z(4) = (1-hdr.hist.originator(3))*hdr.dime.pixdim(4);
   end

   write_header(hdr, fid);

   return;					% save_nii_hdr

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

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

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

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

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

   return;					% write_header

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

   fseek(fid,0,'bof');

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

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

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

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

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

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

   return;					% header_key

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

	%  Original header structures
	%  struct image_dimension
	%       {                                /* off + size      */
	%       short int dim[8];                /* 0 + 16          */
	%       float intent_p1;   % char vox_units[4];   /* 16 + 4       */
	%       float intent_p2;   % char cal_units[8];   /* 20 + 4       */
	%       float intent_p3;   % char cal_units[8];   /* 24 + 4       */
	%       short int intent_code;   % short int unused1;   /* 28 + 2 */
	%       short int datatype;              /* 30 + 2          */
	%       short int bitpix;                /* 32 + 2          */
	%       short int slice_start;   % short int dim_un0;   /* 34 + 2 */
	%       float pixdim[8];                 /* 36 + 32         */
	%			/*
	%				pixdim[] specifies the voxel dimensions:
	%				pixdim[1] - voxel width
	%				pixdim[2] - voxel height
	%				pixdim[3] - interslice distance
	%				pixdim[4] - volume timing, in msec
	%					..etc
	%			*/
	%       float vox_offset;                /* 68 + 4          */
	%       float scl_slope;   % float roi_scale;     /* 72 + 4 */
	%       float scl_inter;   % float funused1;      /* 76 + 4 */
	%       short slice_end;   % float funused2;      /* 80 + 2 */
	%       char slice_code;   % float funused2;      /* 82 + 1 */
	%       char xyzt_units;   % float funused2;      /* 83 + 1 */
	%       float cal_max;                   /* 84 + 4          */
	%       float cal_min;                   /* 88 + 4          */
	%       float slice_duration;   % int compressed; /* 92 + 4 */
	%       float toffset;   % int verified;          /* 96 + 4 */
	%       int glmax;                       /* 100 + 4         */
	%       int glmin;                       /* 104 + 4         */
	%       };                               /* total=108 bytes */

   fwrite(fid, dime.dim(1:8),        'int16');
   fwrite(fid, dime.intent_p1(1),  'float32');
   fwrite(fid, dime.intent_p2(1),  'float32');
   fwrite(fid, dime.intent_p3(1),  'float32');
   fwrite(fid, dime.intent_code(1),  'int16');
   fwrite(fid, dime.datatype(1),     'int16');
   fwrite(fid, dime.bitpix(1),       'int16');
   fwrite(fid, dime.slice_start(1),  'int16');
   fwrite(fid, dime.pixdim(1:8),   'float32');
   fwrite(fid, dime.vox_offset(1), 'float32');
   fwrite(fid, dime.scl_slope(1),  'float32');
   fwrite(fid, dime.scl_inter(1),  'float32');
   fwrite(fid, dime.slice_end(1),    'int16');
   fwrite(fid, dime.slice_code(1),   'uchar');
   fwrite(fid, dime.xyzt_units(1),   'uchar');
   fwrite(fid, dime.cal_max(1),    'float32');
   fwrite(fid, dime.cal_min(1),    'float32');
   fwrite(fid, dime.slice_duration(1), 'float32');
   fwrite(fid, dime.toffset(1),    'float32');
   fwrite(fid, dime.glmax(1),        'int32');
   fwrite(fid, dime.glmin(1),        'int32');

   return;					% image_dimension

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

	% Original header structures
	%struct data_history
	%       {                                /* off + size      */
	%       char descrip[80];                /* 0 + 80          */
	%       char aux_file[24];               /* 80 + 24         */
	%       short int qform_code;            /* 104 + 2         */
	%       short int sform_code;            /* 106 + 2         */
	%       float quatern_b;                 /* 108 + 4         */
	%       float quatern_c;                 /* 112 + 4         */
	%       float quatern_d;                 /* 116 + 4         */
	%       float qoffset_x;                 /* 120 + 4         */
	%       float qoffset_y;                 /* 124 + 4         */
	%       float qoffset_z;                 /* 128 + 4         */
	%       float srow_x[4];                 /* 132 + 16        */
	%       float srow_y[4];                 /* 148 + 16        */
	%       float srow_z[4];                 /* 164 + 16        */
	%       char intent_name[16];            /* 180 + 16        */
	%       char magic[4];   % int smin;     /* 196 + 4         */
	%       };                               /* total=200 bytes */

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

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

   fwrite(fid, hist.qform_code,    'int16');
   fwrite(fid, hist.sform_code,    'int16');
   fwrite(fid, hist.quatern_b,   'float32');
   fwrite(fid, hist.quatern_c,   'float32');
   fwrite(fid, hist.quatern_d,   'float32');
   fwrite(fid, hist.qoffset_x,   'float32');
   fwrite(fid, hist.qoffset_y,   'float32');
   fwrite(fid, hist.qoffset_z,   'float32');
   fwrite(fid, hist.srow_x(1:4), 'float32');
   fwrite(fid, hist.srow_y(1:4), 'float32');
   fwrite(fid, hist.srow_z(1:4), 'float32');

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

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

   return;					% data_history


function varargout = temp_conversion(varargin)
% TEMP_CONVERSION M-file for temp_conversion.fig
%      TEMP_CONVERSION, by itself, creates a new TEMP_CONVERSION or raises the existing
%      singleton*.
%
%      H = TEMP_CONVERSION returns the handle to a new TEMP_CONVERSION or the handle to
%      the existing singleton*.
%
%      TEMP_CONVERSION('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in TEMP_CONVERSION.M with the given input arguments.
%
%      TEMP_CONVERSION('Property','Value',...) creates a new TEMP_CONVERSION or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before temp_conversion_OpeningFunction gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to temp_conversion_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 temp_conversion

% Last Modified by GUIDE v2.5 13-Mar-2004 18:07:02

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @temp_conversion_OpeningFcn, ...
                   'gui_OutputFcn',  @temp_conversion_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 temp_conversion is made visible.
function temp_conversion_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 temp_conversion (see VARARGIN)

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

% Update handles structure
guidata(hObject, handles);

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

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

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

function 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)

% Update all temperature values
deg_f = str2num( get(hObject,'String') );
deg_f = max( [ 32 deg_f] );
deg_f = min( [212 deg_f] );
deg_c = to_c(deg_f);

% Now update the fields
set (handles.Edit1,'String',sprintf('%.1f',deg_f));
set (handles.Edit2,'String',sprintf('%.1f',deg_c));
set (handles.Slider1,'Value',deg_c);

% --- 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
    set(hObject,'BackgroundColor','white');
else
    set(hObject,'BackgroundColor',get(0,'defaultUicontrolBackgroundColor'));
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)

% Update all temperature values
deg_c = str2num( get(hObject,'String') );
deg_c = max( [  0 deg_c] );
deg_c = min( [100 deg_c] );
deg_f = to_f(deg_c);

% Now update the fields
set (handles.Edit1,'String',sprintf('%.1f',deg_f));
set (handles.Edit2,'String',sprintf('%.1f',deg_c));
set (handles.Slider1,'Value',deg_c);

% --- 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
    set(hObject,'BackgroundColor','white');
else
    set(hObject,'BackgroundColor',get(0,'defaultUicontrolBackgroundColor'));
end

% --- Executes on slider movement.
function Slider1_Callback(hObject, eventdata, handles)
% hObject    handle to Slider1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Update all temperature values
deg_c = get(hObject,'Value');
deg_f = to_f(deg_c);

% Now update the fields
set (handles.Edit1,'String',sprintf('%.1f',deg_f));
set (handles.Edit2,'String',sprintf('%.1f',deg_c));
set (handles.Slider1,'Value',deg_c);

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

% Hint: slider controls usually have a light gray background, change
%       'usewhitebg' to 0 to use default.  See ISPC and COMPUTER.
usewhitebg = 1;
if usewhitebg
    set(hObject,'BackgroundColor',[.9 .9 .9]);
else
    set(hObject,'BackgroundColor',get(0,'defaultUicontrolBackgroundColor'));
end


function tests = test_yale_faces
  tests = functiontests(localfunctions);
end

function setupOnce(testCase)
    close all;
end

function teardownOnce(testCase)
    close all;
end

function test_basic(testCase)
    yf = spx.data.image.YaleFaces();
    yf.load();
    verifyEqual(testCase, yf.ImageHeight, 192);
    verifyEqual(testCase, yf.ImageWidth, 168);
    verifyEqual(testCase, yf.num_subjects, 38);
    verifyEqual(testCase, yf.num_total_images, 64*38);
    verifyEqual(testCase, yf.image_size, 192*168);
    yf.describe;
end

function test1(testCase)
    yf = spx.data.image.YaleFaces();
    yf.load();
    yf.describe();
    mf = spx.graphics.Figures();
    mf.new_figure('Example faces');
    canvas = yf.create_random_canvas();
    imshow(canvas);
    colormap(gray);
    axis image;
    axis off;

    yf.resize_all(42, 48);
    mf.new_figure('Subject 1');
    canvas = yf.create_subject_canvas(1);
    imshow(canvas);
    colormap(gray);
    axis image;
    axis off;
end


% MEMMAPDATA - create a memory-mapped data class
%
% Usage:
%   >> data_class = memmapdata(data);
%
% Inputs:
%   data         - input data or data file
%
% Outputs:
%   data_class    - output dataset class
%
% Author: Arnaud Delorme, SCCN, INC, UCSD, Nov. 2008

% Copyright (C) 2008 Arnaud Delorme, SCCN, INC, UCSD
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function dataout = memmapdata(data, datadims);

    dataout.fileformat = 'normal';
    if ischar(data)
        if length(data) > 3
            if strcmpi('.dat', data(end-3:end))
                dataout.fileformat = 'transposed';
            end
        end

        % check that the file is not empty
        % --------------------------------
        a = dir(data);
        if isempty(a)
            error([ 'Data file ''' data '''not found' ]);
        elseif a(1).bytes == 0
            error([ 'Empty data file ''' data '''' ]);
        end

        if ~strcmpi(dataout.fileformat, 'transposed')
            dataout.data = memmapfile(data, 'writable', false, 'format', { 'single' datadims 'x' });
        else
            dataout.data = memmapfile(data, 'writable', false, 'format', { 'single' [ datadims(2:end) datadims(1) ] 'x' });
        end
        dataout = class(dataout,'memmapdata');
    else
        dataout = data;
    end


function out = linearremap(x)
% LINEARREMAP Dumb linear remap
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

if ~isreal(x)
    out=abs(double(x));
else
    out=x;
end

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


function [roitSeries, subCoords] = getTseriesOneROI(vw, ROIcoords, scanNum, getRawTseries, removeRedundant)
%
%   [roitSeries, subCoords] = getTseriesOneROI(vw,ROIcoords,scanNum, getRawTseriesFlag(=0 default), removeRedundantFlag(=1 default) )
%
% For a single ROI, we loop through slices and acquire all of the
% tSeries(voxel by voxel). Return these time courses, removing redundant
% tSeries (which occur because several anatomical coords may reference the
% same functional voxel). Also returns the locations of the non-redundant
% voxels in subCoords.
% The removing redundant can be turned off by removeRedundantFlag = 0;
%
% ras, 04/04: remove redundant time courses from upsampling the functional.
% ras, 05/04: also, return the sub-coords, with the redundant voxels
% removed. (They'll be in the coordinates of the inplane anatomy, but
% there will only be one voxel contained within a given functional voxel.)
% ras, 5/2004 -- now it returns the tSeries in the order that corresponds
% to the voxels specified in ROIcoords (before, it would return in them
% in a semi-shuffled order if you were in the inplane view -- b/c of
% the loop through slices).
% jl, 5/2005 - make "remove redundant from upsampling" optional

% Make sure the input is in the right format
if notDefined('ROIcoords'),         ROIcoords       = viewGet(vw, 'ROI coords'); end
if notDefined('scanNum'),           scanNum         = viewGet(vw, 'Current Scan'); end
if notDefined('getRawTseries'),     getRawTseries   = 0; end
if notDefined('removeRedundant'),   removeRedundant = 1; end

ROIcoords = ROIcoords2cellArray(vw,ROIcoords);

% b/c of upsampling b/w the functionals and anats,
% there tend to be redundant coords specifying the
% same functional voxel -- remove these:
switch vw.viewType
    case 'Inplane',
        if removeRedundant
            % b/c of upsampling b/w the functionals and anats, there tend
            % to be redundant coords specifying the same functional voxel
            % -- remove these:
            subCoords = roiSubCoords(vw,ROIcoords{1});
        end
        ROIcoords = {subCoords};
    case 'Flat',
        % the tSeries will only cover points
        % on the flat map mapped by the ROI,
        % ignoring ones on blank/masked nodes

        % jw: comment out
        %         ind = sub2ind(size(vw.indices),ROIcoords{1}(1,:),...
        %                         ROIcoords{1}(2,:),ROIcoords{1}(3,:));
        %         ind = find(vw.indices(ind)>0);
        %         subCoords = ROIcoords{1}(:,ind);

        % jw: comment in
        subCoords = ROIcoords;
    otherwise,
        subCoords = ROIcoords;
end

roitSeries = [];

if ~getRawTseries
    detrend = detrendFlag(vw,scanNum);
    smoothFrames = detrendFrames(vw,scanNum);
end

% Find the slice indices for this collection of ROIs
sliceInds = getSlicesROI(vw,ROIcoords);

for iSlice = 1:length(sliceInds)
    slice = sliceInds(iSlice);

    % Load tSeries & divide by mean, but don't detrend yet.
    % Otherwise, detrending the entire tSeries is much slower. DJH
    % this crashes on the volume - out of memory - kgs 06/05
    % rewrote this section
    if(getRawTseries)
        vw = percentTSeries(vw,scanNum,slice,0,0,0,1);
     else
        vw = percentTSeries(vw,scanNum,slice,0);
     end

    % Extract time-series from the current slice
    %  The third argument of getTSeriesROI is 'preserveCoords', which is
    %  the logical opposite of removeRedundant. That is, if we remove
    %  redundant voxels, we will not preserve the coordinates (we will get
    %  back fewer time series than coordinates), and vice versa.
    preserveCoords = ~removeRedundant;
    [subtSeries subIndices] = getTSeriesROI(vw,ROIcoords{1}, preserveCoords);

    if removeRedundant & strcmpi(viewGet(vw, 'view type'), 'gray')
        coords = viewGet(vw, 'coords');
        subCoords{1} = coords(:, subIndices);
    end

    if ~isempty(subtSeries) & ~getRawTseries %#ok<*AND2>
        % Norm and Detrend (faster and doesn't crash after extracting subtSeries for a small subset of the voxels)
        subtSeries = detrendTSeries(subtSeries,detrend,smoothFrames);
    end

    switch vw.viewType
        case 'Inplane',
            % assign to the columns in roitSeries that correspond to the selected
            % voxels:
            voxelsInSlice = ROIcoords{1}(3,:) == vw.tSeriesSlice;
            roitSeries(:,voxelsInSlice) = subtSeries;
        case 'Gray',
            roitSeries = subtSeries;
        case 'Volume',
            roitSeries = subtSeries;
        case 'Flat',
            roitSeries = [roitSeries subtSeries];
    end
end

% make a cell (to be in line with multi-ROI analyses)
roitSeries = {roitSeries};
clear vw.tSeries; % free memory

return


global I hi

I=imread('smile.png'); % load image

hi=imshow(I,'InitialMagnification',600);
hold on;
tol=2; % tolerance
r=[20;30]; % start point of flood
zz_flood_fill_movie(r,tol); % make flood fill


function str = valid_named_set_type(obj, set_type)
%VALID_NAMED_SET_TYPE  Returns a label for the given named set type or empty.
%
%   -----  PRIVATE METHOD  -----
%
%   STR = OBJ.VALID_NAMED_SET_TYPE(SET_TYPE)
%
%   Returns a string corresponding to the type of the named set for
%   valid values of SET_TYPE, otherwise an empty string. Can be used to
%   check whether SET_TYPE is a valid type.
%
%   Valid set types, and the corresponding values are defined as a struct
%   returned by the DEF_SET_TYPES method.
%
%   E.g. The following method ...
%       function obj = def_set_types(obj)
%           obj.set_types = struct(...
%                   'var', 'variable', ...
%                   'lin', 'linear constraint' ...
%               );
%       end
%
%   ... indicates the following valid SET_TYPES and corresponding
%   return values:
%
%       SET_TYPE    STR
%       'var'       'variable'
%       'lin'       'linear constraint'

%   MP-Opt-Model
%   Copyright (c) 2017-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.

if isfield(obj.set_types, set_type)
    str = obj.set_types.(set_type);
else
    str = '';
end


function xyb = Xb(s)
x = s ;
y = 0 ;

xyb = [x ; y] ;


function I = cellfind(C,pattern)
% I = cellfind(cellArray,[pattern])
%
% Returns index vector I of cells containing a
% desired pattern. Pattern can be anything that
% would be in a cell: a num, string, struct, another
% cell, etc. If pattern is omitted, I returns the
% indices of non-empty cells.
%
% Note the algorithm for finding a pattern isn't
% optimized to be fast, just convenient.
%
% ras 11/04: updated to include pattern finding
% bw/ab    : caught empty Cell condition

if isempty(C), I = []; return; end
if ndims(C) > 2, error('Cellfind doesn''t work on arrays > 2 dimensions.'); end

if ~iscell(C)
    help cellfind
    error('First argument must be a cell.')
end

if nargin < 2
    % no pattern, just find non-empty cells
	I=zeros(size(C));

	for t = 1:size(C,1)
        for u = 1:size(C,2)
            a = C{t,u};
            I(t,u)=~isempty(a);
        end
	end
else
    % find pattern
    for j = 1:size(C,1)
        for k = 1:size(C,2)
            I(j,k) = isequal(C{j,k},pattern);
        end
    end
end

I = find(I);

return


% SB2_LIKELIHOODS  Convenience function to encapsulate likelihood types
%
% LIKELIHOOD = SB2_LIKELIHOODS(TYPE)
%
% OUTPUT ARGUMENTS:
%
%	LIKELIHOOD	A structure containing an enumeration of possible
%				likelihood types, and specification of the type in use.
%
% INPUT ARGUMENTS:
%
%	TYPE		A string. One of:
%					'Gaussian'
%					'Bernoulli'
%					'Poisson'
%
% EXAMPLE:
%
%	LIKELIHOOD	= SB2_Likelihoods('Gaussian');
%
% NOTES:
%
% This function is "for internal use only" and exists purely for convenience
% of coding and to facilitate potential future expansion.
%

%
% Copyright 2009, Vector Anomaly Ltd
%
% This file is part of the SPARSEBAYES library for Matlab (V2.0).
%
% SPARSEBAYES 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.
%
% SPARSEBAYES 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 SPARSEBAYES in the accompanying file "licence.txt"; if not, write to
% the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
% MA 02110-1301 USA
%
% Contact the author: m a i l [at] m i k e t i p p i n g . c o m
%
function LIKELIHOOD = SB2_Likelihoods(likelihood_)

% For convenience in code, and later expandability,
% we "enum" the available likelihood models
%
% Continuous
LIKELIHOOD.Gaussian		= 1;
% Discrete
LIKELIHOOD.Bernoulli	= 2;
LIKELIHOOD.Poisson		= 3;

% Feel free to add your own ... and work out the maths :-)

% Determine the likelihood to be used
%
LIKELIHOOD.InUse		= 0;
%
switch upper(likelihood_(1:5))
 case 'GAUSS',
  LIKELIHOOD.InUse	= LIKELIHOOD.Gaussian;
  %
 case 'BERNO',
  LIKELIHOOD.InUse	= LIKELIHOOD.Bernoulli;
  %
 case 'POISS',
  LIKELIHOOD.InUse	= LIKELIHOOD.Poisson;
  %
 otherwise
  error('Unknown likelihood ''%s'' specified\n', likelihood_)
end


%RUNSCRIPT Run an M-file in interactive fashion
%
% RUNSCRIPT(FNAME, OPTIONS) runs the M-file FNAME and pauses after every
% executable line in the file until a key is pressed.  Comment lines are shown
% without any delay between lines.
%
% Options::
% 'delay',D    Don't wait for keypress, just delay of D seconds (default 0)
% 'cdelay',D   Pause of D seconds after each comment line (default 0)
% 'begin'      Start executing the file after the comment line %%begin (default false)
% 'dock'       Cause the figures to be docked when created
% 'path',P     Look for the file FNAME in the folder P (default .)
% 'dock'       Dock figures within GUI
%
% Notes::
% - If no file extension is given in FNAME, .m is assumed.
% - If the executable statement has comments immediately afterward (no blank lines)
%   then the pause occurs after those comments are displayed.
% - A simple '-' prompt indicates when the script is paused, hit enter.
% - If the function cprintf() is in your path, the display is more
%   colorful, you can get this file from MATLAB Central.
% - If the file has a lot of boilerplate, you can skip over and not display
%   it by giving the 'begin' option which searchers for the first line
%   starting with %%begin and commences execution at the line after that.
%
% See also eval.

% Copyright (C) 1993-2014, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for MATLAB (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB 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 Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com

function runscript(fname, varargin)

    opt.path = [];
    opt.delay = [];
    opt.begin = false;
    opt.cdelay = 0;
    opt.dock = false;

    opt = tb_optparse(opt, varargin);

    close all

    prevDockStatus = get(0,'DefaultFigureWindowStyle');
    if opt.dock
        set(0,'DefaultFigureWindowStyle','docked');
    else
        set(0,'DefaultFigureWindowStyle','normal');
    end

    if ~isempty(opt.path)
        fname = fullfile(opt.path, [fname '.m']);
    else
        fname = [fname '.m'];
    end

    fp = fopen(fname, 'r');

    clc
    fprintf('--- runscript <-- %s\n', fname);

    running = false;
    shouldPause = false;
    savedText = [];

    if ~opt.begin
        running = true;
    end

    lineNum = 1;

    % stashMode
    %  0 normal
    %  1 loop
    %  2 continuation
    continMode = false;
    compoundDepth = 0;

    while 1
        % get the next line from the file, bail if EOF
        line = fgetl(fp);
        if line == -1
            break
        end
        lineNum = lineNum+1;

        % logic to skip lines until we see one beginning with %%begin
        if ~running
            if strcmp(line, '%%begin')
                running = true;
            else
                continue;
            end
        end;

        if length(strtrim(line)) == 0
            % blank line
            fprintf('\n');
            if shouldPause
                scriptwait(opt);
                shouldPause = false;
            end
            continue
        elseif startswith(strtrim(line), '%')
            % line was a comment
            disp(line)
            pause(opt.cdelay)  % optional comment delay
            continue;
        else
            if shouldPause
                scriptwait(opt);
                shouldPause = false;
            end
        end

        % if the start of a loop, stash the text for now
        if startswith(line, 'for') || startswith(line, 'while') || startswith(line, 'if')
            % found a compound block, don't eval it until we get to the end
            compoundDepth = compoundDepth + 1;
        end
        % if the statement has a continuation
        if endswith(line, '...')  && compoundDepth == 0
            % found a compound statement, don't eval it until we get to the end
            continMode = true;
        end

        if compoundDepth == 0 && ~continMode
            prompt = '>> ';
        else
            prompt = '';
        end

        % display the line with a pretend MATLAB prompt
        if exist('cprintf')
            cprintf('blue', '%s%s\n', prompt, line)
        else
            fprintf('%s', prompt); disp(line)
        end

        if compoundDepth > 0 || continMode
            % we're in stashing mode
            savedText = strcat(savedText, '\n', line);
        end

        if compoundDepth > 0 && startswith(line, 'end')
            % the compound block is fully unnested

            compoundDepth = compoundDepth - 1;
            if compoundDepth == 0
                evalSavedText(savedText, lineNum);
                savedText = '';
                shouldPause = true;
            end
            continue

        elseif continMode && ~endswith(line, '...')
            % no longer in continuation mode

            evalSavedText(savedText, lineNum);
            savedText = '';
            continMode = false;
            shouldPause = true;
            continue
        end

        if compoundDepth == 0 && ~continMode
            % it's a simple executable statement, execute it
            fprintf(' \n');
            evalSavedText(line, lineNum);
            shouldPause = true;
        end
    end
    fprintf('------ done --------\n');
    % restore the docking mode if we set it
    set(0,'DefaultFigureWindowStyle', prevDockStatus)
end

    function evalSavedText(text, lineNum)
        if length(strtrim(text)) == 0
            return
        end

        text = sprintf(text);

        try
            evalin('base', text);
        catch m
            fprintf('error in script %s at line %d', lineNum);
            m.rethrow();
        end
    end

% delay or prompt according to passed options
function scriptwait(opt)
    if isempty(opt.delay)
        %a = input('-', 's');
        prompt = 'continue?';
        if exist('cprintf')
            cprintf('red', prompt); pause;
            for i=1:length(prompt)
                cprintf('text', '\b');
            end
        else
            fprintf(prompt); pause;
            for i=1:length(prompt)
                fprintf('\b');
            end
        end
    else
        pause(opt.delay);
    end
end

% test if s2 is at the start of s1 (ignoring leading spaces)
function res = startswith(s1, s2)

    s1 = strtrim(s1);  % trim leading white space
    r = strfind(s1, s2);
    res = false;
    if ~isempty(r) && (r(1) == 1)
        res = true;
    end
end

% test if s2 is at the end of s1
function res = endswith(s1, s2)

    if length(s1) < length(s2)
        res = false;
    else
        n2 = length(s2)-1;
        res = strcmp(s1(end-n2:end), s2);
    end

end


function [res_map, scale_ind] = cal_scale(res_maps, scale_weights)

% this file selects the most confident scale
% Input:
%       res_maps      -  response maps
%       scale_weights - penalty weight of each scale
% Output:
%       res_map       - response map of the scale
%       scale_ind     - calculated scale index
% By Xin Li, 2017-12-2

% if num_scale == 1
%    res_map = res_maps;
%    scale_ind = 1;
%    return;
% end

num_scale = numel(scale_weights);
res_scale = bsxfun(@times, res_maps, reshape(scale_weights, 1,1, num_scale));

res = reshape(res_scale, [], num_scale);
res_max = max(res);

[~, scale_ind] = max(res_max);
res_map = res_maps(:,:, scale_ind);

end


% Change to your downloaded location
clear
addpath('C:\liblinear\matlab')
addpath('../training_code/');
addpath('../utilities/');
addpath('../../data extraction/');

%% load shared definitions and AU data
all_dataset_aus = [1, 2, 4, 6, 7, 10, 12, 15, 17, 23, 25, 26, 45];

% Set up the hyperparameters to be validated
hyperparams.c = 10.^(-8:0.5:4);
hyperparams.p = 10.^(-2);

hyperparams.validate_params = {'c', 'p'};

% Set the training function
svr_train = @svr_train_linear;

% Set the test function (the first output will be used for validation)
svr_test = @svr_test_linear;

BP4D_aus = [6, 10, 12, 14, 17];
UNBC_aus = [6, 7, 9, 12, 25, 26];
DISFA_aus = [1, 2, 4, 5, 6, 9, 12, 15, 17, 20, 25, 26];
Bosphorus_aus = [1, 2, 4, 5, 6, 7, 9, 10, 12, 14, 15, 17, 20, 23, 25, 26, 45];

for a=1:numel(all_dataset_aus)

    au = all_dataset_aus(a);

    train_samples = [];
    valid_samples = [];

    train_labels = [];
    valid_labels = [];

    % Keeping track which validation sample came from which dataset, as we
    % will be validating based on which hyperparam leads to best
    % performance on all datasets (mean F1)
    eval_ids = [];
    dataset_ids = {};
    vid_ids = {};
    success = [];

    if(~isempty(find(BP4D_aus == au, 1)))
        op = cd('../BP4D/');
        rest_aus = setdiff(BP4D_aus, au);
        shared_defs;
        % load the training and testing data for the current fold
        [train_samples_bp4d, train_labels_bp4d, ~, valid_samples_bp4d, valid_labels_bp4d, vid_ids_bp4d, ~, PC, means, scaling, success_devel] = Prepare_HOG_AU_data_generic_intensity(train_recs, devel_recs, au, BP4D_dir_int, hog_data_dir);

        ignore = valid_labels_bp4d == 9;

        valid_samples_bp4d = valid_samples_bp4d(~ignore, :);
        valid_labels_bp4d = valid_labels_bp4d(~ignore);
        vid_ids_bp4d = vid_ids_bp4d(~ignore);
        success_devel = success_devel(~ignore);

        train_samples = cat(1, train_samples, train_samples_bp4d);
        valid_samples = cat(1, valid_samples, valid_samples_bp4d);

        train_labels = cat(1, train_labels, train_labels_bp4d);
        valid_labels = cat(1, valid_labels, valid_labels_bp4d);
        vid_ids = cat(1, vid_ids, vid_ids_bp4d);

        success = cat(1, success, success_devel);

        if(isempty(eval_ids))
           eval_ids = ones(size(valid_labels_bp4d,1), 1);
        end

        clear 'train_samples_bp4d' 'train_labels_bp4d' 'valid_samples_bp4d' 'valid_labels_bp4d'

        dataset_ids = cat(1, dataset_ids, {'BP4D'});

        cd(op);

    end

   if(~isempty(find(Bosphorus_aus == au, 1)))
        op = cd('../Bosphorus/');
        rest_aus = setdiff(DISFA_aus, au);
        shared_defs;

        % make sure validation data's labels are balanced
        [users_train, users_valid_bosph] = get_balanced_fold(Bosphorus_dir, all_recs, au, 1/3, 1);

        % need to split the rest
        [train_samples_bosph, train_labels_bosph, valid_samples_bosph, valid_labels_bosph, ~, PC, means, scaling, valid_ids, valid_success] = Prepare_HOG_AU_data(users_train, users_valid_bosph, au, rest_aus, Bosphorus_dir, hog_data_dir);

        % As there are only a few Bosphorus images (it being an image dataset)
        % we oversample it quite a bit
        train_samples_bosph = repmat(train_samples_bosph, 10, 1);
        train_labels_bosph = repmat(train_labels_bosph, 10, 1);

        train_samples = cat(1, train_samples, train_samples_bosph);
        valid_samples = cat(1, valid_samples, valid_samples_bosph);

        train_labels = cat(1, train_labels, train_labels_bosph);
        valid_labels = cat(1, valid_labels, valid_labels_bosph);

        vid_ids = cat(1, vid_ids, valid_ids);

        success = cat(1, success, valid_success);

        if(isempty(eval_ids))
           eval_ids = ones(size(valid_labels_bosph, 1), 1);
        else
           eval_ids = cat(1, eval_ids, (eval_ids(end)+1)*ones(size(valid_labels_bosph, 1), 1));
        end

        clear 'train_samples_bosph' 'train_labels_bosph' 'valid_samples_bosph' 'valid_labels_bosph'
        dataset_ids = cat(1, dataset_ids, {'Bosphorus'});
        cd(op);

    end

    if(~isempty(find(DISFA_aus == au, 1)))
        op = cd('../DISFA/');
        rest_aus = setdiff(DISFA_aus, au);
        shared_defs;

        % make sure validation data's labels are balanced
        [users_train, users_valid_disfa] = get_balanced_fold(DISFA_dir, users, au, 1/3, 1);

        % need to split the rest
        [train_samples_disf, train_labels_disf, valid_samples_disf, valid_labels_disf, raw_disfa, PC, means, scaling, vid_ids_disfa, valid_success] = Prepare_HOG_AU_data_generic(users_train, users_valid_disfa, au, rest_aus, DISFA_dir, hog_data_dir);

        train_samples = cat(1, train_samples, train_samples_disf);
        valid_samples = cat(1, valid_samples, valid_samples_disf);

        train_labels = cat(1, train_labels, train_labels_disf);
        valid_labels = cat(1, valid_labels, valid_labels_disf);

        vid_ids = cat(1, vid_ids, vid_ids_disfa);

        success = cat(1, success, valid_success);

        if(isempty(eval_ids))
           eval_ids = ones(size(valid_labels_disf,1), 1);
        else
           eval_ids = cat(1, eval_ids, (eval_ids(end)+1)*ones(size(valid_labels_disf,1), 1));
        end

        clear 'train_samples_disf' 'train_labels_disf' 'valid_samples_disf' 'valid_labels_disf'
        dataset_ids = cat(1, dataset_ids, {'DISFA'});
        cd(op);

    end

    if(~isempty(find(UNBC_aus == au, 1)))
        op = cd('../UNBC/');
        rest_aus = setdiff(UNBC_aus, au);
        shared_defs;

        [users_train, users_valid_unbc] = get_balanced_fold(UNBC_dir, all_recs, au, 1/3, 1);

        % load the training and testing data for the current fold
        [train_samples_unbc, train_labels_unbc, valid_samples_unbc, valid_labels_unbc, ~, PC, means, scaling, vid_ids_unbc, success_devel] = Prepare_HOG_AU_data(users_train, users_valid_unbc, au, rest_aus, UNBC_dir, features_dir);

        train_samples = cat(1, train_samples, train_samples_unbc);
        valid_samples = cat(1, valid_samples, valid_samples_unbc);

        train_labels = cat(1, train_labels, train_labels_unbc);
        valid_labels = cat(1, valid_labels, valid_labels_unbc);

        vid_ids = cat(1, vid_ids, vid_ids_unbc);

        success = cat(1, success, success_devel);

        if(isempty(eval_ids))
           eval_ids = ones(size(valid_labels_unbc,1), 1);
        else
           eval_ids = cat(1, eval_ids, (eval_ids(end)+1)*ones(size(valid_labels_unbc,1), 1));
        end

        clear 'train_samples_unbc' 'train_labels_unbc' 'valid_samples_unbc' 'valid_labels_unbc'
        dataset_ids = cat(1, dataset_ids, {'UNBC'});
        cd(op);

    end

    train_samples = sparse(train_samples);
    dataset_ids
    %% Cross-validate here

    name = sprintf('mat_models/AU_%d_static_intensity.mat', au);
    load(name, 'model');
    model_reg = model;

    valid_all_reg = valid_samples * model_reg.w(1:end-1)' + model_reg.w(end);
    train_all_reg = train_samples * model_reg.w(1:end-1)' + model_reg.w(end);

    name = sprintf('mat_models/AU_%d_static.mat', au);
    load(name, 'model');
    model_class = model;
    valid_all_class = valid_samples * model_class.w(1:end-1)' + model_class.w(end);
    train_all_class = train_samples * model_class.w(1:end-1)' + model_class.w(end);

    valid_samples_p = cat(2, valid_all_reg, valid_all_class);
    train_samples_p = sparse(cat(2, train_all_reg, train_all_class));

    %%
    hyperparams.eval_ids = eval_ids;
    hyperparams.vid_ids = vid_ids;
    hyperparams.valid_samples = valid_samples_p;
    hyperparams.success = success;
    hyperparams.valid_labels = valid_labels;

    [ best_params, ~ ] = validate_grid_search_no_par(svr_train, svr_test, false, train_samples_p, train_labels, valid_samples_p, valid_labels, hyperparams);
    model_fuse = svr_train(train_labels, train_samples_p, best_params);

    % Fust the regressor and classifier based on their corresponding
    % weights
    p = model_fuse.w;
    model = model_reg;
    model.w = model_reg.w * p(1)  + model_class.w * p(2);
    model.w(end) = model.w(end) + p(3);
    %%
    name = sprintf('mat_models/AU_%d_static_intensity_comb.mat', au);

    [~, predictions_all] = svr_test(valid_labels, valid_samples, model);

    eval_ids_uq = unique(eval_ids)';
    cccs = [];
    for i=eval_ids_uq
        [ ~, ~, ~, ccc_c, ~, ~ ] = evaluate_regression_results( predictions_all(eval_ids==i), valid_labels(eval_ids==i));
        cccs = cat(2, cccs, ccc_c);
    end

    mean_ccc = mean(cccs);
    %%
    save(name, 'model', 'mean_ccc', 'mean_ccc', 'cccs', 'predictions_all', 'valid_labels', 'eval_ids', 'dataset_ids');

    % Write out the model
    name = sprintf('regressors/AU_%d_static_intensity_comb.dat', au);

    w = model.w(1:end-1)';
    b = model.w(end);

    svs = bsxfun(@times, PC, 1./scaling') * w;

    write_lin_svr(name, means, svs, b);

    clear 'train_samples' 'train_labels' 'valid_samples' 'valid_labels'
end


function [ pairwise ] = load_pairwise_data( p )

pairwise = struct();
pairwise.graph = [];
nextreg = p.nextreg;

if nextreg
    load(p.pairwise_relations, 'means', 'std_devs', 'graph');
    std_devs = permute(std_devs, [3 4 1 2]);
    means = permute(means, [3 4 1 2]);
    pairwise.graph = graph;
    pairwise.means = means;
    pairwise.std_devs = std_devs;
end

end


% eeg_eegrej() - reject porition of continuous data in an EEGLAB
%                dataset
%
% Usage:
%   >> EEGOUT = eeg_eegrej( EEGIN, regions );
%
% Inputs:
%   INEEG      - input dataset
%   regions    - array of regions to suppress. number x [beg end]  of
%                regions. 'beg' and 'end' are expressed in term of points
%                in the input dataset. Size of the array is
%                number x 2 of regions.
%
% Outputs:
%   INEEG      - output dataset with updated data, events latencies and
%                additional boundary events.
%
% Author: Arnaud Delorme, CNL / Salk Institute, 8 August 2002
%
% See also: eeglab(), eegplot(), pop_rejepoch()

% Copyright (C) 2002 Arnaud Delorme, Salk Institute, arno@salk.edu
%
% 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 should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

function [EEG, com] = eeg_eegrej( EEG, regions);

com = '';
if nargin < 2
	help eeg_eegrej;
	return;
end;
if nargin<3
    probadded = [];
end
if isempty(regions)
	return;
end;

% For AMICA probabilities...Temporarily add model probabilities as channels
%-----------------------------------------------------
if isfield(EEG.etc, 'amica') && ~isempty(EEG.etc.amica) && isfield(EEG.etc.amica, 'v_smooth') && ~isempty(EEG.etc.amica.v_smooth) && ~isfield(EEG.etc.amica,'prob_added')
    if isfield(EEG.etc.amica, 'num_models') && ~isempty(EEG.etc.amica.num_models)
        if size(EEG.data,2) == size(EEG.etc.amica.v_smooth,2) && size(EEG.data,3) == size(EEG.etc.amica.v_smooth,3) && size(EEG.etc.amica.v_smooth,1) == EEG.etc.amica.num_models

            EEG = eeg_formatamica(EEG);
            %-------------------------------------------

            [EEG com] = eeg_eegrej(EEG,regions);

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

            EEG = eeg_reformatamica(EEG);
            EEG = eeg_checkamica(EEG);
            return;
        else
            disp('AMICA probabilities not compatible with size of data, probabilities cannot be epoched')
            disp('Load AMICA components before extracting epochs')
            disp('Resuming rejection...')
        end
    end

end
% ------------------------------------------------------

if isfield(EEG.event, 'latency'),
   	 tmpevent = EEG.event;
     tmpalllatencies = [ tmpevent.latency ];
else tmpalllatencies = [];
end;

% handle regions from eegplot
% ---------------------------
if size(regions,2) > 2, regions = regions(:, 3:4); end;

[EEG.data EEG.xmax tmpalllatencies boundevents] = eegrej( EEG.data, ...
												  regions, EEG.xmax-EEG.xmin, tmpalllatencies);
if isfield(EEG,'srcpot') && ~isempty(EEG.srcpot) && ~isscalar(EEG.srcpot)
    [EEG.srcpot EEG.xmax garbage boundevents] = eegrej( EEG.srcpot, regions, EEG.xmax-EEG.xmin, []);
end
oldEEGpnts = EEG.pnts;
EEG.pnts   = size(EEG.data,2);
EEG.xmax   = EEG.xmax+EEG.xmin;

% add boundary events
% -------------------
if ~isempty(boundevents) % boundevent latencies will be recomputed in the function below
    [ EEG.event ] = eeg_insertbound(EEG.event, oldEEGpnts, regions);
    EEG = eeg_checkset(EEG, 'eventconsistency');
end;

com = sprintf('%s = eeg_eegrej( %s, %s);', inputname(1), inputname(1), vararg2str({ regions }));
return;


function [ hdr ] = Load_BV_hdr( file )
%LOAD_BP_HDR Summary of this function goes here
%   Detailed explanation goes here
global BMI
[fid, message]=fopen(fullfile([file '.vhdr']));
if fid == -1
    [fid, message] = fopen(fullfile(pathname, lower(filename)));
    if fid == -1
        error(message)
    end;
end

hdr.DataFile= getEntry(fid, 'DataFile=', 0, [file '.eeg']);
getEntry(fid, '[Common Infos]');
hdr.DataFile= getEntry(fid, 'DataFile=', 0, [file '.eeg']);
hdr.MarkerFile= getEntry(fid, 'MarkerFile=', 0, [file '.vmrk']);
hdr.DataFormat= getEntry(fid, 'DataFormat=', 0);
hdr.DataOrientation= getEntry(fid, 'DataOrientation=', 0);
hdr.DataType= getEntry(fid, 'DataType=', 0);
getEntry(fid, '[Common Infos]');
hdr.NumberOfChannels= str2num(getEntry(fid, 'NumberOfChannels='));
hdr.DataPoints= getEntry(fid, 'DataPoints=', 0, '0');
getEntry(fid, '[Common Infos]');
hdr.SamplingInterval= str2num(getEntry(fid, 'SamplingInterval='));

getEntry(fid, '[Binary Infos]');
hdr.BinaryFormat= getEntry(fid, 'BinaryFormat=', 0);
hdr.UseBigEndianOrder= getEntry(fid, 'UseBigEndianOrder=', 0);

getEntry(fid, '[Channel Infos]');
hdr.chan=cell(1,hdr.NumberOfChannels);
for chan=1:hdr.NumberOfChannels
    temp=getEntry(fid,['Ch' num2str(chan) '='],0);
    chInfo=strsplit(temp,',');
    chInfo_=chInfo(~cellfun('isempty',chInfo));
    hdr.ChannelResolution(chan)=str2num(chInfo_{2});
    hdr.chan{chan}=chInfo_{1};
end

hdr.fs= 1000000/hdr.SamplingInterval;
%make a check if hdr.fs is a whole number
if(hdr.fs ~= round(hdr.fs))
  warning('file_readBVheader: hdr.fs was not a whole number: %f',hdr.fs);
  hdr.fs= round(hdr.fs);
  hdr.SamplingInterval=1000000/hdr.fs;
end
fclose(fid);
end

function [entry, str]= getEntry(fid, keyword, mandatory, default_value)

if ~exist('mandatory','var'), mandatory=1; end
if ~exist('default_value','var'), default_value=[]; end
entry= 1;

if keyword(1)=='[',
    fseek(fid, 0, 'bof');
end
ok= 0;
while ~ok && ~feof(fid),
    str= fgets(fid);
    ok= strncmp(keyword, str, length(keyword));
end
if ~ok,
    if mandatory,
        error(sprintf('keyword <%s> not found', keyword));
    else
        entry= default_value;
        return;
    end
end
if keyword(end)=='=',
    entry= deblank(str(length(keyword)+1:end));
end

end