function [preprocessSettingStruct, preprocessingSettingsAll] = getRegistrationSettings(obj,inputTitleStr,varargin)
	% Internal function to get user imaging preprocessing settings.
	% Biafra Ahanonu
	% started: 2016.05.31 [14:53:00]
	% inputs
		% inputTitleStr - string title to show user.
	% outputs
		% preprocessSettingStruct - structure containing user settings.
		% preprocessingSettingsAll - structure of the final pre-processing settings.

	% changelog
		% 2019.12.07 [16:23:36] - Added tooltips. Made options list easier on the eyes with improved spacing. Added a callback for user selecting the reference turboreg frame and or adding arbitrary values to a number of other options.
		% 2019.12.07 [17:46:03] - Change how settings are initialized, should make easier to maintain and add new settings.
		% 2019.12.08 [22:34:38] - Added additional tooltips and checks to make sure user inputs correct data type/size.
		% 2019.12.08 [22:49:48] - Allow users to input previous preprocessing settings.
		% 2020.04.18 [19:27:24] - Make sure any modifications from default are propagated upon multiple calls to getRegistrationSettings.
		% 2020.04.19 [15:20:48] - Fix how modified values stored so only store the modified value and not all the options at time of modification.
		% 2020.05.28 [21:07:27] - Added support for nargin=1.
		% 2020.10.21 [16:52:06] - Add support for user canceling the input.
		% 2020.10.24 [18:30:56] - Added support for calculating dropped frames if entire frame of a movie is a set value.
		% 2021.06.21 [14:27:26] - Switch to single page support.
		% 2021.06.21 [20:52:36] - Multi-column layout since most computers are widescreen now.
		% 2021.06.29 [12:52:36] - Added regRegionUseBtwnSessions support and made fix for loading prior settings if they do not contain new settings.
		% 2021.07.06 [09:42:09] - Switch to callbacks to close instead of using pause, allows for more flexibility going forward and use with MATLAB Online.
		% 2021.07.13 [17:55:30] - Added support for certain options (e.g. motion correction) to give a vector
		% 2021.07.22 [12:10:10] - Added movie detrend options.
		% 2021.08.10 [09:57:36] - Updated to handle CIAtah v4.0 switch to all functions inside ciapkg package.
		% 2021.12.01 [19:21:00] - Handle "User selects specific value" going into infinite loop. Allow cancel option to prevent loop.
		% 2022.06.28 [15:28:13] - Add additional black background support.
		% 2022.07.10 [17:21:21] - Added largeMovieLoad setting.
	% TODO
		% DONE: Allow user to input prior settings, indicate those changed from default by orange or similar color.

	import ciapkg.api.* % import CIAtah functions in ciapkg package API.

	%========================
	% Struct: Empty = no previous settings, else a structure of preprocessingSettingsAll from previous run.
	options.inputSettings = [];
	% get options
	options = getOptions(options,varargin);
	% display(options)
	% unpack options into current workspace
	% fn=fieldnames(options);
	% for i=1:length(fn)
	% 	eval([fn{i} '=options.' fn{i} ';']);
	% end
	%========================

	if nargin==1
		disp('No title string given, using blank');
		inputTitleStr = '';
	end

	% Initialize constants
	nWorkersDefault = java.lang.Runtime.getRuntime().availableProcessors-1;
	userSelectStr = 'User selects specific value.';
	userSelectVal = 0;
	defaultTooltips = 'NO TIPS FOR YOU';

	vectorAllowList = {'motionCorrectionRefFrame'};

	% Options that allow users to manually set the value
	userOptionsAllowManualSelect = {...
	'numTurboregIterations',...
	'turboregNumFramesSubset',...
	'pxToCrop',...
	'motionCorrectionRefFrame',...
	'SmoothX',...
	'SmoothY',...
	'filterBeforeRegFreqLow',...
	'filterBeforeRegFreqHigh',...
	'medianFilterSize',...
	'downsampleFactorTime',...
	'downsampleFactorSpace',...
	'stripSize',...
	'stripfreqLowExclude',...
	'stripfreqHighExclude',...
	'filterBeforeRegImagejFFTLarge',...
	'filterBeforeRegImagejFFTSmall',...
	'loadMovieInEqualParts',...
	'nParallelWorkers',...
	'calcDroppedFramesFromMovie'...
	};

	% Create structure with options.
	tS = [];

	% ===================================
	tS.MAIN______________ = [];
		tS.MAIN______________.val = {{'====================='}};
		tS.MAIN______________.str = {{'====================='}};
		tS.MAIN______________.tooltip =  {{'====================='}};
	tS.checkConcurrentAnalysis = [];
		tS.checkConcurrentAnalysis.val = {{0,1}};
		tS.checkConcurrentAnalysis.str = {{'DO NOT check for analysis across workstations','DO check for analysis across workstations'}};
		tS.checkConcurrentAnalysis.tooltip =  {{'Select to allow multiple workstations to analyze several of the same imaging sessions WITHOUT duplicating analysis.'}};
	tS.resetParallelPool = [];
		tS.resetParallelPool.val = {{0,1}};
		tS.resetParallelPool.str = {{'DO NOT restart parallel pool after each folder is analyzed','DO restart parallel pool after each folder is analyzed'}};
		tS.resetParallelPool.tooltip =  {{['Parallel workers sometimes start to use a lot of memory.' 10 'Restart them to reset to lower memory usage.']}};
	tS.analyzeFromDisk = [];
		tS.analyzeFromDisk.val = {{0,1}};
		tS.analyzeFromDisk.str = {{'Load entire movie into RAM','Use disk, load part of movie into RAM'}};
		tS.analyzeFromDisk.tooltip =  {{defaultTooltips}};
	tS.calcDroppedFramesFromMovie = [];
		tS.calcDroppedFramesFromMovie.val = {{[],0,1,NaN}};
		tS.calcDroppedFramesFromMovie.str = {{'Calculate dropped frames from metadata.','All 0 frame is a dropped frame.','All 1 frame is a dropped frame.','All NaN frame is a dropped frame.'}};
		tS.calcDroppedFramesFromMovie.tooltip =  {{'If metadata does not contain dropped frame information, set this if specific frames are set to a single value to indicate dropped frames.'}};

	% ===================================
	tS.REGISTRATION______________ = [];
		tS.REGISTRATION______________.val = {{'====================='}};
		tS.REGISTRATION______________.str = {{'====================='}};
		tS.REGISTRATION______________.tooltip =  {{'====================='}};
	tS.mcMethod = [];
		tS.mcMethod.val = {{'turboreg','normcorre'}};
		tS.mcMethod.str = {{'Turboreg motion correction','NoRMCorre (non-rigid) motion correction'}};
		tS.mcMethod.tooltip =  {{'Method to use for motion correction.'}};
	tS.parallel = [];
		tS.parallel.val = {{1,0}};
		tS.parallel.str = {{'parallel processing','NO parallel processing'}};
		tS.parallel.tooltip =  {{'Use parallel processing during motion correction.'}};
	tS.registrationFxn = [];
		tS.registrationFxn.val = {{'transfturboreg','imwarp','imtransform'}};
		tS.registrationFxn.str = {{'transfturboreg','imwarp','imtransform'}};
		tS.registrationFxn.tooltip =  {{'Keep default unless have issues with transfturboreg (e.g. random frames look dim) then use MATLAB registration functions (imwarp or imtransform).'}};
	tS.turboregRotation = [];
		tS.turboregRotation.val = {{0,1}};
		tS.turboregRotation.str = {{'DO NOT turboreg rotation','DO turboreg rotation'}};
		tS.turboregRotation.tooltip =  {{'Unless you have rotation in your movie, leave OFF. Produces better results.'}};
	tS.RegisType = [];
		tS.RegisType.val = {{1,3,4,2}};
		tS.RegisType.str = {{'affine (1, parallelism maintained, no skew or rotation)','projective (3, parallelism not guaranteed, rotation allowed)','affine (4, parallelism maintained, skew allowed)','affine (2, parallelism maintained, rotation allowed)'}};
		tS.RegisType.tooltip =  {{'"affine" is good for most rigid cases, use "projective" if movie has complex motion'}};
	tS.numTurboregIterations = [];
		tS.numTurboregIterations.val = {{1,userSelectVal,2,3,4,5}};
		tS.numTurboregIterations.str = {{1,userSelectStr,2,3,4,5}};
		tS.numTurboregIterations.tooltip =  {{defaultTooltips}};
	tS.turboregNumFramesSubset = [];
		tS.turboregNumFramesSubset.val = {{5000,userSelectVal,1,5,10,50,100,250,500,1000,2000,3000,5000,10000,15000}};
		tS.turboregNumFramesSubset.str = {{5000,userSelectStr,1,5,10,50,100,250,500,1000,2000,3000,5000,10000,15000}};
		tS.turboregNumFramesSubset.tooltip =  {{'To save memory, motion correction is run on the indicated # of frames from the data.'}};
	tS.pxToCrop = [];
		tS.pxToCrop.val = {{14,userSelectVal,15,16,17,18,19,20,21,22,23,24,25}};
		tS.pxToCrop.str = {{14,userSelectStr,15,16,17,18,19,20,21,22,23,24,25}};
		tS.pxToCrop.tooltip =  {{'Maximum # of pixels to convert to NaNs around the border after motion correction.'}};
	tS.motionCorrectionRefFrame = [];
		tS.motionCorrectionRefFrame.val = {{100,userSelectVal,1,10,100,1000}};
		tS.motionCorrectionRefFrame.str = {{100,userSelectStr,1,10,100,1000}};
		tS.motionCorrectionRefFrame.tooltip =  {{['The reference frame for motion correction.' 10 'Avoid selecting 1st couple of movie frames or one that has issues.']}};
	tS.regRegionUseBtwnSessions = [];
		% tS.regRegionUseBtwnSessions.val = {{-1,0,-2,0}};
		tS.regRegionUseBtwnSessions.val = {{1,2,3,4}};
		tS.regRegionUseBtwnSessions.str = {{'NO | do not duplicate area coords across multiple folders','YES | duplicate area coords across multiple folders','YES | duplicate area coords if subject (animal) the same','YES | duplicate area coords across ALL folders'}};
		tS.regRegionUseBtwnSessions.tooltip =  {{['Between session motion correction area coordinates (area used to get registration translation coordinates).']}};

	% ===================================
	tS.REGISTRATION_NORMALIZATION______________ = [];
		tS.REGISTRATION_NORMALIZATION______________.val = {{'====================='}};
		tS.REGISTRATION_NORMALIZATION______________.str = {{'====================='}};
		tS.REGISTRATION_NORMALIZATION______________.tooltip =  {{'====================='}};
	tS.normalizeMeanSubtract = [];
		tS.normalizeMeanSubtract.val = {{1,0}};
		tS.normalizeMeanSubtract.str = {{'normalize movie before turboreg','do not normalize movie before turboreg'}};
		tS.normalizeMeanSubtract.tooltip = {{['Critical for most movies, normalizes each frame to improve motion correction.' 10 'DO NOT CHANGE unless you know what you are doing.']}};
	tS.normalizeMeanSubtractNormalize = [];
		tS.normalizeMeanSubtractNormalize.val = {{1,0}};
		tS.normalizeMeanSubtractNormalize.str = {{'subtract mean per frame','do not subtract mean per frame'}};
		tS.normalizeMeanSubtractNormalize.tooltip = {{'This subtracts the mean of each frame. Keep enabled is nearly all cases.'}};
	tS.normalizeComplementMatrix = [];
		tS.normalizeComplementMatrix.val = {{1,0}};
		tS.normalizeComplementMatrix.str = {{'invert movie before turboreg','DO NOT invert movie before turboreg'}};
		tS.normalizeComplementMatrix.tooltip = {{'Inverts all movie values to give more weight to dark features (e.g. blood vessels).'}};
	tS.normalizeType = [];
		tS.normalizeType.val = {{'bandpass','divideByLowpass','imagejFFT','highpass','matlabDisk'}};
		tS.normalizeType.str = {{'bandpass','divideByLowpass','imagejFFT','highpass','matlabDisk'}};
		tS.normalizeType.tooltip = {{['Spatial filtering applied before getting spatial translation coordinates.' 10 'Try "matlabDisk" if default does not work.']}};
	tS.normalizeFreqLow = [];
		tS.normalizeFreqLow.val = {{70,10,20,30,40,50,60,70,80,90}};
		tS.normalizeFreqLow.str = {{70,10,20,30,40,50,60,70,80,90}};
		tS.normalizeFreqLow.tooltip = {{'For any "normalizeType" FFT options selected, the lower frequency.'}};
	tS.normalizeFreqHigh = [];
		tS.normalizeFreqHigh.val = {{100,80,90,100,110}};
		tS.normalizeFreqHigh.str = {{100,80,90,100,110}};
		tS.normalizeFreqHigh.tooltip = {{'For any "normalizeType" FFT options selected, the higher frequency.'}};
	tS.normalizeBandpassType = [];
		tS.normalizeBandpassType.val = {{'bandpass','lowpass','highpass'}};
		tS.normalizeBandpassType.str = {{'bandpass','lowpass','highpass'}};
		tS.normalizeBandpassType.tooltip = {{'If "normalizeType" is an FFT, the type'}};
	tS.normalizeBandpassMask = [];
		tS.normalizeBandpassMask.val = {{'gaussian','binary'}};
		tS.normalizeBandpassMask.str = {{'gaussian','binary'}};
		tS.normalizeBandpassMask.tooltip = {{['If "normalizeType" is an FFT, how "normalizeBandpassType" is applied.' 10 '"binary" option will produce ringing.']}};
	tS.SmoothX = [];
		tS.SmoothX.val = {{10,userSelectVal,1,5,10,20,30,40,50,60,70,80,90}};
		tS.SmoothX.str = {{10,userSelectStr,1,5,10,20,30,40,50,60,70,80,90}};
		tS.SmoothX.tooltip = {{'Turboreg''s x smoothing size in pixels.'}};
	tS.SmoothY = [];
		tS.SmoothY.val = {{10,userSelectVal,1,5,10,20,30,40,50,60,70,80,90}};
		tS.SmoothY.str = {{10,userSelectStr,1,5,10,20,30,40,50,60,70,80,90}};
		tS.SmoothY.tooltip = {{'Turboreg''s y smoothing size in pixels.'}};
	tS.zapMean = [];
		tS.zapMean.val = {{0,1}};
		tS.zapMean.str = {{0,1}};
		tS.zapMean.tooltip = {{'Turboreg''s function to remove the mean. Leave disabled since this is already done outside turboreg.'}};

	% ===================================
	tS.MOVIE_NORMALIZATION______________ = [];
		tS.MOVIE_NORMALIZATION______________.val = {{'====================='}};
		tS.MOVIE_NORMALIZATION______________.str = {{'====================='}};
		tS.MOVIE_NORMALIZATION______________.tooltip =  {{'====================='}};
	tS.filterBeforeRegister = [];
		tS.filterBeforeRegister.val = {{[],'divideByLowpass','imagejFFT','bandpass'}};
		tS.filterBeforeRegister.str = {{'NO filtering before registering','matlab divide by lowpass before registering','imageJ divide by lowpass (requires Miji!)','matlab bandpass before registering'}};
		tS.filterBeforeRegister.tooltip = {{'IMPORTANT: type of spatial filtering applied after getting spatial transformation coordinates but BEFORE actually motion correcting the movie.'}};
	tS.saveBeforeFilterRegister = [];
		tS.saveBeforeFilterRegister.val = {{0,1}};
		tS.saveBeforeFilterRegister.str = {{'DO NOT SAVE registered movie sans spatial filtering','DO SAVE registered movie sans spatial filtering'}};
		tS.saveBeforeFilterRegister.tooltip = {{['Save registered movie before spatial filtering applied.' 10 'This is a good way to check the correlation of all frames to mean frame to show improvement with motion correction.']}};
	tS.saveFilterBeforeRegister = [];
		tS.saveFilterBeforeRegister.val = {{[],'save'}};
		tS.saveFilterBeforeRegister.str = {{'DO NOT save lowpass movie.','DO save lowpass movie.'}};
		tS.saveFilterBeforeRegister.tooltip = {{'Save a low-pass version of the movie, e.g. if looking at neuropil activity.'}};
	tS.filterBeforeRegFreqLow = [];
		tS.filterBeforeRegFreqLow.val = {{0,userSelectVal,1,2,3,4,5,7,10,15,20,25,30,35,40,45,50,60,70,80,100,150,200,250,300,350,400,500,600}};
		tS.filterBeforeRegFreqLow.str = {{0,userSelectStr,1,2,3,4,5,7,10,15,20,25,30,35,40,45,50,60,70,80,100,150,200,250,300,350,400,500,600}};
		tS.filterBeforeRegFreqLow.tooltip = {{['Value is in cycles per movie x-y dimensions.' 10 'If divideByLowpass, leave this alone.' 10 'If "matlab bandpass" then set to the lowest spatial frequency to keep (e.g. large objects).']}};
	tS.filterBeforeRegFreqHigh = [];
		tS.filterBeforeRegFreqHigh.val = {{10,userSelectVal,1,2,3,4,5,7,10,15,20,25,30,35,40,45,50,60,70,80,100,150,200,250,300,350,400,500,600}};
		tS.filterBeforeRegFreqHigh.str = {{10,userSelectStr,1,2,3,4,5,7,10,15,20,25,30,35,40,45,50,60,70,80,100,150,200,250,300,350,400,500,600}};
		tS.filterBeforeRegFreqHigh.tooltip = {{['Value is in cycles per movie x-y dimensions.' 10 'If divideByLowpass, set to the highest spatial frequency to exclude.' 10 'If "matlab bandpass" then set to the highest spatial frequency to keep (e.g. small ibjects).']}};
	tS.filterBeforeRegImagejFFTLarge = [];
		tS.filterBeforeRegImagejFFTLarge.val = {{10000,userSelectVal,100,500,1000,5000,8000}};
		tS.filterBeforeRegImagejFFTLarge.str = {{10000,userSelectStr,100,500,1000,5000,8000}};
		tS.filterBeforeRegImagejFFTLarge.tooltip = {{'Generally ignore since ImageJ isn''t needed for spatial filtering anymore'}};
	tS.filterBeforeRegImagejFFTSmall = [];
		tS.filterBeforeRegImagejFFTSmall.val = {{80,userSelectVal,10,20,30,40,50,60,70,90,100}};
		tS.filterBeforeRegImagejFFTSmall.str = {{80,userSelectStr,10,20,30,40,50,60,70,90,100}};
		tS.filterBeforeRegImagejFFTSmall.tooltip = {{'Generally ignore since ImageJ isn''t needed for spatial filtering anymore'}};
	tS.medianFilterSize = [];
		tS.medianFilterSize.val = {{3,userSelectVal,5,7,9,11,13,15}};
		tS.medianFilterSize.str = {{3,userSelectStr,5,7,9,11,13,15}};
		tS.medianFilterSize.tooltip = {{['The size in pixels of the median filter.' 10 'If "medianFilter" is selected for preprocessing.']}};

	% ===================================
	tS.MOVIE_DETREND______________ = [];
		tS.MOVIE_DETREND______________.val = {{'====================='}};
		tS.MOVIE_DETREND______________.str = {{'====================='}};
		tS.MOVIE_DETREND______________.tooltip =  {{'====================='}};
	tS.detrendDegree = [];
		tS.detrendDegree.val = {{1,userSelectVal,2,3,4,5,6}};
		tS.detrendDegree.str = {{1,userSelectStr,2,3,4,5,6}};
		tS.detrendDegree.tooltip = {{'For "detrend" function to compensate for photobleaching, the nth-degree polynomial trend to fit. Usually 1 (linear fit) if sufficient.'}};

	% ===================================
	tS.MOVIE_DOWNSAMPLING______________ = [];
		tS.MOVIE_DOWNSAMPLING______________.val = {{'====================='}};
		tS.MOVIE_DOWNSAMPLING______________.str = {{'====================='}};
		tS.MOVIE_DOWNSAMPLING______________.tooltip =  {{'====================='}};
	tS.downsampleFactorTime = [];
		tS.downsampleFactorTime.val = {{4,userSelectVal,1,2,4,6,8,10,20}};
		tS.downsampleFactorTime.str = {{4,userSelectStr,1,2,4,6,8,10,20}};
		tS.downsampleFactorTime.tooltip = {{'By what factor to downsample movie in time.'}};
	tS.downsampleFactorSpace = [];
		tS.downsampleFactorSpace.val = {{2,userSelectVal,1,2,4,6,8,10,20}};
		tS.downsampleFactorSpace.str = {{2,userSelectStr,1,2,4,6,8,10,20}};
		tS.downsampleFactorSpace.tooltip = {{'By what factor to downsample movie in space.'}};

	% ===================================
	tS.IO_and_MOVIE_IDENTIFICATION______________ = [];
		tS.IO_and_MOVIE_IDENTIFICATION______________.val = {{'====================='}};
		tS.IO_and_MOVIE_IDENTIFICATION______________.str = {{'====================='}};
		tS.IO_and_MOVIE_IDENTIFICATION______________.tooltip =  {{'====================='}};
	tS.inputDatasetName = [];
		tS.inputDatasetName.val = {{obj.inputDatasetName,'/1','/Movie','/movie','/images','/Data/Images','/data'}};
		tS.inputDatasetName.str = {{obj.inputDatasetName,'/1','/Movie','/movie','/images','/Data/Images','/data'}};
		tS.inputDatasetName.tooltip = {{'HDF5 dataset name of input data.'}};
	tS.outputDatasetName = [];
		tS.outputDatasetName.val = {{obj.outputDatasetName,'/1','/Movie','/movie','/images'}};
		tS.outputDatasetName.str = {{obj.outputDatasetName,'/1','/Movie','/movie','/images'}};
		tS.outputDatasetName.tooltip = {{'HDF5 dataset name of output data.'}};
	tS.fileFilterRegexp = [];
		tS.fileFilterRegexp.val = {{obj.fileFilterRegexpRaw,'concat_.*.h5','concatenated_.*.h5','crop.*.h5','recording.*.tif','concat.*.tif','dfstd_.*.h5','dfof_.*.h5','concat'}};
		tS.fileFilterRegexp.str = {{obj.fileFilterRegexpRaw,'concat_.*.h5','concatenated_.*.h5','crop.*.h5','recording.*.tif','concat.*.tif','dfstd_.*.h5','dfof_.*.h5','concat'}};
		tS.fileFilterRegexp.tooltip = {{'Regular expression used to find movie data files in each folder.'}};
	tS.processMoviesSeparately = [];
		tS.processMoviesSeparately.val = {{0,1}};
		tS.processMoviesSeparately.str = {{'No','Yes'}};
		tS.processMoviesSeparately.tooltip = {{['"No", all files in folder concatenated in natural sort order.' 10 'If "Yes" then if folder contains multiple movie files, they will be processed separately instead of concatenated together.']}};
	tS.loadMoviesFrameByFrame = [];
		tS.loadMoviesFrameByFrame.val = {{0,1}};
		tS.loadMoviesFrameByFrame.str = {{'No','Yes'}};
		tS.loadMoviesFrameByFrame.tooltip = {{['"No" allows movies to be loaded in one chunk.' 10 '"Yes" loads movies frame-by-frame, which can potentially improve memory usage.']}};
	tS.treatMoviesAsContinuousSwitch = [];
		tS.treatMoviesAsContinuousSwitch.val = {{1,0}};
		tS.treatMoviesAsContinuousSwitch.str = {{'Yes','No'}};
		tS.treatMoviesAsContinuousSwitch.tooltip = {{['"Yes" treats multiple movie files in a folder as one continuous movie.' 10 '"No" treats each movie file in a folder as separate movies.']}};
	tS.loadMovieInEqualParts = [];
		tS.loadMovieInEqualParts.val = {{0,userSelectVal,1,2,3,4,5,6,7,8,9,10}};
		tS.loadMovieInEqualParts.str = {{0,userSelectStr,1,2,3,4,5,6,7,8,9,10}};
		tS.loadMovieInEqualParts.tooltip = {{'Number of 50-frame segments evenly spaced in time to load.'}};
	tS.useParallel = [];
		tS.useParallel.val = {{1,0}};
		tS.useParallel.str = {{'Yes','No'}};
		tS.useParallel.tooltip = {{'Whether to use parallelization in processing steps.'}};
	tS.nParallelWorkers = [];
		% tS.nParallelWorkers.val = {[nWorkersDefault, userSelectVal, mat2cell([1:(nWorkersDefault*2)],1,ones(1,2*nWorkersDefault))]'};
		% tS.nParallelWorkers.str = {[nWorkersDefault, userSelectStr, mat2cell([1:(nWorkersDefault*2)],1,ones(1,2*nWorkersDefault))]'};
		tS.nParallelWorkers.val = {{nWorkersDefault, userSelectVal, nWorkersDefault*2}};
		tS.nParallelWorkers.str = {{nWorkersDefault, userSelectStr, nWorkersDefault*2}};
		tS.nParallelWorkers.tooltip = {{defaultTooltips}};
	tS.largeMovieLoad = [];
		tS.largeMovieLoad.val = {{0,1}};
		tS.largeMovieLoad.str = {{'No','Yes'}};
		tS.largeMovieLoad.tooltip = {{'Whether to load movie without pre-allocating matrix, useful for single large movie in each folder that needs to be processed.'}};

	% ===================================
	tS.STRIPE_REMOVAL______________ = [];
		tS.STRIPE_REMOVAL______________.val = {{'====================='}};
		tS.STRIPE_REMOVAL______________.str = {{'====================='}};
		tS.STRIPE_REMOVAL______________.tooltip =  {{'====================='}};
	tS.stripOrientationRemove = [];
		tS.stripOrientationRemove.val = {{'none','vertical','horizontal','both'}};
		tS.stripOrientationRemove.str = {{'none','vertical','horizontal','both'}};
		tS.stripOrientationRemove.tooltip = {{'Direction of stripes to remove from movie.'}};
	tS.stripSize = [];
		tS.stripSize.val = {{7,userSelectVal,1,3,5,7,9,11,13,15}};
		tS.stripSize.str = {{7,userSelectStr,1,3,5,7,9,11,13,15}};
		tS.stripSize.tooltip = {{['Width in pixels in FFT domain of filter.' 10 'Higher values allow more tolerance for strips that are not exactly vertical or horizontal.']}};
	tS.stripfreqLowExclude = [];
		tS.stripfreqLowExclude.val = {{20,userSelectVal,1,2,3,4,5,7,10,15,20,25,30,35,40,45,50,60,70,80,100,150,200,250,300,350,400}};
		tS.stripfreqLowExclude.str = {{20,userSelectStr,1,2,3,4,5,7,10,15,20,25,30,35,40,45,50,60,70,80,100,150,200,250,300,350,400}};
		tS.stripfreqLowExclude.tooltip = {{'Lowest frequency of stripe to exclude from strip filter.'}};
	tS.stripfreqHighExclude = [];
		tS.stripfreqHighExclude.val = {{20,userSelectVal,1,2,3,4,5,7,10,15,20,25,30,35,40,45,50,60,70,80,100,150,200,250,300,350,400}};
		tS.stripfreqHighExclude.str = {{20,userSelectStr,1,2,3,4,5,7,10,15,20,25,30,35,40,45,50,60,70,80,100,150,200,250,300,350,400}};
		tS.stripfreqHighExclude.tooltip = {{'Highest frequency of stripe to exclude from strip filter.'}};
	tS.stripfreqBandpassType = [];
		tS.stripfreqBandpassType.val = {{'highpass','bandpass','lowpass'}};
		tS.stripfreqBandpassType.str = {{'highpass','bandpass','lowpass'}};
		tS.stripfreqBandpassType.tooltip = {{'Type of stripe bandpass to use.'}};

	if ~isempty(options.inputSettings)
		try
			nonDefaultProperties = {};
			propertyListTmp = fieldnames(tS);
			nProperties = size(propertyListTmp,1);
			for propertyNo = 1:nProperties
				property = char(propertyListTmp(propertyNo));

				% Check if value had been modified from default, if so then add that as the 1st, default option.
				% if isequal(options.inputSettings.(property).val{1},tS.(property).val{1})
				if isfield(options.inputSettings,property)
					if isfield(options.inputSettings.(property),'modified')
						nonDefaultProperties{end+1} = property;
						tS.(property).val = {[{options.inputSettings.(property).modified.val},tS.(property).val{1}]};
						tS.(property).str = {[options.inputSettings.(property).modified.str,tS.(property).str{1}]};

						% Ensure modification from default is passed onto future edits
						tS.(property).modified = [];
						% tS.(property).modified.val = tS.(property).val{1};
						% tS.(property).modified.str = tS.(property).str{1};
						tS.(property).modified.val = options.inputSettings.(property).modified.val;
						tS.(property).modified.str = options.inputSettings.(property).modified.str;
					end
				end
			end
			options.inputSettings
		catch err
			disp(repmat('@',1,7))
			disp(getReport(err,'extended','hyperlinks','on'));
			disp(repmat('@',1,7))
		end
	else
		nonDefaultProperties = {};
	end

	% propertySettings = turboregSettingDefaults;
	preprocessingSettingsAll = tS;

	propertyList = fieldnames(preprocessingSettingsAll);
	nPropertiesToChange = size(propertyList,1);

	% add current property to the top of the list
	for propertyNo = 1:nPropertiesToChange
		property = char(propertyList(propertyNo));
		% propertyOptions = turboregSettingStr.(property);
		propertyOptions = preprocessingSettingsAll.(property).str{1};
		propertySettingsStr.(property) = propertyOptions;
		% propertySettingsStr.(property);
	end

	modX = 1.05;
	modX_text = 1.1;
	figNoDefault = 1337;
	uiListHandles = {};
	uiTextHandles = {};
	uiXIncrement = 0.025/modX;
	uiXOffset = 0.02/modX;
	uiYOffset = 0.90;
	uiYOffsetOrig = uiYOffset;
	uiTxtSize = 0.4;
	uiBoxSize = 0.55;
	uiFontSize = 9;
	nGuiSubsets = 3;
	% subsetList = round(linspace(1,nPropertiesToChange,nGuiSubsets));
	subsetList = [1 35 nPropertiesToChange];
	propNoSwitch = 36;
	% subsetList
	% for subsetNo = 1:nGuiSubsets
	nGuiSubsetsTrue = (nGuiSubsets-1);

	nGuiSubsets = 2;
	nGuiSubsetsTrue = (nGuiSubsets-1);
	% nGuiSubsetsTrue = 1;
	figure(figNoDefault);
	set(gcf,'color',[0 0 0]);
	for thisSet = 1:nGuiSubsetsTrue
		% 1:nPropertiesToChange
		% subsetStartTime = tic;
		subsetStartIdx = subsetList(thisSet);
		subsetEndIdx = subsetList(thisSet+1);

		subsetStartIdx = 1;
		subsetEndIdx = nPropertiesToChange;

		if thisSet==nGuiSubsetsTrue
			propertySubsetList = subsetStartIdx:(subsetEndIdx);
		else
			propertySubsetList = subsetStartIdx:(subsetEndIdx-1);
		end

		[figHandle figNo] = openFigure(figNoDefault, '');
		clf
		uicontrol('Style','Text','String',inputTitleStr,'Units','normalized','Position',[uiXOffset uiYOffset+0.05 0.8 0.05],'BackgroundColor','black','ForegroundColor','white','HorizontalAlignment','Left','FontSize',uiFontSize);
		uicontrol('Style','Text','String',sprintf('Options page %d/%d: Mouse over each options for tips. To continue, press enter. Orange = previous non-default settings.\n>>>On older MATLAB versions, select the command window before pressing enter.',thisSet,nGuiSubsets-1),'Units','normalized','Position',[uiXOffset uiYOffset+0.02 uiTxtSize+uiBoxSize 0.05],'BackgroundColor','black','ForegroundColor','white','HorizontalAlignment','Left','FontSize',uiFontSize);

		propNoDisp = 1;
		for propertyNo = propertySubsetList
			property = char(propertyList(propertyNo));
			% propertyTooltip = turboregSettingTooltips.(property);
			propertyTooltip = char(preprocessingSettingsAll.(property).tooltip{1});

			if propertyNo==propNoSwitch
				propNoDisp = 1;
				uiYOffset = uiYOffsetOrig;
			end
			if propertyNo>=propNoSwitch
				colNo = 49/100;
				uiTxtSize = 0.4/2;
				uiBoxSize = 0.55/2;
			else
				colNo = 0/100;
				uiTxtSize = 0.4/2;
				uiBoxSize = 0.55/2;
			end

			% disp([num2str(propertyNo) ' | ' property])
			if isempty(intersect(propertyNo,[1,propNoSwitch]))
				if isempty(regexp(property,'______________'))
					spaceMod = 0.00;
					FontWeightH = 'normal';
				else
					spaceMod = 0.02;
					uiYOffset = uiYOffset-spaceMod;
					FontWeightH = 'bold';
				end
			else
				FontWeightH = 'bold';
			end

			textPos = [uiXOffset+colNo uiYOffset-uiXIncrement*propNoDisp+modX_text*(0.027/modX) uiTxtSize 0.0225/modX];
			uiTextHandles{propertyNo} = uicontrol('Style','text','String',[property '' 10],'Units','normalized',...
				'Position',textPos,...
				'BackgroundColor',[0.9 0.9 0.9],'ForegroundColor','black','HorizontalAlignment','Left','FontSize',uiFontSize,'ToolTip',propertyTooltip,'FontWeight',FontWeightH);

			listPos = [uiXOffset+uiTxtSize+colNo uiYOffset-uiXIncrement*propNoDisp uiBoxSize 0.05];
			uiListHandles{propertyNo} = uicontrol('Style', 'popup','String', propertySettingsStr.(property),'Units','normalized',...
				'Position', listPos,'BackgroundColor','black','ForegroundColor','white',...
				'Callback',@subfxnInterfaceCallback,'FontSize',uiFontSize,'Tag',property);

			% jEdit = findjobj(uiTextHandles{propertyNo});
			% lineColor = java.awt.Color(1,0,0);  % =red
			% thickness = 3;  % pixels
			% roundedCorners = true;
			% newBorder = javax.swing.border.LineBorder(lineColor,thickness,roundedCorners);
			% jEdit.Border = newBorder;
			% jEdit.repaint;  % redraw the modified control
			% uiTextHandles{propertyNo}.Enable = 'Inactive';
			% optionCallback = ['set(uiListHandles{propertyNo}, ''Backgroundcolor'', ''g'')'];
			% uiListHandles{propertyNo} = uicontrol('Style', 'popup','String', propertySettingsStr.(property),'Units','normalized','Position', [uiXOffset+uiTxtSize uiYOffset-uiXIncrement*propNoDisp uiBoxSize 0.05],'Callback',@(hObject,callbackdata){set(hObject, 'Backgroundcolor', [208,229,180]/255);},'FontSize',uiFontSize);
			% ,'ToolTip',propertyTooltip

			% If property is non-default, set to orange to alert user.
			if any(ismember(nonDefaultProperties,property))
				set(uiListHandles{propertyNo},'Backgroundcolor',[254 216 177]/255/2);
			end

			propNoDisp = propNoDisp+1;
		end

		startMethodHandle = uicontrol('style','pushbutton','Units', 'normalized','position',[80 94 20 2]/100,'FontSize',9,'string','Click when done.','BackgroundColor',[153 255 153]/255,'callback',@subfxn_closeOptions);
		emptyBox = uicontrol('Style','Text','String',[''],'Units','normalized','Position',[1 1 1 1]/100,'BackgroundColor','black','ForegroundColor','white','HorizontalAlignment','Left','FontWeight','bold','FontSize',7);
		set(gcf,'KeyPressFcn', @subfxn_closeOptionsKey);
		ciapkg.view.changeFont('none','fontColor','w')
		% waitfor(gcf,'Tag');
		waitfor(emptyBox);
		% pause
		uiYOffset = 0.90;

		for propertyNo = propertySubsetList
			property = char(propertyList(propertyNo));
			uiListHandleData = get(uiListHandles{propertyNo});
			if isempty(regexp(property,'______________'))
				preprocessSettingStruct.(property) = preprocessingSettingsAll.(property).val{1}{uiListHandleData.Value};
			else
				preprocessSettingStruct.(property) = preprocessingSettingsAll.(property).val{1};
			end
			% preprocessSettingStruct.(property) = turboregSettingDefaults.(property){uiListHandleData.Value};
		end
	end
	close(1337)

	% ensure rotation setting matches appropriate registration type
	if preprocessSettingStruct.turboregRotation==1
		preprocessSettingStruct.RegisType = 3;
	end

	preprocessSettingStruct.refCropFrame = preprocessSettingStruct.motionCorrectionRefFrame;

	% if preprocessSettingStruct.refCropFrame==0
	% 	movieSettings = inputdlg({...
	% 			'frame to reference to: '...
	% 		},...
	% 		'view movie settings',1,...
	% 		{...
	% 			'100'...
	% 		}...
	% 	);
	% 	preprocessSettingStruct.refCropFrame = str2num(movieSettings{1});
	% end
	function subfxnInterfaceCallback(hObject,callbackdata)
		set(hObject, 'Backgroundcolor', [208,229,180]/255/2);

		% De-select the current option, allows user to press enter to continue.
		set(hObject, 'Enable', 'off');
		drawnow;
		set(hObject, 'Enable', 'on');

		% If user asks to manually specify motion correction frame
		if any(strcmp(userOptionsAllowManualSelect,get(hObject,'Tag')))==1
			thisProperty = userOptionsAllowManualSelect{strcmp(userOptionsAllowManualSelect,get(hObject,'Tag'))};
			gValue = get(hObject,'Value');
			gString = get(hObject,'String');
			gTooltip = char(get(hObject,'ToolTip'));
			gProperty = get(hObject,'Tag');
			if strcmp(thisProperty,'motionCorrectionRefFrame')==1
				defVal = num2str(obj.motionCorrectionRefFrame);
			else
				defVal = char(gString{1});
			end
			if strcmp(gString{gValue},userSelectStr)==1
				inputCheck = 'Americans love a winner.';
				lengthTooLongFlag = 1;
				numericCheckFlag = 1;
				nanCheckFlag = 0;
				updateValueFlag = 0;
				loopBreak = 0;
				while (nanCheckFlag==1||lengthTooLongFlag==1)&loopBreak==0
					movieSettings = inputdlg({...
							gTooltip...
						},...
						[thisProperty ' settings'],[1 70],...
						{...
							defVal...
						}...
					);

					if isempty(movieSettings)
						inputCheck = [];
						updateValueFlag = 0;
						loopBreak = 1;
						% uiwait(ciapkg.overloaded.msgbox('Re-enter a value, do not CANCEL the input dialog.'));
					else
						movieSettings = movieSettings{1};
						inputCheck = movieSettings;

						% Check users has input correct (no str or NaN), else ask again.
						if length(str2num(inputCheck))~=1
						    lengthTooLongFlag = 1;
						else
							lengthTooLongFlag = 0;
						end
						if isempty(str2num(inputCheck))
							numericCheckFlag = 0;
						else
							numericCheckFlag = 1;
						end
						if isnan(str2num(inputCheck))
							nanCheckFlag = 1;
						else
							nanCheckFlag = 0;
						end
						if nanCheckFlag==1||numericCheckFlag==0||lengthTooLongFlag==1
							if any(ismember(thisProperty,vectorAllowList))
								loopBreak = 1;
								updateValueFlag = 1;
							else
								uiwait(ciapkg.overloaded.msgbox('Please input a SINGLE numeric value (no strings or vectors).'));
							end
						else
							loopBreak = 1;
							updateValueFlag = 1;
						end
					end
				end
				% Reset to default value if user cancels
				if updateValueFlag==0
					movieSettings = defVal;
					updateValueFlag = 1;
				end
				if updateValueFlag==1
					gStringNew = [movieSettings;gString];
					set(hObject,'String',gStringNew);
					set(hObject,'Value',1);
					% preprocessingSettingsAll.(gProperty).val = [str2num(movieSettings{1}),preprocessingSettingsAll.(gProperty).val];
					preprocessingSettingsAll.(gProperty).val = {[str2num(movieSettings),preprocessingSettingsAll.(gProperty).val{1}]};
					preprocessingSettingsAll.(gProperty).str = {gStringNew};
					% turboregSettingDefaults.(thisProperty) = [str2num(movieSettings{1}),turboregSettingDefaults.(thisProperty)];
					% turboregSettingStr.(thisProperty) = gStringNew;
				end
			end
		end

		% Indicate value was modified for later input of previous settings.
		gProperty = get(hObject,'Tag');
		gValue = get(hObject,'Value');
		gString = get(hObject,'String');
		preprocessingSettingsAll.(gProperty).modified = [];
		preprocessingSettingsAll.(gProperty).modified.val = preprocessingSettingsAll.(gProperty).val{1}{gValue};
		preprocessingSettingsAll.(gProperty).modified.str = gString{gValue};
		% preprocessingSettingsAll.(gProperty).modified
		% preprocessingSettingsAll.(gProperty)
	end
	function subfxn_closeOptions(src,event)
		delete(emptyBox);
	end
	function subfxn_closeOptionsKey(src,event)
		if event.Key=="return"
			delete(emptyBox)
		end
	end
end


classdef VideoPlayer < handle

    properties (Access = public)
        delegate;
    end

    properties (Access = private)
        videoPlayerHandle;
        figureHandle;
        timer;
        previousFrame;
    end

    properties (GetAccess = public)
        numFrames;
    end

    properties (Dependent)
        currentFrame;
    end

    methods
        function f = get.currentFrame(obj)
            f = obj.videoPlayerHandle.DataSource.Controls.CurrentFrame;
        end
    end

    methods (Access = public)

        function obj = VideoPlayer(fileName,delegate,windowPosition)
            obj.videoPlayerHandle = implay(fileName);
            if nargin > 2
                obj.videoPlayerHandle.Parent.OuterPosition = windowPosition;
            end

            obj.delegate = delegate;
            obj.figureHandle = obj.videoPlayerHandle.Parent;
            obj.numFrames = str2double(obj.videoPlayerHandle.Visual.VideoInfo.PlaybackInfo.Widgets{2,2});
            obj.figureHandle.KeyPressFcn = @obj.handleKeyPress;
            obj.figureHandle.CloseRequestFcn = @obj.handleWindowClosed;
            obj.timer = timer('TimerFcn', @obj.timerTick,'Period',0.03,'ExecutionMode','fixedRate');
            start(obj.timer);
        end

        function frame = displayFrame(obj,frame)
            if frame > obj.numFrames
                frame = obj.numFrames;
            elseif frame < 1
                frame = 1;
            end
            obj.videoPlayerHandle.DataSource.Controls.jumpTo(double(frame));
            obj.previousFrame = frame;
        end

        function handleKeyPress(obj, ~, event)
            switch event.Key
                case 'leftarrow'
                    obj.videoPlayerHandle.DataSource.Controls.stepBack();
                case 'rightarrow'
                    obj.videoPlayerHandle.DataSource.Controls.stepFwd();
                case 'space'
                    obj.videoPlayerHandle.DataSource.Controls.playPause();
            end
            obj.previousFrame = obj.currentFrame;
            if ~isempty(obj.delegate)
                obj.delegate.handleVideoPlayerFrameChanged(obj.currentFrame);
            end
        end

        function close(obj)
            close(obj.figureHandle);
        end

        function makeForeGround(obj)
            figure(obj.videoPlayerHandle.Parent);
        end
    end

    methods (Access = private)

        function timerTick(obj,~,~)
            if(obj.currentFrame ~= obj.previousFrame)
                obj.previousFrame = obj.currentFrame;
                if ~isempty(obj.delegate)
                    obj.delegate.handleVideoPlayerFrameChanged(obj.previousFrame,obj);
                end
            end
        end

        function handleWindowClosed(obj,~,~)
            stop(obj.timer);
            delete(obj.timer);
            delete(obj.figureHandle);
            if ~isempty(obj.delegate)
                obj.delegate.handleVideoPlayerWindowClosed(obj);
            end
        end
    end
end


function CoreRunTests(testsOrDirectory)
    % CoreRunTests Runs MTest unit tests for Matlab
    %
    % Executes the specified unit tests and reports on the sucess and
    % failures.
    %
    % Syntax:
    %     CoreRunTests(testsOrDirectory);
    %
    %         testsOrDirectory - a folder or a cell array of strings, each containing the name of a test to run
    %
    %     Licence
    %     -------
    %     Part of CoreMat. https://github.com/tomdoel/coremat
    %     Author: Tom Doel, 2013.  www.tomdoel.com
    %     Distributed under the MIT licence. Please see website for details.
    %

    if (nargin > 0) && ~isempty(testsOrDirectory)
        if iscell(testsOrDirectory)
            testClasses = testsOrDirectory;
        elseif CoreDiskUtilities.DirectoryExists(testsOrDirectory)
            testClasses = CoreDiskUtilities.GetListOfClassFiles(testsOrDirectory, 'CoreTest');
        elseif ischar(testsOrDirectory) && exist(testsOrDirectory, 'class') == 8
            testClasses = {testsOrDirectory};
        else
            throw(MException('CoreRunTests:UnrecognisedArgument', 'Please specify a test directory or a set of test class names to run'));
        end
        RunTests(testClasses);
    else
        disp('Please specify a test directory or a set of test class names to run');
    end
end

function RunTests(testClasses)
    numTests = numel(testClasses);
    if numTests == 1
        testString = 'test';
    else
        testString = 'tests';
    end
    disp(['Running ' testString '...']);
    passed = 0;
    failed = 0;

    for testClass = testClasses
        testClassName = testClass{1};
        try
            classHandle = feval(testClassName);
            classHandle.delete();
            disp([' + Passed: ' char(testClassName)]);
            passed = passed + 1;
        catch ex
            disp(['***** FAILED: ' char(testClassName)]);
            failed = failed + 1;
        end
    end
    disp(['Complete. ' int2str(failed+passed) ' ' testString ' run. ' int2str(passed) ' passed. ' int2str(failed) ' failed. ' ]);
end


% Copyright (C) 2013, Georgia Tech Research Corporation
% see the LICENSE file included with this software

function data = getSimulatorBlockUserData(modelHandle)

blockName = find_system(modelHandle,...
    'SearchDepth', 1, ...
    'MaskType', 'Simulator');

if numel(blockName) == 0
    error('Cannot find Simulator Block at top level of model');
elseif numel(blockName) > 1
    error('Multiple Simulator Blocks');
end

data = get_param(blockName, 'UserData');
if isempty(data)
   error('Simulator Block is not initialized');
end


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

    indexS = planC{end};
    planC{indexS.dose}(doseNum).cachedColor = [];
    planC{indexS.dose}(doseNum).cachedTime = [];
    planC{indexS.dose}(doseNum).numCachedSlices = 0;


% FT_PREAMBLE_INIT is a helper script that is used at the start of all FieldTrip main
% functions. It checks whether the user specified at lease one input arguments (i.e.
% the cfg) or shows the help of the calling function. It merges the global defaults
% with the cfg. It checks whether the output file already exists and whether it is OK
% to overwrite it. It tracks the function call.
%
% Use as
%   ft_preamble init
%
% See also FT_PREAMBLE, FT_POSTAMBLE, FT_TRACKUSAGE

% Copyright (C) 2011-2016, Robert Oostenveld, DCCN
%
% 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$

% disabled for now, see further down
global ft_default

% Which high-level FieldTrip function is lowest on the stack, and which is
% highest? Lowest could e.g. be ft_selectdata called by another FieldTrip
% function, highest should always be the top-level FieldTrip function that
% was explicitly called by the user. These are used further down below,
% e.g. in the reproducescript functionality.
% (Note that we prepend random strings to local variables in pre- and
% postambles to avoid contaminating the caller's namespace.)
FjmoT6aA_stack = dbstack('-completenames');
% FjmoT6aA_stack(1) is this script
% FjmoT6aA_stack(2) is the calling ft_postamble function
% FjmoT6aA_stack(3) is the lowest FieldTrip function on the stack, the one currently being evaluated
% the highest FieldTrip function on the stack is given by the highest n
% such that FjmoT6aA_stack(n).path begins with the FieldTrip path
FjmoT6aA_lowest_ft = FjmoT6aA_stack(3).name;
FjmoT6aA_highest_ft = FjmoT6aA_stack(3).name;
[FjmoT6aA_ft_ver, FjmoT6aA_ft_path] = ft_version;
for FjmoT6aA_k = 3:numel(FjmoT6aA_stack)
  if startsWith(FjmoT6aA_stack(FjmoT6aA_k).file, FjmoT6aA_ft_path)
    FjmoT6aA_highest_ft = FjmoT6aA_stack(FjmoT6aA_k).name;
  else
    % we are operating under the assumption here that a private FieldTrip
    % function (i.e. one whose name does not start with "ft_") never calls
    % another high-level FieldTrip function.
    break;
  end
end
% check whether we are currently in a top-level user-called FT function
% (note that checking of names only probably is not sufficient, as recursion
% could occur)
FjmoT6aA_current_ft_toplevel = strcmp(FjmoT6aA_lowest_ft, FjmoT6aA_highest_ft) && ...
  (FjmoT6aA_k == 4 || numel(FjmoT6aA_stack) == 3);

if ft_nargin==0
  help(FjmoT6aA_lowest_ft);
  % throw the error as if it happened in the original function
  msg.message     = 'This function requires one or multiple input arguments, please refer to the documentation above';
  msg.identifier  = '';
  msg.stack       = FjmoT6aA_stack;
  error(msg);
end % if nargin

% check if there are fieldnames in the cfg that suggest as if the user
% erroneously inputted a data argument
checkdatafields = isfield(cfg, {'cfg' 'label' 'dimord' 'trialinfo' 'avg' 'powspctrm'});
if any(checkdatafields)
  help(FjmoT6aA_lowest_ft);
  % throw the error as if it happened in the original function
  msg.message     = 'It seems as if the first input argument is a FieldTrip data structure, while a cfg is expected';
  msg.identifier  = '';
  msg.stack       = FjmoT6aA_stack;
  error(msg);
end

% convert automatically from cell-array to structure
if iscell(cfg)
  cfg = ft_keyval2cfg(cfg);
end

% check that it is an struct or empty numeric array
assert(isstruct(cfg) || (isnumeric(cfg) && isempty(cfg)), 'The configuration must be a structure or empty');

% this script requires some options that can be user-specified, but otherwise are obtained from ft_default
% merge the default options into the configuration, except the preamble field which is used for passing arguments
cfg = mergestruct(cfg, ft_default);

% determine whether function execution should be aborted or continued
if isfield(cfg, 'outputfile') && ~isempty(cfg.outputfile)
  assert(any(strcmp(fieldnames(cfg), 'outputfilepresent')), 'cfg.outputfilepresent is a required option, please see FT_DEFAULTS');
  % check whether the output file already exists
  if ischar(cfg.outputfile)
    chiL7fee_outputfile = {cfg.outputfile};
  else
    chiL7fee_outputfile = cfg.outputfile;
  end
  for i=1:numel(chiL7fee_outputfile)
    [p, f, x] = fileparts(chiL7fee_outputfile{i});
    if isempty(p)
      % the relative path was speciield
      chiL7fee_outputfile{i} = fullfile(pwd, chiL7fee_outputfile{i});
    else
      % the absolute path was specified
      chiL7fee_outputfile{i} = chiL7fee_outputfile{i};
    end
    if ~exist(chiL7fee_outputfile{i}, 'file')
      ft_abort = false;
    else
      % the output file exists, determine how to deal with it
      switch cfg.outputfilepresent
        case 'keep'
          if ft_nargout>0
            % continue executing the parent function
            ft_warning('output file %s is already present, but you also requested an output argument: continuing function execution', chiL7fee_outputfile{i});
            ft_abort = false;
          else
            % stop executing the parent function
            ft_warning('output file %s is already present: aborting function execution', chiL7fee_outputfile{i});
            ft_abort = true;
          end
        case 'overwrite'
          ft_warning('output file %s is already present: it will be overwritten', chiL7fee_outputfile{i});
          ft_abort = false;
        case 'error'
          ft_error('output file %s is already present', chiL7fee_outputfile{i});
        otherwise
          ft_error('invalid option for cfg.outputfilepresent');
      end % case
    end
  end % for each of the output files
else
  % there is no reason to abort execution
  ft_abort = false;
end % if chiL7fee_outputfile{i}

if isfield(cfg, 'reproducescript') && ~isempty(cfg.reproducescript)
  % the reproducescript code should only be executed in a top-level FT function
  if ~FjmoT6aA_current_ft_toplevel
    % we are in a FT function that was called by another FT function
    cfg = rmfield(cfg, 'reproducescript');
  else
    % we are in a top-level FT function
    if ~isfolder(cfg.reproducescript)
      mkdir(cfg.reproducescript);
    end
    % user-specified cfg.inputfile or cfg.outputfile are not compatible
    % with cfg.reproducescript functionality, throw error to make them
    % mutually exclusive
    if (isfield(cfg, 'inputfile') && ~isempty(cfg.inputfile)) || ...
       (isfield(cfg, 'outputfile') && ~isempty(cfg.outputfile))
      ft_error('cfg.reproducescript cannot be used together with a user-specified cfg.inputfile or cfg.outputfile');
    end
    % this variable is used in loadvar, savevar and savefig
    Fief7bee_reproducescript = cfg.reproducescript;
    cfg = rmfield(cfg, 'reproducescript');
    % pause one second to ensure that subsequent file names (which contain the time stamp) are unique
    pause(1);
  end
end

if false
  % this is currently generating too much data and therefore disabled
  if isfield(cfg, 'trackusage') && ~(isequal(cfg.trackusage, false) || isequal(cfg.trackusage, 'no') || isequal(cfg.trackusage, 'off'))
    % track the usage of the calling function
    stack = dbstack('-completenames');
    % stack(1) is this script
    % stack(2) is the calling ft_postamble function
    % stack(3) is the main FieldTrip function that we are interested in
    ft_trackusage('function call', 'function', stack(3).name);
  end % if trackusage
end


function qwarning(s)
% warning with option to stop

disp('To interrupt press Ctr-C');
warning(s);
pause;


function cvx_clearspath

%CVX_CLEARSPATH   Clears the cvx solver path.
%   CVX_CLEARSPATH removes the internal solver directories to the Matlab
%   path. CVX automatically clears the solver path after completion of a
%   model computation, so calling this function should not be necessary.
%   Nevertheless, we provide it for completeness and debugging.

global cvx___
osolv = cvx___.solvers.active;
if osolv,
    tstr = cvx___.solvers.list(osolv).path;
    if ~isempty( tstr ),
        path(strrep(path,tstr,''));
    end
    cvx___.solvers.active = 0;
end

% Copyright 2005-2016 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function [metList, noMolMetList] = mol2sdf(mets, molfileDir, sdfFileName, includeRs)
% Concatenates molfiles in `molfileDir` into one SDF file.
%
% USAGE:
%
%    [metList, noMolMetList] = mol2sdf(mets, molfileDir, sdfFileName, includeRs)
%
% INPUTS:
%    mets:            `m x 1` cell array of metabolite identifiers (e.g., BiGG
%                     abbreviations)
%    molfileDir:      Path to directory containing molfiles for metabolites
%                     in mets. Molfile names should match the metabolite
%                     identifiers in mets without compartment assignments.
%
% OPTIONAL INPUTS:
%    sdfFileName:     Name of SDF file. Default is `MetStructures.sdf`.
%    includeRs:       {0, (1)}. If 0, variable structures such as R groups and
%                     repeat units will not be included in SDF.
%
% OUTPUTS:
%    metList:         Cell array listing metabolites in SDF.
%    noMolMetList:    Cell array listing metabolites without mol file.
%
% Written output is `sdfFileName.sdf` - SDF with metabolite structures in same order as in
% metList. Metabolite identifiers in the SDF are the same as in `MetList`.
%
% .. Authors:
%       - Ronan M.T. Fleming
%       - Hulda SH, Nov. 2012   Changed output format from CDF to SDF. Renamed function. Simplified code.

if ~strcmp(molfileDir(end),filesep) % Format inputs
    molfileDir = [molfileDir filesep];
end
if ~exist('sdfFileName','var') ||  isempty(sdfFileName)
    sdfFileName = 'MetStructures.sdf';
end
if ~strcmp(sdfFileName(end-3:end),'.sdf')
    sdfFileName = [sdfFileName '.sdf'];
end
sdfFileName = [molfileDir sdfFileName];

mets = reshape(mets,length(mets),1);
omets = mets; % store original metabolite identifiers
if ischar(mets)
    mets = strtrim(cellstr(mets));
end
if isnumeric(mets)
    mets = strtrim(cellstr(num2str(mets)));
end
mets = regexprep(mets,'(\[\w\])$',''); % Remove compartment assignment

if ~exist('includeRs','var')
    includeRs = 1;
end

% List all molfiles in molfile directory
d = dir(molfileDir);
dirbool = cat(1,d.isdir);
d = d(~dirbool);
molfileNames = {d.name};
molfileNames = regexprep(molfileNames,'(\.mol)$','')';

molfileNames = molfileNames(ismember(molfileNames,mets)); % Only include molfiles for metabolites in mets

noMolMetList = unique(mets(~ismember(mets,molfileNames)));
noMolMetList = reshape(noMolMetList,length(noMolMetList),1);

metList = molfileNames;

% List all elements
elements = {'H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar', 'K', 'Ca',...
            'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'Rb', 'Sr', 'Y',...
            'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe', 'Cs', 'Ba', 'La', 'Ce',...
            'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir',...
            'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn', 'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am', 'Cm',...
            'Bk', 'Cf', 'Es', 'Fm', 'Md', 'No', 'Lr', 'Rf', 'Db', 'Sg', 'Bh', 'Hs', 'Mt', 'Ds', 'Rg', 'Cn', 'Uut', 'Fl', 'Uup', 'Lv', 'Uus', 'Uuo'};

% Concatenate molfiles into single SDF file
fid = fopen(sdfFileName,'w+'); % Create SDF
first = true;
for m = 1:length(molfileNames)
    molfile = fileread([molfileDir molfileNames{m} '.mol']); % Read in molfile
    molfile = reshape(molfile, 1, length(molfile)); % for compatibility with Octave (where fileread returns a column vector of chars)
    molfile = regexprep(molfile,'\r',''); % Remove carriage returns
    molfile = regexprep(molfile,'[^\n]*\n',sprintf('%s\n',molfileNames{m}),'once'); % Replace top line with metabolite identifier
    molfile = regexprep(molfile,'\n+$',''); % Ensure there is only one newline caracter at end of each molfile in the SDF

    if includeRs == 0
        % Get atom list
        lines = regexp(molfile,'\n','split');
        try
            atomCount = str2double(lines{4}(1:3));
        catch
            disp('Failure to read mol file:')
            disp(lines)
            continue;
        end
        if atomCount > 0
            atomBlock = lines(5:5 + atomCount - 1);
            pat = '[^a-z_A-z\*]+(?<atom>[a-z_A-Z\*]+)[^a-z_A-z\*]+';
            atoms = regexp(atomBlock,pat,'names');
            atoms = [atoms{:}]';
            atoms = {atoms.atom}';

            % If structure contains a non-elemental atom or repeat units it
            % will not be appended to SDF
            if ~all(ismember(atoms,elements)) || ~isempty(strmatch('M  STY',lines))
                metList = setdiff(metList,molfileNames{m});
                continue;
            end
        end
    end

    % Add molfile to SDF
    if first
        fprintf(fid,'%s\n',molfile);
        first = false;
    else
        fprintf(fid,'%s\n','$$$$');
        fprintf(fid,'%s\n',molfile);
    end
end
fclose(fid);

noMolFileCount = sum(~ismember(mets,molfileNames'));
fprintf('Percentage of metabolites without mol files: %.1f%%\n', 100*noMolFileCount/length(mets));

metList = reshape(metList,length(metList),1);
if isnumeric(omets)
    metList = str2double(metList);
end


%TIMES Mapping overload


function cvx_clearspath

%CVX_CLEARSPATH   Clears the cvx solver path.
%   CVX_CLEARSPATH removes the internal solver directories to the Matlab
%   path. CVX automatically clears the solver path after completion of a
%   model computation, so calling this function should not be necessary.
%   Nevertheless, we provide it for completeness and debugging.

global cvx___
osolv = cvx___.solvers.active;
if osolv,
    tstr = cvx___.solvers.list(osolv).path;
    if ~isempty( tstr ),
        path(strrep(path,tstr,''));
    end
    cvx___.solvers.active = 0;
end

% Copyright 2005-2014 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function [inchi, metList] = sdf2inchi(sdfFileName, options)
% Converts metabolite structures in an SDF to a cell array of InChI
% strings with OpenBabel.
%
% USAGE:
%
%    [inchi, metList] = sdf2inchi(sdfFileName, options)
%
% INPUT:
%    sdfFileName:    Path to SDF file.
%
% OPTIONAL INPUTS:
%    options:        Write options for InChI strings. See InChI documentation
%                    for details. If no options are specified the function will
%                    output standard InChI.
%
% OUTPUTS:
%    inchi:          Cell array of InChI strings for metabolites in the SDF file.
%    metList:        Cell array of metabolite identifiers (first line of each
%                    molfile in SDF). Will be empty unless write option `t` is
%                    used (i.e., options >= '-xt').
%
% .. Author: - Hulda SH, Nov. 2012

if ~strcmp(sdfFileName(end-3:end),'.sdf') % Check inputs
    sdfFileName = [sdfFileName '.sdf'];
end

if ~exist('options','var')
    options = [];
end
if ~isempty(options)
   options = [' ' strtrim(options)];
end

babelcmd = 'babel';

% Convert to InChI with OpenBabel
[success,result] = system([babelcmd ' ' sdfFileName ' -oinchi' options]);

% Parse output from OpenBabel
if success == 0
    result = regexp(result,'InChI=[^\n]*\n','match');
    result = result';
    result = strtrim(result);

    [inchi,metList] = strtok(result);
    inchi = strtrim(inchi);
    metList = strtrim(metList);
else
    [success,result] = system([babelcmd ' ' sdfFileName ' -oinchi' options])
    fprintf('%s\n','If you get a ''not found'' message from the call to Babel, make sure that Matlab''s LD_LIBRARY_PATH is edited to include correct system libraries. See initVonBertylanffy')
    error('Conversion to InChI not successful. Make sure OpenBabel is installed correctly.\n')
end

if size(inchi,2) > size(inchi,1)
    inchi = inchi';
end
if size(metList,2) > size(metList,1)
    metList = metList';
end


classdef winstonsource < spatiotemporal_database
   %UNTITLED2 Summary of this class goes here
   %   Detailed explanation goes here

   properties
   end

   methods
      function data = retrieve(where_, from_ , until_)
         error('unimplemented base class');
      end

   end

end


%InterfaceUtil
% Checks if a class (or class instance) properly implements a specificed
% interface.
%
% Author: Jonathan Karr, jkarr@stanford.edu
% Affiliation: Covert Lab, Department of Bioengineering, Stanford University
% Last Updated: 9/12/2010
classdef InterfaceUtil
    methods (Static = true)
        %Throws an exception is the class/class instance doesn't properly
        %implement the specified interface.
        %
        %Inputs:
        %- instanceOrClassName is an instance of a class, or a char equal to the
        %  name of a class
        %- metaclass is a struct of duck type meta.class with properties
        %  - Properties: cell array of objects of duck type meta.property. Each
        %    element of Properties must have the field Name,
        %    corresponding to the name of the property whose attributes should
        %    be validated. The other field names of Properties must equal
        %    names of property attributes, and the field values represent
        %    acceptable values of the corresponding property attribute. A
        %    Properties field value of null means that any value of the
        %    property attribute is acceptable.
        %  - Methods: cell array of objects of duck type meta.method. Each
        %    element of Methods must have the field Name, corresponding
        %    to the name of the method whose attributes should be validated. The
        %    other field names of Methods must equal names of method
        %    attributes, and the field values represent acceptable values of the
        %    corresponding method attribute. A Methods field value of
        %    null means that any value of the method attribute is acceptable.
        function assertInterface(instanceOrClassName, instanceOrMetaclass)
            import edu.stanford.covert.util.InterfaceUtil;

            if isa(instanceOrMetaclass, 'meta.class') || isstruct(instanceOrMetaclass)
                metadata = instanceOrMetaclass;
            elseif ischar(instanceOrMetaclass)
                metadata = meta.class.fromName(instanceOrMetaclass);
            else
                metadata = metaclass(instanceOrMetaclass);
            end

            InterfaceUtil.assertPropertyInterface(instanceOrClassName, metadata.Properties);
            InterfaceUtil.assertMethodInterface(instanceOrClassName, metadata.Methods);
        end
    end

    methods (Static = true, Access = protected)
        function assertPropertyInterface(instanceOrClassName, interface)
            import edu.stanford.covert.util.InterfaceUtil;

            if isempty(interface)
                return;
            end

            %validate input
            if ~isvector(interface) || ~iscell(interface) || ~all(cellfun(@InterfaceUtil.hasDuckTypeMetaProperty, interface))
                throw(MException('Interface:invalidInput', 'interface must be a cell array of objects of duck type meta.property'))
            end

            %get metadata
            if ischar(instanceOrClassName)
                metadata = meta.class.fromName(instanceOrClassName);
            else
                metadata = metaclass(instanceOrClassName);
            end

            %check property interface
            propertyNames = cellfun(@(property) property.Name, metadata.Properties, 'UniformOutput', false);
            for i = 1:numel(interface)
                iProperty = find(strcmp(propertyNames, interface{i}.Name), 1, 'first');
                interfaceFieldNames = setdiff(fieldnames(interface{i}), {'Name', 'Description', 'DetailedDescription', 'DefiningClass'});

                if isempty(iProperty)
                    throw(MException('Interface:incompleteInterface', ...
                        'The class %s must implement a %s property', ...
                        metadata.Name, interface{i}.Name));
                end

                property = metadata.Properties{iProperty};
                for j = 1:numel(interfaceFieldNames)
                    if isempty(interface{i}.(interfaceFieldNames{j}))
                        continue;
                    end

                    interfaceValue = interface{i}.(interfaceFieldNames{j});
                    interfaceValueStr = interface{i}.(interfaceFieldNames{j});
                    if ischar(interfaceValue)
                        interfaceValueStr = {interfaceValue};
                        interfaceValue = {interfaceValue};
                    elseif ~iscell(interfaceValue)
                        interfaceValueStr = cellfun(@num2str, num2cell(interfaceValue), 'UniformOutput', false);
                    end

                    propertyValue = property.(interfaceFieldNames{j});
                    if ischar(propertyValue)
                        %GetAccess, SetAccess
                        propertyValue = {propertyValue};
                    elseif isa(propertyValue, 'function_handle')
                        %GetMethod, SetMethod
                        propertyValue = ~isempty(propertyValue);
                    end

                    if ~ismember(propertyValue, interfaceValue)
                        throw(MException('Interface:incompatibleInterface', ...
                            'The class %s %s property must have attribute %s with value {%s}', ...
                            metadata.Name, interface{i}.Name, interfaceFieldNames{j}, ['''' strjoin(''', ''',interfaceValueStr{:}) '''']));
                    end
                end
            end
        end

        function assertMethodInterface(instanceOrClassName, interface)
            import edu.stanford.covert.util.InterfaceUtil;

            if isempty(interface)
                return;
            end

            %validate input
            if ~isvector(interface) || ~iscell(interface) || ~all(cellfun(@InterfaceUtil.hasDuckTypeMetaMethod, interface))
                throw(MException('Interface:invalidInput', 'interface must be a cell array of objects of duck type meta.method'))
            end

            %get metadata
            if ischar(instanceOrClassName)
                metadata = meta.class.fromName(instanceOrClassName);
            else
                metadata = metaclass(instanceOrClassName);
            end

            %check method interface
            methodNames = cellfun(@(method) method.Name, metadata.Methods, 'UniformOutput', false);
            for i = 1:numel(interface)
                iMethod = find(strcmp(methodNames, interface{i}.Name), 1, 'first');
                interfaceFieldNames = setdiff(fieldnames(interface{i}), {'Name', 'Description', 'DetailedDescription', 'DefiningClass'});

                if isempty(iMethod)
                    throw(MException('Interface:incompleteInterface', ...
                        'The class %s must implement a %s method', ...
                        metadata.Name, interface{i}.Name));
                end

                method = metadata.Methods{iMethod};
                for j = 1:numel(interfaceFieldNames)
                    if isempty(interface{i}.(interfaceFieldNames{j}))
                        continue;
                    end

                    interfaceValue = interface{i}.(interfaceFieldNames{j});
                    interfaceValueStr = interface{i}.(interfaceFieldNames{j});
                    if ischar(interfaceValue)
                        interfaceValueStr = {interfaceValue};
                        interfaceValue = {interfaceValue};
                    elseif ~iscell(interfaceValue)
                        interfaceValueStr = cellfun(@num2str, num2cell(interfaceValue), 'UniformOutput', false);
                    end

                    methodValue = method.(interfaceFieldNames{j});
                    if ischar(methodValue)
                        %Access
                        methodValue = {methodValue};

                        if ~ismember(methodValue, interfaceValue)
                            throw(MException('Interface:incompatibleInterface', ...
                                'The class %s %s method must have attribute %s with value {%s}', ...
                                metadata.Name, interface{i}.Name, interfaceFieldNames{j}, ['''' strjoin(''', ''',interfaceValueStr{:}) '''']));
                        end
                    elseif iscell(methodValue)
                        %InputNames, OutputNames
                        methodValue = numel(methodValue);
                        if iscell(interfaceValue)
                            interfaceValue = numel(interfaceValue);
                        elseif numel(interfaceValue)~=1
                            throw(MException('Interface:invalidInput', 'interface must specify number or names of %s',interfaceFieldNames{j}));
                        end

                        if methodValue < interfaceValue
                            throw(MException('Interface:incompatibleInterface', ...
                                'The class %s %s method must have at at least %d %s', ...
                                metadata.Name, interface{i}.Name, interfaceValue, interfaceFieldNames{j}));
                        end
                    else
                        if ~ismember(methodValue, interfaceValue)
                            throw(MException('Interface:incompatibleInterface', ...
                                'The class %s %s method must have attribute %s with value {%s}', ...
                                metadata.Name, interface{i}.Name, interfaceFieldNames{j}, ['''' strjoin(''', ''',interfaceValueStr{:}) '''']));
                        end
                    end
                end
            end
        end

        function tf = hasDuckTypeMetaProperty(prop)
            tf = false;

            if isa(prop, 'meta.property')
                tf = true;
                return;
            end

            metaPropertyFieldNames = {'Name'; 'Description'; 'DetailedDescription';
                'GetAccess'; 'SetAccess'; 'Dependent'; 'Constant'; 'Abstract'; 'Transient';
                'Hidden'; 'GetObservable'; 'SetObservable'; 'AbortSet'; 'GetMethod';
                'SetMethod'; 'HasDefault'; 'DefaultValue'; 'DefiningClass'};

            if isstruct(prop) && ismember('Name',fieldnames(prop)) && all(ismember(fieldnames(prop), metaPropertyFieldNames))
                tf = true;
                return
            end
        end

        function tf = hasDuckTypeMetaMethod(method)
            tf = false;

            if isa(method, 'meta.method')
                tf = true;
                return;
            end

            metaMethodFieldNames = {'Name'; 'Description'; 'DetailedDescription';
                'Access'; 'Static'; 'Abstract'; 'Sealed'; 'Hidden'; 'InputNames';
                'OutputNames'; 'DefiningClass'};

            if isstruct(method) && ismember('Name',fieldnames(method)) && all(ismember(fieldnames(method), metaMethodFieldNames))
                tf = true;
                return
            end
        end
    end
end


function curSliceOri = getCurSliceOri(view)
%
% curSliceOri = getCurSliceOri(view)
%
% Gets current slice orientation from the sliceOriButtons handles
try,
  curSliceOri = findSelectedButton(view.ui.sliceButtons);
catch,
  curSliceOri = findSelectedButton(view.ui.sliceOriButtons);
end


function payload = aip_detector_concatenate(plA, plB)

    if( ~isempty(plA) )
        if isfield(plA,'result')
            plA = plA.result;
        end
    end

    if( ~isempty(plB) )
        if isfield(plB,'result')
            plB = plB.result;
        end
    end

    payload = ConcatenateQRSdetectionPayloads([], plA, plB);


function HeadModel = in_headmodel_bst(HeadModelFile, ApplyOrient, varargin)
% IN_HEADMODEL_BST: Wrapper for in_bst_headmodel (added for backward compatibility)

% @=============================================================================
% 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, 2016

% Display warning
warning('Use in_bst_headmodel instead.');
% Just call in_bst_headmodel()
if (nargin > 2)
    HeadModel = in_bst_headmodel(HeadModelFile, ApplyOrient, varargin{:});
elseif (nargin == 2)
    HeadModel = in_bst_headmodel(HeadModelFile, ApplyOrient);
elseif (nargin == 1)
    HeadModel = in_bst_headmodel(HeadModelFile);
end


function filum_test06 ( )

%*****************************************************************************80
%
%% FILUM_TEST06 tests FILE_EXIST.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    06 June 2007
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'TEST06\n' );
  fprintf ( 1, '  FILE_EXIST is true if a file exists.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Exist?    FILENAME\n' );
  fprintf ( 1, '\n' );

  filename = 'filum_test.m';
  fprintf ( 1, '  %d  %s\n', file_exist ( filename ), filename );

  filename = 'filum.html';
  fprintf ( 1, '  %d  %s\n', file_exist ( filename ), filename );

  filename = 'rabbit.txt';
  fprintf ( 1, '  %d  %s\n', file_exist ( filename ), filename );

  filename = 'make.money.fast';
  fprintf ( 1, '  %d  %s\n', file_exist ( filename ), filename );

  return
end


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

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

% Last Modified by GUIDE v2.5 28-Nov-2012 12:06:59

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

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

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

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

% Update handles structure
guidata(hObject, handles);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
a=(get(handles.popupmenu1,'value'));
real=str2num(get(handles.edit1,'string'));
img=str2num(get(handles.edit2,'string'));
Z0= real+img*i;
real1=str2num(get(handles.edit3,'string'));
img1=str2num(get(handles.edit4,'string'));
Z1=real1+img1*i;
real2=str2num(get(handles.edit5,'string'));
img2=str2num(get(handles.edit6,'string'));
Z2=real2+img2*i;
line_voltage=str2num(get(handles.edit9,'string'));
phase_voltage=line_voltage/(sqrt(3));
kva=str2num(get(handles.edit8,'string'));
% for popup menu commond
a=(get(handles.popupmenu1,'value'));switch a
    case 1
       %LINE TO GROUND FAULT
Io=(phase_voltage)/(Z0+Z1+Z2);
fault_current=(3*(phase_voltage)/(Z0+Z1+Z2));
set(handles.edit10,'string',imag(fault_current));
    case 2
   %LINE TO LINE FAULT
fault_current2=(-i*sqrt(3)*phase_voltage)/(Z1+Z1);
set(handles.edit10,'string',(fault_current2));
end

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

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

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

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

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

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

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

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

% --- Executes on selection change in popupmenu1.
function popupmenu1_Callback(hObject, eventdata, handles)
% hObject    handle to popupmenu1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns popupmenu1 contents as cell array
%        contents{get(hObject,'Value')} returns selected item from popupmenu1

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

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


% 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.


function out = saveobj(obj)
%SAVEOBJ (overloaded)
warning('YALMIP objects cannot be saved in binary format. You will run into troubles if you try to load this file later. You should clear all YALMIP objects first, or avoid having any YALMIP objects in the list of variables which you save.');
out = [];


function setpaths(addremove)

%
% USAGE:
%
%   % 1. Add all search paths for this repo
%   setpaths
%
%   % 2. Same as 1.. Add all search paths for this repo
%   setpaths(1)
%
%   % 3. Add all search paths for this repo while removing search
%   %    paths of all similar workspaces
%   setpaths(2)
%
%   % 4. Remove all search paths for this repo
%   setpaths(0)
%
currdir = pwd;
global logger

try

    warning('off','MATLAB:rmpath:DirNotFound');

    appname = 'Homer3';

    % Parse arguments
    if ~exist('addremove','var')
    addremove = 1;
    end

    % Add libraries on which Homer3 depends
    d = addDependenciesSearchPaths();

    % Start logger only after adding library paths. Logger is in the Utils libary.
    logger = Logger('setpaths');

    % Create list of possible known similar apps that may conflic with current
    % app
    appNameExclList = {'Homer3','DataTree','Homer2_UI','brainScape','ResolveCommonFunctions'};
    appNameInclList = {'AtlasViewerGUI'};
    exclSearchList  = {'.git','.idea','Data','Docs','*_install','*.app','submodules'};

    appThis         = filesepStandard_startup(pwd);
    appThisPaths    = findDotMFolders(appThis, exclSearchList);

    if addremove == 0
        if ~isempty(which('deleteNamespace.m'))
            deleteNamespace(appname);
        end
        removeSearchPaths(appThis);
        return;
    elseif addremove == 2
        appNameExclList = [appNameExclList, appNameInclList];
        appNameInclList = {};
    end

    appExclList = {};
    appInclList = {};

    % Find all root folders of apps to exclude from search paths
    for ii = 1:length(appNameExclList)
        foo = which([appNameExclList{ii}, '.m'],'-all');

        % Before giving up and concluding the path does not exist in list of matlab
        % search paths, try appending the word 'Class' to path name.
        if isempty(foo)
            foo = which([appNameExclList{ii}, 'Class.m'],'-all');
        end

        for jj = 1:length(foo)
            p = filesepStandard_startup(fileparts(foo{jj}));
            if pathscompare_startup(appThis, p)
                continue
            end
            printMethod(sprintf('Exclude paths for %s\n', p));
            appExclList = [appExclList; p]; %#ok<AGROW>
        end
    end

    % Find all root folders of apps to include in search paths
    for ii = 1:length(appNameInclList)
        foo = which([appNameInclList{ii}, '.m'],'-all');
        for jj = 1:length(foo)
            if jj > 1
                p = filesepStandard_startup(fileparts(foo{jj}));
                appExclList = [appExclList; p]; %#ok<AGROW>
                printMethod(sprintf('Exclude paths for %s\n', p));
            else
                p = filesepStandard_startup(fileparts(foo{jj}));
                appInclList = [appInclList; p]; %#ok<AGROW>
                printMethod(sprintf('Include paths for %s\n', p));
            end
        end
    end

    % Remove all search paths for all other apps except for current one, to
    % make sure that we use only search from the current app for download shared
    % libraries (i.e, submodules).
    for ii = 1:length(appExclList)
        removeSearchPaths(appExclList{ii})
    end
    for ii = 1:length(appInclList)
        removeSearchPaths(appInclList{ii})
    end

    addSearchPaths(appThisPaths);

    if ~isempty(which('setNamespace.m'))
        setNamespace(appname);
    end

    % Add back all search paths for all other apps except for current app
    for ii = 1:length(appInclList)
        % This app's path has already been added
        if pathscompare_startup(appInclList{ii}, appThis)
            continue;
        end
        foo = findDotMFolders(appInclList{ii}, exclSearchList);
        addSearchPaths(foo);
    end

    if  ~isempty(which('setpaths_proprietary.m'))
        setpaths_proprietary(addremove);
    end

    warning('on','MATLAB:rmpath:DirNotFound');

    PrintSystemInfo(logger, ['Homer3'; d]);
    logger.CurrTime('Setpaths completed on ');
    logger.Close();
    cd(currdir);

catch ME

    printStack(ME)
    if exist('logger','var')
        logger.Close();
    end
    cd(currdir);
    rethrow(ME)

end

% ---------------------------------------------------
function d = dependencies()
d = {};
submodules = parseGitSubmodulesFile(pwd);
temp = submodules(:,1);
for ii = 1:length(temp)
    [~, d{ii,1}] = fileparts(temp{ii});
end

% ---------------------------------------------------
function setpermissions(appPath)
if isunix() || ismac()
    global logger
    if ~isempty(strfind(appPath, '/bin')) %#ok<*STREMP>
        cmd = sprintf('chmod 755 %s/*\n', appPath);
        logger.Write(cmd);
        files = dir([appPath, '/*']);
        if ~isempty(files)
            system(cmd);
        end
    end
end

% ----------------------------------------------------
function addSearchPaths(appPaths)
if ischar(appPaths)
    p = genpath(appPaths);
    if ispc
        delimiter = ';';
    else
        delimiter = ':';
    end
    appPaths = str2cell(p, delimiter);
end
for kk = 1:length(appPaths)
    if strfind(appPaths{kk}, '.git')
        continue;
    end
    addpath(appPaths{kk}, '-end');
    setpermissions(appPaths{kk});
end
printMethod(sprintf('ADDED search paths for app %s\n', appPaths{1}));

% ----------------------------------------------------
function removeSearchPaths(app)
p = path;
if ispc()
    delimiter = ';';
elseif ismac() || isunix()
    delimiter = ':';
end
[~,appname] = fileparts(fileparts(app));
r = version('-release');
msg = sprintf('Removing search paths for %s ...', appname);
h = waitbar(0, msg);
p = str2cell_startup(p, delimiter);
for kk = 1:length(p)
    if mod(kk,100)==0
        waitbar(kk/length(p), h);
    end
    if ~isempty(strfind(lower(p{kk}), 'matlab')) && ~isempty(strfind(p{kk}, r))
        continue;
    end
    if ~isempty(strfind(filesepStandard_startup(p{kk}), app))
        rmpath(p{kk});
    end
end
close(h);
printMethod(sprintf('REMOVED search paths for app %s\n', app));

% ----------------------------------------------------
function   d = addDependenciesSearchPaths()
if exist([pwd, '/Utils/submodules'],'dir')
    addpath([pwd, '/Utils/submodules'],'-end');
end
d = dependencies();
for ii = 1:length(d)
    rootpath = findFolder(pwd, d{ii});
    rootpath(rootpath=='\') = '/';
    if ispathvalid_startup([rootpath, '/Shared'],'dir')
        rootpath = [rootpath, '/Shared'];
    end
    if ~exist(rootpath,'dir')
        printMethod(sprintf('ERROR: Could not find required dependency %s\n', d{ii}));
        continue;
    end
    addSearchPaths(rootpath);
end
if exist([pwd, '/Utils/submodules'],'dir')
    addpath([pwd, '/Utils/submodules'],'-end');
end

% -----------------------------------------------------------------------------
function [C,k] = str2cell(str, delimiters, options)

% Option tells weather to keep leading whitespaces.
% (Trailing whitespaces are always removed)
if ~exist('options','var')
    options = '';
end

if ~strcmpi(options, 'keepblanks')
    str = strtrim(str);
end
str = deblank(str);

if ~exist('delimiters','var') || isempty(delimiters)
    delimiters{1} = sprintf('\n');
elseif ~iscell(delimiters)
    foo{1} = delimiters;
    delimiters = foo;
end

% Get indices of all the delimiters
k=[];
for kk=1:length(delimiters)
    k = [k, find(str==delimiters{kk})];
end
j = find(~ismember(1:length(str),k));

% The following line seems to hurt performance a little bit. It was
% meant to preallocate to speed things up but it does not seem to do that.
% C = repmat({blanks(max(diff([k,length(str)])))}, length(k)+1, 1);
C = {};
ii=1; kk=1;
while ii<=length(j)
    C{kk} = str(j(ii));
    ii=ii+1;
    jj=2;
    while (ii<=length(j)) && ((j(ii)-j(ii-1))==1)
        C{kk}(jj) = str(j(ii));
        jj=jj+1;
        ii=ii+1;
    end
    C{kk}(jj:end)='';
    kk=kk+1;
end
C(kk:end) = [];

% -------------------------------------------------------------------------
function printMethod(msg)
global logger
if isa(logger', 'Logger')
    try
        logger.Write(msg);
    catch
        fprintf(msg);
    end
else
    fprintf(msg);
end

% -------------------------------------------------------------------------
function submodules = parseGitSubmodulesFile(repo)
submodules = cell(0,3);

if ~exist('repo','var') || isempty(repo)
    repo = pwd;
end
currdir = pwd;
if repo(end) ~= '/' && repo(end) ~= '\'
    repo = [repo, '/'];
end

filename = [repo, '.gitmodules'];
if ~exist(filename, 'file')
    return;
end
cd(repo);

fid = fopen(filename, 'rt');
strs = textscan(fid, '%s');
strs = strs{1};
kk = 1;
for ii = 1:length(strs)
    if strcmp(strs{ii}, '[submodule')
        jj = 1;
        while ~strcmp(strs{ii+jj}, '[submodule')
            if ii+jj+2>length(strs)
                break;
            end
            if strcmp(strs{ii+jj}, 'path')
                submodules{kk,2} = [pwd, '/', strs{ii+jj+2}];
            end
            if strcmp(strs{ii+jj}, 'path')
                submodules{kk,3} = strs{ii+jj+2};
            end
            if strcmp(strs{ii+jj}, 'url')
                submodules{kk,1} = strs{ii+jj+2};
            end
            jj = jj+1;
        end
        kk = kk+1;
    end
end
fclose(fid);
cd(currdir);