text:
function [settings, selection] = pre_processing(varargin)
%PRE_PROCESSING Summary of this function goes here
%   Accepts up to 1 argument
%   @param <int> preselected cached path (-1 if no preselection)

%% ADD ALL NECESSARY PATHS (REQUIRED)
addpath(genpath('./modules'))
addpath(genpath('./data'))
addpath(genpath('./export'))
addpath(genpath('./cache'))
addpath(genpath('./utils'))

%% LOAD SETTINGS IF PRESELECTED
if nargin == 1 && varargin{1} > 0
    load(['cache/cached_paths_' num2str(varargin{1}) '/last_parameters.mat'], ...
        'settings', 'CACHED_PATH_SELECTION')
    fprintf('Selected path to flakes: %s\n\n', settings.pathToFlakes);
    selection.id = num2str(varargin{1});
    selection.path = settings.pathToFlakes;
    return;
end

%% INIT SHARED VARS
CACHED_PATHS_TXT = 'cache/cached_paths.txt';
pathToFlakes = '';
datestart = '';
dateend = '';
isCamColor = zeros(1,3);
outputProcessedImgs = 0;
camFOV = nan(1,3);
backgroundThresh = 0;
   topDiscard = 0; applyTopDiscardToCams = [];
bottomDiscard = 0; applyBotDiscardToCams = [];
  leftDiscard = 0; applyLeftDiscardToCams = [];
 rightDiscard = 0; applyRightDiscardToCams = [];
lineFill = 0;
minFlakePerim = 0;
minCropWidth = 0;
maxEdgeTouch = 0;
avgFlakeBrightness = 0;
filterFocus = 0;
focusThreshold = 0;
internalVariability = 0;
flakeBrighten = 0;
siteName = '';
cameraName = '';
rescanOriginal = 0;
skipProcessed = 0;

filesInPath = [];
changedPathToFlakes = 0;

%% MAIN

% Prompt user to select a cached_path if a cached_paths.txt file has been made
if exist(CACHED_PATHS_TXT,'file')
    [settings, selection, define] = load_settings();
    if ~define
        fprintf('Found previous set of processing parameters!\n');
        s = input('Would you like to change some parameters before continuing (Y/n): ', 's');
        while isempty(s) || length(s) > 1 || (s ~= 'Y' && s ~= 'n')
            s = input('Please type ''Y'' or ''n'': ', 's');
        end
        fprintf('\n');

        if s == 'n'
            return;
        else
            settingsToVariables;
            redefine = 1; %#ok<*NASGU>
        end
    else
        pathToFlakes = selection.path;
    end
else
    define = 1;
    selection.id = 1; % User is running for the first time, so will be the first cached_path
end
clear s

% Check if user chose to redefine existing parameters, or
% has to define new ones because there are no existing parameters
if exist('redefine','var') && redefine
    fprintf(['You chose to redefine some of the parameters from the existing\n' ...
        'set that was loaded. You will be prompted to change each of the\n' ...
        'parameters. To keep the current value when prompted, just hit [Enter].\n'])
    disp('%%% RE-DEFINE PARAMETERS %%%')
    define_params()
    disp('%%% END RE-DEFINE PARAMETERS %%%')
    clear redefine

elseif exist('define','var') && define
    disp('%%% DEFINE PARAMETERS %%%')
    define_params()
    disp('%%% END DEFINE PARAMETERS %%%')
    clear define

end
fprintf('\n')

% Show full list of parameters and ask if user is okay with these values and is ready
% to proceed
s = 'n';
while s == 'n'
    disp('%%%%%%%%%%%%%%%%%%%%%%% LIST OF PARAMETERS %%%%%%%%%%%%%%%%%%%%%%%%')
    fprintf('       pathToFlakes: %s\n', pathToFlakes)
    fprintf('          datestart: %s\n', datestr(datestart))
    fprintf('            dateend: %s\n', datestr(dateend))
    fprintf('         isCamColor: [%i, %i, %i]\n', isCamColor(1), isCamColor(2), isCamColor(3))
    fprintf('outputProcessedImgs: %s\n', outputProcessedImgs)
    fprintf('             camFOV: [%.2f, %.2f, %.2f]\n', camFOV(1), camFOV(2), camFOV(3))
    fprintf('   backgroundThresh: %.0f\n', backgroundThresh)
    fprintf('         topDiscard: %i\n', topDiscard)
    fprintf(['applyTopDiscardToCams: [' num2str(applyTopDiscardToCams) ']\n'])
    fprintf('      bottomDiscard: %i\n', bottomDiscard)
    fprintf(['applyBotDiscardToCams: [' num2str(applyBotDiscardToCams) ']\n'])
    fprintf('        leftDiscard: %i\n', leftDiscard)
    fprintf(['applyLeftDiscardToCams: [' num2str(applyLeftDiscardToCams) ']\n'])
    fprintf('       rightDiscard: %i\n', rightDiscard)
    fprintf(['applyRightDiscardToCams: [' num2str(applyRightDiscardToCams) ']\n'])
    fprintf('           lineFill: %i\n', lineFill)
    fprintf('      minFlakePerim: %.1f\n', minFlakePerim)
    fprintf('       minCropWidth: %.1f\n', minCropWidth)
    fprintf('       maxEdgeTouch: %.0f\n', maxEdgeTouch)
    fprintf(' avgFlakeBrightness: %.1f\n', avgFlakeBrightness)
    fprintf('        filterFocus: %i\n', filterFocus)
    fprintf('     focusThreshold: %.1f\n', focusThreshold)
    fprintf('internalVariability: %.1f\n', internalVariability)
    fprintf('      flakeBrighten: %s\n', flakeBrighten)
    fprintf('           siteName: %s\n', siteName)
    fprintf('         cameraName: %s\n', cameraName)
    fprintf('     rescanOriginal: %i\n', rescanOriginal)
    fprintf('      skipProcessed: %i\n', skipProcessed)
    fprintf(['%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%' ...
             '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n'])
    s = input('Would you like to save these parameters and continue [Y], or go back and change some [n]? (Y/n): ', 's');
    while isempty(s) || (length(s) > 1 || (s ~= 'Y' && s ~= 'n'))
        disp('Please type ''Y'' or ''n''.')
        s = input('Save parameters and continue [Y], or go back and change some [n]? (Y/n): ', 's');
    end
    if s == 'n'
        disp('%%% RE-DEFINE PARAMETERS %%%')
        define_params()
        disp('%%% END RE-DEFINE PARAMETERS %%%')
    end
end
clear s

% At this point, user has finalized the general processing parameters
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% MASC-SPECIFIC FORMATTING
% The most effective way of getting the image's timestamp, flake ID, and/or
% camera ID from the image filename is using a regular expression.

% This is the current format of images from the MASC:
%   yyyy.mm.dd_HH.MM.SS[.FFF]_flake_(image id)[.(particle id)]_cam_(cam id).png
%       -> where the text in brackets indicates something that may or may
%           not be in the filename, and
%       -> where the text in parentheses indicates a reference to a value
%           will be there

% According to this format, below is the pattern that will pull out the
% string between [prefix_] and [_suffix].
mascImgRegPattern = [ ...
    '\d{4}\.{1}\d{2}\.{1}\d{2}' ...                 % yyyy.mm.dd
    '\_{1}' ...                                     % underscore
    '\d{2}\.{1}\d{2}\.{1}\d{2}(\.{1}\d{1,6})?' ...  % HH.MM.SS[.FFF]
    '\_flake_{1}\d+(\.{1}\d+)?' ...                 % flake_(image id)[.(particle id)]
    '\_cam_{1}[0-2]' ...                            % cam_(cam id)
    '\.[pngjpeg]{3,4}';                             % .png, .jpg, or .jpeg
];

% This can be changed should the format of image filenames from the MASC
% ever change.

%% SAVE FILES IN PATH (IF APPLICABLE)
% Now, we'll check if filesInPath returned from define_params is not empty.
% If it isn't, then we need to add the pathToFlakes to the cached_paths,
% along with the list of files given by filesInPath
if ~isempty(filesInPath)
    fprintf('Caching PNG files for the specified pathToFlakes...');
    % Get number of paths already cached
    if exist(CACHED_PATHS_TXT, 'file')
        numPaths = length(strfind(fileread(CACHED_PATHS_TXT), 'Path = "')) + 1;
    else
        numPaths = 1; % Actually 0, but we set to 1 so the index starts at 1
    end

    % Add new path to cached_paths
    fwid = fopen(CACHED_PATHS_TXT,'a');
    fprintf(fwid, 'Path = "%s"\n', pathToFlakes);
    % Set which txt file the path will point to
    fprintf(fwid, 'Cache Dir = "%s"\n\n', ['cache/cached_paths_' num2str(numPaths)]);
    fclose(fwid);

    % Create directory if necessary
    if ~exist(['cache/cached_paths_' num2str(numPaths)], 'dir')
        mkdir(['cache/cached_paths_' num2str(numPaths)])
    end

    % Open a new cache file
    numCacheFiles = 1;
    fwid = fopen(['cache/cached_paths_' num2str(numPaths) '/f1.txt'], 'w');
    for i = 1:length(filesInPath)
        if ~mod(i,500)
            % Start a new cache file every 500 PNGs...
            % Assuming O(100) cropped flakes for each PNG, that would
            % result in O(50,000) records in each txt file.
            fclose(fwid);
            numCacheFiles = numCacheFiles + 1;
            fwid = fopen(['cache/cached_paths_' num2str(numPaths) '/f' num2str(numCacheFiles) '.txt'], 'w');
        end
        fprintf(fwid, '%s\t1\t0\t0\t0\t0\n', filesInPath(i).name);
    end
    fclose(fwid);
    fprintf('done.\n');

    if exist('changedPathToFlakes', 'var') && changedPathToFlakes
        selection.id = numPaths;
    end

end
fclose('all');

% Put all parameters into a struct
settings = paramsAsStruct;

% Save current parameters to file for most recent parameters used
disp('Caching these parameters...')
cacheSettings;

    function cacheSettings
        CACHED_PATH_SELECTION = selection.id;
        clearvars -except settings CACHED_PATH_SELECTION
        save(['cache/cached_paths_' num2str(CACHED_PATH_SELECTION) '/last_parameters.mat'])
        selection.id = CACHED_PATH_SELECTION;
        selection.path = settings.pathToFlakes;
    end

    function [settings] = paramsAsStruct
        % Save all parameters to a settings struct for convenient access and
        % passing of the parameters around to other functions.
        settings.pathToFlakes = pathToFlakes;
        settings.datestart = datestart;
        settings.dateend = dateend;
        settings.mascImgRegPattern = mascImgRegPattern;
        settings.isCamColor = isCamColor;
        settings.outputProcessedImgs = outputProcessedImgs;
        settings.camFOV = camFOV;
        settings.backgroundThresh = backgroundThresh;
        settings.topDiscard = topDiscard;
        settings.applyTopDiscardToCams = applyTopDiscardToCams;
        settings.bottomDiscard = bottomDiscard;
        settings.applyBotDiscardToCams = applyBotDiscardToCams;
        settings.leftDiscard = leftDiscard;
        settings.applyLeftDiscardToCams = applyLeftDiscardToCams;
        settings.rightDiscard = rightDiscard;
        settings.applyRightDiscardToCams = applyRightDiscardToCams;
        settings.lineFill = lineFill;
        settings.minFlakePerim = minFlakePerim;
        settings.minCropWidth = minCropWidth;
        settings.maxEdgeTouch = maxEdgeTouch;
        settings.avgFlakeBrightness = avgFlakeBrightness;
        settings.filterFocus = filterFocus;
        settings.focusThreshold = focusThreshold;
        settings.internalVariability = internalVariability;
        settings.flakeBrighten = flakeBrighten;
        settings.siteName = siteName;
        settings.cameraName = cameraName;
        settings.rescanOriginal = rescanOriginal;
        settings.skipProcessed = skipProcessed;
    end

    % When last parameters are loaded at the beginning of this function,
    % need to break them out of settings struct so we can ask user if they
    % want to keep the old value or set a new one.
    function settingsToVariables
        if isfield(settings, 'pathToFlakes')
            pathToFlakes = settings.pathToFlakes;
        end
        if isfield(settings, 'datestart')
            datestart = settings.datestart;
        end
        if isfield(settings, 'dateend')
            dateend = settings.dateend;
        end
        if isfield(settings, 'mascImgRegPattern')
            mascImgRegPattern = settings.mascImgRegPattern;
        end
        if isfield(settings, 'isCamColor')
            isCamColor = settings.isCamColor;
        end
        if isfield(settings, 'outputProcessedImgs')
            outputProcessedImgs = settings.outputProcessedImgs;
        end
        if isfield(settings, 'camFOV')
            camFOV = settings.camFOV;
        end
        if isfield(settings, 'backgroundThresh')
            backgroundThresh = settings.backgroundThresh;
        end
        if isfield(settings, 'topDiscard')
            topDiscard = settings.topDiscard;
        end
        if isfield(settings, 'applyTopDiscardToCams')
            applyTopDiscardToCams = settings.applyTopDiscardToCams;
        end
        if isfield(settings, 'bottomDiscard')
            bottomDiscard = settings.bottomDiscard;
        end
        if isfield(settings, 'applyBotDiscardToCams')
            applyBotDiscardToCams = settings.applyBotDiscardToCams;
        end
        if isfield(settings, 'leftDiscard')
            leftDiscard = settings.leftDiscard;
        end
        if isfield(settings, 'applyLeftDiscardToCams')
            applyLeftDiscardToCams = settings.applyLeftDiscardToCams;
        end
        if isfield(settings, 'rightDiscard')
            rightDiscard = settings.rightDiscard;
        end
        if isfield(settings, 'applyRightDiscardToCams')
            applyRightDiscardToCams = settings.applyRightDiscardToCams;
        end
        if isfield(settings, 'lineFill')
            lineFill = settings.lineFill;
        end
        if isfield(settings, 'minFlakePerim')
            minFlakePerim = settings.minFlakePerim;
        end
        if isfield(settings, 'minCropWidth')
            minCropWidth = settings.minCropWidth;
        end
        if isfield(settings, 'maxEdgeTouch')
            maxEdgeTouch = settings.maxEdgeTouch;
        end
        if isfield(settings, 'avgFlakeBrightness')
            avgFlakeBrightness = settings.avgFlakeBrightness;
        end
        if isfield(settings, 'filterFocus')
            filterFocus = settings.filterFocus;
        end
        if isfield(settings, 'focusThreshold')
            focusThreshold = settings.focusThreshold;
        end
        if isfield(settings, 'internalVariability')
            internalVariability = settings.internalVariability;
        end
        if isfield(settings, 'flakeBrighten')
            flakeBrighten = settings.flakeBrighten;
        end
        if isfield(settings, 'siteName')
            siteName = settings.siteName;
        end
        if isfield(settings, 'cameraName')
            cameraName = settings.cameraName;
        end
        if isfield(settings, 'rescanOriginal')
            rescanOriginal = settings.rescanOriginal;
        end
        if isfield(settings, 'skipProcessed')
            skipProcessed = settings.skipProcessed;
        end
    end

function define_params
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% REQUIRED PARAMS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    disp('%% REQUIRED PARAMS %%')

    %% Var pathToFlakes
    % Prompts user to set pathToFlakes or keep it the same as before. If it
    % is set or changed, will check to see if new path is in
    % cached_paths.txt file. If not, then searches for PNG files in the new
    % path. If no PNGs are found, reprompts for a path with PNG files. If
    % PNGs are found, filesInPath are saved and returned for caching later.

    fprintf(['pathToFlakes: Where snowflake images are located. The images \n' ...
        '\tdo not need to be in any set directory hierarchy. All PNG images\n' ...
        '\tin the directory will be found. Path MUST be absolute.\n' ...
        '\tNote: When this is set, the path will be searched for PNG files. If none are found\n' ...
        '\toutside of the processed image directories (CROP_CAM, UNCROP_CAM, TRIPLETS, REJECTS),\n' ...
        '\tthen you will be asked to provide a different path.\n'])
    changingPathToFlakes = 0;
    if exist('pathToFlakes', 'var')
        s = input(sprintf('var pathToFlakes = %s;\nChange to: ', strrep(pathToFlakes,'\','\\')), 's');
        changingPathToFlakes = 1;
    else
        % Require user to set a path
        s = input('Set pathToFlakes to: ', 's');
    end

    while ~isempty(s) && ((s(1) ~= '/' && s(2) ~= ':') || (s(end) ~= '/' && s(end) ~= '\'))
        disp('Invalid path, you must specify an absolute path and include a trailing slash. Please try again.')
        s = input('Set pathToFlakes to: ', 's');
    end
    % Initialize filesInPath variable. If the user provides a path that
    % doesn't exist in cached_paths, we'll need to write out the img file
    % names to cached_paths. Instead of having to traverse to get these
    % files again (since we make sure that path user provides contains
    % PNGs), we'll hold onto this array of file structs.
    if ~isempty(s)
        % First, check if user provided path is already in cached_paths
        if exist(CACHED_PATHS_TXT, 'file')
            if strfind(fileread(CACHED_PATHS_TXT), ['"' s '"'])
                % Path has been used before, accept this input
                files = 1;
                disp('Path found in cache! Okay to use again. Continuing...')
            else
                files = 0;
            end
        else
            files = 0;
        end

        if ~files
            imgFilter = @(d) isempty(regexp(d.name,'UNCROP_CAM')) && isempty(regexp(d.name,'TRIPLETS')) && isempty(regexp(d.name,'REJECTS'));
            disp('Searching for PNGs...')
            files = rdir([s '**' filesep '*.png'], imgFilter, s);
        end
        while ~isempty(s) && isempty(files)
            % While user provides a path with NO PNG files, continue to prompt
            if exist('pathToFlakes', 'var')
                % NOTE: This still allows users to keep the existing pathToFlakes, if it is already set
                disp('Invalid path, the path you specified contained no PNG files. Please try again (or keep the existing pathToFlakes).')
                s = input(sprintf('var pathToFlakes = %s;\nChange to: ', strrep(pathToFlakes,'\','\\')), 's');
            else
                disp('Invalid path, the path you specified contained no PNG files. Please try again.')
                % Require user to set a path
                s = input('Set pathToFlakes to: ', 's');
            end

            while isempty(s) || ((s(1) ~= '/' && s(2) ~= ':') || (s(end) ~= '/' && s(end) ~= '\'))
                disp('Invalid path, you must specify an absolute path and include a trailing slash. Please try again.')
                s = input('Set pathToFlakes to: ', 's');
            end
            if ~isempty(s)
                if exist(CACHED_PATHS_TXT, 'file')
                    if ~strfind(fileread(CACHED_PATHS_TXT), ['"' s '"'])
                        % Path has been used before, accept this input
                        files = 1;
                        disp('Path found in cache! Okay to use again. Continuing...')
                    else
                        files = 0;
                    end
                else
                    files = 0;
                end

                if ~files
                    imgFilter = @(d) isempty(regexp(d.name,'CROP_CAM')) && isempty(regexp(d.name,'UNCROP_CAM')) && isempty(regexp(d.name,'TRIPLETS')) && isempty(regexp(d.name,'REJECTS')); %#ok<*RGXP1>
                    disp('Searching for PNGs...')
                    files = rdir([s '**' filesep '*.png'], imgFilter, s);
                end
            end
        end
        if ~isempty(s)
            if isstruct(files)
                disp('PNGs found!')
                filesInPath = files;
                % Signal to pre_processing that the user changed the cached path, indicating a new cached path should be made.
                if changingPathToFlakes
                    changedPathToFlakes = 1;
                end
            end
            pathToFlakes = s;
        else
            disp('Using old pathToFlakes with verified PNG files.')
        end
    else
        disp('Using old pathToFlakes with verified PNG files.')
    end
    pathToFlakes %#ok<NOPRT> % Show user the result of defining pathToFlakes

    %% Var datestart
    fprintf(['datestart: Start date of snowflakes to process. When setting this,\n' ...
        '\tinput the date as a string of the form "yyyymmdd_HHMM".\n'])
    if exist('datestart', 'var')
        s = input(sprintf('var datestart = %s; Change to: ', datestr(datestart, 'yyyymmdd_HHMM')), 's');
        while ~isempty(s) && ~validate_datestr(s, 0)
            disp('Must enter a valid string ("yyyymmdd_HHMM") for datestart.')
            s = input(sprintf('var datestart = %s; Change to: ', datestr(datestart, 'yyyymmdd_HHMM')), 's');
        end
    else
        % Require user to set datestart
        s = input('Set datestart to: ', 's');
        while isempty(s) || ~validate_datestr(s, 0)
            disp('Must enter a valid string ("yyyymmdd_HHMM") for datestart.')
            s = input('Set datestart to: ', 's');
        end
    end
    if ~isempty(s)
        datestart = datenum(s, 'yyyymmdd_HHMM');
    end
    datestr(datestart) % Show user the result of defining datestart

    %% Var dateend
    fprintf(['dateend: End date of snowflakes to process. When setting this,\n' ...
        '\tinput the date as a string of the form "yyyymmdd_HHMM".\n'])
    if exist('dateend', 'var')
        s = input(sprintf('var dateend = %s; Change to: ', datestr(dateend, 'yyyymmdd_HHMM')), 's');
        while ~isempty(s) && ~validate_datestr(s, datestart)
            disp('Must enter a valid string ("yyyymmdd_HHMM") for dateend that is after datestart.')
            s = input(sprintf('var dateend = %s; Change to: ', datestr(dateend, 'yyyymmdd_HHMM')), 's');
        end
    else
        % Require user to set dateend
        s = input('Set dateend to: ', 's');
        while isempty(s) || ~validate_datestr(s, datestart)
            disp('Must enter a valid string ("yyyymmdd_HHMM") for dateend that is after datestart.')
            s = input('Set dateend to: ', 's');
        end
    end
    if ~isempty(s)
        dateend = datenum(s, 'yyyymmdd_HHMM');
    end
    datestr(dateend) % Show user the result of defining dateend

    %% Var isCamColor
    fprintf(['isCamColor: Specifies whether each camera in the MASC takes its pictures\n' ...
        '\tin color. Binary 1x3 array, where the first element corresponds to color for camera 0, second\n' ...
        '\telement corresponds to color camera 1, and third element corresponds to color for camera 2.\n' ...
        '\tValue of 1 signifies camera DOES take pictures in color.\n'])
    if exist('isCamColor', 'var')
        % Camera 0
        s = input(sprintf('var isCamColor(1) = %i; Change to (0 or 1): ', isCamColor(1)), 's');
        while ~isempty(s) && (length(s) > 1 || (s ~= '0' && s ~= '1'))
            disp('If changing this value, you must specify 0 or 1')
            s = input(sprintf('var isCamColor(1) = %i; Change to (0 or 1): ', isCamColor(1)), 's');
        end
        if ~isempty(s)
            isCamColor(1) = str2num(s); %#ok<*ST2NM>
        end
        % Camera 1
        s = input(sprintf('var isCamColor(2) = %i; Change to (0 or 1): ', isCamColor(2)), 's');
        while ~isempty(s) && (length(s) > 1 || (s ~= '0' && s ~= '1'))
            disp('If changing this value, you must specify 0 or 1')
            s = input(sprintf('var isCamColor(2) = %i; Change to (0 or 1): ', isCamColor(2)), 's');
        end
        if ~isempty(s)
            isCamColor(2) = str2num(s);
        end
        % Camera 2
        s = input(sprintf('var isCamColor(3) = %i; Change to (0 or 1): ', isCamColor(3)), 's');
        while ~isempty(s) && (length(s) > 1 || (s ~= '0' && s ~= '1'))
            disp('If changing this value, you must specify 0 or 1')
            s = input(sprintf('var isCamColor(3) = %i; Change to (0 or 1): ', isCamColor(3)), 's');
        end
        if ~isempty(s)
            isCamColor(3) = str2num(s);
        end
    else
        % User must specify color (y/n = 1/0) for each camera
        % Camera 0
        s = input('Is camera 0 a color camera (0 = No, 1 = Yes): ', 's');
        while isempty(s) || (length(s) > 1 || (s ~= '0' && s ~= '1'))
            disp('Invalid input, must specify 0 or 1.')
            s = input('Is camera 0 a color camera (0 = No, 1 = Yes): ', 's');
        end
        isCamColor(1) = str2num(s);
        % Camera 1
        s = input('Is camera 1 a color camera (0 = No, 1 = Yes): ', 's');
        while isempty(s) || (length(s) > 1 || (s ~= '0' && s ~= '1'))
            disp('Invalid input, must specify 0 or 1.')
            s = input('Is camera 1 a color camera (0 = No, 1 = Yes): ', 's');
        end
        isCamColor(2) = str2num(s);
        % Camera 2
        s = input('Is camera 2 a color camera (0 = No, 1 = Yes): ', 's');
        while isempty(s) || (length(s) > 1 || (s ~= '0' && s ~= '1'))
            disp('Invalid input, must specify 0 or 1.')
            s = input('Is camera 2 a color camera (0 = No, 1 = Yes): ', 's');
        end
        isCamColor(3) = str2num(s);
    end
    isCamColor %#ok<NOPRT> % Display results of defining isCamColor

    %% Var outputProcessedImgs
    fprintf(['outputProcessedImgs: Flag that determines if processed images should be\n' ...
        '\twritten to processed output folders. If 0, images will not be written. Any additional img\n' ...
        '\tprocessing functions may have their own flag for this, but if not, they will inherit this flag.\n'...
        '\tNote: This is an important flag because if outputting images, processing\n' ...
        '\t\ttime will be significantly affected. At best, each imwrite takes approx. 0.07 seconds.\n' ...
        '\t\tThis means that an extra hour will be added to processing time for each\n' ...
        '\t\t50,000 flake images. The default for this value is 0 (i.e. NO IMG OUTPUT).\n'])
    if exist('outputProcessedImgs', 'var')
        s = input(sprintf('var outputProcessedImgs = %s; Change to (0 or 1): ', outputProcessedImgs), 's');
        while ~isempty(s) && (length(s) > 1 || (s ~= '0' && s ~= '1'))
            disp('To change this flag, must set to 0 or 1.')
            s = input(sprintf('var outputProcessedImgs = %s; Change to (0 or 1): ', outputProcessedImgs), 's');
        end
        if ~isempty(s)
            outputProcessedImgs = s;
        end
    else
        % Don't require user to set the format (if they don't, default to format 1)
        s = input('Set outputProcessedImgs to (0 or 1): ', 's');
        while ~isempty(s) && (length(s) > 1 || (s ~= '0' && s ~= '1'))
            disp('To set this flag, must input 0 or 1.')
            s = input('Set outputProcessedImgs to (0 or 1): ', 's');
        end
        if ~isempty(s)
            outputProcessedImgs = s;
        else
            outputProcessedImgs = '0';
        end
    end
    outputProcessedImgs %#ok<NOPRT> % Show user the result of defining outputProcessedImgs

    %% Var camFOV
    fprintf(['camFOV: The calculated pixels/mm of each image.\n' ...
        '\tThis can be computed by dividing the pixel width of images that the\n' ...
        '\tMASC camera takes by the field-of-view of the camera (in mm).\n' ...
        '\tIt can also be obtained through observation by dropping an object\n' ...
        '\tof known size through the MASC to then see the number of pixels\n' ...
        '\tthe object spans.\n' ...
        '\tIMPORANT: These values must be accurate in order for size measurement\n' ...
        '\t\tmodules to return accurate results.\n'])
    if exist('camFOV', 'var')
        % Camera 0
        s = input(sprintf('var camFOV(1) = %i; Change to: ', camFOV(1)), 's');
        while ~isempty(s) && isnan(str2double(s))
            disp('If changing this value, you must specify a decimal number')
            s = input(sprintf('var camFOV(1) = %i; Change to: ', camFOV(1)), 's');
        end
        if ~isempty(s)
            camFOV(1) = str2double(s);
        end
        % Camera 1
        s = input(sprintf('var camFOV(2) = %i; Change to: ', camFOV(2)), 's');
        while ~isempty(s) && isnan(str2double(s))
            disp('If changing this value, you must specify a decimal number')
            s = input(sprintf('var camFOV(2) = %i; Change to: ', camFOV(2)), 's');
        end
        if ~isempty(s)
            camFOV(2) = str2double(s);
        end
        % Camera 2
        s = input(sprintf('var camFOV(3) = %i; Change to: ', camFOV(3)), 's');
        while ~isempty(s) && isnan(str2double(s))
            disp('If changing this value, you must specify a decimal number')
            s = input(sprintf('var camFOV(3) = %i; Change to: ', camFOV(3)), 's');
        end
        if ~isempty(s)
            camFOV(3) = str2double(s);
        end
    else
        % User must specify FOV decimal value for each camera
        % Camera 0
        s = input('Define FOV for camera 0: ', 's');
        while isempty(s) || isnan(str2double(s))
            disp('Invalid input, must define each FOV as a decimal number.')
            s = input('Define FOV for camera 0: ', 's');
        end
        camFOV(1) = str2double(s);
        % Camera 1
        s = input('Define FOV for camera 1: ', 's');
        while isempty(s) || isnan(str2double(s))
            disp('Invalid input, must define each FOV as a decimal number.')
            s = input('Define FOV for camera 1: ', 's');
        end
        camFOV(2) = str2double(s);
        % Camera 2
        s = input('Define FOV for camera 2: ', 's');
        while isempty(s) || isnan(str2double(s))
            disp('Invalid input, must define each FOV as a decimal number.')
            s = input('Define FOV for camera 2: ', 's');
        end
        camFOV(3) = str2double(s);
    end
    camFOV %#ok<NOPRT> % Display results of defining camFOV

    %% Var background threshold (all pixels outside flake should fall below
    % this threshold brightness
    fprintf(['backgroundThresh: The brightness threshold for which all pixels outside\n' ...
        '\tthe flake should fall below. Value is on a scale from 0 to 255 in brightness,\n' ...
        '\twith 0 being completely dark and 255 completely white.\n' ...
        '\tIMPORANT: Used in SCAN & CROP!\n\t'])
    cprintf('_text', 'Default ')
    fprintf('= 20\n')
    if exist('backgroundThresh', 'var')
        s = input(sprintf('var backgroundThresh = %.0f; Change to (0-255): ', backgroundThresh), 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0 || str2double(s) > 255)
            disp('To change this value, must set to a value between 0 and 255, inclusive.')
            s = input(sprintf('var backgroundThresh = %.0f; Change to (0-255): ', backgroundThresh), 's');
        end
        if ~isempty(s)
            backgroundThresh = str2double(s);
        end
    else
        % Don't require user to set the format (if they don't, default to format 1)
        s = input('Set backgroundThresh to (0-255): ', 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0 || str2double(s) > 255)
            disp('To set this value, must input a value between 0 and 255.')
            s = input('Set backgroundThresh to (0-255): ', 's');
        end
        if ~isempty(s)
            backgroundThresh = str2double(s);
        else
            backgroundThresh = 20;
        end
    end
    backgroundThresh %#ok<NOPRT> % Display results of defining backgroundThresh

    %% Var topDiscard, bottomDiscard, leftDiscard, rightDiscard, apply*DiscardsToCams
    fprintf(['XXXDiscard: The pixels to crop on each side of the image frame.\n' ...
        '\tYou will be able to specify a value for discarding pixel rows on the top\n' ...
        '\tand bottom of the img frame, as well as pixel columns on the left and right\n' ...
        '\tsides of the img frame. E.g. Specifying 10 for topDiscard would mask out\n' ...
        '\t10 rows of pixels at the top of the image.\n' ...
        '\tIMPORANT: Used in SCAN & CROP!\n\t'])
    cprintf('_text', 'Default ')
    fprintf('= 0\n')
    fprintf(['\napplyXXXDiscardToCams: Array of camera IDs to apply discards to.\n' ...
        '\tThis variable stipulates which cameras of the MASC you want to apply\n' ...
        '\tthe top/bottom/left/right discard to. The possible options are 0, 1, and 2.\n' ...
        '\tIMPORANT: Used in SCAN & CROP!\n\t'])
    cprintf('_text', 'Default (if discard not set)')
    fprintf(' = []\n\t')
    cprintf('_text', 'Default (if discard > 0)')
    fprintf(' = [0, 1, 2]\n')
    if exist('topDiscard', 'var')
        s = input(sprintf('var topDiscard = %i; Change to: ', topDiscard), 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input(sprintf('var topDiscard = %i; Change to: ', topDiscard), 's');
        end
        if ~isempty(s)
            topDiscard = str2num(s);
        end
    else
        s = input('Set topDiscard to: ', 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input('Set topDiscard to: ', 's');
        end
        if ~isempty(s)
            topDiscard = str2num(s);
        else
            topDiscard = 0;
        end
    end
    if exist('applyTopDiscardToCams', 'var')
        cur = applyTopDiscardToCams;
    else, cur = -1;
    end
    applyTopDiscardToCams = applyDiscardToCams('Top', cur);
    if exist('bottomDiscard', 'var')
        s = input(sprintf('var bottomDiscard = %i; Change to: ', bottomDiscard), 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input(sprintf('var bottomDiscard = %i; Change to: ', bottomDiscard), 's');
        end
        if ~isempty(s)
            bottomDiscard = str2num(s);
        end
    else
        s = input('Set bottomDiscard to: ', 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input('Set bottomDiscard to: ', 's');
        end
        if ~isempty(s)
            bottomDiscard = str2num(s);
        else
            bottomDiscard = 0;
        end
    end
    if exist('applyBotDiscardToCams', 'var')
        cur = applyBotDiscardToCams;
    else, cur = -1;
    end
    applyBotDiscardToCams = applyDiscardToCams('Bot', cur);
    if exist('leftDiscard', 'var')
        s = input(sprintf('var leftDiscard = %i; Change to: ', leftDiscard), 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input(sprintf('var leftDiscard = %i; Change to: ', leftDiscard), 's');
        end
        if ~isempty(s)
            leftDiscard = str2num(s);
        end
    else
        s = input('Set leftDiscard to: ', 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input('Set leftDiscard to: ', 's');
        end
        if ~isempty(s)
            leftDiscard = str2num(s);
        else
            leftDiscard = 0;
        end
    end
    if exist('applyLeftDiscardToCams', 'var')
        cur = applyLeftDiscardToCams;
    else, cur = -1;
    end
    applyLeftDiscardToCams = applyDiscardToCams('Left', cur);
    if exist('rightDiscard', 'var')
        s = input(sprintf('var rightDiscard = %i; Change to: ', rightDiscard), 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input(sprintf('var rightDiscard = %i; Change to: ', rightDiscard), 's');
        end
        if ~isempty(s)
            rightDiscard = str2num(s);
        end
    else
        s = input('Set rightDiscard to: ', 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input('Set rightDiscard to: ', 's');
        end
        if ~isempty(s)
            rightDiscard = str2num(s);
        else
            rightDiscard = 0;
        end
    end
    if exist('applyRightDiscardToCams', 'var')
        cur = applyRightDiscardToCams;
    else, cur = -1;
    end
    applyRightDiscardToCams = applyDiscardToCams('Right', cur);

    % Display results of settings discard variables
    topDiscard %#ok<NOPRT>
    applyTopDiscardToCams %#ok<NOPRT>
    bottomDiscard %#ok<NOPRT>
    applyBotDiscardToCams %#ok<NOPRT>
    leftDiscard %#ok<NOPRT>
    applyLeftDiscardToCams %#ok<NOPRT>
    rightDiscard %#ok<NOPRT>
    applyRightDiscardToCams %#ok<NOPRT>

    %% Var lineFill
    fprintf(['lineFill: In order to assess the flake area, internal\n' ...
        '\tcomplexities are blurred with the lineFill parameter. This avoids small,\n' ...
        '\tlocal discontinuities to make a single flake. This is essentially a guess\n' ...
        '\tfor the minimum flake size (in microns).\n' ...
        '\tIMPORANT: Used in Module processing!\n\t'])
    cprintf('_text', 'Default ')
    fprintf('= 200 (microns) \n')
    if exist('lineFill', 'var')
        s = input(sprintf('var lineFill = %.0f; Change to: ', lineFill), 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input(sprintf('var lineFill = %.0f; Change to: ', lineFill), 's');
        end
        if ~isempty(s)
            lineFill = str2double(s);
        end
    else
        % Don't require user to set the format (if they don't, default to format 1)
        s = input('Set lineFill to:', 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input('Set lineFill to: ', 's');
        end
        if ~isempty(s)
            lineFill = str2double(s);
        else
            lineFill = 200;
        end
    end
    lineFill %#ok<NOPRT> % Display results of setting lineFill

    %% Var minFlakePerim
    fprintf(['minFlakePerim: The minimum acceptable perimeter of a flake in pixels.\n' ...
             '\tIMPORANT: Used in SCAN & CROP!\n\t'])
    cprintf('_text', 'Default ')
    fprintf('= 250\n')
    if exist('minFlakePerim', 'var')
        s = input(sprintf('var minFlakePerim = %.0f; Change to: ', minFlakePerim), 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input(sprintf('var minFlakePerim = %.0f; Change to: ', minFlakePerim), 's');
        end
        if ~isempty(s)
            minFlakePerim = str2double(s);
        end
    else
        % Don't require user to set the format (if they don't, default to format 1)
        s = input('Set minFlakePerim to:', 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input('Set minFlakePerim to: ', 's');
        end
        if ~isempty(s)
            minFlakePerim = str2double(s);
        else
            minFlakePerim = 250;
        end
    end
    minFlakePerim %#ok<NOPRT> % Display results of setting minFlakePerim

    %% Var minCropWidth
    fprintf(['minCropWidth: The minimum acceptable dimensions of the box\n' ...
             '\tthat contains a cropped flake.\n' ...
             '\tIMPORANT: Used in SCAN & CROP!\n\t'])
    cprintf('_text', 'Default ')
    fprintf('= 40\n')
    if exist('minCropWidth', 'var')
        s = input(sprintf('var minCropWidth = %.0f; Change to: ', minCropWidth), 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input(sprintf('var minCropWidth = %.0f; Change to: ', minCropWidth), 's');
        end
        if ~isempty(s)
            minCropWidth = str2double(s);
        end
    else
        % Don't require user to set the format (if they don't, default to format 1)
        s = input('Set minCropWidth to:', 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input('Set minCropWidth to: ', 's');
        end
        if ~isempty(s)
            minCropWidth = str2double(s);
        else
            minCropWidth = 40;
        end
    end
    minCropWidth %#ok<NOPRT> % Display results of setting minFlakePerim

    %% Var maxEdgeTouch
    fprintf(['maxEdgeTouch: The maximum acceptable length for a flake to touch the\n' ...
        '\timage frame edge. This is used to filter out flakes where a relatively large\n' ...
        '\tportion of the flake is outside of the image frame.\n' ...
        '\tIMPORANT: Used in SCAN & CROP!\n\t'])
    cprintf('_text', 'Default ')
    fprintf('= 100\n')
    if exist('maxEdgeTouch', 'var')
        s = input(sprintf('var maxEdgeTouch = %.0f; Change to: ', maxEdgeTouch), 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input(sprintf('var maxEdgeTouch = %.0f; Change to: ', maxEdgeTouch), 's');
        end
        if ~isempty(s)
            maxEdgeTouch = str2double(s);
        end
    else
        % Don't require user to set the format (if they don't, default to format 1)
        s = input('Set maxEdgeTouch to:', 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input('Set maxEdgeTouch to: ', 's');
        end
        if ~isempty(s)
            maxEdgeTouch = str2double(s);
        else
            maxEdgeTouch = 100;
        end
    end
    maxEdgeTouch %#ok<NOPRT> % Display results of setting maxEdgeTouch

    %% Var avgFlakeBrightness
    fprintf(['avgFlakeBrightness: The minimum acceptable average pixel brightness.\n' ...
         '\tDarker flakes tend to be out of focus, thus having a slight threshold on\n' ...
         '\tavg pixel brightness of the flakes should eliminate some unuseful flakes.\n' ...
         '\tIMPORANT: Used in SCAN & CROP!\n\t'])
    cprintf('_text', 'Default ')
    fprintf('= 10 (Ranges from 0-255, like backgroundThresh)\n')
    if exist('avgFlakeBrightness', 'var')
        s = input(sprintf('var avgFlakeBrightness = %.0f; Change to (0-255): ', avgFlakeBrightness), 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0 || str2double(s) > 255)
            disp('To change this value, must set to a value between 0 and 255, inclusive.')
            s = input(sprintf('var avgFlakeBrightness = %.0f; Change to (0-255): ', avgFlakeBrightness), 's');
        end
        if ~isempty(s)
            avgFlakeBrightness = str2double(s);
        end
    else
        % Don't require user to set the format (if they don't, default to format 1)
        s = input('Set avgFlakeBrightness to (0-255): ', 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0 || str2double(s) > 255)
            disp('To set this value, must input a value between 0 and 255.')
            s = input('Set avgFlakeBrightness to (0-255): ', 's');
        end
        if ~isempty(s)
            avgFlakeBrightness = str2double(s);
        else
            avgFlakeBrightness = 10;
        end
    end
    avgFlakeBrightness %#ok<NOPRT> % Display results of defining avgFlakeBrightness

    %% Var filterFocus
    fprintf(['filterFocus: Whether to filter objects in SCAN & CROP by their\n' ...
         '\tin-focus measure. This uses the same number that''s calculated by the Focus module.\n' ...
         '\tIf enabled, SCAN & CROP will accept objects with at least the value specified by\n' ...
         '\tfocusThreshold OR all of the other conditions satisfied. The focus is used as a condition\n' ...
         '\tto allow objects through SCAN & CROP that otherwise would have been filtered out.\n' ...
         '\tSet this to 1 to enable.\n'...
         '\tIMPORANT: Used in SCAN & CROP!\n\t'])
    cprintf('_text', 'Default ')
    fprintf('= 1\n')
    if exist('filterFocus', 'var')
        s = input(sprintf('var filterFocus = %i; Change to: ', filterFocus), 's');
        while ~isempty(s) && s ~= '0' && s ~= '1'
            disp('Must input a 0 or 1.')
            s = input(sprintf('var filterFocus = %i; Change to: ', filterFocus), 's');
        end
        if ~isempty(s)
            filterFocus = str2num(s);
        end
    else
        % Don't require user to set the format (if they don't, default to format 1)
        s = input('Set filterFocus to:', 's');
        while ~isempty(s) && s ~= '0' && s ~= '1'
            disp('Must input a 0 or 1.')
            s = input('Set filterFocus to: ', 's');
        end
        if ~isempty(s)
            filterFocus = str2num(s);
        else
            filterFocus = 1;
        end
    end
    filterFocus %#ok<NOPRT> % Display results of setting filterFocus

    %% Var focusThreshold
    fprintf(['focusThreshold: If filterFocus is enabled, this setting is used to\n' ...
        '\tcontrol the minimum acceptable focus measure value.\n' ...
        '\t\tValues < 10 => Almost always out of focus\n' ...
        '\t\tValues <= 20 => Difficult to tell\n' ...
        '\t\tValues > 20 => In-focus or some pixels with high specular reflection\n']);
    cprintf('_text', 'Default ')
    fprintf('= 15\n')
    if exist('focusThreshold', 'var')
        s = input(sprintf('var focusThreshold = %.0f; Change to: ', focusThreshold), 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input(sprintf('var focusThreshold = %.0f; Change to: ', focusThreshold), 's');
        end
        if ~isempty(s)
            focusThreshold = str2double(s);
        end
    else
        % Don't require user to set the format (if they don't, default to format 1)
        s = input('Set focusThreshold to:', 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input('Set focusThreshold to: ', 's');
        end
        if ~isempty(s)
            focusThreshold = str2double(s);
        else
            focusThreshold = 15;
        end
    end
    focusThreshold %#ok<NOPRT> % Display results of setting focusThreshold

    %% Var internalVariability
    fprintf(['internalVariability: Images that only have small irregularities in\n' ...
        '\tthe background or that are out-of-focus will have relatively lower internal\n' ...
        '\tvariability. This threshold specifies the minimum variability an image must\n' ...
        '\thave to be accepted.\n\t'])
    cprintf('_text', 'Default ')
    fprintf('= 5\n')
    if exist('internalVariability', 'var')
        s = input(sprintf('var internalVariability = %.0f; Change to: ', internalVariability), 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input(sprintf('var internalVariability = %.0f; Change to: ', internalVariability), 's');
        end
        if ~isempty(s)
            internalVariability = str2double(s);
        end
    else
        % Don't require user to set the format (if they don't, default to format 1)
        s = input('Set internalVariability to:', 's');
        while ~isempty(s) && (isnan(str2double(s)) || str2double(s) < 0)
            disp('Must input a non-negative value.')
            s = input('Set internalVariability to: ', 's');
        end
        if ~isempty(s)
            internalVariability = str2double(s);
        else
            internalVariability = 5;
        end
    end
    internalVariability %#ok<NOPRT> % Display results of setting internalVariability

    %% Var flakeBrighten
    fprintf(['flakeBrighten: Set to 1 if you would like to modify images for\n' ...
        '\timproved display by applying some brightening.\n'])
    if exist('flakeBrighten', 'var')
        s = input(sprintf('var flakeBrighten = %s; Change to (0 or 1): ', flakeBrighten), 's');
        while ~isempty(s) && (length(s) > 1 || (s ~= '0' && s ~= '1'))
            disp('To change this flag, must set to 0 or 1.')
            s = input(sprintf('var flakeBrighten = %s; Change to (0 or 1): ', flakeBrighten), 's');
        end
        if ~isempty(s)
            flakeBrighten = s;
        end
    else
        % Don't require user to set the format (if they don't, default to format 1)
        s = input('Set flakeBrighten to (0 or 1): ', 's');
        while ~isempty(s) && (length(s) > 1 || (s ~= '0' && s ~= '1'))
            disp('To set this flag, must input 0 or 1.')
            s = input('Set flakeBrighten to (0 or 1): ', 's');
        end
        if ~isempty(s)
            flakeBrighten = s;
        else
            flakeBrighten = '0';
        end
    end
    flakeBrighten %#ok<NOPRT> % Show user the result of defining flakeBrighten

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% OPTIONAL PARAMS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    fprintf('\n')
    disp('%% OPTIONAL PARAMS %%')
    fprintf(['%% The following variables are not required for the snowflake image\n' ...
        '%% processing. However, some variables are recommended to be set and will\n' ...
        '%% be indicated as such. If the variable hasn''t been set and you do not\n' ...
        '%% wish to set it, just hit [Enter] when prompted for it. If it has been set,\n' ...
        '%% you will be able to keep the current value, change it, or unset it.\n'])

    %% Var siteName
    fprintf('siteName (RECOMMENDED): Where the MASC is located.\n')
    if exist('siteName', 'var') && ~isempty(siteName)
        s = input(sprintf(['var siteName = %s; Would you like to\n' ...
            '\t(1) keep it the same,\n' ...
            '\t(2) change it, or\n' ...
            '\t(3) unset it (make it blank) ?\n' ...
            '\tChoose one of the options above (1,2,3): '], siteName), 's');
        while isempty(s) || length(s) > 1 || (s ~= '1' && s ~= '2' && s ~= '3')
            s = input(sprintf('\tChoose one of the options above (1,2,3): '), 's');
        end

        if s == '2'
            s = input(sprintf('\tEnter the new site name: '), 's');
            if isempty(s)
                siteName = '';
            else
                siteName = s;
            end
        elseif s == '3'
            siteName = '';
        end
    else
        s = input(sprintf('\tEnter site name (or hit [Enter] to skip): '), 's');
        if isempty(s)
            siteName = '';
        else
            siteName = s;
        end
    end
    siteName %#ok<NOPRT> % Display results of settings siteName

    %% Var cameraName
    fprintf('cameraName (RECOMMENDED): Which MASC''s images you are processing.\n')
    if exist('cameraName', 'var') && ~isempty(cameraName)
        s = input(sprintf(['var cameraName = %s; Would you like to\n' ...
            '\t(1) keep it the same,\n' ...
            '\t(2) change it, or\n' ...
            '\t(3) unset it (make it blank) ?\n' ...
            '\tChoose one of the options above (1,2,3): '], cameraName), 's');
        while isempty(s)|| length(s) > 1 || (s ~= '1' && s ~= '2' && s ~= '3')
            s = input(sprintf('\tChoose one of the options above (1,2,3): '), 's');
        end

        if s == '2'
            s = input(sprintf('\tEnter the new camera name: '), 's');
            if isempty(s)
                cameraName = '';
            else
                cameraName = s;
            end
        elseif s == '3'
            cameraName = '';
        end
    else
        s = input(sprintf('\tEnter camera name (or hit [Enter] to skip): '), 's');
        if isempty(s)
            cameraName = '';
        else
            cameraName = s;
        end
    end
    cameraName %#ok<NOPRT> % Display results of setting camerName

    %% Var rescanOriginals
    fprintf(['rescanOriginals: After pre-processing, system will move on to\n' ...
        '\tscanning, filtering and cropping the original images. If you have done this before,\n' ...
        '\tbut would like to re-scan these images, set this variable to 1. Default is 0.\n'])
    s = input('Enter (0) or (1) for rescanOriginal variable: ', 's');
    while ~isempty(s) && (length(s) > 1 || (s ~= '0' && s ~= '1'))
        s = input('If specifying rescanOriginal, must be (0) or (1): ', 's');
    end
    if isempty(s) || s == '0'
        rescanOriginal = 0;
    else
        rescanOriginal = 1;
    end
    rescanOriginal %#ok<NOPRT> % Display results of setting rescanOriginal

    %% Var skipProcessed
    fprintf(['skipProcessed: If there are snowflake images in the\n' ...
        '\tspecified path for the specified date range that have already been\n' ...
        '\tprocessed by this tool, you can set this variable to 1 to skip those\n' ...
        '\timages. Default value is 0.\n'])
    s = input('Enter (0) or (1) for skipProcessed variable: ', 's');
    while ~isempty(s) && (length(s) > 1 || (s ~= '0' && s ~= '1'))
        s = input('If specifying skipProcessed, must be (0) or (1): ', 's');
    end
    if isempty(s) || s == '0'
        skipProcessed = 0;
    else
        skipProcessed = 1;
    end
    skipProcessed %#ok<NOPRT> % Display results of setting skipProcessed

end

end

function [isValid] = validate_datestr(s, dstart)
    try
        d = datenum(s, 'yyyymmdd_HHMM');
        if dstart ~= 0 % We are validating dateend, thus need to make sure
                      % that dateend is after datestart
            if d < dstart
                isValid = 0;
            else
                isValid = 1;
            end
        else
            isValid = 1;
        end
    catch %#ok<*CTCH>
        isValid = 0;
    end

end

function [applied_cams] = applyDiscardToCams(type, curSetting)
    if length(curSetting) ~= 1 || curSetting ~= -1
        invalidList = 1;
        firstInput = 1;
        while invalidList
            if ~firstInput
                fprintf('Invalid element in list.\n');
            else
                firstInput = 0;
            end
            s = input(['var apply' type 'DiscardToCams = [' num2str(curSetting) ']; ' ...
                'Change to (input comma-delimited list, e.g. 0,1,2): '], 's');
            if isempty(s)
                break;
            end
            s = strsplit(s, ',');
            tmp = [];
            for j = 1:length(s)
                if isempty(str2num(s{j}))
                    break;
                end
                tmp(j) = str2num(s{j}); %#ok<AGROW>
                if tmp(j) < 0 || tmp(j) > 2
                    break;
                end
            end
            invalidList = 0;
        end
        if ~invalidList
            applied_cams = tmp;
        else
            applied_cams = curSetting;
        end
    else
        invalidList = 1;
        firstInput = 1;
        while invalidList
            if ~firstInput
                fprintf('Invalid element in list.\n');
            else
                firstInput = 0;
            end
            s = input(['Set apply' type 'DiscardToCams to (input comma-delimited list, e.g. 0,1,2): '], 's');
            if isempty(s)
                break;
            end
            s = strsplit(s, ',');
            tmp = [];
            for j = 1:length(s)
                if isempty(str2num(s{j}))
                    break;
                end
                tmp(j) = str2num(s{j}); %#ok<AGROW>
                if tmp(j) < 0 || tmp(j) > 2
                    break;
                end
            end
            invalidList = 0;
        end
        if ~invalidList
            applied_cams = tmp;
        else
            applied_cams = [];
        end
    end

end


text:
import logging
import traceback
import sys
from difflib import HtmlDiff
import os

'''
This Script is useful for making diff files between specific commits.

How to make diff files.
(1) git archive --format=zip <CommitID1> `git diff <CommitID1>..<CommitID2> --name-only` -o after.zip
(2) git archive --format=zip <CommitID2> `git diff <CommitID1>..<CommitID2> --name-only` -o before.zip
(3) unzip after.zip and before.zip
(4) Execute this script like as follow
    Python dirdiff before after
'''

MAIN_HTML_FORMAT ='''

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>diff result</title>

<frameset cols="200,*">
<frame src="contents/filelink.htm" name="filelist">
<frame name="diff">
</frameset>

'''

FILE_LIST_HTML_FORMAT = '''

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>filelist</title>

{link_list}

'''

LINK_FORMAT = '
{file_name}
'

def make_diff(f1, f2, encoding='utf-8'):
    from_lines = open(f1, encoding=encoding).readlines()
    to_lines = open(f2, encoding=encoding).readlines()
    diff_file = HtmlDiff().make_file(from_lines, to_lines, os.path.basename(f1), os.path.basename(f2))

    output_file_name = 'diff_' + os.path.basename(f1) + '.htm'

    with open("contents/" +output_file_name, 'w') as f:
        f.writelines(diff_file)

    return LINK_FORMAT.format(htm_file_name=output_file_name, file_name=os.path.basename(f1))

def dir_diff(before_dir, after_dir, encoding='utf-8'):
    if not(os.path.exists('contents')):
        os.mkdir('contents')

    link_list = ''
    for root, dirs, files in os.walk(before_dir):
        for file_name in files:
            before_file_path = os.path.join(root, file_name)
            after_file_path = os.path.join(after_dir, file_name)
            if os.path.exists(after_file_path):
                link_list += make_diff(before_file_path, after_file_path, encoding)

    with open('contents/filelink.htm', 'w') as f:
        f.writelines(FILE_LIST_HTML_FORMAT.format(link_list=link_list))

    with open('diff_result.htm', 'w') as f:
        f.writelines(MAIN_HTML_FORMAT)

if __name__ == "__main__":
    try:
        before_dir = sys.argv[1]
        after_dir = sys.argv[2]

        if len(sys.argv) == 3:
            dir_diff(before_dir, after_dir)
        elif len(sys.argv) == 4:
            encoding = sys.argv[3]
            dir_diff(before_dir, after_dir, encoding)
    except Exception as e:
        logging.error(e)
        logging.error(traceback.format_exc())

redpajama_set_name: RedPajamaGithub


text:
module Crypto.Classical.Cipher
   ( module Crypto.Classical.Cipher.Affine
   , module Crypto.Classical.Cipher.Caesar
   , module Crypto.Classical.Cipher.Enigma
   , module Crypto.Classical.Cipher.Stream
   , module Crypto.Classical.Cipher.Substitution
   , module Crypto.Classical.Cipher.Vigenere
   ) where

import Crypto.Classical.Cipher.Affine
import Crypto.Classical.Cipher.Caesar
import Crypto.Classical.Cipher.Enigma
import Crypto.Classical.Cipher.Stream
import Crypto.Classical.Cipher.Substitution
import Crypto.Classical.Cipher.Vigenere


text:
import { Observable } from '../Observable';
import { map } from './map';

/**
 * Maps each source value (an object) to its specified nested property.
 *
 * Like {@link map}, but meant only for picking one of
 * the nested properties of every emitted object.
 *
 *
 *
 * Given a list of strings describing a path to an object property, retrieves
 * the value of a specified nested property from all values in the source
 * Observable. If a property can't be resolved, it will return `undefined` for
 * that value.
 *
 * @example
Map every every click to the tagName of the clicked target element

 * var clicks = Rx.Observable.fromEvent(document, 'click');
 * var tagNames = clicks.pluck('target', 'tagName');
 * tagNames.subscribe(x => console.log(x));
 *
 * @see {@link map}
 *
 * @param {...string} properties The nested properties to pluck from each source
 * value (an object).
 * @return {Observable} Returns a new Observable of property values from the
 * source values.
 * @method pluck
 * @owner Observable
 */
export function pluck<T, R>(this: Observable<T>, ...properties: string[]): Observable<R> {
  const length = properties.length;
  if (length === 0) {
    throw new Error('list of properties cannot be empty.');
  }
  return map.call(this, plucker(properties, length));
}

function plucker(props: string[], length: number): (x: string) => any {
  const mapper = (x: string) => {
    let currentProp = x;
    for (let i = 0; i < length; i++) {
      const p = currentProp[props[i]];
      if (typeof p !== 'undefined') {
        currentProp = p;
      } else {
        return undefined;
      }
    }
    return currentProp;
  };

  return mapper;
}


text:
<!DOCTYPE html>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width" />

<link rel="shortcut icon" type="image/x-icon" href="../../../../favicon.ico" />
<title>LogManager - Android SDK | Android Developers</title>

<link rel="stylesheet"
href="http://fonts.googleapis.com/css?family=Roboto:regular,medium,thin,italic,mediumitalic,bold" title="roboto">
<link href="../../../../assets/css/default.css" rel="stylesheet" type="text/css">

<link href="../../../../assets/css/fullscreen.css" rel="stylesheet" class="fullscreen"
type="text/css">

          	Quicknav
			      Quicknav

                  Design

Develop

Distribute

Links

Google Play Developer Console

Android Developers Blog

About Android

Android Sites

Android.com

Android Developers

Android Open Source Project

      <form onsubmit="return submit_search()">
        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
onkeydown="return search_changed(event, true, '../../../../')"
onkeyup="return search_changed(event, false, '../../../../')" />
      </form>

        close

Get Started

Style

Patterns

Building Blocks

Downloads

Videos

Training

API Guides

Reference

Tools

Get the SDK

Google Services

Google Play

Publishing

Promoting

App Quality

Spotlight

Open Distribution

Results

Loading...

Training

API Guides

Reference

Tools

Google Services

to top

          API level:

            <select id="apiLevelSelector">

            </select>

Android APIs

  android

  android.accessibilityservice

  android.accounts

  android.animation

  android.app

  android.app.admin

  android.app.backup

  android.appwidget

  android.bluetooth

  android.content

  android.content.pm

  android.content.res

  android.database

  android.database.sqlite

  android.drm

  android.gesture

  android.graphics

  android.graphics.drawable

  android.graphics.drawable.shapes

  android.graphics.pdf

  android.hardware

  android.hardware.display

  android.hardware.input

  android.hardware.location

  android.hardware.usb

  android.inputmethodservice

  android.location

  android.media

  android.media.audiofx

  android.media.effect

  android.mtp

  android.net

  android.net.http

  android.net.nsd

  android.net.rtp

  android.net.sip

  android.net.wifi

  android.net.wifi.p2p

  android.net.wifi.p2p.nsd

  android.nfc

  android.nfc.cardemulation

  android.nfc.tech

  android.opengl

  android.os

  android.os.storage

  android.preference

  android.print

  android.print.pdf

  android.printservice

  android.provider

  android.renderscript

  android.sax

  android.security

  android.service.dreams

  android.service.notification

  android.service.textservice

  android.service.wallpaper

  android.speech

  android.speech.tts

  android.support.v13.app

  android.support.v4.accessibilityservice

  android.support.v4.app

  android.support.v4.content

  android.support.v4.content.pm

  android.support.v4.database

  android.support.v4.graphics.drawable

  android.support.v4.hardware.display

  android.support.v4.media

  android.support.v4.net

  android.support.v4.os

  android.support.v4.print

  android.support.v4.text

  android.support.v4.util

  android.support.v4.view

  android.support.v4.view.accessibility

  android.support.v4.widget

  android.support.v7.app

  android.support.v7.appcompat

  android.support.v7.gridlayout

  android.support.v7.media

  android.support.v7.mediarouter

  android.support.v7.view

  android.support.v7.widget

  android.support.v8.renderscript

  android.telephony

  android.telephony.cdma

  android.telephony.gsm

  android.test

  android.test.mock

  android.test.suitebuilder

  android.text

  android.text.format

  android.text.method

  android.text.style

  android.text.util

  android.transition

  android.util

  android.view

  android.view.accessibility

  android.view.animation

  android.view.inputmethod

  android.view.textservice

  android.webkit

  android.widget

  dalvik.bytecode

  dalvik.system

  java.awt.font

  java.beans

  java.io

  java.lang

  java.lang.annotation

  java.lang.ref

  java.lang.reflect

  java.math

  java.net

  java.nio

  java.nio.channels

  java.nio.channels.spi

  java.nio.charset

  java.nio.charset.spi

  java.security

  java.security.acl

  java.security.cert

  java.security.interfaces

  java.security.spec

  java.sql

  java.text

  java.util

  java.util.concurrent

  java.util.concurrent.atomic

  java.util.concurrent.locks

  java.util.jar

  java.util.logging

  java.util.prefs

  java.util.regex

  java.util.zip

  javax.crypto

  javax.crypto.interfaces

  javax.crypto.spec

  javax.microedition.khronos.egl

  javax.microedition.khronos.opengles

  javax.net

  javax.net.ssl

  javax.security.auth

  javax.security.auth.callback

  javax.security.auth.login

  javax.security.auth.x500

  javax.security.cert

  javax.sql

  javax.xml

  javax.xml.datatype

  javax.xml.namespace

  javax.xml.parsers

  javax.xml.transform

  javax.xml.transform.dom

  javax.xml.transform.sax

  javax.xml.transform.stream

  javax.xml.validation

  javax.xml.xpath

  junit.framework

  junit.runner

  org.apache.http

  org.apache.http.auth

  org.apache.http.auth.params

  org.apache.http.client

  org.apache.http.client.entity

  org.apache.http.client.methods

  org.apache.http.client.params

  org.apache.http.client.protocol

  org.apache.http.client.utils

  org.apache.http.conn

  org.apache.http.conn.params

  org.apache.http.conn.routing

  org.apache.http.conn.scheme

  org.apache.http.conn.ssl

  org.apache.http.conn.util

  org.apache.http.cookie

  org.apache.http.cookie.params

  org.apache.http.entity

  org.apache.http.impl

  org.apache.http.impl.auth

  org.apache.http.impl.client

  org.apache.http.impl.conn

  org.apache.http.impl.conn.tsccm

  org.apache.http.impl.cookie

  org.apache.http.impl.entity

  org.apache.http.impl.io

  org.apache.http.io

  org.apache.http.message

  org.apache.http.params

  org.apache.http.protocol

  org.apache.http.util

  org.json

  org.w3c.dom

  org.w3c.dom.ls

  org.xml.sax

  org.xml.sax.ext

  org.xml.sax.helpers

  org.xmlpull.v1

  org.xmlpull.v1.sax2

Interfaces

Filter

LoggingMXBean

Classes

ConsoleHandler

ErrorManager

FileHandler

Formatter

Handler

Level

Logger

LoggingPermission

LogManager

LogRecord

MemoryHandler

SimpleFormatter

SocketHandler

StreamHandler

XMLFormatter

      fullscreen
      Use Tree NavigationUse Panel Navigation

Summary:

  Constants

  | Protected Ctors

  | Methods

  | Inherited Methods

| [Expand All]

  Added in API level 1

    public

    class

LogManager

    extends Object

        java.lang.Object

               ↳

        java.util.logging.LogManager

Class Overview

LogManager is used to maintain configuration properties of the
 logging framework, and to manage a hierarchical namespace of all named
 Logger objects.

 There is only one global LogManager instance in the
 application, which can be get by calling static method
 getLogManager(). This instance is created and
 initialized during class initialization and cannot be changed.

 The LogManager class can be specified by
 java.util.logging.manager system property, if the property is unavailable or
 invalid, the default class LogManager will
 be used.

 On initialization, LogManager reads its configuration from a
 properties file, which by default is the "lib/logging.properties" in the JRE
 directory.

 However, two optional system properties can be used to customize the initial
 configuration process of LogManager.

"java.util.logging.config.class"

"java.util.logging.config.file"

 These two properties can be set in three ways, by the Preferences API, by the
 "java" command line property definitions, or by system property definitions
 passed to JNI_CreateJavaVM.

 The "java.util.logging.config.class" should specifies a class name. If it is
 set, this given class will be loaded and instantiated during
 LogManager initialization, so that this object's default
 constructor can read the initial configuration and define properties for
 LogManager.

 If "java.util.logging.config.class" property is not set, or it is invalid, or
 some exception is thrown during the instantiation, then the
 "java.util.logging.config.file" system property can be used to specify a
 properties file. The LogManager will read initial
 configuration from this file.

 If neither of these properties is defined, or some exception is thrown
 during these two properties using, the LogManager will read
 its initial configuration from default properties file, as described above.

 The global logging properties may include:

"handlers". This property's values should be a list of class names for
 handler classes separated by whitespace, these classes must be subclasses of
 Handler and each must have a default constructor, these
 classes will be loaded, instantiated and registered as handlers on the root
 Logger (the Logger named ""). These
 Handlers maybe initialized lazily.

"config". The property defines a list of class names separated by
 whitespace. Each class must have a default constructor, in which it can
 update the logging configuration, such as levels, handlers, or filters for
 some logger, etc. These classes will be loaded and instantiated during
 LogManager configuration

 This class, together with any handler and configuration classes associated
 with it, must be loaded from the system classpath when
 LogManager configuration occurs.

 Besides global properties, the properties for loggers and Handlers can be
 specified in the property files. The names of these properties will start
 with the complete dot separated names for the handlers or loggers.

 In the LogManager's hierarchical namespace,
 Loggers are organized based on their dot separated names. For
 example, "x.y.z" is child of "x.y".

 Levels for Loggers can be defined by properties whose name end
 with ".level". Thus "alogger.level" defines a level for the logger named as
 "alogger" and for all its children in the naming hierarchy. Log levels
 properties are read and applied in the same order as they are specified in
 the property file. The root logger's level can be defined by the property
 named as ".level".

 This class is thread safe. It is an error to synchronize on a
 LogManager while synchronized on a Logger.

Summary

Constants

        String
        LOGGING_MXBEAN_NAME
        The String value of the LoggingMXBean's ObjectName.

Protected Constructors

        <nobr>

            </nobr>

        <nobr>
        LogManager()</nobr>

Default constructor.

Public Methods

        <nobr>

            synchronized

            boolean</nobr>

        <nobr>
        addLogger(Logger logger)</nobr>

Add a given logger into the hierarchical namespace.

        <nobr>

            void</nobr>

        <nobr>
        addPropertyChangeListener(PropertyChangeListener l)</nobr>

Add a PropertyChangeListener, which will be invoked when
 the properties are reread.

        <nobr>

            void</nobr>

        <nobr>
        checkAccess()</nobr>

Does nothing.

        <nobr>

            static

            LogManager</nobr>

        <nobr>
        getLogManager()</nobr>

Get the global LogManager instance.

        <nobr>

            synchronized

            Logger</nobr>

        <nobr>
        getLogger(String name)</nobr>

Get the logger with the given name.

        <nobr>

            synchronized

            Enumeration<String></nobr>

        <nobr>
        getLoggerNames()</nobr>

Get a Enumeration of all registered logger names.

        <nobr>

            static

            LoggingMXBean</nobr>

        <nobr>
        getLoggingMXBean()</nobr>

Get the LoggingMXBean instance.

        <nobr>

            String</nobr>

        <nobr>
        getProperty(String name)</nobr>

Get the value of property with given name.

        <nobr>

            void</nobr>

        <nobr>
        readConfiguration()</nobr>

Re-initialize the properties and configuration.

        <nobr>

            void</nobr>

        <nobr>
        readConfiguration(InputStream ins)</nobr>

Re-initialize the properties and configuration from the given
 InputStream

 Notice : No PropertyChangeEvent are fired.

        <nobr>

            void</nobr>

        <nobr>
        removePropertyChangeListener(PropertyChangeListener l)</nobr>

Remove a PropertyChangeListener, do nothing if the given
 listener is not found.

        <nobr>

            synchronized

            void</nobr>

        <nobr>
        reset()</nobr>

Reset configuration.

  [Expand]

Inherited Methods

From class

  java.lang.Object

        <nobr>

            Object</nobr>

        <nobr>
        clone()</nobr>

Creates and returns a copy of this Object.

        <nobr>

            boolean</nobr>

        <nobr>
        equals(Object o)</nobr>

Compares this instance with the specified object and indicates if they
 are equal.

        <nobr>

            void</nobr>

        <nobr>
        finalize()</nobr>

Invoked when the garbage collector has detected that this instance is no longer reachable.

        <nobr>

            final

            Class<?></nobr>

        <nobr>
        getClass()</nobr>

Returns the unique instance of Class that represents this
 object's class.

        <nobr>

            int</nobr>

        <nobr>
        hashCode()</nobr>

Returns an integer hash code for this object.

        <nobr>

            final

            void</nobr>

        <nobr>
        notify()</nobr>

Causes a thread which is waiting on this object's monitor (by means of
 calling one of the wait() methods) to be woken up.

        <nobr>

            final

            void</nobr>

        <nobr>
        notifyAll()</nobr>

Causes all threads which are waiting on this object's monitor (by means
 of calling one of the wait() methods) to be woken up.

        <nobr>

            String</nobr>

        <nobr>
        toString()</nobr>

Returns a string containing a concise, human-readable description of this
 object.

        <nobr>

            final

            void</nobr>

        <nobr>
        wait()</nobr>

Causes the calling thread to wait until another thread calls the notify() or notifyAll() method of this object.

        <nobr>

            final

            void</nobr>

        <nobr>
        wait(long millis, int nanos)</nobr>

Causes the calling thread to wait until another thread calls the notify() or notifyAll() method of this object or until the
 specified timeout expires.

        <nobr>

            final

            void</nobr>

        <nobr>
        wait(long millis)</nobr>

Causes the calling thread to wait until another thread calls the notify() or notifyAll() method of this object or until the
 specified timeout expires.

Constants

        public
        static
        final
        String

        LOGGING_MXBEAN_NAME

  Added in API level 1

The String value of the LoggingMXBean's ObjectName.

        Constant Value:

                "java.util.logging:type=Logging"

Protected Constructors

        protected

      LogManager
      ()

  Added in API level 1

Default constructor. This is not public because there should be only one
 LogManager instance, which can be get by
 LogManager.getLogManager(). This is protected so that
 application can subclass the object.

Public Methods

        public

        synchronized
        boolean

      addLogger
      (Logger logger)

  Added in API level 1

Add a given logger into the hierarchical namespace. The
 Logger.addLogger() factory methods call this method to add newly
 created Logger. This returns false if a logger with the given name has
 existed in the namespace

 Note that the LogManager may only retain weak references to
 registered loggers. In order to prevent Logger objects from being
 unexpectedly garbage collected it is necessary for applications
 to maintain references to them.

Parameters

          logger
          the logger to be added.

Returns

true if the given logger is added into the namespace
         successfully, false if the given logger exists in the namespace.

        public

        void

      addPropertyChangeListener
      (PropertyChangeListener l)

  Added in API level 3

Add a PropertyChangeListener, which will be invoked when
 the properties are reread.

Parameters

          l
          the PropertyChangeListener to be added.

        public

        void

      checkAccess
      ()

  Added in API level 1

Does nothing.

        public
        static

        LogManager

      getLogManager
      ()

  Added in API level 1

Get the global LogManager instance.

Returns

the global LogManager instance

        public

        synchronized
        Logger

      getLogger
      (String name)

  Added in API level 1

Get the logger with the given name.

Parameters

          name
          name of logger

Returns

logger with given name, or null if nothing is found.

        public

        synchronized
        Enumeration<String>

      getLoggerNames
      ()

  Added in API level 1

Get a Enumeration of all registered logger names.

Returns

enumeration of registered logger names

        public
        static

        LoggingMXBean

      getLoggingMXBean
      ()

  Added in API level 3

Get the LoggingMXBean instance. this implementation always throws
 an UnsupportedOperationException.

Returns

the LoggingMXBean instance

        public

        String

      getProperty
      (String name)

  Added in API level 1

Get the value of property with given name.

Parameters

          name
          the name of property

Returns

the value of property

        public

        void

      readConfiguration
      ()

  Added in API level 1

Re-initialize the properties and configuration. The initialization
 process is same as the LogManager instantiation.

 Notice : No PropertyChangeEvent are fired.

Throws

            IOException
            if any IO related problems happened.

        public

        void

      readConfiguration
      (InputStream ins)

  Added in API level 1

Re-initialize the properties and configuration from the given
 InputStream

 Notice : No PropertyChangeEvent are fired.

Parameters

          ins
          the input stream

Throws

            IOException
            if any IO related problems happened.

        public

        void

      removePropertyChangeListener
      (PropertyChangeListener l)

  Added in API level 3

Remove a PropertyChangeListener, do nothing if the given
 listener is not found.

Parameters

          l
          the PropertyChangeListener to be removed.

        public

        synchronized
        void

      reset
      ()

  Added in API level 1

Reset configuration.

All handlers are closed and removed from any named loggers. All loggers'
 level is set to null, except the root logger's level is set to
 Level.INFO.

  Except as noted, this content is licensed under Apache 2.0.
  For details and restrictions, see the
  Content License.

    Android 4.4 r1 —

    About Android  |
    Legal  |
    Support


text:
Nucleus 2 is a major rewrite of much of the base code. It is designed to make future work to the system simpler, easier to understand, and hopefully, easier for people to contribute to.

As it stands, Nucleus 2 is semi-stable, but please do not use it on production servers without testing first. I would appreciate any testing I can get. I am only one person!

Here is a rundown of some of what is new, changed, removed, fixed and crucially, known to be broken.

# PSA: Before you use Nucleus 2...

Nucleus 2 does not change how your data is stored, but the entire storage system has been completely rewritten. There may be issues with the storage system that I have been unable to test that might cause unexpected data loss. If this happens, please tell me via Github Issues.

No migration is necessary for the following:

* `main.conf`
* `info.txt` and other info files
* User data
* World data
* Kits, warps, and other general data

Nucleus 2 also uses a new format for the `commands.conf` file and no migrator has been provided.

Also, a note on the version. The Nucleus version will no longer contain the Sponge API version that it is built for, instead preferring new major versions to denote the change. This will still be denoted in the file name.

Nucleus 2 is for Sponge API 7.3 or any later version of Sponge API 7.x.

## For Server Owners and Players

If you need help to decide which version of Nucleus to use, [please visit our guide on how to choose](https://v2-beta.nucleuspowered.org/docs/howto/version-choice.html).

For the things YOU need to do as a server owner, [please visit our instructions on how to upgrade](https://v2-beta.nucleuspowered.org/docs/howto/migrate.html).

### ADDED: Permission Levels/Powers for moderation tasks

Many of you have been asking "permission levels" because you don't trust lower level staff to not abuse their powers and use them against higher level staff. They already existed for social spy, but now they exist for muting, jailing, kicking and banning. This feature allows you to give a numeric level to each player - by default, if your level is higher than the person you're trying to act upon, your action will go through. By default, those with the same power for an action will not be able to affect each other.

Because this is an advanced feature, you must turn it on for the respective modules. The options in the `mute`, `jail`, `kick`, `admin` (for `/sudo`) and `ban` modules are:

* `use-permission-level`: set to `true` to use permission levels
* `can-affect-same-level`: set to `true` to let two players with the same permission level affect each other, `false` if not.

To specify a permission level, you have to give a specific permission option to the player in question. In LuckPerms, options are referred to as "meta". The options you need to assign are specified in the config file (at least for now, will be on docs later), but for convenience, they are:

* `nucleus.ban.level`
* `nucleus.jail.level`
* `nucleus.kick.level`
* `nucleus.mute.level`
* `nucleus.sudo.level`
* `nucleus.socialspy.level` (this already existed)

No prizes for guessing which one is which! In LuckPerms, you would then specify the level an option using the command:

```
/lp user <user> meta set <option> <level>
```

For a ban level of 4 on dualspiral:

```
/lp user dualspiral meta set nucleus.ban.level 4
```

If a level is invalid or does not exist, having the permission to run the command you are running is considered a level of 1, not having the permission is considered a level of 0.

**This has only been lightly tested. Please report any feedback on the system to me during your testing.**

### ADDED: Ability to specify arbitrary command names for Nucleus commands (EXPERIMENTAL)

Nucleus commands can now be given arbitrary command names in `commands.conf` under the "root level aliases" section, and Nucleus will attempt to register the command under that alias.

This feature is still subject to some testing, but I realised it was easy to add with the new codebase.

### ADDED: Per User translation of Nucleus system messages

Nucleus will support sending translated messages to players based on either:

* The locale set via `/nucleussetlanguage` on a per-player basis; or
* The client's locale.

This will be available as we (hopefully) receive more translations.

You will be able to turn this off, of course, if you want all clients to see the same language.

(If you want to help with the translation effort, see https://v2-beta.nucleuspowered.org/docs/translation/)

### ADDED: Permission context when running a Nucleus command

When a player is running a Nucleus command, they will obtain a permission context for the duration of that call. This context is `nucleus_command`, and will have a context value corresponding to the command in question - this can be seen by looking at the help page for the command in question.

### ADDED: Compatibility Warning system

Nucleus comes packaged with information about known plugins and mods that conflict with its functions. These warnings may appear on startup, and on demand by running `/nucleus compat`.

### ADDED: Kit data can now be reloaded from persistence on demand

I don't recommend that you ever do this manually, but you can now update the kits data from persistence and reload it using `/kit reload`.

### ADDED: `/basictitle`, `/basicsubtitle` and `/basicactionbar` commands

These commands allow you to send title, subtitle and actionbar messages to all or specific players. They work the same way as `/planbroadcast`. The flags for these commands are:

* `-p [player]`: The name of the player or a selector that defines who to send the message to. If omitted, sends to all on the server.
* `-i [seconds]`: The amount of time taken by the fade in effect, in seconds (does not affect action bar messages).
* `-o [seconds]`: The amount of time taken by the fade out effect, in seconds.
* `-t [seconds]`: The amount of time taken the message remains on the screen, in seconds.

### ADDED: Notification module

This module houses the broadcast commands, as well as the new `/basictitle`, `/basicsubtitle` and `/basicactionbar` commands. Relaxant config from the admin module will be auto-migrated.

### ADDED: Support for automatic USER permissions on the default group

Particularly useful for OP based servers, if you want all players to have access to all permissions in the nucleus USER role, you can now set `core.give-default-group-user-permissions` to
`true` and all users will be granted all permissions in the USER role. This is equivalent to granting the `nucleus.user` permission, but can also be used on servers with no permissions plugin installed.

### MODIFIED: Chat tokens no longer accept `pl` style tokens

Chat tokens work similar to before, but are no longer plugin namespaced (so, `{{pl:[]}}` will no longer work). `{{o:[]}}` style tokens, those that select options from your permissions plugin, will still work.

### MODIFIED: The `/tp` alias for `/teleport` defaults to disabled

Many mods, such as JourneyMap, were using the `/tp` command to perform teleports

Other commands may get the same treatment if the Nucleus team figures that it would be in the best interest of the community.

### MODIFIED: The `/mute` and `/unmute`, `/jail` and `/unjail` commands are no longer toggles

This also has the side effect of making these actions all require their own permission.

### MODIFIED: Warps now always require the permission `nucleus.warps.<name>` to redeem

Until recently, this was a configuration toggle. This is no longer the case. To emulate the previous behaviour, simply grant the `nucleus.warps` permission.

### MODIFIED: Permission Group Chat Templates

The original way Nucleus attempted to determine which group template to use when displaying chat formatting was unpredictable and was very slow as it had to collect a lot of data from a permissions plugin. This has now been removed.

Nucleus has supported a `nucleus.chat.group` permission option (meta in LuckPerms) for some time. This option is now the only way to determine the group template a permission group or user will use - falling back to the default if this does not match.

### MODIFIED: Permission Group `/list` groups

For similar reasons to chat groups no longer relying on parent groups, `/list` no longer does either. Groups are now defined by the `nucleus.list.group` option/meta.
The group alias config has also been removed, as you can just provide them the same `nucleus.list.group` option value.

As a bonus, `/list` groups now use text colour codes in the group names.

### MODIFIED: `/kit add` has been merged into `/kit create`

The action performed by `/kit add` in v1 was to create a kit based on your inventory. This is now `/kit create -c` instead.

Both `/kit create` and `/kit create -c` now require the edit kit permission to actually add items to kits.

### REMOVED: Debug Mode

Nucleus will just spit out errors to the console now, as they should never happen (or if they do, you should know about them).

### REMOVED: The Warnings module has been removed

It wasn't used much and, honestly, it was actually pushing the boundaries as to what Nucleus really should be doing. There are no migration paths available as it stands, however plugin developers can use the Nucleus API to extract any warnings against a player if they wish to enable such migration.

### REMOVED: The Server Shop module has been removed

It wasn't used much, and it had many issues with it that were not simple to fix. There are no migration paths available.

### REWRITTEN: Teleportation Routines

Player teleportation should now be more reliable as the base teleport code has been deleted and completely rebuilt.

### REWRITTEN: Message channel support removed for higher compatibility with other plugins

Nucleus will no longer use message channels, instead using an in-house solution to support formatting with other mods, (and for reporting formatting to other plugins). However, when possible, the message channels will still be applied to the event so plugins can see that Nucleus is doing something with them.

### BUG FIXES: Miscellaneous fixes

While many bugs might have been introduced, other bugs have been fixed. Notable issues that have been fixed will be noted here.

## For Plugin Developers that use the API

### REMOVED: The Nucleus static object

I'm going to start with something that isn't in the API - `Nucleus.getNucleus()`. I've had the occasional complaint that updates to Nucleus have broken some plugins that depend on it. It always turns out to be developers not asking for API additions (which I try to guarantee) but just decide to use `Nucleus.getNucleus()` everywhere. Don't do it - I do not class that as part of the API and it was a horrible object that allowed me to be lazy. v2 is about stopping me being lazy.

You shouldn't do it anyway, but you will not be able to do it at all in v2, because the `Nucleus` object has been deleted. Please use the API. If there is something missing from the API that you wish to use, please open a Github issue.

### MODIFIED: The location of nearly everything

To try to make things a little more sane, all APIs are now classified by their module or overreaching theme first, rather than whether they are a service, event etc. This should make it simpler to see what APIs are available for each module.

### MODIFIED: TeleportResults is now TeleportResult, an enum. Other CatalogTypes are now Suppliers

`TeleportResult` is now an enum. Other `CatalogType`s are now represented by `Supplier`s to remove reliance on hacky reflection techniques.

### MODIFIED: The Kit API has been updated

A failed redemption will no longer throw a `KitRedeemException`. Instead, a `KitRedeemResult` will be returned and that will tell you if about the success (or failure).

You can also now get the status of a cooldown for a `Kit`/`User` combination.

### REMOVED: NucleusMessageTokenService has been removed in favour of the SpongeAPI 7.3 placeholder solution

The message token service has been completely removed, Nucleus now supports the SpongeAPI 7.3 central placeholder system.

Nucleus Gluon v1 will no longer work for supporting placeholder API tokens.

### REMOVED: Nucleus MessageChannels

**These will be restored in a marker capacity only**

In order to enable Nucleus formatting in chat events and to avoid future conflicts with other plugin message channels, Nucleus will now apply its formatting during the `MessageChannelEvent.Chat` event, and will no longer use `MessageChannel`s for formatting. Nucleus will dynamically create message channels during the `LATE` priority.

As a result, no API for message channels is available in the API.

### REMOVED: NucleusModuleService

The `NucleusModuleService` has been removed. Plugins wishing to disable modules should listen to the `NucleusModuleEvent.AboutToConstruct` event instead.

### MODIFIED: All kinds of stuff

Please take a look through the API yourself for now. It's all subject to change, but I have tried to add sensible documents. I will flesh out this section once we approach Beta.

## For Developers considering contributing to Nucleus

Nucleus' biggest changes have happened in this area. v2 no longer uses the static Nucleus object, but instead uses Guice and DI to create a series of cross cutting concerns to provide Nucleus wide actions. Commands, listeners and tasks should all have `INucleusServiceCollection` injected into themselves for access to these systems.

### MODIFIED: Nucleus now uses Gradle 5.6.4

We have jumped from Gradle 4.10 to 5.6.4, as this is the last version that the SpongeGradle plugin has been tested with.

### MODIFIED: Nucleus Implementation has been moved to the `nucleus-core` subproject

This gives a cleaner separation of the project, and allows for other sub projects to be added more easily. The root project now handles project wide actions only.

### MODIFIED: Nucleus now uses the Kotlin DSL

The build scripts have been rewritten in Kotlin to improve type safety and being some more order to the scripts.

---

For more information, have a look around our documentation site at https://v2-beta.nucleuspowered.org/docs.


text:
layout: post
title:  "Jumping into Arrays!!!"
date:   2017-07-30 21:45:59 +0000
---

Today was all about Jumping into Arrays in Ruby. It was getting the family to finally work together as a group.
Arrays store pieces of data in a collection and retrieves a certain element by referring to it's position.
They can contain all kinds of things such as strings, intergers, hashes, etc.
It is best practice to stay with one element at a time.

A defined variable with [] is the proper syntax.
I discovered new gateways of behavior such as the shovel method, .push, .unshift, .pop and .shift.
These methods give the elements in a program the ability of movement with organization.

Completing the tic tac toe lab you were able to practice and experience how beneficial they are to coding.

Can't wait to see what next !!!


text:
package jp.co.exacorp.matchingapp.logic.api;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.ejb.Stateless;
import javax.net.ssl.HttpsURLConnection;

import jp.co.exacorp.matchingapp.util.Constants;
import jp.co.exacorp.matchingapp.util.LINEConstants;

@Stateless
public class LineReplyAPIContact {

	public void sendMessageToReplyAPI (String mesJson) {
		HttpURLConnection con = null;
		PrintWriter pw = null;
		BufferedReader br = null;

		System.out.println(mesJson);

		try {
			con = (HttpsURLConnection) new URL(LINEConstants.LINE_REPLY_API).openConnection();
			con.setDoOutput(true);
			con.setUseCaches(false);
			con.setRequestMethod("POST");
			con.setConnectTimeout(10000);
			con.setRequestProperty("Content-Type", "application/json" );
			con.setRequestProperty("Authorization",  "Bearer " + LINEConstants.LINE_CHANNEL_ACCESS_TOKEN);
			pw = new PrintWriter(new OutputStreamWriter(con.getOutputStream(), Constants.CHARSET));
			pw.print(mesJson);
			pw.close();
			if (con.getResponseCode() == HttpURLConnection.HTTP_OK) {
				System.out.println("Reply API OK");
				br = new BufferedReader(new InputStreamReader(con.getInputStream(), Constants.CHARSET));
				br.readLine();
				br.close();
			} else {
				System.out.println("HTTP response is " + con.getResponseCode());
				br = new BufferedReader(new InputStreamReader(con.getErrorStream(), Constants.CHARSET));
				System.out.println(br.readLine());
				br.close();

			}
		} catch (Exception e ){
			e.printStackTrace();
		}
		return;
	}
}


text:
package main

import (
	"context"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	util "github.com/shijuvar/gokit/examples/bookmark-api/apputil"
	"github.com/shijuvar/gokit/examples/bookmark-api/bootstrapper"
	"github.com/shijuvar/gokit/examples/bookmark-api/router"
)

// Entry point of the program
func main() {

	// Calls startup logic
	bootstrapper.StartUp()
	// Get the mux router object
	router := router.InitRoutes()

	// Create the Server
	server := &http.Server{
		Addr:     bootstrapper.AppConfig.Server,
		Handler:  router,
		ErrorLog: util.Error,
	}

	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)

	// Running the HTTP server
	go func() {
		server.ListenAndServe()
	}()

	interruptSignal := <-interrupt
	switch interruptSignal {
	case os.Kill:
		util.Error.Print("Got SIGKILL...")
	case os.Interrupt:
		util.Error.Print("Got SIGINT...")
	case syscall.SIGTERM:
		util.Error.Print("Got SIGTERM...")
	}

	util.Info.Print("The service is shutting down...")
	server.Shutdown(context.Background())
	util.Info.Print("Shut down is done")
}


text:
package org.simmetrics.metrics;

import static com.google.common.base.Preconditions.checkNotNull;

import org.simmetrics.Distance;
import org.simmetrics.Metric;

/**
 * Identity similarity and distance metric that returns a distance of 0.0 and
 * similarity 1.0 when the inputs are equals, and vice-versa when they're not.
 *

 *
 * similarity(a,b) = equals(a,b) ? 1.0f : 0.0f
 *

 * distance(a,b) = equals(a,b) ? 0.0f : 1.0f
 *
 *

 * This class is immutable and thread-safe.
 *
 * @param <T>
 *            type of token
 */
public final class Identity<T> implements Metric<T>, Distance<T> {

	@Override
	public float compare(T a, T b) {
		checkNotNull(a);
		checkNotNull(b);
		return a.equals(b) ? 1.0f : 0.0f;
	}

	@Override
	public float distance(T a, T b) {
		checkNotNull(a);
		checkNotNull(b);
		return a.equals(b) ? 0.0f : 1.0f;
	}

	@Override
	public String toString() {
		return "Identity";
	}
}