classdef prtFeatSel < prtAction
    % prtFeatSel

    properties (SetAccess = protected)

        isSupervised = true   %True
        isCrossValidateValid = true; % False
    end

    methods
        function obj = prtFeatSel()
            % As an action subclass we must set the properties to reflect
            % our dataset requirements
            obj.classTrain = 'prtDataSetStandard';
            obj.classRun = 'prtDataSetStandard';
            obj.classRunRetained = true;
        end
    end
end


function [ fn ] = getBatchWrapper_Remat_rgbdiff(opts, numThreads, trainopts)

fn = @(imdb,batch, moreopts) getBatch(imdb,batch,opts,numThreads, trainopts, moreopts) ;
end

% -------------------------------------------------------------------------
function [im,labels] = getBatch(imdb, batch, opts, numThreads, trainopts, moreopts)
% -------------------------------------------------------------------------
opts.nFrames = imdb.images.nFrames(batch);

images = cell(1,numel(opts.nFrames));
labels = imdb.images.label(batch) ;
for k = 1:numel(opts.nFrames)
  images{k}  = strcat([imdb.images.name{batch(k)} filesep], images{k} ) ;
%   images{k}  = strcat([imdb.images.name{batch(k)}(1:end-4) filesep], images{k} ) ;
end
if ~isempty(moreopts) || nargin < 6
  for f = fieldnames(moreopts)'
    f = char(f) ;
    trainopts.(f) = moreopts.(f);
  end
end

opts.nFramesPerVid = trainopts.nFramesPerVid;
opts.numAugments = trainopts.numAugments;
opts.frameSample = trainopts.frameSample;
opts.augmentation =  trainopts.augmentation;

if isfield(trainopts, 'temporalStride')
  opts.temporalStride =  trainopts.temporalStride(randi(numel(trainopts.temporalStride))) ; % shuffle;
end
if isfield(trainopts, 'nFrameStack')
  opts.nFrameStack = trainopts.nFrameStack;
else
  opts.nFrameStack = trainopts.nFramesPerVid;
end
if isfield(trainopts, 'keepFramesDim')
  keepFramesDim = trainopts.keepFramesDim;
else
  keepFramesDim = false;
end
if isfield(trainopts, 'cheapResize')
  opts.cheapResize =  trainopts.cheapResize;
end

if isfield(trainopts, 'prefetch')
    opts.prefetch = trainopts.prefetch;
end
if isfield(trainopts, 'frameList')
    opts.frameList = trainopts.frameList;
end

im = cnn_ucf101_get_im_diff_batch(images, opts, ...
                            'numThreads', numThreads, ...
                          'flowDir', imdb.flowDir, ...
                          'imageDir', imdb.imageDir) ;

if iscell(im), return; end

if nargout == 1 % to work with dagnn & simplenn code
  if ndims(im) > 4 && ~keepFramesDim
    sz = size(im);
    nFrames = sz(5:end);
    im = permute(im, [1 2 3 5 4]);
    im = reshape(im, sz(1), sz(2), sz(3), []);
  end
  im = {'input', im(:,:,end-2:end,:,:), 'label', labels, 'input_flow', im(:,:,1:end-3,:,:)} ;
end

end


%% SO3Kernel


function success = test_mp_opt_model(verbose, exit_on_fail)
%TEST_MP_OPT_MODEL  Run all MP-Opt-Model tests.
%   TEST_MP_OPT_MODEL
%   TEST_MP_OPT_MODEL(VERBOSE)
%   TEST_MP_OPT_MODEL(VERBOSE, EXIT_ON_FAIL)
%   SUCCESS = TEST_MP_OPT_MODEL(...)
%
%   Runs all of the MP-Opt-Model tests. If VERBOSE is true (false by default),
%   it prints the details of the individual tests. If EXIT_ON_FAIL is true
%   (false by default), it will exit MATLAB or Octave with a status of 1
%   unless T_RUN_TESTS returns ALL_OK.
%
%   See also T_RUN_TESTS.

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

if nargin < 2
    exit_on_fail = 0;
    if nargin < 1
        verbose = 0;
    end
end

tests = {};

%% MP-Opt-Model tests
tests{end+1} = 't_have_fcn';
tests{end+1} = 't_nested_struct_copy';
tests{end+1} = 't_nleqs_master';
tests{end+1} = 't_pnes_master';
tests{end+1} = 't_qps_master';
tests{end+1} = 't_miqps_master';
tests{end+1} = 't_nlps_master';
tests{end+1} = 't_opt_model';
tests{end+1} = 't_om_solve_leqs';
tests{end+1} = 't_om_solve_nleqs';
tests{end+1} = 't_om_solve_pne';
tests{end+1} = 't_om_solve_qps';
tests{end+1} = 't_om_solve_miqps';
tests{end+1} = 't_om_solve_nlps';

%% run the tests
all_ok = t_run_tests( tests, verbose );

%% handle success/failure
if exit_on_fail && ~all_ok
    exit(1);
end
if nargout
    success = all_ok;
end


function V = load_images(params)
  sequence_name = params.sequences_name(params.current_sequence).name;
  path = fullfile(params.sequences_path,sequence_name,params.sequences_format);
  list = dir(fullfile(path,params.sequences_ext));
  names = char({list.name}');
  frames = size(names,1);
  V = [];
  for i = 1:frames
    if(mod(i,10) == 0) fprintf('%d ',i); end
    I = imread(fullfile(path,names(i,:)));
    I = im2double(I);
    V(:,:,:,i) = I;
  end
  disp(i);
end


function expdirs = makeMovies(rootdir,varargin)

[doforce,dosoftlink,~,rotatesideview] = ...
  myparse(varargin,'doforce',false,...
  'dosoftlink',false,'rotatefrontview',0,'rotatesideview',0);
% function makeMovies(rootdir)
% makes a jaaba folder for all the avi's nested in the rootdir.

expdirs = {};

dd = dir(rootdir);
for ndx =1:numel(dd)
  if strcmp(dd(ndx).name(1),'.'), continue; end
  curd = fullfile(rootdir,dd(ndx).name);
  if isdir(curd)

    if exist([curd '.avi'],'file') && exist(fullfile(curd,'movie.avi'),'file'),
      continue;
    else
      expdirs1 = makeMovies(curd);
      expdirs = [expdirs,expdirs1]; %#ok<AGROW>
    end

  else

    [~,fname,ext] = fileparts(dd(ndx).name);
    if strcmpi(ext,'.avi')

      if ismember(dd(ndx).name,{'movie.avi','movie_sde.avi','movie_frt.avi'}),
        fprintf('Not creating directory for %s, %s is a reserved name.\n',fullfile(rootdir,dd(ndx).name),dd(ndx).name);
        continue;
      end

      m = regexp(dd(ndx).name,'_front_','once');
      if ~isempty(m),
        fprintf('%s is a front-facing movie, not creating a directory for it.\n',fullfile(rootdir,dd(ndx).name));
        continue;
      end

      curf  = fullfile(rootdir,fname);
      if ~exist(curf,'dir')
        mkdir(curf);
      end
%       scurd = regexprep(curd,' ','\\ ');
%       scurf = regexprep(curf,' ','\\ ');
      if exist(fullfile(curf,'movie.avi'),'file') && doforce,
        delete(fullfile(curf,'movie.avi'));
      end
      if ~exist(fullfile(curf,'movie.avi'),'file'),
        try
          if rotatesideview ~= 0,
            rotatemov(curd,fullfile(curf,'movie.avi'),rotatesideview);
          else
            if isunix && ~ismac && nargin > 1 && dosoftlink,
              fprintf('Soft-linking %s to %s...\n',curd,fullfile(curf,'movie.avi'));
              [~,n,e] = fileparts(curd);
              % use relative links so that maybe this works when mounting from windows/mac?
              n = [n,e];
              syscmd = sprintf('ln -s ''../%s'' ''%s/movie.avi''',n,curf);
              unix(syscmd);
            else
              fprintf('Copying %s to %s...\n',curd,fullfile(curf,'movie.avi'));
              copyfile(curd,fullfile(curf,'movie.avi'));
            end
          end
        catch ME,
          fprintf('Could not copy video file for %s (%s)\n',curf,ME.message);
          continue;
        end
      else
        fprintf('%s exists, not re-copying it.\n',fullfile(curf,'movie.avi'));
      end
      if ~exist(fullfile(curf,'trx.mat'),'file')
        try
          fprintf('Generating trx file %s...\n',fullfile(curf,'trx.mat'));
          [~,nframes,~,~] = get_readframe_fcn(fullfile(curf,'movie.avi'));
          T.trx = genTrack(nframes,[640 480]);
          save(fullfile(curf,'trx.mat'),'-struct','T');
        catch ME,
          fprintf('Could not create trx file for %s (%s)\n',curf,ME.message);
          continue;
        end
      else
        fprintf('Trx file exists for %s, not regenerating\n',curf);
      end
      expdirs{end+1} = curf; %#ok<AGROW>
    end

  end

end


% PrintSegyFormatRevsisionNumber: Prints/returns the SEGY format revision number
%
% Call:
%     Revision=PrintSegyFormatRevsisionNumber(SegyHeader);
%     Revision=PrintSegyFormatRevsisionNumber(SegyHeader,vlevel);
%

function Revision=PrintSegyFormatRevsisionNumber(SegyHeader,vlevel);
if nargin<2
    vlevel=0;
end
Revision=str2num(dec2base(SegyHeader.SegyFormatRevisionNumber,16))/100;
SegymatVerbose(sprintf('%s: Using SEG Y revision %3.2f',mfilename,Revision),vlevel)


function aedat = ImportAedatDataVersion3(aedat)
%{
This is a sub-function of importAedat - it process the data where the aedat
file format is determined to be 3.x
The .aedat file format is documented here:
http://inilabs.com/support/software/fileformat/
This function is based on a combination of the loadaerdat function and
sensor-specific address interpretation functions.
There is a single input "info", a structure with the following
fields:
	- beginningOfDataPointer - Points to the byte before the beginning of the
		data
	- fileHandle - handle of the open aedat file in question
	- fileFormat - indicates the version of the aedat file format - should
		be 3.xx
	- startTime (optional) - if provided, any data with a timeStamp lower
		than this will not be returned.
	- endTime (optional) - if provided, any data with a timeStamp higher than
		this time will not be returned.
	- startPacket (optional) Any packets with a lower count that this will not be returned.
	- endPacket (optional) Any packets with a higher count that this will not be returned.
	- modPacket (optional) For sparse sampling of a file,
        packets are imported if mod(packetNumber,modPacket) = 0
	- source - a string containing the name of the chip class from
		which the data came. Options are:
		- dvs128
		- davis240a
		- davis240b
		- davis240c
		- davis128mono
		- davis128rgb
		- davis208rgbw
		- davis208mono
		- davis346rgb
		- davis346mono
		- davis346bsi
		- davis640rgb
		- davis640mono
		- hdavis640mono
		- hdavis640rgbw
		- das1
		- file
		- network
	- dataTypes (optional) cellarray. If present, only data types specified
		in this cell array are returned. Options are:
		special; polarity; frame; imu6; imu9; sample; ear; config; 1dPoint;
		2dPoint; 3dPoint 4dPoint; dynapse

The output is a structure with 2 fields.
	- info - the input structure, embelished with other data
	- data a structure which contains one structure for each type of
		data present. These structures are named according to the type of
		data; the options are:
		- special
		- polarity
		- frame
		- imu6
		- sample
		- ear
		Other data types supported in aedat3.0 are not implemented
		because no chip class currently implements them.
		Within each of these structures, there are typically a set of column
			vectors containing timeStamp, a valid bit and then other data fields,
			where each vector has the same number of elements.
			There are some exceptionss to this.
			In detail the contents of these structures are:
		- special
			- valid (colvector bool)
			- timeStamp (colvector uint64)
			- address (colvector uint32)
		- polarity
			- valid (colvector bool)
			- timeStamp (colvector uint64)
			- x (colvector uint16)
			- y (colvector uint16)
			- polarity (colvector bool)
		- frame
			- valid (bool)
			- roiId (uint8)
			- colorChannel (uint8)
			- colorFilter (uint8)
			- frame timeStamp start (uint64)
			- frame timeStamp end (uint64)
			- timeStampExposureStart (uint64)
			- timeStampExposureEnd (uint64)
			- samples (cellArray, with one cell for each frame; cells
				contain a matrix of uint16 row*col*chn, where row is the number of rows,
				col is the number of columns, and chn is the number of
				(colour) channels. Where frames have only one channel, the
				third dimension is squeezed out.
			- xLength (uint32)
			- yLength (uint32)
			- xPosition (uint32)
			- yPosition (uint32)
		- imu6
			- valid (colvector bool)
			- timeStamp (colvector uint64)
			- accelX (colvector single)
			- accelY (colvector single)
			- accelZ (colvector single)
			- gyroX (colvector single)
			- gyroY (colvector single)
			- gyroZ (colvector single)
			- temperature (colvector single)
		- sample
			- valid (colvector bool)
			- timeStamp (colvector uint64)
			- sampleType (colvector uint8)
			- sample (colvector uint32)
		- ear
			- valid (colvector bool)
			- timeStamp (colvector uint64)
			- position (colvector uint8)
			- channel (colvector uint16)
			- neuron (colvector uint8)
			- filter (colvector uint8)

Implementation: There is an efficient implementation of startPacket and
EndPacket, since the correct file locations to read from can be determined
in advance.
There are two possibilities for handling startTime and endTime; one is with
strict capture of events within the prescribed time window. The other is a
loose interpretation with capture of all events whose packets start within
the prescribed time window. It is much more efficient to implement this
second approach, and nevertheless allows a calling function to iterate
through all the data in bite-sized chunks.
There is a switch info.strictTime - if this is present and
true then the strict time approach is used, otherwise the packet-based time
approach is used. In the strict approach, data must be accumulated from the
beginning of the file and then cut off once packets' first timestamp is
greater than endTime. In the strict approach, frames are considered part of
the time window if the time which is half way between exposure start and
exposure end is within the time window.
2016_06_27 Strict time handling is not implemented yet.
Since there is no way to know in advance how big the data vectors must be,
the data vectors/matrices are started off when they are needed
and are grown by a factor of 2 each time they need to be enlarged.
At the end of the run they are clipped to the correct size.
%}

dbstop if error

info = aedat.info;
importParams = aedat.importParams;
fileHandle = importParams.fileHandle;

% Check the startEvent and endEvent parameters
if isfield(importParams, 'startPacket')
    startPacket = importParams.startPacket;
else
	startPacket = 1;
end

if isfield(importParams, 'endPacket')
	endPacket = importParams.endPacket;
else
	endPacket = inf;
end

if startPacket > endPacket
	error([	'The startPacket parameter is ' num2str(startPacket) ...
		', but the endPacket parameter is ' num2str(endPacket) ]);
end
if isfield(importParams, 'startEvent')
	error('The startEvent parameter is set, but range by events is not available for .aedat version 3.x files')
end
if isfield(importParams, 'endEvent')
	error('The endEvent parameter is set, but range by events is not available for .aedat version 3.x files')
end
if isfield(importParams, 'startTime')
    startTime = importParams.startTime;
else
	startTime = 0;
end
if isfield(importParams, 'endTime')
    endTime = importParams.endTime;
else
	endTime = inf;
end
if startTime > endTime
	error([	'The startTime parameter is ' num2str(startTime) ...
		', but the endTime parameter is ' num2str(endTime) ]);
end
% By default, throw away timeStampFrameStart/End,
% renaming timeStampExposureStart/End to timeStampStart/End
if isfield(importParams, 'simplifyFrameTimeStamps')
  simplifyFrameTimeStamps = importParams.simplifyFrameTimeStamps;
else
  simplifyFrameTimeStamps = true;
end

% By default, throw away the valid flags,
% and any events which are set as invalid.
if isfield(importParams, 'validOnly')
  validOnly = importParams.validOnly;
else
  validOnly = true;
end

% By default, do not skip any packets.
if isfield(importParams, 'modPacket')
  modPacket = importParams.modPacket;
else
  modPacket = 1;
end

%By default, import the full data, rather than just indexing the packets
if isfield(importParams, 'noData')
  noData = importParams.noData;
else
  noData = false;
end

% By default, import all data types
if isfield(importParams, 'dataTypes')
    allDataTypes = false;
    dataTypes = importParams.dataTypes;
else
    allDataTypes = true;
end

packetCount = 0;

% Has this file already been indexed in a previous pass?
if isfield(info, 'packetPointers')
	packetTypes = info.packetTypes;
	packetPointers = info.packetPointers;
	packetTimeStamps = info.packetTimeStamps;
elseif endPacket < inf
    packetTypes = ones(endPacket, 1, 'uint16');
    packetPointers = zeros(endPacket, 1, 'uint64');
    packetTimeStamps = zeros(endPacket, 1, 'uint64');
else
    packetTypes = ones(1000, 1, 'uint16');
    packetPointers = zeros(1000, 1, 'uint64');
    packetTimeStamps = zeros(1000, 1, 'uint64');
end

if noData == false
    % Create structures to hold the output data

    specialNumEvents	= 0;
    specialValid		= false(0); % initialising this tells the first pass
                                     % to set up the arrays with the size
                                     % necessary for the initial packet
    specialDataMask = hex2dec('7E');
    specialDataShiftBits = 1;

    polarityNumEvents	= 0;
    polarityValid		= false(0);
    polarityYMask = hex2dec('1FFFC');
    polarityYShiftBits = 2;
    polarityXMask = hex2dec('FFFE0000');
    polarityXShiftBits = 17;

    frameNumEvents	= 0;
    frameValid		= false(0);
    frameColorChannelsMask = hex2dec('E');
    frameColorChannelsShiftBits = 1;
    frameColorFilterMask = hex2dec('70');
    frameColorFilterShiftBits = 4;
    frameRoiIdMask = hex2dec('3F80');
    frameRoiIdShiftBits = 7;

    imu6NumEvents	= 0;
    imu6Valid		= false(0);

    sampleNumEvents	= 0;
    sampleValid		= false(0);

    earNumEvents	= 0;
    earValid		= false(0);

    point1DNumEvents = 0;
    point1DValid	= false(0);
    point1DTypeMask = hex2dec('FE');
    point1DTypeShiftBits = 1;

    point2DNumEvents = 0;
    point2DValid	= false(0);
    point2DTypeMask = hex2dec('FE');
    point2DTypeShiftBits = 1;

    point3DNumEvents = 0;
    point3DValid	= false(0);
    point3DTypeMask = hex2dec('FE');
    point3DTypeShiftBits = 1;
end

cellFind = @(string)(@(cellContents)(strcmp(string, cellContents)));

% Go back to the beginning of the data
fseek(fileHandle, info.beginningOfDataPointer, 'bof');

% If the file has been indexed or partially indexed, and there is a
% startPacket or startTime parameter, then jump ahead to the right place
if isfield(info, 'packetPointers')
    if startPacket > 1
        fseek(fileHandle, double(packetPointers(startPacket)), 'bof');
        packetCount = startPacket - 1;
    elseif startTime > 0
        targetPacketIndex = find(info.packetTimeStamps < startTime * 1e6, 1, 'last');
        if ~isempty(targetPacketIndex)
            fseek(fileHandle, double(packetPointers(targetPacketIndex)), 'bof');
            packetCount = targetPacketIndex - 1;
        end
    end
end

% If the file has already been indexed (PARTIAL INDEXING NOT HANDLED), and
% we are using modPacket to skip a proportion of the data, then use this
% flag to speed up the loop
modSkipping = isfield(info, 'packetPointers') && modPacket > 1;

while true % implement the exit conditions inside the loop - allows to distinguish between different types of exit
%% Headers
    % Read the header of the next packet
    packetCount = packetCount + 1;
    if modSkipping
        packetCount = ceil(packetCount / modPacket) * modPacket;
        fseek(fileHandle, double(packetPointers(packetCount)), 'bof');
    end
	header = uint8(fread(fileHandle, 28));

	if feof(fileHandle)
        packetCount = packetCount - 1;
		info.numPackets = packetCount;
		break
	end
	if length(packetTypes) < packetCount
		% Double the size of packet index arrays as necessary
		packetTypes		= [packetTypes;		ones(packetCount, 1, 'uint16') * 32768];
		packetPointers	= [packetPointers;	zeros(packetCount, 1, 'uint64')];
		packetTimeStamps	= [packetTimeStamps;	zeros(packetCount, 1, 'uint64')];
	end
	packetPointers(packetCount) = ftell(fileHandle) - 28;
	if mod(packetCount, 100) == 0
		disp(['packet: ' num2str(packetCount) '; file position: ' num2str(floor(ftell(fileHandle) / 1000000)) ' MB'])
	end
	if startPacket > packetCount || mod(packetCount, modPacket) > 0
		% Ignore this packet as its count is too low
		eventSize = typecast(header(5:8), 'int32');
		eventNumber = typecast(header(21:24), 'int32');
		fseek(fileHandle, eventNumber * eventSize, 'cof');
    elseif endPacket < packetCount
        packetCount = packetCount - 1;
		info.numPackets = packetCount;
        break
    else
		eventSize = typecast(header(5:8), 'int32');
		eventTsOffset = typecast(header(9:12), 'int32');
		eventTsOverflow = typecast(header(13:16), 'int32');
		%eventCapacity = typecast(header(17:20), 'int32');
		eventNumber = typecast(header(21:24), 'int32');
		%eventValid = typecast(header(25:28), 'int32');
		% Read the full packet
		numBytesInPacket = eventNumber * eventSize;
		packetData = uint8(fread(fileHandle, numBytesInPacket));
		% Find the first timestamp and check the timing constraints
		packetTimeStampOffset = uint64(eventTsOverflow) * uint64(2^31);
		mainTimeStamp = uint64(typecast(packetData (eventTsOffset + 1 : eventTsOffset + 4), 'int32')) + packetTimeStampOffset;
     	packetTimeStamps(packetCount) = mainTimeStamp;

        if mainTimeStamp > endTime * 1e6 && ...
                mainTimeStamp ~= hex2dec('7FFFFFFF') % This may be a timestamp reset - don't let it stop the import
            % Naively assume that the packets are all ordered correctly and finish
            packetCount = packetCount - 1;
            break
        end
        if startTime * 1e6 <= mainTimeStamp
			eventType = typecast(header(1:2), 'int16');
			packetTypes(packetCount) = eventType;

			%eventSource = typecast(data(3:4), 'int16'); % Multiple sources not handled yet

            if ~noData
    			% Handle the packet types individually:
    %% Special events
                if eventType == 0
                    if allDataTypes || any(cellfun(cellFind('special'), dataTypes))
                        % First check if the array is big enough
                        currentLength = length(specialValid);
                        if currentLength == 0
                            specialValid		= false(eventNumber, 1);
                            specialTimeStamp	= zeros(eventNumber, 1, 'uint64');
                            specialAddress		= zeros(eventNumber, 1, 'uint32');
                        else
                            while eventNumber > currentLength - specialNumEvents
                                specialValid		= [specialValid;		false(currentLength, 1)];
                                specialTimeStamp	= [specialTimeStamp;	zeros(currentLength, 1, 'uint64')];
                                specialAddress		= [specialAddress;		zeros(currentLength, 1, 'uint32')];
                                currentLength = length(specialValid);
                                %disp(['Special array resized to ' num2str(currentLength)])
                            end
                        end
                        % Iterate through the events, converting the data and
                        % populating the arrays
                        % TO DO - MATRICISE THIS COMPUTATION, FOLLOWING THE
                        % EXAMPLE IN POLARITY
                        for dataPointer = 1 : eventSize : numBytesInPacket % This points to the first byte for each event
                            specialNumEvents = specialNumEvents + 1;
                            specialValid(specialNumEvents) = mod(packetData(dataPointer), 2) == 1; %Pick off the first bit
                            specialTimeStamp(specialNumEvents) = packetTimeStampOffset + uint64(typecast(packetData(dataPointer + 4 : dataPointer + 7), 'int32'));
                            specialAddress(specialNumEvents) = uint8(bitshift(bitand(packetData(dataPointer), specialDataMask), -specialDataShiftBits));
                        end
                    end
    %% Polarity events
                elseif eventType == 1
                    if allDataTypes || any(cellfun(cellFind('polarity'), dataTypes))
                        % First check if the array is big enough
                        currentLength = length(polarityValid);
                        if currentLength == 0
                            polarityValid		= false(eventNumber, 1);
                            polarityTimeStamp	= zeros(eventNumber, 1, 'uint64');
                            polarityX			= zeros(eventNumber, 1, 'uint16');
                            polarityY			= zeros(eventNumber, 1, 'uint16');
                            polarityPolarity	= false(eventNumber, 1);
                        else
                            while eventNumber > currentLength - polarityNumEvents
                                polarityValid		= [polarityValid;		false(currentLength, 1)];
                                polarityTimeStamp	= [polarityTimeStamp;	zeros(currentLength, 1, 'uint64')];
                                polarityX			= [polarityX;			zeros(currentLength, 1, 'uint16')];
                                polarityY			= [polarityY;			zeros(currentLength, 1, 'uint16')];
                                polarityPolarity	= [polarityPolarity;	false(currentLength, 1)];
                                currentLength = length(polarityValid);
                                %disp(['Polarity array resized to ' num2str(currentLength)])
                            end
                        end
                        dataMatrix = reshape(packetData, [eventSize, eventNumber]);
                        dataTempTimeStamp = dataMatrix(5:8, :);
                        polarityTimeStamp(polarityNumEvents + (1 : eventNumber)) = packetTimeStampOffset + uint64(typecast(dataTempTimeStamp(:), 'int32'));
                        dataTempAddress = dataMatrix(1:4, :);
                        dataTempAddress = typecast(dataTempAddress(:), 'uint32');
                        polarityValid(polarityNumEvents + (1 : eventNumber)) = mod(dataTempAddress, 2) == 1; % Pick off the first bit
                        polarityPolarity(polarityNumEvents + (1 : eventNumber)) = mod(floor(dataTempAddress / 2), 2) == 1; % Pick out the second bit
                        polarityY(polarityNumEvents + (1 : eventNumber)) = uint16(bitshift(bitand(dataTempAddress, polarityYMask), -polarityYShiftBits));
                        polarityX(polarityNumEvents + (1 : eventNumber)) = uint16(bitshift(bitand(dataTempAddress, polarityXMask), -polarityXShiftBits));
                        polarityNumEvents = polarityNumEvents + eventNumber;
                    end
    %% Frames
                elseif eventType == 2
                    if allDataTypes || any(cellfun(cellFind('frame'), dataTypes))
                        % First check if the array is big enough
                        currentLength = length(frameValid);
                        if currentLength == 0
                            frameValid					= false(eventNumber, 1);
                            frameColorChannels			= zeros(eventNumber, 1, 'uint8');
                            frameColorFilter			= zeros(eventNumber, 1, 'uint8');
                            frameRoiId					= zeros(eventNumber, 1, 'uint8');
                            if simplifyFrameTimeStamps
                                frameTimeStampStart     = zeros(eventNumber, 1, 'uint64');
                                frameTimeStampEnd		= zeros(eventNumber, 1, 'uint64');
                            else
                                frameTimeStampFrameStart	= zeros(eventNumber, 1, 'uint64');
                                frameTimeStampFrameEnd		= zeros(eventNumber, 1, 'uint64');
                                frameTimeStampExposureStart = zeros(eventNumber, 1, 'uint64');
                                frameTimeStampExposureEnd	= zeros(eventNumber, 1, 'uint64');
                            end
                            frameXLength				= zeros(eventNumber, 1, 'uint16');
                            frameYLength				= zeros(eventNumber, 1, 'uint16');
                            frameXPosition				= zeros(eventNumber, 1, 'uint16');
                            frameYPosition				= zeros(eventNumber, 1, 'uint16');
                            frameSamples				= cell(eventNumber, 1);
                        else
                            while eventNumber > currentLength - frameNumEvents
                                frameValid					= [frameValid;                  false(currentLength, 1)];
                                frameColorChannels			= [frameColorChannels;			zeros(currentLength, 1, 'uint8')];
                                frameColorFilter			= [frameColorFilter;			zeros(currentLength, 1, 'uint8')];
                                frameRoiId					= [frameRoiId;					zeros(currentLength, 1, 'uint8')];
                                if simplifyFrameTimeStamps
                                    frameTimeStampStart	= [frameTimeStampStart;         zeros(currentLength, 1, 'uint64')];
                                    frameTimeStampEnd		= [frameTimeStampEnd;		zeros(currentLength, 1, 'uint64')];
                                else
                                    frameTimeStampFrameStart	= [frameTimeStampFrameStart;	zeros(currentLength, 1, 'uint64')];
                                    frameTimeStampFrameEnd		= [frameTimeStampFrameEnd;		zeros(currentLength, 1, 'uint64')];
                                    frameTimeStampExposureStart = [frameTimeStampExposureStart; zeros(currentLength, 1, 'uint64')];
                                    frameTimeStampExposureEnd	= [frameTimeStampExposureEnd;	zeros(currentLength, 1, 'uint64')];
                                end
                                frameXLength				= [frameXLength;				zeros(currentLength, 1, 'uint16')];
                                frameYLength				= [frameYLength;				zeros(currentLength, 1, 'uint16')];
                                frameXPosition				= [frameXPosition;				zeros(currentLength, 1, 'uint16')];
                                frameYPosition				= [frameYPosition;				zeros(currentLength, 1, 'uint16')];
                                frameSamples				= [frameSamples;				cell(currentLength, 1)];
                                currentLength = length(frameValid);
                                %disp(['Frame array resized to ' num2str(currentLength)])
                            end
                        end

                        % Iterate through the events, converting the data and
                        % populating the arrays
                        for dataPointer = 1 : eventSize : numBytesInPacket % This points to the first byte for each event
                            frameNumEvents = frameNumEvents + 1;
                            frameValid(frameNumEvents) = mod(packetData(dataPointer), 2) == 1; % Pick off the first bit
                            frameData = typecast(packetData(dataPointer : dataPointer + 3), 'uint32');
                            frameColorChannels(frameNumEvents) = uint16(bitshift(bitand(frameData, frameColorChannelsMask), -frameColorChannelsShiftBits));
                            frameColorFilter(frameNumEvents)	= uint16(bitshift(bitand(frameData, frameColorFilterMask),	-frameColorFilterShiftBits));
                            frameRoiId(frameNumEvents)		= uint16(bitshift(bitand(frameData, frameRoiIdMask),		-frameRoiIdShiftBits));
                            if simplifyFrameTimeStamps
                                frameTimeStampStart(frameNumEvents)		= packetTimeStampOffset + uint64(typecast(packetData(dataPointer + 12 : dataPointer + 15), 'int32'));
                                frameTimeStampEnd(frameNumEvents)		= packetTimeStampOffset + uint64(typecast(packetData(dataPointer + 16 : dataPointer + 19), 'int32'));
                            else
                                frameTimeStampFrameStart(frameNumEvents)		= packetTimeStampOffset + uint64(typecast(packetData(dataPointer + 4 : dataPointer + 7), 'int32'));
                                frameTimeStampFrameEnd(frameNumEvents)		= packetTimeStampOffset + uint64(typecast(packetData(dataPointer + 8 : dataPointer + 11), 'int32'));
                                frameTimeStampExposureStart(frameNumEvents)	= packetTimeStampOffset + uint64(typecast(packetData(dataPointer + 12 : dataPointer + 15), 'int32'));
                                frameTimeStampExposureEnd(frameNumEvents)		= packetTimeStampOffset + uint64(typecast(packetData(dataPointer + 16 : dataPointer + 19), 'int32'));
                            end
                            frameXLength(frameNumEvents)		= typecast(packetData(dataPointer + 20 : dataPointer + 21), 'uint16'); % strictly speaking these are 4-byte signed integers, but there's no way they'll be that big in practice
                            frameYLength(frameNumEvents)		= typecast(packetData(dataPointer + 24 : dataPointer + 25), 'uint16');
                            frameXPosition(frameNumEvents)	= typecast(packetData(dataPointer + 28 : dataPointer + 29), 'uint16');
                            frameYPosition(frameNumEvents)	= typecast(packetData(dataPointer + 32 : dataPointer + 33), 'uint16');
                            numSamples = int32(frameXLength(frameNumEvents)) * int32(frameYLength(frameNumEvents)) * int32(frameColorChannels(frameNumEvents)); % Conversion to int32 allows addition with 'dataPointer' below
                            % At least one recording has a file ending half way
                            % through the frame data due to a laptop dying,
                            % hence the following check
                            if length(packetData) >= dataPointer + 35 + numSamples * 2
                                sampleData = cast(typecast(packetData(dataPointer + 36 : dataPointer + 35 + numSamples * 2), 'uint16'), 'uint16');
                                frameSamples{frameNumEvents}		= reshape(sampleData, frameColorChannels(frameNumEvents), frameXLength(frameNumEvents), frameYLength(frameNumEvents));
                                if frameColorChannels(frameNumEvents) == 1
                                    frameSamples{frameNumEvents} = squeeze(frameSamples{frameNumEvents});
                                    frameSamples{frameNumEvents} = permute(frameSamples{frameNumEvents}, [2 1]);
                                else
                                    % Change the dimensions of the frame array to
                                    % the standard for matlab: column, then row,
                                    % then channel number
                                    frameSamples{frameNumEvents} = permute(frameSamples{frameNumEvents}, [3 2 1]);
                                end
                            else
                                frameSamples{frameNumEvents} = zeros(frameYLength(frameNumEvents), frameXLength(frameNumEvents), frameColorChannels(frameNumEvents));
                            end
                            % aedat3 uses left-justified 16 bit samples -
                            % for consistency with aedat2, revert to
                            % fundamental 10 bit representation
                            frameSamples{frameNumEvents} = frameSamples{frameNumEvents} / 2^6;
                        end

                    end
    %% IMU6
                elseif eventType == 3
                     if allDataTypes || any(cellfun(cellFind('imu6'), dataTypes))
                        % First check if the array is big enough
                        currentLength = length(imu6Valid);
                        if currentLength == 0
                            imu6Valid			= false(eventNumber, 1);
                            imu6TimeStamp		= zeros(eventNumber, 1, 'uint64');
                            imu6AccelX			= zeros(eventNumber, 1, 'single');
                            imu6AccelY			= zeros(eventNumber, 1, 'single');
                            imu6AccelZ			= zeros(eventNumber, 1, 'single');
                            imu6GyroX			= zeros(eventNumber, 1, 'single');
                            imu6GyroY			= zeros(eventNumber, 1, 'single');
                            imu6GyroZ			= zeros(eventNumber, 1, 'single');
                            imu6Temperature     = zeros(eventNumber, 1, 'single');
                        else
                            while eventNumber > currentLength - imu6NumEvents
                                imu6Valid			= [imu6Valid;        false(currentLength, 1)];
                                imu6TimeStamp		= [imu6TimeStamp;    zeros(currentLength, 1, 'uint64')];
                                imu6AccelX			= [imu6AccelX;       zeros(currentLength, 1, 'single')];
                                imu6AccelY			= [imu6AccelY;       zeros(currentLength, 1, 'single')];
                                imu6AccelZ			= [imu6AccelZ;       zeros(currentLength, 1, 'single')];
                                imu6GyroX			= [imu6GyroX;        zeros(currentLength, 1, 'single')];
                                imu6GyroY			= [imu6GyroY;        zeros(currentLength, 1, 'single')];
                                imu6GyroZ			= [imu6GyroZ;        zeros(currentLength, 1, 'single')];
                                imu6Temperature     = [imu6Temperature;  zeros(currentLength, 1, 'single')];
                                currentLength = length(imu6Valid);
                            end
                        end
                        % Matricise computation on a packet
                        dataMatrix = reshape(packetData, [eventSize, eventNumber]);
                        dataTempTimeStamp = dataMatrix(5:8, :);
                        imu6TimeStamp(imu6NumEvents + (1 : eventNumber)) = packetTimeStampOffset + uint64(typecast(dataTempTimeStamp(:), 'int32'));
                        % The following is overkill - only need to pick out 1
                        % byte to get to the valid flag
                        dataTempAddress = dataMatrix(1:4, :);
                        dataTempAddress = typecast(dataTempAddress(:), 'uint32');
                        imu6Valid(imu6NumEvents + (1 : eventNumber)) = mod(dataTempAddress, 2) == 1; % Pick off the first bit
                        tempDataMatrix = dataMatrix(9:12, :);
                        imu6AccelX      (imu6NumEvents + (1 : eventNumber)) = typecast(tempDataMatrix(:), 'single');
                        tempDataMatrix = dataMatrix(13:16, :);
                        imu6AccelY      (imu6NumEvents + (1 : eventNumber)) = typecast(tempDataMatrix(:), 'single');
                        tempDataMatrix = dataMatrix(17:20, :);
                        imu6AccelZ      (imu6NumEvents + (1 : eventNumber)) = typecast(tempDataMatrix(:), 'single');
                        tempDataMatrix = dataMatrix(21:24, :);
                        imu6GyroX       (imu6NumEvents + (1 : eventNumber)) = typecast(tempDataMatrix(:), 'single');
                        tempDataMatrix = dataMatrix(25:28, :);
                        imu6GyroY       (imu6NumEvents + (1 : eventNumber)) = typecast(tempDataMatrix(:), 'single');
                        tempDataMatrix = dataMatrix(29:32, :);
                        imu6GyroZ       (imu6NumEvents + (1 : eventNumber)) = typecast(tempDataMatrix(:), 'single');
                        tempDataMatrix = dataMatrix(33:36, :);
                        imu6Temperature (imu6NumEvents + (1 : eventNumber)) = typecast(tempDataMatrix(:), 'single');
                        imu6NumEvents = imu6NumEvents + eventNumber;
                    end
    %% Sample
                elseif eventType == 5
                     if allDataTypes || any(cellfun(cellFind('sample'), dataTypes))
                        %{
                        sampleValid			= bool([]);
                        sampleTimeStamp		= uint64([]);
                        sampleSampleType	= uint8([]);
                        sampleSample		= uint32([]);
                        %}
                    end
    %% Ear
                elseif eventType == 6
                     if allDataTypes || any(cellfun(cellFind('ear'), dataTypes))
                            %{
                            earValid		= bool([]);
                            earTimeStamp	= uint64([]);
                            earPosition 	= uint8([]);
                            earChannel		= uint16([]);
                            earNeuron		= uint8([]);
                            earFilter		= uint8([]);
                            %}
                    end
    %% Point1D

                elseif eventType == 8
                    if allDataTypes || any(cellfun(cellFind('point1D'), dataTypes))
                        % First check if the array is big enough
                        currentLength = length(point1DValid);
                        if currentLength == 0
                            point1DValid		= false(eventNumber, 1);
                            point1DType         = zeros(eventNumber, 1, 'uint8');
                            point1DTimeStamp	= zeros(eventNumber, 1, 'uint64');
                            point1DX            = zeros(eventNumber, 1, 'single');
                        else
                            while eventNumber > currentLength - point1DNumEvents
                                point1DValid		= [point1DValid;		false(currentLength, 1)];
                                point1DType     	= [point1DType;     	zeros(currentLength, 1, 'uint8')];
                                point1DTimeStamp	= [point1DTimeStamp;	zeros(currentLength, 1, 'uint64')];
                                point1DX            = [point1DX;            zeros(currentLength, 1, 'single')];
                                currentLength = length(point1dValid);
                            end
                        end
                        % Iterate through the events, converting the data and
                        % populating the arrays
                        for dataPointer = 1 : eventSize : numBytesInPacket % This points to the first byte for each event
                            point1DNumEvents = point1DNumEvents + 1;
                            point1DValid(point1DNumEvents) = boolean(bitand(packetData(dataPointer), 1)); %Pick off the first bit
                            point1DType(point1DNumEvents) = bitshift(bitand(packetData(dataPointer), point1DTypeMask), -point1DTypeShiftBits);
                            point1DTimeStamp(point1DNumEvents) = packetTimeStampOffset + uint64(typecast(packetData(dataPointer + 8 : dataPointer + 11), 'int32'));
                            point1DX(point1DNumEvents) = typecast(packetData(dataPointer + 4 : dataPointer + 7), 'single');
                        end
                    end
    %% Point2D
                elseif eventType == 9
                    if allDataTypes || any(cellfun(cellFind('point2D'), dataTypes))
                        % First check if the array is big enough
                        currentLength = length(point2DValid);
                        if currentLength == 0
                            point2DValid		= false(eventNumber, 1);
                            point2DType         = zeros(eventNumber, 1, 'uint8');
                            point2DTimeStamp	= zeros(eventNumber, 1, 'uint64');
                            point2DX            = zeros(eventNumber, 1, 'single');
                            point2DY            = zeros(eventNumber, 1, 'single');
                        else
                            while eventNumber > currentLength - point2DNumEvents
                                point2DValid		= [point2DValid;		false(currentLength, 1)];
                                point2DType     	= [point2DType;     	zeros(currentLength, 1, 'uint8')];
                                point2DTimeStamp	= [point2DTimeStamp;	zeros(currentLength, 1, 'uint64')];
                                point2DX            = [point2DX;            zeros(currentLength, 1, 'single')];
                                point2DY            = [point2DY;            zeros(currentLength, 1, 'single')];
                                currentLength = length(point2DValid);
                            end
                        end
                        % Iterate through the events, converting the data and
                        % populating the arrays
                        for dataPointer = 1 : eventSize : numBytesInPacket % This points to the first byte for each event
                            point2DNumEvents = point2DNumEvents + 1;
                            point2DValid(point2DNumEvents) = boolean(bitand(packetData(dataPointer), 1)); %Pick off the first bit
                            point2DType(point2DNumEvents) = bitshift(bitand(packetData(dataPointer), point2DTypeMask), -point2DTypeShiftBits);
                            point2DTimeStamp(point2DNumEvents) = packetTimeStampOffset + uint64(typecast(packetData(dataPointer + 12 : dataPointer + 15), 'int32'));
                            point2DX(point2DNumEvents) = typecast(packetData(dataPointer + 4 : dataPointer + 7), 'single');
                            point2DY(point2DNumEvents) = typecast(packetData(dataPointer + 8 : dataPointer + 11), 'single');
                        end
                    end
    %% Point3D
                elseif eventType == 10
                    if allDataTypes || any(cellfun(cellFind('point3D'), dataTypes))
                        % First check if the array is big enough
                        currentLength = length(point3DValid);
                        if currentLength == 0
                            point3DValid		= false(eventNumber, 1);
                            point3DType         = zeros(eventNumber, 1, 'uint8');
                            point3DTimeStamp	= zeros(eventNumber, 1, 'uint64');
                            point3DX            = zeros(eventNumber, 1, 'single');
                            point3DY            = zeros(eventNumber, 1, 'single');
                            point3DZ            = zeros(eventNumber, 1, 'single');
                        else
                            while eventNumber > currentLength - point3DNumEvents
                                point3DValid		= [point3DValid;		false(currentLength, 1)];
                                point3DType     	= [point3DType;     	zeros(currentLength, 1, 'uint8')];
                                point3DTimeStamp	= [point3DTimeStamp;	zeros(currentLength, 1, 'uint64')];
                                point3DX            = [point3DX;            zeros(currentLength, 1, 'single')];
                                point3DY            = [point3DY;            zeros(currentLength, 1, 'single')];
                                point3DZ            = [point3DZ;            zeros(currentLength, 1, 'single')];
                                currentLength = length(point3DValid);
                            end
                        end
                        % Iterate through the events, converting the data and
                        % populating the arrays
                        for dataPointer = 1 : eventSize : numBytesInPacket % This points to the first byte for each event
                            point3DNumEvents = point3DNumEvents + 1;
                            point3DValid(point3DNumEvents) = boolean(bitand(packetData(dataPointer), 1)); %Pick off the first bit
                            point3DType(point3DNumEvents) = bitshift(bitand(packetData(dataPointer), point3DTypeMask), -point3DTypeShiftBits);
                            point3DTimeStamp(point3DNumEvents) = packetTimeStampOffset + uint64(typecast(packetData(dataPointer + 16 : dataPointer + 19), 'int32'));
                            point3DX(point3DNumEvents) = typecast(packetData(dataPointer + 4 : dataPointer + 7), 'single');
                            point3DY(point3DNumEvents) = typecast(packetData(dataPointer + 8 : dataPointer + 11), 'single');
                            point3DZ(point3DNumEvents) = typecast(packetData(dataPointer + 12 : dataPointer + 15), 'single');
                        end
                    end
                else
                    error('Unknown event type')
                end
            end
        end
	end
	if packetCount == endPacket
		break
	end
end

%% Clip data arrays to correct size

if noData == false

    outputData = struct;

    if specialNumEvents > 0
        keepLogical = false(size(specialValid, 1), 1);
        keepLogical(1:specialNumEvents) = true;
        special.valid = specialValid(keepLogical);
        special.timeStamp = specialTimeStamp(keepLogical);
        special.address = specialAddress(keepLogical);
        outputData.special = special;
    end

    if polarityNumEvents > 0
        keepLogical = false(size(polarityValid, 1), 1);
        keepLogical(1:polarityNumEvents) = true;
        polarity.valid = polarityValid(keepLogical);
        polarity.timeStamp	= polarityTimeStamp(keepLogical);
        polarity.y			= polarityY(keepLogical);
        polarity.x			= polarityX(keepLogical);
        polarity.polarity	= polarityPolarity(keepLogical);
        outputData.polarity = polarity;
    end

    if frameNumEvents > 0
        keepLogical = false(size(frameValid, 1), 1);
        keepLogical(1:frameNumEvents) = true;
        frame.valid = frameValid(keepLogical);
        frame.roiId					= frameRoiId(keepLogical);
        frame.colorChannels			= frameColorChannels(keepLogical);
        frame.colorFilter			= frameColorFilter(keepLogical);
        if simplifyFrameTimeStamps
            frame.timeStampStart	= frameTimeStampStart(keepLogical);
            frame.timeStampEnd		= frameTimeStampEnd(keepLogical);
        else
            frame.timeStampFrameStart	= frameTimeStampFrameStart(keepLogical);
            frame.timeStampFrameEnd		= frameTimeStampFrameEnd(keepLogical);
            frame.timeStampExposureStart = frameTimeStampExposureStart(keepLogical);
            frame.timeStampExposureEnd	= frameTimeStampExposureEnd(keepLogical);
        end
        frame.samples				= frameSamples(keepLogical);
        frame.xLength				= frameXLength(keepLogical);
        frame.yLength				= frameYLength(keepLogical);
        frame.xPosition				= frameXPosition(keepLogical);
        frame.yPosition				= frameYPosition(keepLogical);
        outputData.frame = frame;
    end

    if imu6NumEvents > 0
        keepLogical = false(size(imu6Valid, 1), 1);
        keepLogical(1:imu6NumEvents) = true;
        imu6.valid = imu6Valid(keepLogical);
        imu6.timeStamp	= imu6TimeStamp(keepLogical);
        imu6.gyroX		= imu6GyroX(keepLogical);
        imu6.gyroY		= imu6GyroY(keepLogical);
        imu6.gyroZ		= imu6GyroZ(keepLogical);
        imu6.accelX		= imu6AccelX(keepLogical);
        imu6.accelY		= imu6AccelY(keepLogical);
        imu6.accelZ		= imu6AccelZ(keepLogical);
        imu6.temperature = imu6Temperature(keepLogical);
        outputData.imu6 = imu6;
    end

    if sampleNumEvents > 0
        keepLogical = false(size(sampleValid, 1), 1);
        keepLogical(1:sampleNumEvents) = true;
        sample.valid = sampleValid(keepLogical);
        sample.timeStamp	= sampleTimeStamp(keepLogical);
        sample.sampleType	= sampleSampleType(keepLogical);
        sample.sample		= sampleSample(keepLogical);
        outputData.sample = sample;
    end

    if earNumEvents > 0
        keepLogical = false(size(earValid, 1), 1);
        keepLogical(1:earNumEvents) = true;
        ear.valid = earValid(keepLogical);
        ear.timeStamp	= earTimeStamp(keepLogical);
        ear.position	= earosition(keepLogical);
        ear.channel		= earChannel(keepLogical);
        ear.neuron		= earNeuron(keepLogical);
        ear.filter		= earFilter(keepLogical);
        outputData.ear = ear;
    end

    if point1DNumEvents > 0
        keepLogical = false(size(point1DValid, 1), 1);
        keepLogical(1:point1DNumEvents) = true;
        point1D.valid       = point1DValid      (keepLogical);
        point1D.type        = point1DType       (keepLogical);
        point1D.timeStamp   = point1DTimeStamp  (keepLogical);
        point1D.x           = point1DX          (keepLogical);
        outputData.point1D = point1D;
    end

    if point2DNumEvents > 0
        keepLogical = false(size(point2DValid, 1), 1);
        keepLogical(1:point2DNumEvents) = true;
        point2D.valid       = point2DValid      (keepLogical);
        point2D.type        = point2DType       (keepLogical);
        point2D.timeStamp   = point2DTimeStamp  (keepLogical);
        point2D.x           = point2DX          (keepLogical);
        point2D.y           = point2DY          (keepLogical);
        outputData.point2D = point2D;
    end

    if point3DNumEvents > 0
        keepLogical = false(size(point3DValid, 1), 1);
        keepLogical(1:point3DNumEvents) = true;
        point3D.valid       = point3DValid      (keepLogical);
        point3D.type        = point3DType       (keepLogical);
        point3D.timeStamp   = point3DTimeStamp  (keepLogical);
        point3D.x           = point3DX          (keepLogical);
        point3D.y           = point3DY          (keepLogical);
        point3D.z           = point3DZ          (keepLogical);
        outputData.point3D = point3D;
    end
end

%% Pack packet info
info.packetTypes	= packetTypes(1 : packetCount);
info.packetPointers	= packetPointers(1 : packetCount);
info.packetTimeStamps	= packetTimeStamps(1 : packetCount);

%% Calculate data volume by type

% This calculation excludes the final packet for simplicity.
% It doesn't handle partial imports or invalid data.

packetSizes = [info.packetPointers(2 : end) - info.packetPointers(1 : end - 1) - 28; 0];
info.dataVolumeByEventType = {};
eventTypesTemp = info.packetTypes;
eventTypesTemp(eventTypesTemp == 32768) = 0;
for eventType = max(eventTypesTemp): -1 : 0 % counting down means the array is only assigned once
	info.dataVolumeByEventType(eventType + 1, 1 : 2) = [{EventTypes(eventType)} sum(packetSizes(info.packetTypes == eventType))];
end

%% Pack the data into the output structure

aedat.info = info;
if exist ('outputData', 'var')
    aedat.data = outputData;
end
% the unpacked importParams should not have been changed

%% Remove invalid events

if validOnly && noData == false
	aedat = RemoveInvalidEvents(aedat);
end

%% Add NumEvents field for each data type

if noData == false
    aedat = NumEventsByType(aedat);
end

%% Find first and last time stamps

if noData == false
    aedat = FindFirstAndLastTimeStamps(aedat);
end

disp('Import finished')


%kgcreate2dtex 'Create a 2d texture from an image.'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros gcreate2dtex.pane file
%
% Parameters:
% InputFile: i 'Input ', required: 'First Input data object'
% OutputFile: o 'Output', required: 'Resulting output data object'
% Double: umin 'Umin', default: 0: 'Minimum u-coordinate value associated with origin of image data.'
% Double: vmin 'Vmin', default: 0: 'Mininum v-coordinate assigned to the origin of the texture.'
% Double: umax 'Umax', default: 1: 'Maximum u-coordinate to use for the non-origin corner of the texture image.'
% Double: vmax 'Vmax', default: 1: 'Maximum v-coordinate to use for the non-origin corner of the texture image.'
%
% Example: o = kgcreate2dtex(i, {'i','';'o','';'umin',0;'vmin',0;'umax',1;'vmax',1})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% gcreate2dtex - Create a 2d texture from an image.
%
%  DESCRIPTION
%
%
%
%  EXAMPLES
%
%  "SEE ALSO"
% gbindtexture
%
%  RESTRICTIONS
% Textures are created so as to contain 3 channels of floating point RGB data,
% so space efficiency is not optimal.  Only RGB textures are created.  Future
% work includes generating luminance textures, color-mapped textures and other
% lower-color-resolution texture formats.
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1996,1997 , The Regents of the University of California.  All rights reserved.
%

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

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


function r = model_has_colors(model)
r = isfield(model,'r') && length(model.r) > 1;


function [headers, fid] = readPLXHeaders(filename, fullread)
% readPLXHeaders - Read file headers and channel information from PLX file.
%
% [headers, fid] = readPLXHeaders(filename)
%
% readPLXHeaders will read the header data from a PLX file and return a
% structure with fields corresponding to each piece of header data.
%
% Input:
%   filename - Filename of a PLX file. A valid file-ID can be provided
%              instead of a filename. In this case, the file-ID will not be
%              closed after reading.
%   fullread - Verify the contents of the file header by reading the entire
%              file. This effects the values of headers.tscounts,
%              headers.wfcounts, headers.evcounts, and headers.slowcounts.
%              It will also verify that headers.chans(n).nunits is
%              accurate, and that headers.numPointsWave is accurate.
%              (default = false)
%
% Output:
%   headers - PLX file header information.
%   fid     - File-ID of the
%
% WARNING: Plexon didn't have much foresight for the number of
% units/channel, and only left enough space in the headers for 4
% units/channel. Therefore, the data stored in the headers (and output as
% headers.tscounts and headers.wfcounts) can't account for more than 4
% units/channel. The only way to get an accurate count of the number of
% timestamps, waveforms, and events is to read the entire data file. If you
% call this function with the 'fullread' argument set false (default) it
% will only read the values provided in the header. If you set 'fullread'
% to true, it will read the entire file to verify the information in the
% header. This is similar to the behavior of the Plexon function called
% plx_info.
%
% Note: This function behaves slightly different than plx_info. In
% particular:
%     tscounts   = 27 x m array. The entry at tscounts(c,u) refers to
%                  channel c and unit u-1. Channel numbers start at 1.
%                  Unit 0 (in row 1) is unsorted waves.
%     wfcounts   = 27 x m array. The entry at wfcounts(c,u) refers to
%                  channel c and unit u-1. Channel numbers start at 1.
%                  Unit 0 (in row 1) is unsorted waves.
%     evcounts   = 1 x m array. The entry at evcounts(c) refers to
%                  channel c. Channel numbers start at 1. m is the event
%                  with the largest channel number (usually 259).
%     slowcounts = 1 x m+1 array. The entry at slowcounts(c) refers to
%                  channel c+1. Channel numbers start at 0. m is one
%                  greater than the largest slow channel number.
%
% See also writePLXFile, checkPLXData, plx_info, plx_information.
%
% AUTHOR: Benjamin Kraus (bkraus@bu.edu, ben@benkraus.com)
% Copyright (c) 2011, Benjamin Kraus
% $Id$

DEBUG = true;

if (nargin == 0 || isempty(filename))
    FilterSpec = {'*.plx', 'Plexon PLX File (*.plx)';
                  '*', 'All Files'};
    [fname, pathname] = uigetfile(FilterSpec, 'Select a Plexon PLX file');
    if(fname == 0); headers = struct([]); return; end
    filename = strcat(pathname, fname);
end

if(~ischar(filename));
    % If the filename input is not a character string, check to see if it
    % is a valid file ID instead. We can do this by calling 'frewind'. If
    % 'frewind' succeeds, then we know we have a valid file ID.
    fid = filename;
    frewind(fid);
else
    fid = fopen(filename, 'r');
    if(fid ~= -1 && nargout < 2); c = onCleanup(@()fclose(fid)); end
end

if(fid == -1); error('readPLXHeaders:FileError','Error opening file'); end

if(nargin < 2); fullread = false; shortread = false;
elseif(islogical(fullread)); shortread = false;
elseif(ischar(fullread))
    switch lower(fullread)
        case 'true';   fullread = true;  shortread = false;
        case 'false';  fullread = false; shortread = false;
        case 'full';   fullread = true;  shortread = false;
        case 'short';  fullread = false; shortread = true;
        otherwise;     fullread = false; shortread = false;
    end
end

% Determine file size:
fseek(fid,0,'eof');
fsize = ftell(fid);
frewind(fid);

% File header is 256 bytes

magic = fread(fid, 4, '*char')';
if(~strcmp(magic,'PLEX'))
    error('readPLXHeaders:InvalidPLXFile','This file is not a valid .plx file');
end

headers.version = fread(fid, 1, 'int32');
headers.comment = deblank(fread(fid, 128, '*char')');
headers.ADFrequency = fread(fid, 1, 'int32');
headers.numDSPChannels = fread(fid, 1, 'int32');
headers.numEventChannels = fread(fid, 1, 'int32');
headers.numSlowChannels = fread(fid, 1, 'int32');
headers.numPointsWave = fread(fid, 1, 'int32');
headers.numPointsPreThr = fread(fid, 1, 'int32');

YR = fread(fid, 1, 'int32');
MO = fread(fid, 1, 'int32');
DA = fread(fid, 1, 'int32');
HR = fread(fid, 1, 'int32');
MI = fread(fid, 1, 'int32');
SC = fread(fid, 1, 'int32');
headers.date = datenum([YR, MO, DA, HR, MI, SC]);

headers.fastread = fread(fid, 1, 'int32');
headers.waveformfreq = fread(fid, 1, 'int32');
headers.lasttimestamp = fread(fid, 1, 'double');

if(headers.version >= 103)
    headers.trodalness = fread(fid, 1, 'uint8');
    headers.datatrodalness = fread(fid, 1, 'uint8');
    headers.bitsperspikesample = fread(fid, 1, 'uint8');
    headers.bitsperslowsample = fread(fid, 1, 'uint8');
    headers.spikeMaxMagnitudeMV = fread(fid, 1, 'ushort');
    headers.slowMaxMagnitudeMV = fread(fid, 1, 'ushort');
else
    headers.trodalness = 1;
    headers.datatrodalness = 1;
    headers.bitsperspikesample = 12;
    headers.bitsperslowsample = 12;
    headers.spikeMaxMagnitudeMV = 3000;
    headers.slowMaxMagnitudeMV = 5000;
    fread(fid, 8, 'uint8');
end

if(headers.version >= 105)
    headers.spikePreAmpGain = fread(fid, 1, 'ushort');
else
    headers.spikePreAmyGain = 1000;
    fread(fid, 1, 'ushort');
end

if(headers.version >= 106)
    headers.acquiringsoftware = deblank(fread(fid, 18, '*char')');
    headers.processingsoftware = deblank(fread(fid, 18, '*char')');
    fread(fid, 10, 'uint8');
else
    headers.acquiringsoftware = '';
    headers.processingsoftware = '';
    fread(fid, 46, 'char');
end

% Current position = 256

% Timestamps, waveforms, event counts total 7248 bytes.

tscounts = fread(fid, [5, 130], 'int32');
wfcounts = fread(fid, [5, 130], 'int32');
evcounts = fread(fid, [1, 512], 'int32');

headers.tscounts = tscounts(:,2:min(headers.numDSPChannels+1,130));
headers.wfcounts = wfcounts(:,2:min(headers.numDSPChannels+1,130));
headers.evcounts = evcounts(2:300);
headers.slowcounts = evcounts(301:min(300+headers.numSlowChannels,512));

% Current position = 7504

% If instructed to do a 'short' read, stop here.
if(shortread); return; end

% Each channel header is 1020 bytes.
headers.chans = struct([]);
for ii = 1:headers.numDSPChannels;
    headers.chans(ii,1).name = deblank(fread(fid, 32, '*char')');
    headers.chans(ii,1).signame = deblank(fread(fid, 32, '*char')');
    headers.chans(ii,1).channel = fread(fid, 1, 'int32');
    headers.chans(ii,1).wfrate = fread(fid, 1, 'int32');
    headers.chans(ii,1).sig = fread(fid, 1, 'int32');
    headers.chans(ii,1).ref = fread(fid, 1, 'int32');
    headers.chans(ii,1).gain = fread(fid, 1, 'int32');
    headers.chans(ii,1).filter = fread(fid, 1, 'int32');
    headers.chans(ii,1).threshold = fread(fid, 1, 'int32');
    headers.chans(ii,1).method = fread(fid, 1, 'int32');
    headers.chans(ii,1).nunits = fread(fid, 1, 'int32');
    headers.chans(ii,1).template = fread(fid, [5, 64], 'short');
    headers.chans(ii,1).fit = fread(fid, 5, 'int32');
    headers.chans(ii,1).sortwidth = fread(fid, 1, 'int32');
    headers.chans(ii,1).boxes = zeros(5, 2, 4);
    headers.chans(ii,1).boxes(:) = fread(fid, 5*2*4, 'short');
    headers.chans(ii,1).sortbeg = fread(fid, 1, 'int32');
    if(headers.version>=105)
        headers.chans(ii,1).comment = deblank(fread(fid, 128, '*char')');
    else
        headers.chans(ii,1).comment = '';
        fread(fid, 128, 'char');
    end

    if(headers.version>=106)
        headers.chans(ii,1).srcid = fread(fid, 1, 'uchar');
        fread(fid, 1, 'uchar');
        headers.chans(ii,1).chanid = fread(fid, 1, 'ushort');
        fread(fid, 10, 'int32');
    else fread(fid, 11, 'int32');
    end
end

% Current position = 7504 + 1020*nchans

% Each event channel header is 296 bytes
headers.evchans = struct([]);
for ii = 1:headers.numEventChannels;
    headers.evchans(ii,1).name = deblank(fread(fid, 32, '*char')');
    headers.evchans(ii,1).num = fread(fid, 1, 'int32');

    if(headers.version>=105)
        headers.evchans(ii,1).comment = deblank(fread(fid, 128, '*char')');
    else
        headers.evchans(ii,1).comment = '';
        fread(fid, 128, 'char');
    end

    if(headers.version>=106)
        headers.evchans(ii,1).srcid = fread(fid, 1, 'uchar');
        fread(fid, 1, 'uchar');
        headers.evchans(ii,1).chanid = fread(fid, 1, 'ushort');
        fread(fid, 32, 'int32');
    else fread(fid, 33, 'int32');
    end
end

% Current position = 7504 + 1020*nchans + 296*nevchans

% Each slow channel header is 296 bytes
headers.slowchans = struct([]);
for ii = 1:headers.numSlowChannels;
    headers.slowchans(ii,1).name = deblank(fread(fid, 32, '*char')');
    headers.slowchans(ii,1).channel = fread(fid, 1, 'int32');
    headers.slowchans(ii,1).ADFrequency = fread(fid, 1, 'int32');
    headers.slowchans(ii,1).adgain = fread(fid, 1, 'int32');
    headers.slowchans(ii,1).enabled = fread(fid, 1, 'int32');
    headers.slowchans(ii,1).preampgain = fread(fid, 1, 'int32');

    if(headers.version>=104)
        headers.slowchans(ii,1).spikechannel = fread(fid, 1, 'int32');
    else
        headers.slowchans(ii,1).spikechannel = 0;
        fread(fid, 1, 'int32');
    end

    if(headers.version>=105)
        headers.slowchans(ii,1).comment = deblank(fread(fid, 128, '*char')');
    else
        headers.slowchans(ii,1).comment = '';
        fread(fid, 128, 'char');
    end

    if(headers.version>=106)
        headers.slowchans(ii,1).srcid = fread(fid, 1, 'uchar');
        fread(fid, 1, 'uchar');
        headers.slowchans(ii,1).chanid = fread(fid, 1, 'ushort');
        fread(fid, 27, 'int32');
    else fread(fid, 28, 'int32');
    end
end

% Current position = 7504 + 1020*nchans + 296*nevchans + 296*nslowchans

% Keep track of the current position.
headers.datastart = ftell(fid);

% Unless instructed to read the entire file, stop here.
if(~fullread); return; end
if(DEBUG); fprintf(1,'Starting full file read.\n'); end

% If we are still going, then we were instructed to read the entire file to
% get accurate counts for spikes, events, and waveforms.

% Lets start by looking up the channel numbers.
if(headers.numDSPChannels>0)
    channums = vertcat(headers.chans.channel);
    maxchan = max(channums);
else
    maxchan = 0;
end

if(headers.numEventChannels>0)
    evnums = vertcat(headers.evchans.num);
    maxev = max(evnums);
else
    maxev = 0;
end

if(headers.numSlowChannels>0)
    slownums = vertcat(headers.slowchans.channel);
    maxslow = max(slownums);
else
    maxslow = 0;
end

tscounts   = zeros(27, maxchan);
wfcounts   = zeros(27, maxchan);
evcounts   = zeros(1,  maxev);
slowcounts = zeros(1,  maxslow+1);
slowfrags  = zeros(1,  maxslow+1);

% Read data headers and count number of each type of channel.
fseek(fid,headers.datastart,'bof');

numpointswave = headers.numPointsWave;

    function fillbuffer()
        dbufloc(1) = dbufloc-ndbuf;
        ndbuf(1) = min(floor((fsize-ftell(fid))/2),dbufsize);
        dbuf(1:ndbuf) = fread(fid,ndbuf,'*short');
    end

datablocks = 0;

dbufsize = 1024*1024*2;
dbuf = int16(zeros(dbufsize,1));
ndbuf = 0;
dbufloc = 1;

fillbuffer();

% type    = db(1);   db(end-7);
% upperts = db(2);   db(end-6);
% lowerts = db(3:4); db(end-5:end-4);
% chan    = db(5);   db(end-3);
% unit    = db(6);   db(end-2);
% nwaves  = db(7);   db(end-1);
% nwords  = db(8);   db(end);
dbh = int16(zeros(8,1));
needvals = 0;
havevals = 0;

while(ndbuf > 0)
    datablocks = datablocks + 1;
    if(DEBUG && mod(datablocks,100000)==0);
        fprintf('Block: %.0f\n',datablocks);
    end

    if(ndbuf-dbufloc>=7)
        dbh(1:8) = dbuf(dbufloc:dbufloc+7);
        dbufloc = dbufloc+8;
    else
        havevals(1) = max(0,ndbuf-dbufloc+1);
        dbh(1:havevals) = dbuf(dbufloc:ndbuf);
        needvals(1) = 8-havevals;
        dbufloc = dbufloc+havevals;
        fillbuffer();
        if(ndbuf-dbufloc+1<needvals); break; end
        dbh(havevals+1:8) = dbuf(dbufloc:dbufloc+needvals-1);
        dbufloc = dbufloc+needvals;
    end
    dbufloc = dbufloc+double(dbh(7)*dbh(8));

    if(dbh(1)==1)
        tscounts(dbh(6)+1,dbh(5)) = tscounts(dbh(6)+1,dbh(5)) + 1;
        wfcounts(dbh(6)+1,dbh(5)) = wfcounts(dbh(6)+1,dbh(5)) + dbh(7);
        if(dbh(8) ~= numpointswave(end))
            numpointswave(end+1) = dbh(8); %#ok<AGROW>
        end
    elseif(dbh(1) == 4)
        evcounts(dbh(5)) = evcounts(dbh(5)) + 1;
    elseif(dbh(1) == 5)
        slowfrags(dbh(5)+1) = slowfrags(dbh(5)+1) + 1;
        slowcounts(dbh(5)+1) = slowcounts(dbh(5)+1) + double(dbh(7)*dbh(8));
    end
end

if(~isscalar(numpointswave))
    headers.numPointsWave = max(numpointswave);

    warning('readPLXHeaders:NumPointsWaveMismatch',...
        'Number of points per wave is inconsistent or doesn''t match header information.');
end

headers.tscounts = tscounts;
headers.wfcounts = wfcounts;
headers.evcounts = evcounts;
headers.slowfrags = slowfrags;
headers.slowcounts = slowcounts;

for ii = 1:headers.numDSPChannels
    headers.chans(ii,1).nunits = find(tscounts(:,ii)>0,1,'last')-1;
end

end


% UPDATE generates html help files for all classes and updates funct.html

d = '/Users/marcelge/Code/DMLT/html';
cd(d);

% read implemented methods

D = dir('../+dml/*.m');

% write method help

s = which('help2html');

f = strfind(s,'/');
if isempty(f)
  cd(d);
  error('path not found');
end

ds = s(1:(f(end)-1));
cd(ds);

for i=1:length(D)
  nme = D(i).name(1:(end-2));
  s = help2html(['dml.' nme]);
  fname = fullfile(d,[nme '.html']);
  bf = exist(fname);
  fid = fopen(fname,'w');
  fprintf(fid,'%s',s);
  fclose(fid);
  if ~bf
    fprintf('added %s.html\n',nme);
    cd(d);
    system(sprintf('git add %s.html',nme));
    cd(ds);
  end
end

% write funct.m

fid = fopen(fullfile(d,'funct.m'),'w');
fprintf(fid,'%%%% DML Toolbox Functions\n%%\n');
for i=1:length(D)
  nme = D(i).name(1:(end-2));
  x = help(sprintf('dml.%s',nme));
  b = strfind(lower(x),nme)+length(nme)+1; b = b(1);
  e = min(b+50,(strfind(x,'.')-1)); e = e(1);
  x = x(b:e);
  fprintf(fid,['%% * <' nme '.html |dml.' nme '|> - ' x '\n']);
end
fclose(fid);

cd(d);

publish('funct.m','outputDir',d);


% Print CERR screen
%
% Shunde 7/14/05

% 24 Apr 2006 KU  Changed to 'print' (with no UI controls) instead of printpreview because of bug(?) in
%                 Matlab 7.2.  Printpreview hangs up if figure is in fullscreen mode.  Maybe try
%                 printpreview again in future version??
% 27 Dec 2006 KU  Switched back to zbuffer for CERR 3.0.
%
% 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/>.

% set(gcf,'renderer','painters');
% set(gcf,'PaperPositionMode','auto');
% orient landscape;
% printpreview;

set(gcf,'renderer','zbuffer');
set(gcf,'PaperPositionMode','auto');
orient landscape;

sentence1 = {'To adjust the size of the printed figure, adjust the screensize of the ',...
                'CERR window rather than changing the printer options.  (The CERR window ',...
                'will fill a standard 8.5x11 paper if it is adjusted to be fullscreen ',...
                'with a screen setting of 1024x768.)'};
            h=msgbox(sentence1, 'Printing Tip', 'help');
            waitfor(h);
if ispc
    print -v -noui;
else
    print -dsetup -noui;    %untested code for non-windows platforms
end


function doseCompare(command,varargin)
% doseCompare
% Used to show dose associated with scan in a compare mode.
%
% Written DK
%
% Usage: doseCompare(command,varargin)
%
% 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/>.

global planC stateS
indexS = planC{end};
hCSVA = stateS.handle.CERRSliceViewerAxis;
switch upper(command)
    case 'INIT'
        if stateS.layout == 7
            return
        end
        scanNum = getAxisInfo(hCSVA,'scanSets');

        if isempty(scanNum)
            scanNum = stateS.scanSet;
        end

        % doseNum = length(planC{indexS.dose});%Get number of dose
        doseNum = getScanAssociatedDose(scanNum,'all');

        if length(doseNum) < 2
            warndlg('Dose Comparison tool requires 2 or more doses associated to currnet scan');
            return
        elseif length(doseNum) > 4
            newAxis = 3;
        else
            newAxis = length(doseNum)-1;
        end
        stateS.doseCompare.newAxis = newAxis;

        if stateS.layout == 6
            scanCompare('exit');
        end

        if length( stateS.handle.CERRAxis)>4
            delete(stateS.handle.CERRAxis(4:end));
            stateS.handle.CERRAxisLabel1(5:end)=[];
            stateS.handle.CERRAxisLabel2(5:end)=[];
            stateS.handle.CERRAxis(5:end)=[];
        end

        %Calculating positions for each viewport
        leftMarginWidth = 195; bottomMarginHeight = 70;
        pos = get(stateS.handle.CERRSliceViewer, 'position');
        figureWidth = pos(3); figureHeight = pos(4);
        wid = (figureWidth-leftMarginWidth-70-10)/5;
        hig = (figureHeight-bottomMarginHeight-20)/2;

        stateS.oldDoseSet = stateS.doseSet;
        stateS.doseSet = doseNum(1);

        %change the layout after checking the number of dose in the plan
        stateS.layout = 7;
        stateS.Oldlayout = 7;
        doseSetsLast = getAxisInfo(hCSVA,'doseSets');
        scanSetsLast = getAxisInfo(hCSVA,'scanSets');
        setAxisInfo(hCSVA,'doseSets',doseNum(1),'doseSelectMode', 'manual','doseSetsLast',doseSetsLast,'scanSetsLast',scanSetsLast);
        %delete any new duplicate axis.
        if length(stateS.handle.CERRAxis) > 4
            delete(stateS.handle.CERRAxis(5:end));
            stateS.handle.CERRAxis = stateS.handle.CERRAxis(1:4);
        end

        for i = 1:newAxis % create linked axis to the transverse axis
            stateS.handle.CERRAxis(end+1) = axes('parent',stateS.handle.CERRSliceViewer, 'units', 'pixels', 'position', [1 1 1 1],...
                'color', [0 0 0], 'xTickLabel', [], 'yTickLabel', [], 'xTick', [], 'yTick', [], 'buttondownfcn',...
                'sliceCallBack(''axisClicked'')', 'nextplot', 'add', 'yDir', 'reverse', 'linewidth', 2,'visible','off','Tag','doseCompareAxes');

            stateS.handle.CERRAxisLabel1(end+1) = text('parent', stateS.handle.CERRAxis(end), 'string', '', 'position', [.02 .98 0],...
                'color', [1 0 0], 'units', 'normalized', 'visible', 'off', 'horizontalAlignment', 'left', 'verticalAlignment', 'top');

            stateS.handle.CERRAxisLabel2(end+1) = text('parent', stateS.handle.CERRAxis(end), 'string', '', 'position', [.90 .98 0],...
                'color', [1 0 0], 'units', 'normalized', 'visible', 'off', 'horizontalAlignment', 'left', 'verticalAlignment', 'top');

            AI(i).miscHandles = [stateS.handle.CERRAxisLabel1(end) stateS.handle.CERRAxisLabel2(end)];
        end

        axisInfo = get(hCSVA, 'userdata');
        axisInfo.scanObj(1:end) = [];
        axisInfo.doseObj(1:end) = [];
        axisInfo.structureGroup(1:end) = [];
        axisInfo.miscHandles = [];
        axisInfo.coord       = {'Linked', hCSVA};
        axisInfo.view        = {'Linked', hCSVA};
        axisInfo.xRange      = {'Linked', hCSVA};
        axisInfo.yRange      = {'Linked', hCSVA};

        for i = 1:newAxis
            axisInfo.miscHandles = AI(i).miscHandles;
            set(stateS.handle.CERRAxis(4+i), 'userdata', axisInfo);
            setAxisInfo(stateS.handle.CERRAxis(4+i),'doseSets',doseNum(i+1),'doseSelectMode', 'manual');
            CERRAxisMenu(stateS.handle.CERRAxis(4+i));
            set(stateS.handle.CERRAxis(4+i),'visible','on');
        end

        if stateS.MLVersion >= 8.4
            set(stateS.handle.CERRAxis,'ClippingStyle','rectangle')
        end

        stateS.handle.doseColorbar.Compare = axes('units', 'pixels', 'position', [leftMarginWidth+60+wid*4+20 bottomMarginHeight+30 50 hig-40],...
            'xTickLabel', [], 'yTickLabel', [], 'xTick', [], 'yTick', [], 'Tag', 'ColorbarCompare', 'visible', 'off');
        stateS.doseSetChanged = 1;
        CERRRefresh
        sliceCallBack('RESIZE');

    case 'COMPAREMODE'
        hAxis = gca;
        stateS.doseSetChanged = 1;
        refDose= getAxisInfo(hCSVA,'doseSets');
        tarDose= getAxisInfo(hAxis,'doseSets');

        doseNumOld = length(planC{indexS.dose});

        switch upper(varargin{1})
            case 'DEFAULT'
                doseNum = getAssociatedDose(planC{indexS.dose}(getAxisInfo(hAxis,'doseSetsLast')).doseUID);
                setappdata(hAxis,'compareMode',[]);
            otherwise
                setappdata(hAxis,'compareMode',upper(varargin{1}));
                [doseNum flag] = chkDose(refDose,tarDose);
                if ~flag & isempty(doseNum)%if not calculated
                    DoseAdditionSubtraction(planC{indexS.dose}(refDose),planC{indexS.dose}(tarDose),'Subtract',0);
                    doseNum = length(planC{indexS.dose});
                    if doseNumOld == doseNum
                        return
                    end
                end
        end
        setAxisInfo(hAxis,'doseSets',doseNum);
        CERRRefresh

    case 'EXIT'
        stateS.Oldlayout = [];
        stateS.doseSet = stateS.oldDoseSet;
        stateS.doseSetChanged = 1;
        delete(stateS.handle.doseColorbar.Compare)

        hDel = (findobj('Tag','doseCompareAxes'));
        for i = 1:length(hDel)
            hDel_ind = find(stateS.handle.CERRAxis == hDel(i));
            delete(stateS.handle.CERRAxis(hDel_ind));
            stateS.handle.CERRAxisLabel1(hDel_ind)=[];
            stateS.handle.CERRAxisLabel2(hDel_ind)=[];
            stateS.handle.CERRAxis(hDel_ind)=[];
        end
        for i = 1:length(stateS.handle.CERRAxis)
            setAxisInfo(stateS.handle.CERRAxis(i),'doseSets',getAxisInfo(stateS.handle.CERRAxis(i),'doseSetsLast'),...
                'scanSets',getAxisInfo(stateS.handle.CERRAxis(i),'scanSetsLast'));
            setappdata(stateS.handle.CERRAxis(i),'compareMode',[]);
        end
        sliceCallBack('resize');
        CERRRefresh
end


function [varargout] = rdir(rootdir,varargin)
% RDIR - Recursive directory listing
%
%  d = rdir(ROOT)
%  d = rdir(ROOT, TEST)
%  d = rdir(ROOT, TEST, RMPATH)
%  d = rdir(ROOT, TEST, 1)
%  d = rdir(ROOT, '', ...)
%  rdir(...)
%
%
% *Inputs*
%
% * ROOT
%
% rdir(ROOT) lists the specified files.
% ROOT can be a pathname, filename, or can include both. One can use
% absolute and relative pathnames and wildcards (*). Wildcard can be placed
% anywhere and used many times like 'path*\*.m'
%
% One can also use a double wildcard (**) to match multiple directory
% levels. For example ROOT = 'path\**\*.m' will match all ".m" files in
% "path" and all subdirectories of "path".
%
% NOTE : ".svn" directories created by SubVersion (SVN) are excluded from
% the recursive listing.
%
% * TEST
%
% Optional test that can be performed on the returned files.
%
% TEST is a string indicating expression to be evaluated on selected field
% of rdir output.
% All fields (ie name, date, bytes, isdir and datenum) can be used.
%
% Tests are strings similar to what one would use in a "if" statement e.g.
%  'bytes>1024 & datenum>now-7'
% One can also use function like "regexp" or "strfind" with string fields
% like "name" and "date" e.g 'regexp(name, 'expr')'.
%
% * RMPATH
%
% Optional path to remove from beginning of "name" field in returned
% output. Specified path must be common to all items found.
%
% If RMPATH = 1 or true, path to remove is part of ROOT before the first
% wildcard.
%
%
% *Outputs*
%
% d is a structure with the same fields as Matlab DIR output.
%
% The "name" field includes the relative path as well as the name to the
% file that was found. Path can be shorten or ommited when using 3rd
% argument RMPATH.
%
% If not output variable is specified then the output is sent to the
% screen.
%
%
% *Versions*
%
% * 1.0 - 2009, Gus Brown
% * 2.0 - 26/05/2011 Thomas Vanaret
%         No longer exclude all directories from a simple search (no *);
%         Fixing bug on returned path;
%         Exclude ".svn" directories;
%         Extended test possibilies;
%         Subfunctions created;
% * 2.1 - 14/07/2011 Thomas Vanaret
%         New argument allowing to remove common path from name;
%         Comments review;
% * 2.2 - 20/12/2011 Thomas Vanaret
%         Fixing bug on display with 0b files;
%         Specific display when no file match filter;
%
%
%
% *Examples*
%
%   D = rdir('*.m');
%     for ii=1:length(D), disp(D(ii).name); end;
%
%   % to find all files in the current directory and sub directories
%   D = rdir('**\*')
%
%   % If no output is specified then the files are sent to
%   % the screen.
%   rdir('c:\program files\windows *\*.exe');
%   rdir('c:\program files\windows *\**\*.dll');
%
%   % Using the test function to find files modified today
%   rdir('c:\win*\*','datenum>floor(now)');
%   % Using the test function to find files of a certain size
%   rdir('c:\program files\win*\*.exe','bytes>1024 & bytes<1048576');
%   % Using the test function to find files modified in 2011
%   rdir('c:\win*\*','strfind(date, ''2011'')');
%
%   % Using the 3rd input to shorten output name
%   rdir([matlabroot, '\*.txt'], '', 'C:\Program Files\')
%   % Using the 3rd input to shorten output name
%   rdir([matlabroot, '\*.txt'], '', 1)
%
%
% See also DIR
%

%--------------------------------------------------------------------------
%% Input validation

% use the current directory if nothing is specified
if ~exist('rootdir','var'),
  rootdir = '*';
end

prepath = '';       % the path before the wild card
wildpath = '';      % the path wild card
postpath = rootdir; % the path after the wild card
I = find(rootdir==filesep,1,'last');

% Directory separator for current platform
if filesep == '\'
  % On PC, filesep is '\'
  anti_filesep = '/';
else
  % On UNIX system, filesep is '/'
  anti_filesep = '\';
end

if isempty(I) && ~isempty(strfind(rootdir, anti_filesep))
  error([mfilename, ':FileSep'],...
    'Use correct directory separator "%s".', filesep)
end

%--------------------------------------------------------------------------
%% Split rootdir
% split the file path around the wild card specifiers

if ~isempty(I),
  prepath = rootdir(1:I);
  postpath = rootdir(I+1:end);
  I = find(prepath=='*',1,'first');
  if ~isempty(I),
    postpath = [prepath(I:end) postpath];
    prepath = prepath(1:I-1);
    I = find(prepath==filesep,1,'last');
    if ~isempty(I),
      wildpath = prepath(I+1:end);
      prepath = prepath(1:I);
    end;
    I = find(postpath==filesep,1,'first');
    if ~isempty(I),
      wildpath = [wildpath postpath(1:I-1)];
      postpath = postpath(I:end);
    end;
  end;
end;

% disp([' "' prepath '" ~ "' wildpath '" ~ "' postpath '" ']);

%--------------------------------------------------------------------------
%% Recursive listing

if isempty(wildpath)
  % If no directory wildcards then just get file and directoties list

  D = dir([prepath postpath]);

  % Exclude ".", ".." and ".svn" directories from the list
  excl = isdotdir(D) | issvndir(D);
  D(excl) = [];

  if isdir([prepath postpath]);
    fullpath = [prepath postpath];
  else
    fullpath = prepath;
  end

  % Place directories on the top of the list
  is_dir = [D.isdir]';
  D = [D(is_dir); D(~is_dir)];

  % Add path before name
  for ii = 1:length(D)
    D(ii).name = fullfile(fullpath, D(ii).name);
  end

  % disp(sprintf('Scanning "%s"   %g files found',[prepath postpath],length(D)));

elseif strcmp(wildpath,'**')
  % A double wildcards directory means recurs down into sub directories

  % first look for files in the current directory (remove extra filesep)
  D = rdir([prepath postpath(2:end)]);

  % then look for sub directories
  tmp = dir([prepath '*']);

  % Exclude ".", "..", ".svn" directories and files from the list
  excl = isdotdir(tmp) | issvndir(tmp) | ~([tmp.isdir]');
  tmp(excl) = [];

  % Process each sub directory found
  Dt = dir('');
  for ii = 1:length(tmp),
    Dt = [Dt; rdir([prepath tmp(ii).name filesep wildpath postpath])]; %#ok<AGROW>
  end
  D = [D; Dt];

else
  % Process directory wild card looking for sub directories that match

  tmp = dir([prepath wildpath]);

  % Exclude ".", "..", ".svn" directories and files from the list
  excl = isdotdir(tmp) | issvndir(tmp) | ~([tmp.isdir]');
  tmp(excl) = [];

  if ~isdir(prepath)
    % Fix case like rdir('path*\...') where prepath is not a directoty
    % name.
    prepath = '';
  end

  % Process each directory found
  D = dir('');
  for ii = 1:length(tmp),
    D = [D; rdir([prepath tmp(ii).name postpath])]; %#ok<AGROW>
  end

end

%--------------------------------------------------------------------------
%% Apply filter

nb_before_filt = length(D);
if (nargin>=2 && ~isempty(varargin{1})),
  try
    test_tf = evaluate(D, varargin{1});

    D = D(test_tf);

  catch
    warning([mfilename, ':InvalidTest'],...
      'Invalid TEST "%s" : %s', varargin{1}, lasterr);
  end
end

%--------------------------------------------------------------------------
%% Remove path

common_path = '';
if (nargin>=3 && ~isempty(varargin{2})),

  arg2 = varargin{2};
  if ischar(arg2)
    common_path = arg2;
  elseif (isnumeric(arg2) || islogical(arg2)) && arg2
    common_path = prepath;
  end

  rm_path = regexptranslate('escape', common_path);

  % Check that path is common to all
  start = regexp({D.name}', ['^', rm_path]);

  % Convert to a logical.
  is_common = not( cellfun(@isempty, start) );

  if all(is_common)
    for k = 1:length(D)
      D(k).name = regexprep(D(k).name, ['^', rm_path], '');
    end

  else
    common_path = '';
  end

end

%--------------------------------------------------------------------------
%% Display listing if no output variables are specified

if nargout==0,
  if isempty(D)
    if nb_before_filt == 0
      fprintf('%s not found.\n', rootdir)
    else
      fprintf('No item matching filter.\n')
    end
  else

    if ~isempty(common_path)
     fprintf('All in : %s\n', common_path)
    end

    pp = {'' 'k' 'M' 'G' 'T'};
    for ii = 1:length(D)
      if D(ii).isdir
        % Directory item : display name
        disp(sprintf(' %29s %-64s','',D(ii).name));
      else
        % File item : display size, modification date and name
        sz = D(ii).bytes;
        if sz > 0
          ss = min(4,floor(log2(sz)/10));
        else
          ss = 0;
        end
        disp(sprintf('%4.0f %1sb  %20s  %-64s ',...
          sz/1024^ss, pp{ss+1}, datestr(D(ii).datenum, 0), D(ii).name));
      end
    end
  end
else
  % send list out
  varargout{1} = D;
end;

%---------------------------- end of main function ------------------------

%% ------------------------------------------------------------------------
function tf = issvndir(d)
% True for ".svn" directories.
% d is a structure returned by "dir"
%

is_dir = [d.isdir]';

is_svn = strcmp({d.name}, '.svn')';
%is_svn = false; % uncomment to disable ".svn" filtering

tf = (is_dir & is_svn);

%---------------------------- end of subfunction --------------------------

%% ------------------------------------------------------------------------
function tf = isdotdir(d)
% True for "." and ".." directories.
% d is a structure returned by "dir"
%

is_dir = [d.isdir]';

is_dot = strcmp({d.name}, '.')';
is_dotdot = strcmp({d.name}, '..')';

tf = (is_dir & (is_dot | is_dotdot) );

%---------------------------- end of subfunction --------------------------

%% ------------------------------------------------------------------------
function tf = evaluate(d, expr)
% True for item where evaluated expression is correct or return a non empty
% cell.
% d is a structure returned by "dir"
%

% Get fields that can be used
name = {d.name}'; %#ok<NASGU>
date = {d.date}'; %#ok<NASGU>
datenum = [d.datenum]'; %#ok<NASGU>
bytes = [d.bytes]'; %#ok<NASGU>
isdir = [d.isdir]'; %#ok<NASGU>

tf = eval(expr);

% Convert cell outputs returned by "strfind" or "regexp" filters to a
% logical.
if iscell(tf)
  tf = not( cellfun(@isempty, tf) );
end

%---------------------------- end of subfunction --------------------------

%---------------------------- END OF FUNCTION -----------------------------


%% QUAD_BATCH_LOCAL uses the BATCH command to run the QUAD code locally.
%
%  Discussion:
%
%    The QUAD code is a function, so first we must write a script
%    called QUAD_SCRIPT that runs the function.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    31 March 2010
%
%  Author:
%
%    John Burkardt
%
  clear

  fprintf ( 1, '\n' );
  fprintf ( 1, 'QUAD_BATCH_LOCAL\n' );
  fprintf ( 1, '  Run QUAD_SCRIPT locally.\n' );
%
%  BATCH sends the script for execution.
%
  job = batch ( 'quad_script', ...
    'Configuration', 'local', ...
    'CaptureDiary', true, ...
    'FileDependencies', { 'quad_fun' }, ...
    'matlabpool', 7 );
%
%  WAIT pauses MATLAB session til the job completes.
%
  wait ( job );
%
%  DIARY displays any messages printed during execution.
%
  diary ( job );
%
%  LOAD makes the script's workspace available.
%
%  value = estimated integral.
%
  load ( job );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Estimated integral = %f\n', value );
  fprintf ( 1, '  Exact integral    is %f\n', pi );
  fprintf ( 1, '  Error is             %e\n', abs ( value - pi ) );
%
%  DESTROY cleans up data about the job we no longer need.
%
  destroy ( job );

  fprintf ( 1, '\n' );
  fprintf ( 1, 'QUAD_BATCH_LOCAL\n' );
  fprintf ( 1, '  Normal end of execution.\n' );