function saveNEVSpikes(spikeStruct, newFileName)

% saveNEVSpikes
%
% Allows the user to save a modified version of the spike waveforms into a
% NEV file. This can be very useful for those who want to save MATLAB
% sorted or rethresholded NEV data back into the NEV file. It also re-saves
% the other data in the original NEV file into the new NEV. A
%
% Use saveNEVSpikes(spikeStruct, newFileName)
%
%   spikeStruct: The structure containing the spike data needed to be
%                saved. The structure format must match the one that
%                openNEV outputs.
%                spikeStruct.TimeStamp: contains all the timestamps
%                spikeStruct.Electrode: contains all the electrode #s
%                spikeStruct.Unit: contains all the sorted unit #s
%                spikeStruct.Waveform: Spike waveforms, containing 48 data
%                                      points
%
%   newFileName: The file name of the new NEV file.
%                DEFAULT: User will be prmpted for a file name.
%
%   Example 1:
%   saveNEVSpikes(spikeStruct, 'sortedNEV';
%
%   In the example above, the user will be prompted to select a NEV file.
%   The data stored in spikeStruct will be saved into sortedNEV alongside
%   the data in the user-selected NEV file. The new NEV will be saved as
%   sortedNEV.nev
%
%   Kian Torab
%   ktorab@blackrockmicro.com
%   Blackrock Microsystems
%   Version 1.2.1.0
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Version History
%
% 1.0.0.0: Initial Release.
%
% 1.2.0.0:
%   - Fixed a bug where the data saved incorrectly under the Windows OS.
%   - Sped up the processing significantly.
%
% 1.2.1.0
%   - Fixed a bug introduced in 1.2.0.0.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Validating the input argument
if ~exist('spikeStruct', 'var')
    disp('spikeStruct is a required input argument.');
    return;
end

% if isfield(spikeStruct, 'Data') && isfield(spikeStruct, 'MetaTags')
%     newFileName = fullfile(NEV.MetaTags.FilePath, [NEV.MetaTags.Filename, '.nev']);
%     spikeStruct = NEV.Data.Spikes;
% end

if ~exist('newFileName', 'var')
    newFileName = input('What file name would you like to use to save the new NEV? ', 's');
    if isempty(newFileName)
        disp('A filename is required.');
        return;
    end
end

%% Opening the file and reading header
[dataFilename dataFolder] = getFile('*.nev', 'Choose a NEV that you would like to modify.');
fileFullPath = [dataFolder dataFilename];
FID = fopen(fileFullPath, 'r', 'ieee-le');

%% Calculating the header bytes
BasicHeader = fread(FID, 20, '*uint8');
headerBytes  = double(typecast(BasicHeader(13:16), 'uint32'));
dataPacketByteLength = double(typecast(BasicHeader(17:20), 'uint32'));

%% Calculating the data file length and eeking to the beginning of the file
fseek(FID, 0, 'eof');
endOfDataByte = ftell(FID);
dataByteLength = endOfDataByte - headerBytes;
numberOfPackets = double(dataByteLength) / double(dataPacketByteLength);

%% Reading the header binaries and saving it for future
fseek(FID, 0, 'bof');
headerBinaries = fread(FID, headerBytes, '*uint8');

%% Reading the data binaries
dataBinaries = fread(FID, [dataPacketByteLength numberOfPackets], '*uint8', 0);

%% Finding what PacketIDs have the desired channels
PacketIDs = zeros(1,size(dataBinaries,2));
for IDX = 1:size(dataBinaries,2)
    PacketIDs(IDX) = typecast(dataBinaries(5:6, IDX), 'uint16');
end

%% Only capturing all the binary lines that contain non-spike events, such
% as comments, tracking, patient trigger, etc.
newDataBinaries = dataBinaries(:, PacketIDs > 256); clear dataBinaries;

%% Extracting the timestamps of all the above non-spike events
dataTimestamps = zeros(1,size(newDataBinaries,2));
for IDX = 1:size(newDataBinaries,2)
    dataTimestamps(IDX) = typecast(newDataBinaries(1:4, IDX), 'uint32');
end

%% Converting all the user supplied data into binaries for saving into the
% new structure
newSpikesBinary = zeros(size([typecast(uint32(spikeStruct.TimeStamp(1)), 'uint8'),...
                         typecast(uint16(spikeStruct.Electrode(1)), 'uint8'),...
                         typecast(uint8(spikeStruct.Unit(1)), 'uint8'),...
                         1,...
                         typecast(int16(spikeStruct.Waveform(:,1))', 'uint8')]',1), size(spikeStruct.Electrode,2));
for idx = 1:size(spikeStruct.Electrode,2)
    newSpikesBinary(:,idx) = [typecast(uint32(spikeStruct.TimeStamp(idx)), 'uint8'),...
                         typecast(uint16(spikeStruct.Electrode(idx)), 'uint8'),...
                         typecast(uint8(spikeStruct.Unit(idx)), 'uint8'),...
                         1,...
                         typecast(int16(spikeStruct.Waveform(:,idx))', 'uint8')]';
end

%% Processing data
% Concatinating the user supplied data (non-spike) and the user supplied data
newDataBinaries = [newDataBinaries, newSpikesBinary];

% Ranking the spike and re-ranking the data for saving (timestamp descending)
allTimestamps = [dataTimestamps, spikeStruct.TimeStamp];
[~, ranking] = sort(allTimestamps);
newDataBinaries = newDataBinaries(:,ranking);

%% Saving the new NEV containig the desired channels
FIDw = fopen([dataFolder newFileName '.nev'], 'w+', 'ieee-le');
fwrite(FIDw, headerBinaries, 'uint8');
fwrite(FIDw, newDataBinaries, 'uint8');
fclose(FID);
fclose(FIDw);


function [vol, sens, cfg] = prepare_headmodel(cfg, data)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION that helps to prepare the electrodes/gradiometers and the volume
% this is used in sourceanalysis and dipolefitting
%
% This function will get the gradiometer/electrode definition from
%   cfg.channel
%   cfg.gradfile
%   cfg.elecfile
%   cfg.elec
%   cfg.grad
%   data.grad
%   data.elec
% and the volume conductor definition from
%   cfg.hdmfile
%   cfg.vol
%   data.vol
% Subsequently it will remove the gradiometers/electrodes that are not
% present in the data. Finally it with attach the gradiometers to a
% multi-sphere head model (if supplied) or attach the electrodes to
% a BEM head model.
%
% This function will return the electrodes/gradiometers in an order that is
% consistent with the order in cfg.channel, or in case that is empty in the
% order of the input electrode/gradiometer definition.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

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

% set the defaults
if ~isfield(cfg, 'channel'), cfg.channel = 'all';   end
if ~isfield(cfg, 'order'),   cfg.order = 10;        end % order of expansion for Nolte method; 10 should be enough for real applications; in simulations it makes sense to go higher

if nargin<2
  data = [];
end

% get the volume conduction model
if isfield(cfg, 'hdmfile')
  fprintf('reading headmodel from file ''%s''\n', cfg.hdmfile);
  vol = ft_read_vol(cfg.hdmfile);
elseif isfield(cfg, 'vol')
  fprintf('using headmodel specified in the configuration\n');
  vol = cfg.vol;
elseif isfield(data, 'vol')
  fprintf('using headmodel specified in the data\n');
  vol = data.vol;
else
  error('no headmodel specified');
end

% get the gradiometer or electrode definition
if isfield(cfg, 'gradfile')
  fprintf('reading gradiometers from file ''%s''\n', cfg.gradfile);
  sens = read_sens(cfg.gradfile);
elseif isfield(cfg, 'grad')
  fprintf('using gradiometers specified in the configuration\n');
  sens = cfg.grad;
elseif isfield(data, 'grad')
  fprintf('using gradiometers specified in the data\n');
  sens = data.grad;
elseif isfield(cfg, 'elecfile')
  fprintf('reading electrodes from file ''%s''\n', cfg.elecfile);
  sens = read_sens(cfg.elecfile);
elseif isfield(cfg, 'elec')
  fprintf('using electrodes specified in the configuration\n');
  sens = cfg.elec;
elseif isfield(data, 'elec')
  fprintf('using electrodes specified in the data\n');
  sens = data.elec;
else
  error('no electrodes or gradiometers specified');
end

if isfield(data, 'topolabel')
  % the data reflects a componentanalysis, where the topographic and the
  % timecourse labels are different
  cfg.channel = ft_channelselection(cfg.channel, data.topolabel);
elseif isfield(data, 'label')
  % In the subsequent code, the matching channels in the sensor array and
  % in the configuration will be selected. To ensure that these channels
  % are also present in the data, update the configuration to match the data.
  cfg.channel = ft_channelselection(cfg.channel, data.label);
else
  % update the selected channels based on the electrode/gradiometer definition
  cfg.channel = ft_channelselection(cfg.channel, sens.label);
end

% ensure that these are a struct, which may be required in case configuration tracking is used
vol  = struct(vol);
sens = struct(sens);

% the prepare_vol_sens function from the forwinv module does most of the actual work
[vol, sens] = ft_prepare_vol_sens(vol, sens, 'channel', cfg.channel, 'order', cfg.order);

% update the selected channels in the configuration
cfg.channel = sens.label;


classdef TestAGAST
    %TestAGAST

    properties (Constant)
        im = fullfile(mexopencv.root(),'test','tsukuba_l.png');
        kfields = {'pt', 'size', 'angle', 'response', 'octave', 'class_id'};
    end

    methods (Static)
        function test_detect_img
            img = imread(TestAGAST.im);
            kpts = cv.AGAST(img, ...
                'Threshold',10, 'NonmaxSuppression',true);
            validateattributes(kpts, {'struct'}, {'vector'});
            assert(all(ismember(TestAGAST.kfields, fieldnames(kpts))));
        end

        function test_detect_types
            types = {'AGAST_5_8', 'AGAST_7_12d', 'AGAST_7_12s', 'OAST_9_16'};
            img = imread(TestAGAST.im);
            for i=1:numel(types)
                kpts = cv.AGAST(img, 'Type',types{i});
                validateattributes(kpts, {'struct'}, {'vector'});
            end
        end

        function test_error_argnum
            try
                cv.AGAST();
                throw('UnitTest:Fail');
            catch e
                assert(strcmp(e.identifier,'mexopencv:error'));
            end
        end
    end

end


function planC = insertDeformS(planC,deformS)

indexS = planC{end};

deformIndex = length(planC{indexS.deform}) + 1;
planC{indexS.deform}  = dissimilarInsert(planC{indexS.deform},deformS,deformIndex);


executable = '"../../x64/Release/FeatureExtraction.exe"';

outputDir = 'D:\Datasets\face2face\2006_processed/';

% First collect the filenames of the data to be used
input_label_dir = 'D:\Datasets\face2face\rapport-oct-2006-all-transcriptions/';

folds = dir([input_label_dir, '*SES*']);

listener_file_labels = {};
speaker_file_labels = {};

listener_vid_files = {};
speaker_vid_files = {};

speaker_vid_dir = 'D:\Datasets\face2face\rapport-oct-2006-all-movie-speaker/';
listener_vid_dir = 'D:\Datasets\face2face\rapport-oct-2006-all-movie-listener/';
verbose = true;
for i=1:numel(folds)

    listener_file = dir([input_label_dir, folds(i).name, '/*.L.nod.eaf']);
    speaker_file = dir([input_label_dir, folds(i).name, '/*.S.nod.eaf']);

    if(~isempty(listener_file))
        % Need to find the appropriate video file if it exists
        num = listener_file.name(end-13:end-10);
        vid_file_dir = dir([listener_vid_dir, '/*', num, '*']);
        vid_file = dir([listener_vid_dir, '/', vid_file_dir.name, '/*.mp4']);
        if(~isempty(vid_file))
            listener_vid_files = cat(1, listener_vid_files, [listener_vid_dir, '/', vid_file_dir.name, '/', vid_file.name]);
            listener_file_labels = cat(1, listener_file_labels, [input_label_dir, '/' folds(i).name, '/' listener_file.name]);
        end
    end

    if(~isempty(speaker_file))
        num = speaker_file.name(end-13:end-10);
        vid_file_dir = dir([speaker_vid_dir, '/*', num, '*']);
        vid_file = dir([speaker_vid_dir, '/', vid_file_dir.name, '/*.mp4']);
        if(~isempty(vid_file))
            speaker_vid_files = cat(1, speaker_vid_files, [speaker_vid_dir, '/', vid_file_dir.name, '/', vid_file.name]);
            speaker_file_labels = cat(1, speaker_file_labels, [input_label_dir, '/' folds(i).name, '/' speaker_file.name]);
        end
    end

end

% file_labels = cat(1, listener_file_labels, speaker_file_labels);
% video_files = cat(1, listener_vid_files, speaker_vid_files);

file_labels = listener_file_labels;
video_files = listener_vid_files;

parfor i=1:numel(file_labels)

    [~,short_name,vid_ext] = fileparts(video_files{i});

    command = executable;

    inputFile = video_files{i};
    outputFile = [outputDir short_name '.txt'];

    outputEaf = [outputDir short_name '.eaf'];

    command = cat(2, command, [' -f "' inputFile '" -of "' outputFile  '"']);

    if(verbose)
        outputVideo = [outputDir short_name '.track.avi'];
        command = cat(2, command, [' -ov "' outputVideo '"']);
    end

    command = cat(2, command, [' -no2Dfp -no3Dfp -noMparams -noAUs -noGaze']);

    dos(command);

    copyfile(file_labels{i}, outputEaf);
    copyfile(video_files{i}, [outputDir '/' short_name, '.mp4']);

end


function [sFileOut, errMsg] = out_fopen(RawFile, FileFormat, sFileIn, ChannelMat, iChannels)
% OUT_FOPEN: Saves the header of a new empty binary file.
%
% INPUTS:
%    - RawFile    : Full path of the file to create
%    - FileFormat : String ('EEG-EDF', 'BST-BIN', ...)
%    - sFileIn    : Structure of the header of the file to create
%    - ChannelMat : Channel file associated with the file to save
%    - iChannels  : Subset of channels from input file to save in output file

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

% Parse inputs
if (nargin < 5) || isempty(iChannels)
    iChannels = [];
end
% Output variables
sFileOut = [];
errMsg = [];
% Get default epoch size
EpochSize = bst_process('GetDefaultEpochSize', sFileIn);

% Select channels in channel file
if ~isempty(iChannels)
    sFileIn.channelflag = sFileIn.channelflag(iChannels);
end

% Trying to open the output file
try
    % Create file header
    switch (FileFormat)
        case 'EEG-EGI-RAW'
            sFileOut = out_fopen_egi(RawFile, sFileIn, ChannelMat);
        case 'EEG-BRAINAMP'
            sFileOut = out_fopen_brainamp(RawFile, sFileIn, ChannelMat);
        case 'BST-BIN'
            sFileOut = out_fopen_bst(RawFile, sFileIn, ChannelMat, EpochSize);
        case 'SPM-DAT'
            sFileOut = out_fopen_spm(RawFile, sFileIn, ChannelMat);
        case 'EEG-EDF'
            sFileOut = out_fopen_edf(RawFile, sFileIn, ChannelMat, EpochSize, iChannels);
        case 'FIF'
            error('copy input file');
        case 'CTF-CONTINUOUS'
            error('copy input file');
        otherwise
            error('Unsupported file format');
    end
catch
    % Get error message
    e = lasterror();
    if ~isempty(e)
        errMsg = str_striptag(e.message);
    end
end


% MacromoleculeUtility test
%
% Author: Derek Macklin, macklin@stanford.edu
% Author: Jonathan Karr, jkarr@stanford.edu
% Affiliation: Covert Lab, Department of Bioengineering, Stanford University
% Last updated 6/29/2011
classdef MacromoleculeUtil_Test < TestCase
    properties
        simulation
    end

    methods
        function this = MacromoleculeUtil_Test(name)
            this = this@TestCase(name);
        end

        function setUp(this)
            sim = edu.stanford.covert.cell.sim.SimulationFixture.load();
            this.simulation = sim;
        end

        function testGetMacromoleculeIndexsIDsNames(this)
            import edu.stanford.covert.cell.sim.util.MacromoleculeUtil;

            s = this.simulation;

            % Gene that doesn't exist
            [idx, compIdx, id, name, type, ...
                geneIdxs, geneCompIdxs, geneIds, geneNames, ...
                nascentRnaIdxs, nascentRnaCompIdxs, nascentRnaIds, nascentRnaNames, ...
                matureRnaIdxs, matureRnaCompIdxs, matureRnaIds, matureRnaNames, ...
                monomerIdxs, monomerCompIdxs, monomerIds, monomerNames, ...
                complexIdxs, complexCompIdxs, complexIds, complexNames] = ...
                MacromoleculeUtil.getMacromoleculeIndexsIDsNames('DOES_NOT_EXIST', s);

            assert(isequal(idx,[]));
            assert(isequal(compIdx,[]));
            assert(isequal(id,[]));
            assert(isequal(name,[]));
            assert(isequal(type,[]));
            assert(isequal(geneIdxs,[]));
            assert(isequal(geneCompIdxs,[]));
            assert(isequal(geneIds,[]));
            assert(isequal(geneNames,[]));
            assert(isequal(nascentRnaIdxs,[]));
            assert(isequal(nascentRnaCompIdxs,[]));
            assert(isequal(nascentRnaIds,[]));
            assert(isequal(nascentRnaNames,[]));
            assert(isequal(matureRnaIdxs,[]));
            assert(isequal(matureRnaCompIdxs,[]));
            assert(isequal(matureRnaIds,[]));
            assert(isequal(matureRnaNames,[]));
            assert(isequal(monomerIdxs,[]));
            assert(isequal(monomerCompIdxs,[]));
            assert(isequal(monomerIds,[]));
            assert(isequal(monomerNames,[]));
            assert(isequal(complexIdxs,[]));
            assert(isequal(complexCompIdxs,[]));
            assert(isequal(complexIds,[]));
            assert(isequal(complexNames,[]));

            % Two species present in a protein complex
            [idx, compIdx, id, name, type, ...
                geneIdxs, geneCompIdxs, geneIds, geneNames, ...
                nascentRnaIdxs, nascentRnaCompIdxs, nascentRnaIds, nascentRnaNames, ...
                matureRnaIdxs, matureRnaCompIdxs, matureRnaIds, matureRnaNames, ...
                monomerIdxs, monomerCompIdxs, monomerIds, monomerNames, ...
                complexIdxs, complexCompIdxs, complexIds, complexNames] = ...
                MacromoleculeUtil.getMacromoleculeIndexsIDsNames('MG_008_379_TETRAMER',s);

            assert(isequal(id,'MG_008_379_TETRAMER'));

            assert(isequal(name,'tRNA uridine 5-carboxymethylaminomethyl modification enzyme'));

            assert(isequal(type,'complex'));

            assert(isequal(size(geneIdxs),[2 1]));

            assert(isequal(size(geneCompIdxs),[2 1]));

            assert(isequal(size(geneIds),[2 1]));
            assert(isequal(geneIds,{'MG_008';'MG_379'}));

            assert(isequal(size(geneNames),[2 1]));
            assert(isequal(geneNames,{'tRNA modification GTPase TrmE';'tRNA uridine 5-carboxymethylaminomethyl modification enzyme GidA'}));

            assert(isequal(size(nascentRnaIdxs),[1 2]));

            assert(isequal(size(nascentRnaCompIdxs),[1 2]));

            assert(isequal(size(nascentRnaIds),[2 1]));
            assert(isequal(nascentRnaIds,{'TU_003';'TU_275'}));

            assert(isequal(size(nascentRnaNames),[2 1]));
            assert(isequal(nascentRnaNames,{'MG_005 - MG_009';'MG_379 - MG_381'}));

            assert(isequal(size(matureRnaIdxs),[1 2]));

            assert(isequal(size(matureRnaCompIdxs),[1 2]));

            assert(isequal(size(matureRnaIds),[2 1]));
            assert(isequal(matureRnaIds,{'TU_003';'TU_275'}));

            assert(isequal(size(matureRnaNames),[2 1]));
            assert(isequal(matureRnaNames,{'MG_005 - MG_009';'MG_379 - MG_381'}));

            assert(isequal(size(monomerIdxs),[2 1]));
            assert(isequal(size(monomerCompIdxs),[2 1]));

            assert(isequal(size(monomerIds),[2 1]));
            assert(isequal(monomerIds,{'MG_008_MONOMER';'MG_379_MONOMER'}));

            assert(isequal(size(monomerNames),[2 1]));
            assert(isequal(monomerNames,{'tRNA modification GTPase TrmE';'tRNA uridine 5-carboxymethylaminomethyl modification enzyme GidA'}));

            assert(isequal(complexIds,{'MG_008_379_TETRAMER'}));
            assert(isequal(complexNames,{'tRNA uridine 5-carboxymethylaminomethyl modification enzyme'}));
        end

        function testGetMacromoleculeCounts(~)
            import edu.stanford.covert.cell.sim.util.MacromoleculeUtil;
            import edu.stanford.covert.cell.sim.util.SimulationDiskUtil;

            %select a simulation to analyze
            [simDir, ~, sim] = SimulationDiskUtil.getLatestSimulation();

            %load data
            [cnts, ...
                geneCnts, ...
                nascentRnaCnts, processedRnaCnts, matureRnaCnts, boundRnaCnts, misfoldedRnaCnts, damagedRnaCnts, aminoacylatedRnaCnts, ...
                nascentMonCnts, processedIMonCnts, translocatedMonCnts, processedIIMonCnts, foldedMonCnts, matureMonCnts, inactivatedMonCnts, boundMonCnts, misfoldedMonCnts, damagedMonCnts, ...
                nascentCpxCnts, matureCpxCnts, inactivatedCpxCnts, boundCpxCnts, misfoldedCpxCnts, damagedCpxCnts, ...
                rnaPolTUs, rnaPolPosStrnds, ribMRNAs, ribPos] = ...
                MacromoleculeUtil.getMacromoleculeCounts('MG_357', sim, simDir);
        end
    end
end


function removeLayer(obj, name, chainInputs)
%REMOVELAYER Remove a layer from the network
%   REMOVELAYER(OBJ, NAME) removes the layer NAME from the DagNN object
%   OBJ.

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

if nargin < 3, chainInputs = true; end
f = find(strcmp(name, {obj.layers.name})) ;
if isempty(f), error('There is no layer ''%s''.', name), end
layer = obj.layers(f) ;

if chainInputs
  % chain input of l that has layer as input
  for l = 1:numel(obj.layers)
    for i = layer.outputIndexes
      sel = find(intersect(obj.layers(l).inputIndexes, i));
      if any(sel)
        obj.layers(l).inputs{sel} = layer.inputs{1};
      end
    end
  end
end
obj.layers(f) = [] ;
obj.rebuild() ;


function p = geodesic_create_surface_point(type,id,x,y,z)

p.type = type;
p.id = id;

if nargin == 3
    p.x = x(1);
    p.y = x(2);
    p.z = x(3);
else
    p.x = x;
    p.y = y;
    p.z = z;
end


function s = s_low ( s )

%*****************************************************************************80
%
%% S_LOW replaces all uppercase letters by lowercase ones.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    20 November 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string S, the string to be transformed.
%
%    Output, string S, a lowercase copy of the input string.
%
  nchar = s_len_trim ( s );

  for i = 1 : nchar
    s(i) = ch_low ( s(i) );
  end

  return
end


function ViewClusters_Callback(hObject, eventdata, handles)
[ClusteringData,clustAssign] = CreateClusteringData(handles, 'forClustering', false);

[~, clusterName, rejected, finished, clustAssign] = clusteringGUI(clustAssign, ClusteringData);

% Save the clusters
if finished == 1
    saveChoice =  questdlg('Update files with new clusters?','Save clusters','Yes','No','No');
    switch saveChoice
        case 'Yes'
            [~, ~, clustAssign] = unique(clustAssign);
            UpdateCluster(ClusteringData, clustAssign, clusterName, rejected)
        case 'No'
            return
    end
end

end


%SETUP  Compile the SPGL1 MEX interfaces

%   setup.m
%   $Id: spgsetup.m 1019 2008-06-17 19:33:48Z mpf $
%
%   ----------------------------------------------------------------------
%   This file is part of SPGL1 (Spectral Projected Gradient for L1).
%
%   Copyright (C) 2007 Ewout van den Berg and Michael P. Friedlander,
%   Department of Computer Science, University of British Columbia, Canada.
%   All rights reserved. E-mail: <{ewout78,mpf}@cs.ubc.ca>.
%
%   SPGL1 is free software; you can redistribute it and/or modify it
%   under the terms of the GNU Lesser General Public License as
%   published by the Free Software Foundation; either version 2.1 of the
%   License, or (at your option) any later version.
%
%   SPGL1 is distributed in the hope that it will be useful, but WITHOUT
%   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
%   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
%   Public License for more details.
%
%   You should have received a copy of the GNU Lesser General Public
%   License along with SPGL1; if not, write to the Free Software
%   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
%   USA
%   ----------------------------------------------------------------------

root = pwd;
try
    cd('private')
    mex oneProjectorMex.c oneProjectorCore.c heap.c -output oneProjectorMex -DNDEBUG
    fprintf('Successfully compiled oneProjector.\n');
    cd(root)
catch err
    cd(root)
    fprintf('Could not compile oneProjector.');
    fprintf('You can still use the slower ".m" version.');
    rethrow(err);
end

try
    cd('private')
    mex productBMex.c -DNDEBUG
    fprintf('Successfully compiled productB.\n');
    cd(root)
catch err
    cd(root)
    fprintf('Could not compile productB.');
    rethrow(err);
end


function plotmainmap(obj)
    % PLOTMAINMAP set up main map window

    % TAG : PURPOSE
    % "active quakes" : selected events
    % "big evens" : selected events, above a threshhold magnitude

    % %
    % this probably belongs somewhere else...
    if ~isempty(obj.shape) && ~isvalid(obj.shape)
        msg.dbdisp('shape had been deleted');
        obj.shape = ShapeGeneral();
    end
    % %
    axm = obj.map_axes;
    axm.Visible = 'off';
    if isempty(axm)||~isvalid(axm)
        error('Somehow lost track of main map');
    end

    % update the active earthquakes
    eq=findobj(axm,'Tag','active quakes');

    mainEventOpts = obj.mainEventProps; % local copy
    szFcn = str2func(mainEventOpts.MarkerSizeFcn);

    if mainEventOpts.UseDotsForTooManyEvents && obj.catalog.Count > mainEventOpts.HowManyAreTooMany
        mainEventOpts.Marker = '.';
    end
    if isempty(eq)
        % CREATE the plot

        axm.NextPlot='add';
        dispname = replace(obj.catalog.Name,'_','\_');

        szFcn = str2func(mainEventOpts.MarkerSizeFcn);
        eq=scatter(axm, obj.catalog.X, obj.catalog.Y, ...
            szFcn(obj.catalog.Magnitude), getLegalColors(),...
            'Tag','active quakes',...
            'HitTest','off',...
            'DisplayName',dispname);
        eq.ZData = obj.catalog.Z;
        axm.NextPlot='replace';
        %obj.do_colorbar(axm);

    else

        % REUSE the plot
        eq.XData = obj.catalog.X;
        eq.YData = obj.catalog.Y;
        eq.ZData = obj.catalog.Z;
        eq.SizeData = szFcn(obj.catalog.Magnitude);
        eq.MarkerEdgeColor='flat';
        eq.CData = getLegalColors();

        % this is a kludge, because if a MarkerEdgeColor is defined that isn't specifically 'flat'
        % then it overrides the CData colors.
        if size(eq.CData(:,1)) > 1
            mainEventOpts=renameStructField(mainEventOpts,'MarkerEdgeColor','Marker_Edge_Color');
        else
            mainEventOpts=renameStructField(mainEventOpts,'Marker_Edge_Color','MarkerEdgeColor');
        end
        dispname = replace(obj.catalog.Name, '_', '\_');
        if ~strcmp(eq.DisplayName, dispname)
            eq.DisplayName = dispname;
        end
    end

    fix_colorbar()

    set_valid_properties(eq, mainEventOpts);

    % update the largest events
    update_large()

    % update the shape
    axm.NextPlot='add';
    if ~isempty(obj.shape)
        obj.shape.plot(axm);
    end
    axm.NextPlot='replace';

    % update the grid
    if ~isempty(obj.Grid)
        if isempty(obj.shape) && all(obj.Grid.ActivePoints(:))
            % do nothing needs to be done.
            obj.Grid.plot(obj.map_axes, 'HitTest', 'off', 'ActiveOnly');
        else
            maskedGrid = obj.Grid.MaskWithShape(obj.shape);
            if ~isequal(maskedGrid.ActivePoints, obj.Grid.ActivePoints)
                obj.Grid.ActivePoints = maskedGrid.ActivePoints;
                obj.Grid.plot(obj.map_axes, 'HitTest', 'off', 'ActiveOnly');
            end
        end
    end
    axm.Visible='on';

    function update_large()
        beq = findobj(axm,'Tag','big events');

        if ~isempty(obj.bigEvents)
            beq.XData = obj.bigEvents.X;
            beq.YData = obj.bigEvents.Y;
            beq.ZData = obj.bigEvents.Z;
            beq.SizeData=mag2dotsize(obj.bigEvents.Magnitude);
        else
            [beq.XData, beq.YData, beq.ZData, beq.SizeData]=deal([]);
        end

    end

    function c = getLegalColors()
        % because datetime isn't allowed
        switch  obj.colorField
            case '-none-'
                c=[0 0 .15];
            case 'Date'
                c=datenum(obj.catalog.Date);
            otherwise
                c=obj.catalog.(obj.colorField);
        end
    end

    function fix_colorbar()
        h = obj.map_axes.Colorbar;
        if isempty(h) && obj.colorField ~= "-none-"
            h = colorbar(obj.map_axes);
        end

        if isempty(h) || h.Label.String == string(obj.colorField)
            return
        end

        h.Label.String = obj.colorField;

        switch obj.colorField
            case '-none-'
                delete(h)

            case 'Depth'
                h.Direction = 'reverse';
                h.TickLabels = h.Ticks;

            case 'Date'
                    h.TickLabels   = datestr(h.Ticks,'yyyy-mm-dd');
                    h.Label.String = 'Date';
                    h.Direction    = 'normal';

            otherwise
                h.Direction = 'normal';
                h.TickLabels = h.Ticks;
        end

    end

end


function labels=dtiGetMoriLabels(short)

%ER 11/2009 wrote it

tdir = fullfile(fileparts(which('mrDiffusion.m')), 'templates');
labels = readTab(fullfile(tdir,'MNI_JHU_tracts_prob.txt'),',',false);
labels = labels(1:20,2);
if exist('short', 'var') && short
labels={'ATR_L', 'ATR_R', 'CST_L', 'CST_R', 'CCG_L', 'CCG_R', 'CHC_L','CHC_R', 'Forceps Major', 'Forceps Minor', 'IFO_L', 'IFO_R', 'ILF_L', 'ILF_R', 'SLF_L', 'SLF_R', 'UF_L', 'UF_R', 'SLF_t_L', 'SLF_t_R' }';
end


function e = end(q,i,n)
% overloads end function

if n==1
  e = numel(q.a);
else
  e = size(q,i);
end


% Function to load the stored optical flow based on some given method
%
%    Copyright (C) 2013  Anestis Papazoglou
%
%    You can redistribute and/or modify this software for non-commercial use
%    under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    This program is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with this program.  If not, see <http://www.gnu.org/licenses/>.
%
%    For commercial use, contact the author for licensing options.
%
%    Contact: a.papazoglou@sms.ed.ac.uk

function result = loadFlow( options)

    file = fullfile( options.outfolder, 'flow', 'flow.mat' );
    if( exist( file, 'file' ) )
        flow = load( file );
        if( isfield( flow, 'input' ) )
            result = flow.input;
        elseif( isfield( flow, 'flow' ) )
            result = flow.flow;
        else
            warning( '%s: no known field found\n', file );
            result = [];
        end
    else
        warning( '%s not found\n', file );
        result = [];
    end

end


function h_group = im_pix_line(h_parent,x_init,y_init)
%IM_PIX_LINE Create draggable and resizable line pixel by pixel.
% H = IM_PIX_LINE(HPARENT, X, Y) creates a draggable line on
%   the object specified by HPARENT.  The function returns H, a handle to
%   the line, which is an hggroup object.  HPARENT specifies the hggroups's
%   parent, which is typically an axes object, but can also be any other
%   object that can be the parent of an hggroup. X and Y specify the
%   initial end point positions of the line in the form
%   X = [X1 X2], Y =[Y1 Y2].
%
%   A draggable line can be dragged interactively using the mouse.
%
%   The draggable line has a context menu associated with it that allows you to
%   copy the current end point positions to the clipboard in the form
%   [X1 Y1; X2 Y2] and change the color used to display the line.
%
%   API Function Syntaxes
%   ---------------------
%   A draggable line contains a structure of function handles, called
%   an API, that can be used to manipulate it.  To retrieve this
%   structure from the draggable line, use the IPTGETAPI function.
%
%       API = IPTGETAPI(H)
%
%   Functions in the API, listed in the order of the structure fields, include:
%
%   setPosition
%
%       Sets the end point positions of the line.
%
%           api.setPosition(X,Y)
%           api.setPosition([X1 Y1; X2 Y2])
%
%   getPosition
%
%       Returns the end point positions of the line.
%
%           pos = api.getPosition()
%
%       where pos is a 2-by-2 array [X1 Y1; X2 Y2].
%
%   delete
%
%       Deletes the draggable line associated with the API.
%
%           api.delete()
%
%   setColor
%
%       Sets the color used to draw the draggable line.
%
%           api.setColor(new_color)
%
%       where new_color is a three-element vector specifying an RGB
%       value.
%
%   addNewPositionCallback
%
%       Adds the function handle FCN to the list of new-position callback
%       functions.
%
%           id = api.addNewPositionCallback(fcn)
%
%       Whenever the draggable line changes its position, each
%       function in the list is called with the syntax:
%
%           fcn(pos)
%
%       where pos is a 2-by-2 array [X1 Y1; X2 Y2].
%
%       The return value, id, is used only with removeNewPositionCallback.
%
%   removeNewPositionCallback
%
%       Removes the corresponding function from the new-position callback
%       list.
%
%           api.removeNewPositionCallback(id)
%
%       where id is the identifier returned by api.addNewPositionCallback.
%
%   setDragConstraintFcn
%
%       Sets the drag constraint function to be the specified function
%       handle, fcn.
%
%           api.setDragConstraintFcn(fcn)
%
%       Whenever the draggable line is moved or resized because of a mouse drag,
%       the constraint function is called using the syntax:
%
%           constrained_position = fcn(new_position)
%
%       where new_position is a 2-by-2 array [X1 Y1; X2 Y2].
%
%       This allows a client, for example, to control where the line may be
%       moved and how the line may be resized.
%
%   getDragConstraintFcn
%
%       Returns a function handle to the current drag constraint function.
%
%           fcn = api.getDragConstraintFcn()
%
%   Remarks
%   -------
%   If you use IM_PIX_LINE with an axis that contains an image object,
%   and do not specify a drag constraint function, users can drag
%   the point outside the extent of the image and lose the point.
%   When used with an axis created by the PLOT function, the axis
%   limits automatically expand to accommodate the movement of
%   the point.
%
%   Examples
%   --------
%       % Use a custom color for displaying the line.
%       figure, imshow('pout.tif');
%       h = im_pix_line(gca,[10 100], [100 100]);
%       api = iptgetapi(h);
%       api.setColor([0 1 0]);
%       % Now, explore the context menu of the draggable line by right
%       % clicking on the line.
%       % Try to zoom in and out, you will find the line is drawed pixel
%       % by pixel
%
%       % Use addNewPositionCallback API function.
%       figure, imshow('pout.tif');
%       h = im_pix_line(gca,[10 100], [100 100]);
%       api = iptgetapi(h);
%       id = api.addNewPositionCallback(@(pos) title(mat2str(pos,3)));
%       % Now move the mouse, note that the 2-by-2 position vector of the
%       % line is displayed in the title above the image.  Finally, remove
%       % the callback using removeNewPositionCallback
%       api.removeNewPositionCallback(id);
%
%       % Use makeConstrainToRectFcn to prevent dragging out line outside
%       % extent of image.
%       figure, imshow('pout.tif');
%       h = im_pix_line(gca,[10 100], [100 100]);
%       api = iptgetapi(h);
%       % IMPORTANT: use 'imline' here since makeConstrainToRectFcn can
%       % only recognize one of the imline, imrect, impoint !!!
%       fcn = makeConstrainToRectFcn('imline',get(gca,'XLim'),get(gca,'YLim'));
%       api.setDragConstraintFcn(fcn);
%
%   See also IMPOINT, IMRECT, IPTGETAPI, makeConstrainToRectFcn.

%   Copyright 2004-2005 The MathWorks, Inc.
%   $Revision: 1.1.6.3 $  $Date: 2005/12/12 23:22:09 $
%
%   adopted by gauss.1982@gmali.com
%   15:52 2006-12-15 $
%

iptchecknargin(3, 3, nargin, mfilename);
if ~ishandle(h_parent)
    error('Images:im_pix_line:invalidHandle', ...
        'HPARENT must be a valid graphics handle.');
end
if strcmp(get(h_parent, 'type'), 'axes')
    h_axes = h_parent;
else
    h_axes = ancestor(h_parent, 'axes');
    if isempty(h_axes)
        error('Images:im_pix_line:noAxesAncestor', ...
            'HPARENT must be a descendent of an axes object.');
    end
end

try
    h_group = hggroup('ButtonDownFcn', @startDrag, 'Parent', h_parent);
catch
    error('Images:im_pix_line:failureToParent', ...
        'HPARENT must be able to have an hggroup object as a child.');
end

%Returns API used to draw line graphic.
draw_api = pixLineSymbol(h_group);

% Initialize position variable for managing end point positions of line.
% This position variable is created to allow for abstraction of drag
% behavior in future.  Position is in the form [X1 Y1; X2 Y2]
position = [reshape(x_init,2,1),reshape(y_init,2,1)];

% constraint_function is used by dragMotion() to give a client the
% opportunity to constraint where the draggable line can be
% dragged.
drag_constraint_function  = identityFcn;

% new_position_callback_functions is used by sendNewPosition() to
% notify interested clients whenever the rectangle position changes.
new_position_callback_functions = makeList;

% Pattern for set associated with callbacks that get called as a
% result of the set.
insideSetPosition = false;

% Size of SelectionHighlight markers on end of line is 5 pixels.  This
% constant is used throughout im_pix_line
marker_end_size = 5;

h_fig = iptancestor(h_axes, 'figure');
cmenu = uicontextmenu('Parent', h_fig);

%In order for IMDISTLINE to be draggable in IMTOOL, the HitTest property
%of the line objects created by LineSymbol() must be set to 'on'.
%this requires that the context menu be associated with the line objects
%rather than the h_group.
set(findobj(h_group,'Type','line'), 'UIContextMenu', cmenu);

uimenu(cmenu, ...
    'Label', 'Copy Position', ...
    'Callback', @copyPosition');

set_color_menu = uimenu(cmenu, ...
    'Label', 'Set Line Color');
color_choices = getColorChoices;

for k = 1:numel(color_choices)
    uimenu(set_color_menu, 'Label', color_choices(k).Label, ...
        'Callback', @(varargin) setColor(color_choices(k).Color));
end
setColor(color_choices(1).Color);

api.setPosition                 = @setPosition;
api.getPosition                 = @getPosition;
api.delete                      = @deleteLine;
api.setColor                    = @setColor;
api.addNewPositionCallback      = @addNewPositionCallback;
api.removeNewPositionCallback   = @removeNewPositionCallback;
api.getDragConstraintFcn        = @getDragConstraintFcn;
api.setDragConstraintFcn        = @setDragConstraintFcn;

setappdata(h_group, 'API', api);

updateView(position);

% Create update function that knows how to get the position it needs when it
% will be called from HG contexts where it may not have access to the position
% otherwise.
update_fcn = @(varargin) updateView(api.getPosition());

% Install pointer manager in figure.
iptPointerManager(h_fig);

% Store pointer behavior in the hggroup object and all its children.
enterFcn = @(f,cp) set(f, 'Pointer', 'fleur');
iptSetPointerBehavior(findobj(h_group), enterFcn);

updateAncestorListeners(h_group,update_fcn);

    %----------------------------
    function setPosition(varargin)

        % Validate inputs before caling break recursion pattern.
        iptchecknargin(1, 2, nargin, sprintf('%s/setPosition',mfilename));

        % Pattern to break recursion
        if insideSetPosition
            return
        else
            insideSetPosition = true;
        end

        switch nargin
            case 1
                position = varargin{1};
            case 2
                %Ensure that position vector always remains
                %in the form [X1 Y1; X2 Y2] independent of whether data is
                %entered as row or column vectors
                position = [reshape(varargin{1},2,1),...
                    reshape(varargin{2},2,1)];
        end

        updateView(position);
        sendNewPosition;

        % Pattern to break recursion
        insideSetPosition = false;
    end

    %-------------------------
    function pos = getPosition
        pos = position;
    end

    %---------------------------------------
    function id = addNewPositionCallback(fun)
        id = new_position_callback_functions.appendItem(fun);
    end

    %------------------------------------
    function removeNewPositionCallback(id)
        new_position_callback_functions.removeItem(id);
    end

    %--------------------------------
    function setDragConstraintFcn(fun)
        drag_constraint_function = fun;
    end

    %---------------------------------
    function fh = getDragConstraintFcn
        fh = drag_constraint_function;
    end

    %--------------------------------
    function deleteLine(src, varargin) %#ok varargin needed by HG caller
        if ishandle(h_group)
            delete(h_group);
        end
    end

    %---------------------------
    function updateView(position)
        draw_api.updateView(position);
    end

    %----------------------
    function setColor(color)
        draw_api.setColor(color)
    end

    %------------------------------
    function copyPosition(varargin) %#ok varargin needed by HG caller

        clipboard('copy', position);

    end

    %--------------------------------
    function sendNewPosition(varargin) %#ok varargin needed by HG caller

        list = new_position_callback_functions.getList();
        for k = 1:numel(list)
            fun = list{k};
            fun(position);
        end

    end

    %-------------------------------
    function startDrag(varargin) %#ok varargin needed by HG caller

        % Calculate scale of current axes.  CurrentPoint property of axes
        % is reported in axes units.  Convert marker size to axes units to
        % determine whether an end point has been selected.

        [dx_per_pixel,dy_per_pixel]=getAxesScale(h_axes);

        if strcmp(get(h_fig, 'SelectionType'), 'normal')
            % Get the mouse location in data space.
            [start_click_x,start_click_y] = getCurrentPoint(h_axes);

            % Disable figure's pointer manager.
            iptPointerManager(h_fig, 'disable');

            initial_pos_x = position(:,1);
            initial_pos_y = position(:,2);
            start_position = position;

            end_point_index = ...
                abs(initial_pos_x-start_click_x)< marker_end_size*dx_per_pixel...
                & abs(initial_pos_y-start_click_y) < marker_end_size*dy_per_pixel;

            if ( any(end_point_index) )
                %move end point
                drag_motion_callback_id = iptaddcallback(h_fig, ...
                    'WindowButtonMotionFcn', ...
                    @endPointMotion);

                drag_up_callback_id = iptaddcallback(h_fig, ...
                    'WindowButtonUpFcn', ...
                    @stopEndPointMotion);
            else
                %translate entire line
                drag_motion_callback_id = iptaddcallback(h_fig, ...
                    'WindowButtonMotionFcn', ...
                    @dragMotion);

                drag_up_callback_id = iptaddcallback(h_fig, ...
                    'WindowButtonUpFcn', ...
                    @stopDrag);
            end

        end

        %---------------------------
        function dragMotion(varargin) %#ok varargin needed by HG caller

            if ~ishandle(h_axes)
                return;
            end

            [new_x new_y] = getCurrentPoint(h_axes);
            delta_x = new_x - start_click_x;
            delta_y = new_y - start_click_y;

            candidate_position = start_position + ...
                [repmat(delta_x,2,1) repmat(delta_y,2,1)];

            new_position = drag_constraint_function(candidate_position);

            setPosition(new_position);

        end % end dragMotion

        %-------------------------
        function stopDrag(varargin) %#ok varargin needed by HG caller
            dragMotion();

            iptremovecallback(h_fig, 'WindowButtonMotionFcn', ...
                drag_motion_callback_id);
            iptremovecallback(h_fig, 'WindowButtonUpFcn', ...
                drag_up_callback_id);

            % Enable figure's pointer manager.
            iptPointerManager(h_fig, 'enable');

        end % end stopDrag

        %-------------------------------
        function endPointMotion(varargin) %#ok varargin needed by HG caller

            ax = ancestor(h_group, 'axes');
            if ~ishandle(ax)
                return;
            end

            [new_x new_y] = getCurrentPoint(h_axes);
            delta_x = new_x - start_click_x;
            delta_y = new_y - start_click_y;

            if (all(end_point_index))
                %if end points overlap, arbitrarily choose one of the end
                %points to drag
                end_point_index = logical([1 0]);
            end

            fixed_point = start_position(~end_point_index,:);
            moving_point = start_position(end_point_index,:);

            candidate_position(end_point_index,:) =...
                moving_point + [delta_x delta_y];

            candidate_position(~end_point_index,:) = fixed_point;

            new_position=drag_constraint_function(candidate_position);
            setPosition(new_position);

        end % end endPointMotion

        %-----------------------------------
        function stopEndPointMotion(varargin) %#ok varargin needed by HG caller
            endPointMotion();

            iptremovecallback(h_fig, 'WindowButtonMotionFcn', ...
                drag_motion_callback_id);
            iptremovecallback(h_fig, 'WindowButtonUpFcn', ...
                drag_up_callback_id);

            % Enable figure's pointer manager.
            iptPointerManager(h_fig, 'enable');

        end % end stopEndPointMotion

    end % end startDrag

end %end im_pix_line


function obj = updateSpiderPlot(obj,spiderIndex)

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

    %-INITIALIZATIONS-%
    axIndex = obj.getAxisIndex(obj.State.Plot(spiderIndex).AssociatedAxis);
    plotData = obj.State.Plot(spiderIndex).Handle;
    [xSource, ySource] = findSourceAxis(obj, axIndex);

    nTraces = size(plotData.P, 1);
    isLegend = false;

    axesStruct = setAxes(obj, spiderIndex);
    updateSpiderLayout(obj, spiderIndex);
    setAnnotation(obj, axesStruct, spiderIndex);

    if ~isempty(plotData.LegendHandle)
        isLegend = true;
        setLegeng(obj, spiderIndex);
    end

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

    %-set traces-%
    for t = 1:nTraces

        %-get plotIndex-%
        obj.PlotOptions.nPlots = obj.PlotOptions.nPlots + 1;
        plotIndex = obj.PlotOptions.nPlots;

        %-associate axis-%
        obj.data{plotIndex}.xaxis = sprintf('x%d', xSource);
        obj.data{plotIndex}.yaxis = sprintf('y%d', ySource);

        %-trace settings-%
        obj.data{plotIndex}.type = 'scatter';
        obj.data{plotIndex}.mode = 'lines+markers';

        if strcmp(plotData.Marker{t, 1}, 'none')
            obj.data{plotIndex}.mode = 'lines';
        end

        %-set data-%
        [xData, yData] = getCartesianPoints(plotData, axesStruct, t);

        obj.data{plotIndex}.x = xData;
        obj.data{plotIndex}.y = yData;

        %-marker settings-%
        obj.data{plotIndex}.marker = getMarker(plotData, t);

        %-line settings-%
        obj.data{plotIndex}.line = getLine(plotData, t);

        %-fill area-%
        if strcmp(plotData.FillOption{t}, 'on')
            [fillColor, ~] = getColor(plotData.Color, t, ...
                plotData.FillTransparency);
            obj.data{plotIndex}.fillcolor = fillColor;
            obj.data{plotIndex}.fill = 'toself';
        end

        %-legend-%
        if isLegend
            if strcmp(plotData.LegendHandle.Visible, 'on')
                obj.data{plotIndex}.name = plotData.LegendLabels{t};
                obj.data{plotIndex}.showlegend = true;
            end
        end

    end

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

function [xData, yData] = getCartesianPoints(plotData, axesStruct, traceIndex)

    %-initializations-%
    rData = plotData.P(traceIndex, :);
    axesAngle = axesStruct.axesAngle;
    nAxes = axesStruct.nAxes;
    nTicks = axesStruct.nTicks;

    for a = 1:nAxes

        %-get axis limits-%
        try
            axesLim = plotData.AxesLimits(:, a)';
        catch
            axesLim = [min(plotData.P(:, a)), max(plotData.P(:, a))];
        end

        %-normalize radial data-%
        rPoint = [rData(a), axesLim];
        if strcmpi(plotData.AxesScaling(a), 'log')
            rPoint = log10(rPoint);
        end
        if strcmpi(plotData.AxesDirection(a), 'reverse');
            rPoint = -rPoint;
        end
        rPoint = rescale(rPoint, 1/nTicks, 1);

        %-convertion-%
        xData(a) = rPoint(1) * cos(axesAngle(a));
        yData(a) = rPoint(1) * sin(axesAngle(a));
    end

    %-return-%
    xData = [xData, xData(1)];
    yData = [yData, yData(1)];
end

function lineStruct = getLine(plotData, traceIndex)
    %-INITIALIZATIONS-%
    lineStruct = struct();

    %-line color-%
    [lineColor, ~] = getColor(plotData.Color, traceIndex, ...
        plotData.LineTransparency);
    lineStruct.color = lineColor;

    %-line width-%
    lineStruct.width = plotData.LineWidth(traceIndex);

    %-line style-%
    switch plotData.LineStyle{traceIndex, 1}
        case '-'
            lineStyle = 'solid';
        case '--'
            lineStyle = 'dash';
        case ':'
            lineStyle = 'dot';
        case '-.'
            lineStyle = 'dashdot';
    end

    lineStruct.dash = lineStyle;
end

function markerStruct = getMarker(plotData, traceIndex)

    %-INITIALIZATIONS-%
    markerStruct = struct();

    %-marker color-%
    [markerColor, ~] = getColor(plotData.Color, traceIndex, ...
        plotData.MarkerTransparency);
    markerStruct.color = markerColor;
    markerStruct.line.color = markerColor;

    %-marker size-%
    markerStruct.size = plotData.MarkerSize(traceIndex, 1) * 0.2;

    %-marker symbol-%
    if ~strcmp(plotData.Marker{traceIndex, 1}, 'none')

        switch plotData.Marker{traceIndex, 1}
            case '.'
                mSymbol = 'circle';
            case 'o'
                mSymbol = 'circle';
            case 'x'
                mSymbol = 'x-thin-open';
            case '+'
                mSymbol = 'cross-thin-open';
            case '*'
                mSymbol = 'asterisk-open';
            case {'s','square'}
                mSymbol = 'square';
            case {'d','diamond'}
                mSymbol = 'diamond';
            case 'v'
                mSymbol = 'triangle-down';
            case '^'
                mSymbol = 'triangle-up';
            case '<'
                mSymbol = 'triangle-left';
            case '>'
                mSymbol = 'triangle-right';
            case {'p','pentagram'}
                mSymbol = 'star';
            case {'h','hexagram'}
                mSymbol = 'hexagram';
        end

        markerStruct.symbol = mSymbol;
    end
end

function setAnnotation(obj, axesStruct, spiderIndex)

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

    %-INITIALIZATIONS-%
    axIndex = obj.getAxisIndex(obj.State.Plot(spiderIndex).AssociatedAxis);
    anIndex = obj.PlotlyDefaults.anIndex;

    plotData = obj.State.Plot(spiderIndex).Handle;
    [xSource, ySource] = findSourceAxis(obj, axIndex);

    axesLabels = plotData.AxesLabels;
    axesLabelsOffset = plotData.AxesLabelsOffset * 0.5;
    axesDisplay = plotData.AxesDisplay;
    axesLim = plotData.AxesLimits;
    axesFontColor = plotData.AxesFontColor;
    axesPrecision = plotData.AxesPrecision;
    axesLabelsEdge = plotData.AxesLabelsEdge;

    nAxes = axesStruct.nAxes;
    axesAngle = axesStruct.axesAngle;
    tickValues = axesStruct.axesAngle;
    nTicks = axesStruct.nTicks;
    if strcmp(axesDisplay, 'data'), nTicks = size(plotData.P, 1); end

    labelColor = 'rgb(0,0,0)';
    labelSize = plotData.LabelFontSize;
    labelFamily = matlab2plotlyfont(plotData.LabelFont);

    nAxesFontColor = size(axesFontColor, 1);
    axesSize = plotData.AxesFontSize;
    axesFamily = matlab2plotlyfont(plotData.AxesFont);

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

    %-set axes labels-%
    for l = 1:nAxes

        %-create annotation-%
        annotations{anIndex}.showarrow = false;
        annotations{anIndex}.xref = sprintf('x%d', xSource);
        annotations{anIndex}.yref = sprintf('y%d', ySource);
        annotations{anIndex}.bgcolor = 'rgba(0,0,0,0)';
        annotations{anIndex}.bordercolor = getLabelEdgeColor(axesLabelsEdge);
        annotations{anIndex}.borderwidth = 1;
        annotations{anIndex}.borderpad = labelSize * 0.5;

        %-text label-%
        textLabel = axesLabels{l};
        if isempty(textLabel), textLabel = parseString(textLabel, 'tex'); end

        annotations{anIndex}.text = textLabel;

        %-location-%
        lastXTick = cos(axesAngle(l));
        lastYTick = sin(axesAngle(l));

        if abs(lastXTick) < 1e-3
            annotations{anIndex}.x = lastXTick;
            annotations{anIndex}.xanchor = 'middle';
        elseif lastXTick > 0
            annotations{anIndex}.x = lastXTick + axesLabelsOffset;
            annotations{anIndex}.xanchor = 'left';
        elseif lastXTick < 0
            annotations{anIndex}.x = lastXTick - axesLabelsOffset;
            annotations{anIndex}.xanchor = 'right';
        end

        if abs(lastYTick) < 1e-3
            annotations{anIndex}.y = lastYTick;
            annotations{anIndex}.yanchor = 'middle';
        elseif lastYTick > 0
            annotations{anIndex}.y = lastYTick + axesLabelsOffset;
            annotations{anIndex}.yanchor = 'bottom';
        elseif lastYTick < 0
            annotations{anIndex}.y = lastYTick - axesLabelsOffset;
            annotations{anIndex}.yanchor = 'top';
        end

        %-font properties-%
        annotations{anIndex}.font.color = labelColor;
        annotations{anIndex}.font.size = labelSize;
        annotations{anIndex}.font.family = labelFamily;

        %-update annotation Index-%
        anIndex = anIndex + 1;
    end

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

    %-set axes tick labels-%
    for t = 1:nTicks

        indexColor = mod(t-1, nAxesFontColor) + 1;
        axesColor = 255*axesFontColor(indexColor, :);
        axesColor = sprintf('rgb(%f,%f,%f)', axesColor);

        for a = 1:nAxes

            %-create annotation-%
            annotations{anIndex}.showarrow = false;
            annotations{anIndex}.xref = sprintf('x%d', xSource);
            annotations{anIndex}.yref = sprintf('y%d', ySource);
            annotations{anIndex}.bgcolor = 'rgba(0,0,0,0)';
            annotations{anIndex}.bordercolor = 'rgba(0,0,0,0)';

            %-get tick label-%
            try
                axesLim = plotData.AxesLimits(:, a)';
            catch
                axesLim = [min(plotData.P(:, a)), max(plotData.P(:, a))];
            end

            if strcmp(axesDisplay, 'data')
                tickLabel = plotData.P(t, a);

            else
                tickLabel = linspace(axesLim(1), axesLim(2), nTicks);
                tickLabel = tickLabel(t);

                if strcmpi(plotData.AxesScaling(a), 'log')
                    tickLabel = 10^(t-1);
                end
            end

            %-get tick value-%
            tickValue = [tickLabel, axesLim];

            if strcmpi(plotData.AxesScaling(a), 'log')
                tickValue = log10(tickValue);
            end

            if strcmpi(plotData.AxesDirection(a), 'reverse');
                tickValue = -1 * tickValue;
            end

            tickValue = rescale(tickValue, 1/axesStruct.nTicks, 1);
            tickValue = tickValue(1);

            %-set tick label-%
            tickLabel = num2str(tickLabel, sprintf('%%.%df', axesPrecision(a)));
            annotations{anIndex}.text = tickLabel;

            %-set tick location-%
            annotations{anIndex}.x = tickValue * cos(axesAngle(a));
            annotations{anIndex}.y = tickValue * sin(axesAngle(a));
            annotations{anIndex}.xanchor = plotData.AxesHorzAlign;
            annotations{anIndex}.yanchor = plotData.AxesVertAlign;
            annotations{anIndex}.align = plotData.AxesHorzAlign;

            if strcmp(axesDisplay, 'data')
                if annotations{anIndex}.y > 0
                    annotations{anIndex}.yanchor = 'bottom';
                elseif annotations{anIndex}.y < 0
                    annotations{anIndex}.yanchor = 'top';
                end

                if abs(annotations{anIndex}.x) < 1e-3
                    annotations{anIndex}.xanchor = 'middle';
                elseif annotations{anIndex}.x > 0
                    annotations{anIndex}.xanchor = 'left';
                elseif annotations{anIndex}.x < 0
                    annotations{anIndex}.xanchor = 'right';
                end
            end

            %-font properties-%
            annotations{anIndex}.font.color = axesColor;
            annotations{anIndex}.font.size = axesSize;
            annotations{anIndex}.font.family = axesFamily;

            %-update annotation Index-%
            anIndex = anIndex + 1;

            %-stop according AxesDisplay-%
            if strcmp(axesDisplay, 'one')
                if a==1, break; end
            elseif strcmp(axesDisplay, 'two')
                if a==2, break; end
            elseif strcmp(axesDisplay, 'three')
                if a==3, break; end
            end
        end

    end

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

    %-set annotations to layout-%
    obj.layout = setfield(obj.layout, 'annotations', annotations);

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

    obj.PlotlyDefaults.anIndex = anIndex;

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

function axesStruct = setAxes(obj, spiderIndex)

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

    %-INITIALIZATIONS-%
    axIndex = obj.getAxisIndex(obj.State.Plot(spiderIndex).AssociatedAxis);
    plotData = obj.State.Plot(spiderIndex).Handle;
    [xSource, ySource] = findSourceAxis(obj, axIndex);

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

    %-set axes-%
    nAxes = size(plotData.P,2);
    angleStep = 2*pi/nAxes;
    axesAngle = [pi/2];
    plotIndex = spiderIndex;
    axesColor = sprintf('rgb(%f,%f,%f)', 255*plotData.AxesColor);

    for a = 1:nAxes

        %-get plotIndex-%
        if a > 1
            obj.PlotOptions.nPlots = obj.PlotOptions.nPlots + 1;
            plotIndex = obj.PlotOptions.nPlots;
        end

        %-set axes-%
        obj.data{plotIndex}.xaxis = sprintf('x%d', xSource);
        obj.data{plotIndex}.yaxis = sprintf('y%d', ySource);

        obj.data{plotIndex}.type = 'scatter';
        obj.data{plotIndex}.mode = 'lines';
        obj.data{plotIndex}.line.color = axesColor;
        obj.data{plotIndex}.line.width = 1.75;

        obj.data{plotIndex}.x = [0, cos(axesAngle(a))];
        obj.data{plotIndex}.y = [0, sin(axesAngle(a))];

        %-update axesAngle list-%
        if a ~= nAxes
            if strcmp(plotData.Direction, 'clockwise')
                axesAngle(a+1) = axesAngle(a) - angleStep;
            else
                axesAngle(a+1) = axesAngle(a) + angleStep;
            end
        end

        %-hide associated trace-%
        obj.data{plotIndex}.showlegend = false;

    end

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

    %-set grid-%
    nTicks = plotData.AxesInterval + 1;
    tickValues = linspace(1/nTicks, 1, nTicks);
    xData = cos([axesAngle, axesAngle(1)]);
    yData = sin([axesAngle, axesAngle(1)]);

    for g = 1:nTicks

        %-get plotIndex-%
        obj.PlotOptions.nPlots = obj.PlotOptions.nPlots + 1;
        plotIndex = obj.PlotOptions.nPlots;

        %-set current line grid-%
        obj.data{plotIndex}.xaxis = sprintf('x%d', xSource);
        obj.data{plotIndex}.yaxis = sprintf('y%d', ySource);

        obj.data{plotIndex}.type = 'scatter';
        obj.data{plotIndex}.mode = 'lines';
        obj.data{plotIndex}.line.color = axesColor;
        obj.data{plotIndex}.line.width = 0.4;

        obj.data{plotIndex}.x = tickValues(g)*xData;
        obj.data{plotIndex}.y = tickValues(g)*yData;

        %-hide associated trace-%
        obj.data{plotIndex}.showlegend = false;

    end

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

    %-return-%
    axesStruct.axesAngle = axesAngle;
    axesStruct.nAxes = nAxes;
    axesStruct.nTicks = nTicks;
    axesStruct.tickValues = tickValues;

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

function updateSpiderLayout(obj, spiderIndex)

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

    %-INITIALIZATIONS-%
    axIndex = obj.getAxisIndex(obj.State.Plot(spiderIndex).AssociatedAxis);
    plotData = obj.State.Plot(spiderIndex).Handle;
    [xSource, ySource] = findSourceAxis(obj, axIndex);

    xo = plotData.Position(1);
    yo = plotData.Position(2);
    w = plotData.Position(3);
    h = plotData.Position(4);

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

    %-get x axis-%
    xaxis.domain = min([xo xo + w],1);
    xaxis.range = [-1.5, 1.5];
    xaxis.showline = false;
    xaxis.zeroline = false;
    xaxis.showgrid = false;
    xaxis.showticklabels = false;

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

    %-get y axis-%
    yaxis.domain = min([yo yo + h],1);
    yaxis.range = [-1.25, 1.25];
    yaxis.showline = false;
    yaxis.zeroline = false;
    yaxis.showgrid = false;
    yaxis.showticklabels = false;

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

    %-set axis-%
    obj.layout = setfield(obj.layout, sprintf('xaxis%d', xSource), xaxis);
    obj.layout = setfield(obj.layout, sprintf('yaxis%d', ySource), yaxis);

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

function setLegeng(obj, spiderIndex)

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

    %-INITIALIZATIONS-%
    axIndex = obj.getAxisIndex(obj.State.Plot(spiderIndex).AssociatedAxis);
    plotData = obj.State.Plot(spiderIndex).Handle;
    [xSource, ySource] = findSourceAxis(obj, axIndex);

    legData = plotData.LegendHandle;
    obj.layout.showlegend = strcmpi(plotData.Visible,'on');

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

    %-legend location-%
    obj.layout.legend.x = legData.Position(1);
    obj.layout.legend.y = legData.Position(2);
    obj.layout.legend.xref = 'paper';
    obj.layout.legend.yref = 'paper';
    obj.layout.legend.xanchor = 'left';
    obj.layout.legend.yanchor = 'top';

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

    %-legend settings-%
    if (strcmp(legData.Box,'on') && strcmp(legData.Visible, 'on'))
        edgeColor = 255*legData.EdgeColor;
        bgColor = 255*legData.Color;
        textColor = 255*legData.TextColor;

        obj.layout.legend.traceorder = 'normal';
        obj.layout.legend.borderwidth = legData.LineWidth;
        obj.layout.legend.bordercolor = sprintf('rgb(%f,%f,%f)', edgeColor);
        obj.layout.legend.bgcolor = sprintf('rgb(%f,%f,%f)', bgColor);
        obj.layout.legend.font.size = legData.FontSize;
        obj.layout.legend.font.family = matlab2plotlyfont(legData.FontName);
        obj.layout.legend.font.color = sprintf('rgb(%f,%f,%f)', textColor);
    end
end

function [strColor, numColor] = getColor(colorMatrix, traceIndex, ...
    colorOpacities)

    colorOpacity = 1;

    if nargin > 2
        colorOpacity = colorOpacities(traceIndex);
    end

    nColors = size(colorMatrix, 1);
    colorIndex = mod(traceIndex-1, nColors) + 1;
    numColor = 255*colorMatrix(colorIndex, :);
    strColor = sprintf('rgba(%f,%f,%f,%f)', numColor, colorOpacity);
end

function edgeColor = getLabelEdgeColor(axesLabelsEdge)
    if isnumeric(axesLabelsEdge)
        edgeColor = sprintf('rgb', 255*axesLabelsEdge);

    elseif strcmp(axesLabelsEdge, 'none')
        edgeColor = 'rgba(0,0,0,0)';

    else
        switch axesLabelsEdge
            case {'b', 'blue'}
                edgeColor = 'rgb(0,0,1)';
            case {'k', 'black'}
                edgeColor = 'rgb(0,0,0)';
            case {'r', 'red'}
                edgeColor = 'rgb(1,0,0)';
            case {'g', 'green'}
                edgeColor = 'rgb(0,1,0)';
            case {'y', 'yellow'}
                edgeColor = 'rgb(1,1,0)';
            case {'c', 'cyan'}
                edgeColor = 'rgb(0,1,1)';
            case {'m', 'magenta'}
                edgeColor = 'rgb(1,0,1)';
            case {'w', 'white'}
                edgeColor = 'rgb(1,1,1)';
        end
    end
end


classdef ConicalSensorState < AbstractSensorState
    %ConicalSensorState Summary of this class goes here
    %   Detailed explanation goes here

    properties
        sensor ConicalSensor

        activeTf(1,1) logical = true;
        steeringModel(1,1) AbstractSensorSteeringModel
        angle(1,1) double {mustBeGreaterThan(angle,0)} = deg2rad(10);
        range(1,1) double {mustBeGreaterThan(range,0)} = 1;
    end

    methods
        function obj = ConicalSensorState(sensor, activeTf, steeringModel, angle, range)
            arguments
                sensor(1,1) ConicalSensor
                activeTf(1,1) logical
                steeringModel(1,1) AbstractSensorSteeringModel
                angle(1,1) double {mustBeGreaterThanOrEqual(angle,0)}
                range(1,1) double {mustBeGreaterThan(range, 0)}
            end

            obj.sensor = sensor;
            obj.activeTf = activeTf;
            obj.steeringModel = steeringModel;
            obj.angle = angle;
            obj.range = range;
        end

        function sensor = getSensor(obj)
            sensor = obj.sensor;
        end

        function activeTf = getSensorActiveState(obj)
            activeTf = obj.activeTf;
        end

        function setSensorActiveState(obj, activeTf)
            obj.activeTf = activeTf;
        end

        function steeringModel = getSensorSteeringMode(obj)
            steeringModel = obj.steeringModel;
        end

        function setSteeringModel(obj, steeringModel)
            obj.steeringModel = steeringModel;
        end

        function angle = getSensorAngle(obj)
            angle = obj.angle;
        end

        function setSensorAngle(obj, angle)
            obj.angle = angle;
        end

        function range = getSensorMaxRange(obj)
            range = obj.range;
        end

        function setSensorMaxRange(obj, range)
            obj.range = range;
        end

        function angle = getMaxAngle(obj)
            angle = obj.getSensorAngle();
        end
    end
end


function val = get_param_val(param_list, group_name,param_name)

[col, row] = size(param_list);

for i = 1:row
   if strcmp(param_list(i).name, group_name)
      for j = 1:param_list(i).num_param
          if strcmp(param_list(i).param(j).name, param_name)
              val = param_list(i).param(j).val;
              return;
          end
      end
   end
end
% do not find parameter, return nan
val = NaN;

end


function value = s_eqi ( s1, s2 )

%*****************************************************************************80
%
%% S_EQI is a case insensitive comparison of two strings for equality.
%
%  Example:
%
%    S_EQI ( 'Anjana', 'ANJANA' ) is TRUE.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    30 April 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string S1, S2, the strings to compare.
%
%    Output, logical VALUE, is TRUE if the strings are equal.
%
  len1 = length ( s1 );
  len2 = length ( s2 );
  lenc = min ( len1, len2 );

  for i = 1 : lenc

    c1 = ch_cap ( s1(i) );
    c2 = ch_cap ( s2(i) );

    if ( c1 ~= c2 )
      value = 0;
      return
    end

  end

  for i = lenc + 1 : len1
    if ( s1(i) ~= ' ' )
      value = 0;
      return
    end
  end

  for i = lenc + 1 : len2
    if ( s2(i) ~= ' ' )
      value = 0;
      return
    end
  end

  value = 1;

  return
end


function display(c)

%tstoolbox/@core/display
%   Syntax:
%     * display(c)
%
%   Input Arguments:
%     * c - core object
%
% Copyright 1997-2001 DPI Goettingen, License http://www.physik3.gwdg.de/tstool/gpl.txt

disp(['  Dlens : ' num2str(c.dlens)])


function download_finviz_data(destination_dir)
clearvars -except destination_dir
source_dir = '/Users/ansonwong/Downloads';
source_filename=strcat(source_dir,'/finviz.csv');
destination_filename=strcat(destination_dir,'/finviz.csv');

% Download finviz data using my default browser
finviz_URL_full=...
  strcat('http://finviz.com/export.ashx?v=152&ft=4',...
            '&c=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72');
web(finviz_URL_full,'-browser');

% Wait for the download to finish
fprintf('Downloaded ''%s'' (success=%d)\n',source_filename,wait_for_existence(source_filename));

% Now that the download has finished, move the file to our destination directory
[status,message,messageid]=movefile(source_filename,destination_filename);
if(status==0), error('Error in moving finviz file!\n'); end
end

function success = wait_for_existence(filename)
success = 1;

seconds_elapsed=0;
wait_seconds=0.5;
while( exist(filename)==0 ),
  pause(wait_seconds);
  seconds_elapsed=seconds_elapsed+wait_seconds;
  if(seconds_elapsed > 120),
    error('Waited too long for %s to exist!\n',filename)
    success=0; return
  end
end

fprintf('Waited %.1f seconds.\n',seconds_elapsed);
end


function item = cfg_entry(varargin)

% This is the entry configuration item class
%
% Data structure
% ==============
% Description fields
%    * name  - display name of config item
%    * tag   - tag of the menu item
%    * val   - 1x1 cell array
%    * check - (optional) function handle to implement configuration
%              specific subsasgn checks based on the harvested subtree
%              rooted at this node
%    * help  - help text
% GUI/job manager fields
%    * expanded
%    * hidden
% All fields above are inherited from the generic configuration item class.
%    * strtype
%    * num     - A 1-by-ndims vector of non-negative numbers, describing
%                the expected dimensions of the input. Dimensions with a
%                .num value of 0 or Inf can have an arbitrary number of
%                elements. In case of 2 dimensions, .val inputs will be
%                tried to match in un-transposed order first. If this
%                does not work, then .val inputs will be transposed and
%                matched again. If num is an empty matrix, no dimension
%                and size checks will be performed.
%                If strtype is 's' and num has 2 elements, these 2
%                elements code the min/max length of a string. This is a
%                workaround - in future versions num may be changed to a
%                2-by-ndims array encoding min/max values for each
%                dimension.
%    * def
%    * extras  - Extra information used for content checks of item.val{1}. The
%                following strtypes can use this extra information:
%                's' - a cell array of regular expressions. The val
%                string must match at least one of the regular
%                expressions.
%                'e' - a function handle [sts val] = f(val, item.num)
%
% Public Methods
% ==============
%    * get_strings - returns name of object
%    * gettag      - returns tag
%    * help        - returns help text
%    * harvest     - returns item.val{1}, or '<UNDEFINED>' if empty, see below
%    * all_set     - returns ~isempty(item.val), checks numel(item.val{1})
%                    against item.num
%
% Public internal Methods
% =======================
%    * subsasgn
%    * subsref
%
% 'strtype'
% The type of values that are entered by typing.  e.g. 'e' for evaluated.
% The valid value types are:
%   's'   string
%   'e'   evaluated expression - this can be any expression, even a struct
%          or cell
%   'f'   function or function handle
%   'n'   natural number (1..n)
%   'w'   whole number (0..n)
%   'i'   integer
%   'r'   real number
%   The following types are supported too, but there are no special
%   checks for validity of contents
%   'c'   indicator vector (e.g., 0101... or abab...)
%   'x'   contrast matrix
%   'p'   permutation
%
% Subscript Assignment Checks
% ===========================
% .num must conform to the semantics described above.
% The contents of item.val{1} will be checked to match .num and .strtype
% restrictions.
%
% Output in Job Structure (harvest)
% =================================
% cfg_entry uses cfg_item/harvest. If multiple dependencies are present
% and all can be resolved, the result will be a concatenation of all
% inputs. If concatenation fails, dependencies will not be resolved.
%
% The layout of the configuration tree and the types of configuration items
% have been kept compatible to a configuration system and job manager
% implementation in SPM5 (Statistical Parametric Mapping, Copyright (C)
% 2005 Wellcome Department of Imaging Neuroscience). This code has been
% completely rewritten based on an object oriented model of the
% configuration tree.
%
% This code is part of a batch job configuration system for MATLAB. See
%      help matlabbatch
% for a general overview.
%_______________________________________________________________________
% Copyright (C) 2007 Freiburg Brain Imaging

% Volkmar Glauche
% $Id: cfg_entry.m 5678 2013-10-11 14:58:04Z volkmar $

rev = '$Rev: 5678 $'; %#ok

myclass = mfilename;
% Get local fields and defaults from private/mysubs_fields
[fn, defs] = mysubs_fields;

if nargin == 1
    if isstruct(varargin{1})
        % assume input is a struct to be converted back into a class
        % return with error if this does not work
        if numel(fieldnames(varargin{1})) == numel(fn)+2 && ...
                all(isfield(varargin{1}, [fn(:)', {'cfg_item' 'cfg_leaf'}]))
            gitem = varargin{1}.cfg_item;
            sitem = rmfield(varargin{1},{'cfg_item', 'cfg_leaf'});
            item  = class(sitem, myclass, gitem, cfg_leaf);
            return;
        else
            cfg_message('matlabbatch:constructor:reclassify', ['Don''t know how to convert this ' ...
                            'into class ''%s''.'], myclass);
        end;
    end;
    if isa(varargin{1},myclass)
        item = varargin{1};
        return;
    end;
end;

mxpnargin = 4; % Max 4 arguments to parent initialisation
pnargin = min([nargin,mxpnargin]);
switch nargin
    case 0
        gitem = cfg_item;
    case {1,2,3,4,5,6,7,8,9}
        gitem = cfg_item(varargin{1:pnargin});
    otherwise
        cfg_message('matlabbatch:constructor:nargin', 'Wrong number of arguments.');
end;
for k=1:numel(fn)
    sitem.(fn{k})=defs{k};
end;
item = class(sitem, myclass, gitem, cfg_leaf);
if nargin > mxpnargin
    item.cfg_item.val{1} = varargin{mxpnargin+1};
    mxpnargin = mxpnargin+1;
end;
% set additional fields (if any) - field order as in mysubs_fields
for k = 1:min(numel(fn),nargin-mxpnargin)
    item.(fn{k}) = varargin{k+mxpnargin};
end;


function vis_sticks(expidxs,nImgs,bSort,bTrain)

fprintf('vis_sticks()\n');

if (nargin < 3)
    bSort = false;
end

if (nargin < 4)
    bTrain = false;
end

nJoints = 14;

for expidx = expidxs
    fprintf('**********************************************************************************\n');
    % load experiment parameters
    p = exp_params(expidx);
    % load ground truth
    if (bTrain)
        load(p.trainGT);
        path = fileparts(p.evalTrain);
    else
        load(p.testGT);
        path = fileparts(p.evalTest);
    end
    if (~exist('annolist','var'))
        annolist = single_person_annolist;
    end
    annolist = set_full_path(annolist,p.imgDir);
    fnameDist = [path '/distAll'];

    try
%         assert(false);
        load(fnameDist,'pidxs','keypointsAll','matchPCK');
        assert(exist('keypointsAll','var') && length(pidxs) == length(p.pidxs) && ...
               sum(pidxs ~= p.pidxs) == 0 && size(matchPCK,2) == nJoints);
    catch
        warning('keypoints are not found, running evalPCK...');
        evalPCK(expidx);
        load(fnameDist,'pidxs','keypointsAll','matchPCK');
        assert(exist('keypointsAll','var') && length(pidxs) == length(p.pidxs) && ...
               sum(pidxs ~= p.pidxs) == 0 && size(matchPCK,2) == nJoints);
    end

    nImgs = min(length(keypointsAll),nImgs);
    keypointsAll = keypointsAll(1:nImgs);
    if (isfield(p, 'testGTnopad'))
        load(p.testGTnopad,'annolist');
        keypointsAll = projectKeypoints(keypointsAll,fileparts(p.testGTnopad),fileparts(p.testGT));%,annolist
        endpointsAllGT = gt2endpoints(p.testGTnopad);
    else
        endpointsAllGT = gt2endpoints(p.testGT);
    end
    endpointsAll = keypoints2endpoints(keypointsAll);
    matchPCP = eval_match_parts_gt(endpointsAll, annolist(1:min(length(annolist),length(endpointsAll))), 1.0, 1);
    pcp = eval_plot_pcp(matchPCP,1:10);

    if (bSort)
        visDir = [p.expDir '/' p.shortName '/cachedir/test/vis/sort'];
        pckImg = zeros(nImgs,1);
        nanImg = zeros(nImgs,1);
        for imgidx = 1:nImgs
            pckImg(imgidx) = sum(matchPCK(imgidx,~isnan(matchPCK(imgidx,:))));
            allNaNImg(imgidx) = sum(~isnan(matchPCK(imgidx,:))) == 0;
        end
        pckImg(allNaNImg) = nan;
        [~,idxs] = sort(pckImg);
        endpointsAll = endpointsAll(idxs,:);
        keypointsAll = keypointsAll(idxs,:);
        matchPCP = matchPCP(idxs,:);
        matchPCK = matchPCK(idxs,:);
        annolist = annolist(idxs);
        endpointsAllGT = endpointsAllGT(idxs);
    else
        visDir = [p.expDir '/' p.shortName '/cachedir/test/vis/'];
    end
    plot_sticks(p, endpointsAll, annolist, visDir, matchPCP, keypointsAll, matchPCK, p.pidxs, endpointsAllGT, bSort);
end

end


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

    properties
        lv LaunchVehicle

        e2TConns EngineToTankConnState
        t2TConns TankToTankConnState
        holdDownEnabled(1,1) logical = false
    end

    properties(Transient)
        cachedEngines LaunchVehicleEngine
        cachedConnTanks cell
    end

    properties(Constant)
        emptyTankArr = LaunchVehicleTank.empty(1,0);
    end

    methods
        function obj = LaunchVehicleState(lv)
            obj.lv = lv;
            obj.clearCachedConnEnginesTanks();
        end

        %Engine to Tank Connections
        function addE2TConnState(obj, newConnState)
            obj.e2TConns(end+1) = newConnState;

            obj.clearCachedConnEnginesTanks();
        end

        function removeE2TConnStateForConn(obj, conn)
            ind = [];
            for(i=1:length(obj.e2TConns)) %#ok<*NO4LP>
                if(obj.e2TConns(i).conn == conn)
                    ind = i;
                    break;
                end
            end

            if(not(isempty(ind)))
                obj.e2TConns(ind) = [];
            end

            obj.clearCachedConnEnginesTanks();
        end

        function tanks = getTanksConnectedToEngine(obj, engine)
            bool = obj.cachedEngines == engine;
            if(any(bool))
                tanks = obj.cachedConnTanks{bool};
            else
                tanks = obj.emptyTankArr;

                connStates = obj.e2TConns([obj.e2TConns.active] == true);
                connections = [connStates.conn];

                if(not(isempty(connections)))
                    connections = connections([connections.engine] == engine);
                    tanks = [connections.tank];
                end

                if(isempty(tanks))
                    tanks = obj.emptyTankArr;
                end

                obj.cachedEngines(end+1) = engine;
                obj.cachedConnTanks(end+1) = {tanks};
            end
        end

        function tanks = getTanksConnectedToEngineForStage(obj, engine, stage)
%             tanks = obj.emptyTankArr;

            engineTanks = obj.getTanksConnectedToEngine(engine);
%             for(i=1:length(engineTanks))
%                 if(engineTanks(i).stage == stage)
%                     tanks(end+1) = engineTanks(i); %#ok<AGROW>
%                 end
%             end
            if(not(isempty(engineTanks)))
                bool = [engineTanks.stage] == stage;
                tanks = engineTanks(bool);
            else
                tanks = obj.emptyTankArr;
            end
        end

        %Tank To Tank Connections
        function addT2TConnState(obj, newConnState)
            obj.t2TConns(end+1) = newConnState;
        end

        function removeT2TConnStateForConn(obj, conn)
            ind = [];
            for(i=1:length(obj.t2TConns)) %#ok<*NO4LP>
                if(obj.t2TConns(i).conn == conn)
                    ind = i;
                    break;
                end
            end

            if(not(isempty(ind)))
                obj.t2TConns(ind) = [];
            end
        end

        function t2TConnState = getTank2TankConnStateForConn(obj, conn)
            ind = [];
            for(i=1:length(obj.t2TConns)) %#ok<*NO4LP>
                if(obj.t2TConns(i).conn == conn)
                    ind = i;
                    break;
                end
            end

            if(not(isempty(ind)))
                t2TConnState = obj.t2TConns(ind);
            end
        end

        function tanks = getTanksWithActiveTankToTankConnectionsForStage(obj, stageState)
            tanks = LaunchVehicleState.emptyTankArr;

            for(i=1:length(obj.t2TConns))
                connState = obj.t2TConns(i);

                if(connState.active)
                    conn = connState.conn;

                    if((not(isempty(conn.srcTank)) && conn.srcTank.stage == stageState.stage))
                        tanks(end+1) = conn.srcTank; %#ok<AGROW>
                    end

                    if((not(isempty(conn.tgtTank)) && conn.tgtTank.stage == stageState.stage))
                        tanks(end+1) = conn.tgtTank; %#ok<AGROW>
                    end
                end
            end

            if(length(tanks) > 1)
                tanks = unique(tanks);
            end
        end

        %Misc
        function newLvState = deepCopy(obj)
            newLvState = obj.copy();

            for(i=1:length(obj.e2TConns))
                newLvState.e2TConns(i) = obj.e2TConns(i).deepCopy();
            end

            for(i=1:length(obj.t2TConns))
                newLvState.t2TConns(i) = obj.t2TConns(i).deepCopy();
            end

            newLvState.clearCachedConnEnginesTanks();
        end

        function clearCachedConnEnginesTanks(obj)
            obj.cachedEngines = LaunchVehicleEngine.empty(1,0);
            obj.cachedConnTanks = {};
        end
    end
end


function msg = er_displayParfiles(view);
%
% msg = er_displayParfiles(view);
%
% Pop up a message box with the scan group currently assigned
% to the present scan (if any), and the parfiles for each
% scan in the group. Returns the message text.
%
%
% ras, 02/06.
if notDefined('view'), view = getSelectedInplane;   end

mrGlobals;

dt = view.curDataType;
scan = view.curScan;
dtName = dataTYPES(dt).name;

if ~isfield(dataTYPES(dt).scanParams(scan), 'scanGroup') | ...
        ~isfield(dataTYPES(dt).scanParams(scan), 'parfile')
    msg = 'Parfiles and/or scan group not assigned for this scan.';
    myWarnDlg(msg);
    return
end

if ~isempty(dataTYPES(dt).scanParams(scan).scanGroup)
    [scans dt] = er_getScanGroup(view);
    scanGroup = sprintf('%s scans %s', dataTYPES(dt).name, num2str(scans));
else
    % just use cur scan / dt
    scans = scan;
    scanGroup = 'none';
end

msg = [sprintf('%s %s scan %i \n', view.name, dtName, scan) ...
       sprintf('Scan Group: %s \n\n', scanGroup) ...
       sprintf('Parfiles: \n')];
for s = scans
    msg = [msg sprintf('%i: %s \n', s, dataTYPES(dt).scanParams(s).parfile)];
end

msgbox(msg, 'Event-Related Info');

return


function options = prunecplexoptions(options)

try
    if strfind(version,'2016')
        o1 = cplexoptimset;
    else
        o1 = cplexoptimset('cplex');
    end
    o2 = options.cplex;
    n = fieldnames(o1);
    for i = 1:length(n)
        if isequal(o1.(n{i}),o2.(n{i}))
            options.cplex = rmfield(options.cplex,n{i});
        end
    end
catch
end


classdef DisplayFactory < handle

    methods (Access = public, Static)

        function display = create(chartType,title)
            switch chartType
                case 'plot'
                    display = Display_Plot(title);
                case 'log'
                    display = Display_SemilogY(title);
                case 'bar'
                    display = Display_Bar(title);
                otherwise
                    error('Invalid Chart Type.')
            end
        end

    end

end


function [dat] = read_neuralynx_sdma(dataset, begsample, endsample, chanindx)

% READ_NEURALYNX_SDMA read specified channels and samples from a Neuralynx splitted DMA dataset
%
% Use as
%    [hdr] = read_neuralynx_sdma(dataset)
%    [dat] = read_neuralynx_sdma(dataset, begsample, endsample, chanindx)
%
% The splitted DMA dataset is not a formal Neuralynx format, but at
% the FCDC we use it in conjunction with SPIKEDOWNSAMPLE. The dataset
% directory contains files, one for each channel, each containing a
% 8-byte header followed by the binary values for all samples. Commonly
% the binary values are represented as int32, but it is possible to use
% int16 or other numeric representations. The 8-byte header specifies the
% numeric representation and the bitshift that should be applied (in case
% of integer representations).
%
% This function returns the electrophysiological data in AD units
% and not in uV. You should look up the details of the headstage and
% the Neuralynx amplifier and scale the values accordingly.

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

needhdr = (nargin==1);
needdat = (nargin>=2);

if ~isfolder(dataset)
  ft_error('dataset should be a directory');
end

% determine the content of the dataset directory
dirlist = dir(dataset);

% determine the correspondence between files and channels
label         = cell(length(dirlist),1);
filesel       = zeros(length(dirlist),1);
headerfile    = [];
[pd, nd, xd]  = fileparts(dataset);
for i=1:length(dirlist)
  [pf, nf, x1] = fileparts(dirlist(i).name);
  [pf, nf, x2] = fileparts(nf);
  % compare the name of the channel with the name of the dataset and look at the file extention
  % the file should be called "dataset/dataset.chanlabel" or "dataset/dataset.chanlabel.bin"
  if strcmp(nf, nd) && ~isempty(x1)
    if ~isempty(x2)
      label{i}   = x2(2:end);
      filesel(i) = 1;
    elseif strcmp(x1, '.txt')
      % this is not a proper channel, but an ascii file with header info
      label{i}   = [];
      filesel(i) = 0;
      headerfile = fullfile(dataset, dirlist(i).name);
    else
      label{i}   = x1(2:end);
      filesel(i) = 1;
    end
  else
    label{i}   = [];
    filesel(i) = 0;
  end
end
label = label(filesel==1);
bytes = cell2mat({dirlist(filesel==1).bytes}); % number of bytes in each file
filelist = {dirlist(filesel==1).name};         % filename excluding the path
clear dirlist filesel pd nd xd

for i=1:length(filelist)
  % include the full path in the filename
  filelist{i} = fullfile(dataset, filelist{i});
end

% there is a preferred ordering, which corresponds with the channel order in the non-splitted DMA file
preferred = {
  'stx'
  'pid'
  'siz'
  'tsh'
  'tsl'
  'cpu'
  'ttl'
  'x01'
  'x02'
  'x03'
  'x04'
  'x05'
  'x06'
  'x07'
  'x08'
  'x09'
  'x10'
  'csc001'
  'csc002'
  'csc003'
  'csc004'
  'csc005'
  'csc006'
  'csc007'
  'csc008'
  'csc009'
  'csc010'
  'csc011'
  'csc012'
  'csc013'
  'csc014'
  'csc015'
  'csc016'
  'csc017'
  'csc018'
  'csc019'
  'csc020'
  'csc021'
  'csc022'
  'csc023'
  'csc024'
  'csc025'
  'csc026'
  'csc027'
  'csc028'
  'csc029'
  'csc030'
  'csc031'
  'csc032'
  'csc033'
  'csc034'
  'csc035'
  'csc036'
  'csc037'
  'csc038'
  'csc039'
  'csc040'
  'csc041'
  'csc042'
  'csc043'
  'csc044'
  'csc045'
  'csc046'
  'csc047'
  'csc048'
  'csc049'
  'csc050'
  'csc051'
  'csc052'
  'csc053'
  'csc054'
  'csc055'
  'csc056'
  'csc057'
  'csc058'
  'csc059'
  'csc060'
  'csc061'
  'csc062'
  'csc063'
  'csc064'
  'csc065'
  'csc066'
  'csc067'
  'csc068'
  'csc069'
  'csc070'
  'csc071'
  'csc072'
  'csc073'
  'csc074'
  'csc075'
  'csc076'
  'csc077'
  'csc078'
  'csc079'
  'csc080'
  'csc081'
  'csc082'
  'csc083'
  'csc084'
  'csc085'
  'csc086'
  'csc087'
  'csc088'
  'csc089'
  'csc090'
  'csc091'
  'csc092'
  'csc093'
  'csc094'
  'csc095'
  'csc096'
  'csc097'
  'csc098'
  'csc099'
  'csc100'
  'csc101'
  'csc102'
  'csc103'
  'csc104'
  'csc105'
  'csc106'
  'csc107'
  'csc108'
  'csc109'
  'csc110'
  'csc111'
  'csc112'
  'csc113'
  'csc114'
  'csc115'
  'csc116'
  'csc117'
  'csc118'
  'csc119'
  'csc120'
  'csc121'
  'csc122'
  'csc123'
  'csc124'
  'csc125'
  'csc126'
  'csc127'
  'csc128'
  'csc129'
  'csc130'
  'csc131'
  'csc132'
  'csc133'
  'csc134'
  'csc135'
  'csc136'
  'csc137'
  'csc138'
  'csc139'
  'csc140'
  'csc141'
  'csc142'
  'csc143'
  'csc144'
  'csc145'
  'csc146'
  'csc147'
  'csc148'
  'csc149'
  'csc150'
  'csc151'
  'csc152'
  'csc153'
  'csc154'
  'csc155'
  'csc156'
  'csc157'
  'csc158'
  'csc159'
  'csc160'
  'csc161'
  'csc162'
  'csc163'
  'csc164'
  'csc165'
  'csc166'
  'csc167'
  'csc168'
  'csc169'
  'csc170'
  'csc171'
  'csc172'
  'csc173'
  'csc174'
  'csc175'
  'csc176'
  'csc177'
  'csc178'
  'csc179'
  'csc180'
  'csc181'
  'csc182'
  'csc183'
  'csc184'
  'csc185'
  'csc186'
  'csc187'
  'csc188'
  'csc189'
  'csc190'
  'csc191'
  'csc192'
  'csc193'
  'csc194'
  'csc195'
  'csc196'
  'csc197'
  'csc198'
  'csc199'
  'csc200'
  'csc201'
  'csc202'
  'csc203'
  'csc204'
  'csc205'
  'csc206'
  'csc207'
  'csc208'
  'csc209'
  'csc210'
  'csc211'
  'csc212'
  'csc213'
  'csc214'
  'csc215'
  'csc216'
  'csc217'
  'csc218'
  'csc219'
  'csc220'
  'csc221'
  'csc222'
  'csc223'
  'csc224'
  'csc225'
  'csc226'
  'csc227'
  'csc228'
  'csc229'
  'csc230'
  'csc231'
  'csc232'
  'csc233'
  'csc234'
  'csc235'
  'csc236'
  'csc237'
  'csc238'
  'csc239'
  'csc240'
  'csc241'
  'csc242'
  'csc243'
  'csc244'
  'csc245'
  'csc246'
  'csc247'
  'csc248'
  'csc249'
  'csc250'
  'csc251'
  'csc252'
  'csc253'
  'csc254'
  'csc255'
  'csc256'
  'crc'
  };

[sel1, sel2] = match_str(preferred, label);
if length(sel2)==length(label)
  % all reorder the labels/files
  label = label(sel2);
  bytes = bytes(sel2);
  filelist = filelist(sel2);
else
  % not all files in this SDMA dataset could be accounted for in the
  % preference list, hence do not attempt to apply the preferred ordering
end

if needhdr
  % construct a general header for the complete dataset
  if ~isempty(headerfile)
    orig             = neuralynx_getheader(headerfile);
    hdr.Fs           = orig.SamplingFrequency;
    hdr.nSamples     = [];        % see below
    hdr.nSamplesPre  = 0;         % number of pre-trigger samples in each trial
    hdr.nTrials      = 1;         % number of trials
    hdr.label        = label;
    hdr.nChans       = length(label);
    hdr.orig.dataset = orig;       % keep the header details
  else
    % some parts of the header have to be hardcoded, since the splitted dataset does not contain all header information
    hdr.Fs           = 32556;     % sampling frequency
    hdr.nSamples     = [];        % see below
    hdr.nSamplesPre  = 0;         % number of pre-trigger samples in each trial
    hdr.nTrials      = 1;         % number of trials
    hdr.label        = label;
    hdr.nChans       = length(label);
  end

  % read the header of each individual file, i.e. for each variable
  clear orig
  for i=1:length(filelist)
    orig(i) = read_neuralynx_bin(filelist{i});
  end

  % determine the number of samples for each channel
  nsamples = cell2mat({orig.nSamples});
  if any(nsamples~=nsamples(1))
    ft_error('different number of samples over channels are not supported');
  else
    hdr.nSamples = nsamples(1);
  end

  % determine the sampling frequency for each channel
  fsample = cell2mat({orig.Fs});
  if any(diff(fsample))
    ft_error('different sampling rates over channels are not supported');
  elseif any(fsample~=hdr.Fs)
    ft_error('inconsistent sampling rates');
  end

  % determine the first and last timestamp, by reading them from the timestamp channels
  tslfile = filelist{find(strcmp('tsl', label))};
  tshfile = filelist{find(strcmp('tsh', label))};
  beg_tsl = read_neuralynx_bin(tslfile, 1, 1);
  beg_tsh = read_neuralynx_bin(tshfile, 1, 1);
  end_tsl = read_neuralynx_bin(tslfile, hdr.nSamples, hdr.nSamples);
  end_tsh = read_neuralynx_bin(tshfile, hdr.nSamples, hdr.nSamples);
  hdr.FirstTimeStamp = timestamp_neuralynx(beg_tsl, beg_tsh);
  hdr.LastTimeStamp  = timestamp_neuralynx(end_tsl, end_tsh);
  hdr.TimeStampPerSample = double(hdr.LastTimeStamp-hdr.FirstTimeStamp)./(hdr.nSamples-1);  % this should be double, since it can be fractional

  % also remember the original header details
  hdr.orig.chan = orig;

  % only return the header information
  dat = hdr;

else
  % allocate memory for all data
  dat = zeros(length(chanindx), endsample-begsample+1);

  % read all channels, one small chunk at at time, and write it to separate files
  for i=1:length(chanindx)
    j = chanindx(i);
    dat(i,:) = double(read_neuralynx_bin(filelist{j}, begsample, endsample));
  end
end