% PURPOSE: Converts decoded "bin descriptor(s)" into a numeric structure, in order to be used by binlister.
%
% FORMAT:
%
% [BIN, isparsednumerically] = bdf2struct(BIN)
%
% Inputs:
%
%   BIN                    - BIN structure containing "bin descriptor(s)"
%
% Output
%
% BIN                      - BIN structure
% isparsednumerically      - boolean, 1=everything ok; 0= there is error.
%
%
% See binlister.m, decodebdf.m
%
%
% *** This function is part of ERPLAB Toolbox ***
% Author: Javier Lopez-Calderon
% Center for Mind and Brain
% University of California, Davis,
% Davis, CA
% 2009

%b8d3721ed219e65100184c6b95db209bb8d3721ed219e65100184c6b95db209b
%
% ERPLAB Toolbox
% Copyright ? 2007 The Regents of the University of California
% Created by Javier Lopez-Calderon and Steven Luck
% Center for Mind and Brain, University of California, Davis,
% javlopez@ucdavis.edu, sjluck@ucdavis.edu
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.

function [BIN, isparsednumerically] = bdf2struct(BIN, allowMixedSigns)

% allowMixedSigns ... allows the event codes within one '{}' to have
%                     different signs

if nargin < 2 || isempty(allowMixedSigns)
    allowMixedSigns = false;
end

if nargin < 1
        help bdf2struct
        return
end

%
% For debugging...
%
condition  = 0;  % 1 = displays processing comments;  0 = don't do that!

%
% Since the data extraction routine is the same for prehome, athome, and
% posthome, we will use the variable logEventSelector for looping.
%
isparsednumerically = 1;    % Numeric parsing is approved by default
logEventSelector{1} = 'prehome';  %(log event selector = LES)
logEventSelector{2} = 'athome';
logEventSelector{3} = 'posthome';
nBin = length(BIN);
fprintf('\n');

for iBin = 1:nBin       % Bin's loop

        isworkingFine = 1;   %boolean condition if everything goes well
        jLogES = 1;

        while  (jLogES <= length(logEventSelector)) && (isworkingFine) % LES's loop

        % Take each field and divide it by curly braces = sequencers
                [segmentedBrackets]    =   regexp(BIN(iBin).expression(jLogES), '.+?\d+.*?}', 'match');
                % Detects special codes as * (all) and ~* (none)
                [spCodes specialCodesToken]    =   regexp(BIN(iBin).expression(jLogES), '(\~)*(\*+)', 'match','tokens');  % 21 febrero 2008!

                if ~isempty(segmentedBrackets{:}) && isempty(spCodes{:})  % The sequencer exists and is numeric
                        nSequencer = length(segmentedBrackets{:});             % Number of sequencers
                        auxt1pre = [];
                        auxt2pre = [];

                        for kSequencer = 1:nSequencer                          % Sequencer's loop
                                %
                                % extract each sequencer from one to nSequencer, one by one
                                %
                                sequencerString = char(segmentedBrackets{1}(kSequencer));
                                sequencerString = regexprep(sequencerString, ':rt<".*?">', ''); % hides reaction time (if any)

                                %
                                % Check if sequencer are simple or they
                                % have more complex conditions like time,
                                % flags, etc.

                                storeCode   = [];
                                storeSign   = [];
                                catch_IC    = [];
                                catch_Sign  = []; % catchs interval code ans sign

                                %
                                % First, searchs event code given as an interval e.g {1-10;30-40}
                                % Careful: There might be several of these
                                % defined intervals
                                %
                                [intervalString intervalToken] = regexp(sequencerString, '[{;,>](\~*)(\d+)\-(\d+)',...
                                        'match','tokens'); % 4 February: added on">"

                                if ~isempty(intervalToken)   % Only if intervals were found
                                        coluInTok = size(intervalToken,2);
                                        pointerInterval   = 1;
                                        dispcond( condition, 'There is a specified interval x !')

                                        % generate all number given by interval
                                        for k = 1:coluInTok
                                                intervalCodeStart = str2double(cell2mat(intervalToken{k}(2)));
                                                intervalCodeStop  = str2double(cell2mat(intervalToken{k}(3)));

                                                if intervalCodeStart == intervalCodeStop
                                                        catch_IC(pointerInterval) = intervalCodeStart;

                                                        if strcmp(char(intervalToken{k}(1)),'~')    % There is negation
                                                                catch_Sign(pointerInterval) = 0;
                                                        else                                        % There is no negation
                                                                catch_Sign(pointerInterval) = 1;
                                                        end

                                                        pointerInterval = pointerInterval + 1;
                                                        dispcond( condition, 'but the values are equals...')

                                                elseif intervalCodeStart < intervalCodeStop

                                                        intervalArray = intervalCodeStart : intervalCodeStop;
                                                        catch_IC( pointerInterval:length(intervalArray) + pointerInterval - 1 ) = intervalArray;

                                                        if strcmp(char(intervalToken{k}(1)),'~')  % There is negation
                                                                catch_Sign( pointerInterval:length(intervalArray) + pointerInterval - 1 ) = zeros(1,length(intervalArray));
                                                        else                             % THere is no negation
                                                                catch_Sign( pointerInterval:length(intervalArray) + pointerInterval - 1 ) = ones(1,length(intervalArray));
                                                        end

                                                        pointerInterval = pointerInterval + length(intervalArray);
                                                        dispcond( condition, 'building a list from the specified interval !')

                                                else
                                                        fprintf('Fatal Error: bad ordered interval at BIN:%g\n', iBin);
                                                        isparsednumerically = 0;  % Numeric parsin was not approved
                                                        return
                                                end
                                                storeCode = catch_IC;      %28 feb 2008
                                                storeSign = catch_Sign;              %28 feb 2008
                                        end
                                        % sort generated event code list
                                        [auxMatrix] = cat(1,storeCode, storeSign)';
                                        [MatSorted] = sortrows(auxMatrix,1);
                                        storeCode   = MatSorted(:,1)';
                                        storeSign   = MatSorted(:,2)';
                                        storeTime   = repmat(-1,length(storeCode),2);
                                        storeFlag   = repmat(uint16(0),1, length(storeCode));
                                        storeFmask  = repmat(uint16(0),1, length(storeCode));
                                        storeWrite  = repmat(uint16(0),1, length(storeCode));
                                        storeWmask  = repmat(uint16(0),1, length(storeCode));
                                        % replacements...
                                        sequencerString = regexprep(sequencerString, '>(\~*)(\d+)\-(\d+)', '>1000000');
                                        sequencerString = regexprep(sequencerString, '(\~*)(\d+)\-(\d+):f', '2000000:f');
                                        sequencerString = regexprep(sequencerString, '(\~*)(\d+)\-(\d+):w', '3000000:w');
                                        sequencerString = regexprep(sequencerString, '(\~*)(\d+)\-(\d+)[,;}]', '');
                                        dispcond(condition,'Erasing Interval Expressions......')
                                else
                                        storeCode  = []; % There is no defined interval eventcode
                                        storeSign  = [];
                                        storeTime  = [];
                                        storeFlag  = [];
                                        storeFmask = [];
                                        storeWrite = [];
                                        storeWmask = [];
                                        dispcond( condition, 'there was not a specified interval ...')
                                end

                                %
                                % Second, detect discrete format for event code e.g {1;2;3;4} or {1,2,3,4}
                                %
                                [ma2 cod] = regexp(sequencerString, '[{;,](\~*)(\d+)(?=[;,}])',...
                                        'match','tokens') ;

                                if ~isempty(cod)
                                        dispcond( condition, 'There is a discrete event code!')
                                        auxSign = zeros(1,length(ma2));
                                        catchSingleCode    = zeros(1,length(ma2));

                                        for m = 1:length(ma2) % For each unique code detected
                                                dispcond( condition, 'extracting discrete event code!')
                                                catchSingleCode(m) = str2double(cell2mat(cod{m}(2)));

                                                if strcmp(char(cod{m}(1)),'~')  % There is negation
                                                        auxSign(m) = 0;
                                                else
                                                        auxSign(m) = 1;         % There is no negation
                                                end
                                        end

                                        storeCode   = cat(2,storeCode, catchSingleCode);
                                        storeSign   = cat(2,storeSign, auxSign);
                                        [auxMatrix] = cat(1,storeCode, storeSign)';
                                        [MatSorted] = sortrows(auxMatrix,1);
                                        dispcond( condition, 'Showing "simple" Values of complex expressions:',...
                                                storeCode, storeSign, storeTime, storeFlag, storeWrite)
                                        storeCode   = MatSorted(:,1)';
                                        storeSign   = MatSorted(:,2)';
                                        storeTime   =  repmat(-1,   length(storeCode),2);
                                        storeFlag   =  repmat(uint16(0),1, length(storeCode));
                                        storeFmask  =  repmat(uint16(0),1, length(storeCode));
                                        storeWmask  =  repmat(uint16(0),1, length(storeCode));
                                        storeWrite  =  repmat(uint16(0),1, length(storeCode));

                                        %**********************************************************
                                else
                                        dispcond( condition, 'there was not a discret complex interval ...')
                                end

                                %
                                % Now it searches for time specification and/or flag
                                %
                                dispcond( condition, 'EXTRACTING T, F, y W')
                                % All possible combinations!!!

                                expp =  cell(1);
                                expp{1}  = 't<(\d+)+-(\d+)+>(\~)*(\d+)+:f<(\w+)+>:w<(\w+)+>';    % 1  full-flag full-write
                                expp{2}  = 't<(\d+)+-(\d+)+>(\~)*(\d+)+:f<(\w+)+>(\TONGO)*';     % 2  full-flag ----------
                                expp{3}  = 't<(\d+)+-(\d+)+>(\~)*(\d+)+(\TONGO)*:w<(\w+)+>';     % 3  --------- full-write
                                expp{4}  = 't<(\d+)+-(\d+)+>(\~)*(\d+)+(\TONGO)*(\TONGO)*';      % 4  --------- ----------
                                expp{5}  = '(\TONGO)*(\TONGO)*(\~)*(\d+):f<(\w+)+>:w<(\w+)+>';   % 5  full-flag full-write
                                expp{6}  = '(\TONGO)*(\TONGO)*(\~)*(\d+):f<(\w+)+>(\TONGO)*';    % 6  full-flag ----------
                                expp{7}  = '(\TONGO)*(\TONGO)*(\~)*(\d+)+(\TONGO)*:w<(\w+)+>';   % 7  --------- full-write

                                expp{8}  = 't<(\d+)+-(\d+)+>(\~)*(\d+)+:fa<(\w+)+>:wa<(\w+)+>';  % 8  low-flag  low-write
                                expp{9}  = 't<(\d+)+-(\d+)+>(\~)*(\d+)+:fa<(\w+)+>:wb<(\w+)+>';  % 9  low-flag  high-write
                                expp{10} = 't<(\d+)+-(\d+)+>(\~)*(\d+)+:fb<(\w+)+>:wa<(\w+)+>';  % 10  high-flag low-write
                                expp{11} = 't<(\d+)+-(\d+)+>(\~)*(\d+)+:fb<(\w+)+>:wb<(\w+)+>';  % 11 high-flag high-write

                                expp{12} = 't<(\d+)+-(\d+)+>(\~)*(\d+)+:fa<(\w+)+>(\TONGO)*';    % 12 low-flag  ----------
                                expp{13} = 't<(\d+)+-(\d+)+>(\~)*(\d+)+:fb<(\w+)+>(\TONGO)*';    % 13 high-flag ----------
                                expp{14} = 't<(\d+)+-(\d+)+>(\~)*(\d+)+(\TONGO)*:wa<(\w+)+>';    % 14 --------- low-write
                                expp{15} = 't<(\d+)+-(\d+)+>(\~)*(\d+)+(\TONGO)*:wb<(\w+)+>';    % 15 --------- high-write

                                expp{16} = '(\TONGO)*(\TONGO)*(\~)*(\d+):fa<(\w+)+>:wa<(\w+)+>'; % 16 low-flag low-write
                                expp{17} = '(\TONGO)*(\TONGO)*(\~)*(\d+):fa<(\w+)+>:wb<(\w+)+>'; % 17 low-flag high-write
                                expp{18} = '(\TONGO)*(\TONGO)*(\~)*(\d+):fb<(\w+)+>:wa<(\w+)+>'; % 18 high-flag low-write
                                expp{19} = '(\TONGO)*(\TONGO)*(\~)*(\d+):fb<(\w+)+>:wb<(\w+)+>'; % 19 high-flag high-write

                                expp{20} = '(\TONGO)*(\TONGO)*(\~)*(\d+):fa<(\w+)+>(\TONGO)*';   % 20 low-flag  ---------
                                expp{21} = '(\TONGO)*(\TONGO)*(\~)*(\d+):fb<(\w+)+>(\TONGO)*';   % 21 high-flag ---------
                                expp{22} = '(\TONGO)*(\TONGO)*(\~)*(\d+)+(\TONGO)*:wa<(\w+)+>';  % 22 --------- low-write
                                expp{23} = '(\TONGO)*(\TONGO)*(\~)*(\d+)+(\TONGO)*:wb<(\w+)+>';  % 23 --------- high-write

                                auxstr   = sequencerString;
                                countexp = zeros(1,length(expp));  % January 28,2008
                                istimedetected = 0;   % boolean
                                isflagdetected = 0;   % boolean
                                isWritedetected= 0;   % boolean

                                for e = 1:length(expp)

                                        [mtr rtimes] = regexp(auxstr, expp{e},'match','tokens');

                                        if ~isempty(mtr)
                                                countexp(e) = length(mtr); % Test the take-all event (*)

                                                for n = 1:countexp(e)

                                                        catchComplexExpression = [rtimes{n}(1) rtimes{n}(2) rtimes{n}(4) rtimes{n}(5)...
                                                                rtimes{n}(6)];

                                                        t1 = str2double(cell2mat(catchComplexExpression(1)));
                                                        t2 = str2double(cell2mat(catchComplexExpression(2)));
                                                        captureCode = str2double(cell2mat(catchComplexExpression(3)));

                                                        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
                                                        % Capture Flag (f, fa, and fb)
                                                        %
                                                        strflag = catchComplexExpression{4};
                                                        lestrf  = length(strflag);

                                                        if ismember_bc2(e,[1 2 5 6]) % full flag (16bits)
                                                                if lestrf > 16
                                                                        fprintf('Fatal Error: BIN %g. 16-bit Flag (f<>) format was violated',iBin)
                                                                        isparsednumerically = 0;  % Numeric parsing was not approved
                                                                        return
                                                                elseif lestrf <= 16 && lestrf >= 1

                                                                        %  Steve's option: always 'x' replaces blanks
                                                                        %  Example:  Flag = 10011  means xxxxxxxxxxx10011
                                                                        %  Example:  Flag = x10011  means xxxxxxxxxxx10011
                                                                        %
                                                                        if strflag(1)=='1' || strflag(1)=='0'
                                                                                strflag = [repmat('x',1, 16-lestrf) strflag];
                                                                        else
                                                                                strflag = [repmat('x',1, 16-lestrf) strflag];
                                                                        end
                                                                end
                                                        elseif ismember_bc2(e,[8 9 12 16 17 20]) % fa = low flag  = LSB byte = artifact flag

                                                                if lestrf > 8
                                                                        fprintf('Fatal Error: BIN %g. 8-bit Flag (fa<>) format was violated',iBin)
                                                                        isparsednumerically = 0;  % Numeric parsing was not approved
                                                                        return
                                                                elseif lestrf <= 8 && lestrf >= 1

                                                                        %  Steve's option: always 'x' replaces blanks
                                                                        %  Example:  Flag = 10011   means xxxxxxxxxxx10011
                                                                        %  Example:  Flag = x10011  means xxxxxxxxxxx10011
                                                                        %
                                                                        if strflag(1)=='1' || strflag(1)=='0'
                                                                                strflag = [repmat('x',1, 16-lestrf) strflag];
                                                                        else
                                                                                strflag = [repmat('x',1, 16-lestrf) strflag];
                                                                        end
                                                                end
                                                        elseif ismember_bc2(e,[10 11 13 18 19 21]) % fb = high flag  = MSB byte = user? flag

                                                                if lestrf > 8
                                                                        fprintf('Fatal Error: BIN %g. 8-bit Flag (fb<>) format was violated',iBin)
                                                                        isparsednumerically = 0;  % Numeric parsing was not approved
                                                                        return
                                                                elseif lestrf <= 8 && lestrf >= 1

                                                                        %  Steve's option: always 'x' replaces blanks
                                                                        %  Example:  Flag = 10011   means xxx10011xxxxxxxx
                                                                        %  Example:  Flag = x10011  means xxx10011xxxxxxxx
                                                                        %
                                                                        if strflag(1)=='1' || strflag(1)=='0'
                                                                                strflag = [repmat('x',1, 8-lestrf) strflag repmat('x',1, 8)];
                                                                        else
                                                                                strflag = [repmat('x',1, 8-lestrf) strflag repmat('x',1, 8)];
                                                                        end
                                                                end
                                                        end

                                                        [matf, tokf, indxf] = regexpi(strflag, '0|1','match','tokens','start');

                                                        if isempty(indxf)
                                                                captureFlag    = uint16(bin2dec(strflag));
                                                                maskFlagstring = '1111111111111111';
                                                                captFlagMask   = uint16(bin2dec(maskFlagstring)); % Flag's Logic Mask
                                                        else
                                                                strflag        =  regexprep(strflag, 'x','0','ignorecase');
                                                                captureFlag    = uint16(bin2dec(strflag));
                                                                maskFlagstring = repmat('0', 1, 16);
                                                                maskFlagstring(indxf) = '1';
                                                                captFlagMask   = uint16(bin2dec(maskFlagstring)); % Flag's Logic Mask
                                                        end

                                                        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
                                                        % Capture Write and masking  10-27-2008
                                                        %
                                                        strWrite = catchComplexExpression{5};
                                                        lestrs  = length(strWrite);

                                                        if ismember_bc2(e,[1 3 5 7]) % full Write (16bits)
                                                                if lestrs > 16
                                                                        fprintf('Fatal Error: BIN %g. 16-bit Write (w<>) format was violated',iBin)
                                                                        isparsednumerically = 0;  % Numeric parsing was not approved
                                                                        return
                                                                elseif lestrs <= 16 && lestrs >= 1

                                                                        %  Steve's option: always 'x' replaces blanks
                                                                        %  Example:  Flag = 10011  means xxxxxxxxxxx10011
                                                                        %  Example:  Flag = x10011  means xxxxxxxxxxx10011
                                                                        %
                                                                        if strWrite(1)=='1' || strWrite(1)=='0'
                                                                                strWrite = [repmat('x',1, 16-lestrs) strWrite];
                                                                        else
                                                                                strWrite = [repmat('x',1, 16-lestrs) strWrite];
                                                                        end
                                                                end
                                                        elseif ismember_bc2(e,[8 10 14 16 18 22]) % wa = low write  = LSB byte = artifact write

                                                                if lestrs > 8
                                                                        fprintf('Fatal Error: BIN %g. 8-bit Write (wa<>) format was violated',iBin)
                                                                        isparsednumerically = 0;  % Numeric parsing was not approved
                                                                        return
                                                                elseif lestrs <= 8 && lestrs >= 1

                                                                        %  Steve's option: always 'x' replaces blanks
                                                                        %  Example:  write = 10011   means xxxxxxxxxxx10011
                                                                        %  Example:  write = x10011  means xxxxxxxxxxx10011
                                                                        %
                                                                        if strWrite(1)=='1' || strWrite(1)=='0'
                                                                                strWrite = [repmat('x',1, 16-lestrs) strWrite];
                                                                        else
                                                                                strWrite = [repmat('x',1, 16-lestrs) strWrite];
                                                                        end
                                                                end
                                                        elseif ismember_bc2(e,[9 11 15 17 19 23]) % wb = high write  = MSB byte = user? write

                                                                if lestrs > 8
                                                                        fprintf('Fatal Error: BIN %g. 8-bit Write (wb<>) format was violated',iBin)
                                                                        isparsednumerically = 0;  % Numeric parsing was not approved
                                                                        return
                                                                elseif lestrs <= 8 && lestrs >= 1

                                                                        %  Steve's option: always 'x' replaces blanks
                                                                        %  Example:  write = 10011   means xxx10011xxxxxxxx
                                                                        %  Example:  write = x10011  means xxx10011xxxxxxxx
                                                                        %
                                                                        if strWrite(1)=='1' || strWrite(1)=='0'
                                                                                strWrite = [repmat('x',1, 8-lestrs) strWrite repmat('x',1, 8)];
                                                                        else
                                                                                strWrite = [repmat('x',1, 8-lestrs) strWrite repmat('x',1, 8)];
                                                                        end
                                                                end
                                                        end

                                                        [mats, toks, indxs] = regexpi(strWrite, '0|1','match','tokens','start');

                                                        if isempty(indxs)
                                                                captureWrite    = uint16(bin2dec(strWrite));
                                                                maskWriteString = '1111111111111111';
                                                                captWriteMask   = uint16(bin2dec(maskWriteString)); % Write's Logic Mask
                                                        else
                                                                strWrite        =  regexprep(strWrite, 'x','0','ignorecase');
                                                                captureWrite    = uint16(bin2dec(strWrite));
                                                                maskWriteString = repmat('0', 1, 16);
                                                                maskWriteString(indxs) = '1';
                                                                captWriteMask   = uint16(bin2dec(maskWriteString)); % Write's Logic Mask
                                                        end
                                                        if ~isempty(t1) && ~isempty(t2)
                                                                if t1 >= t2
                                                                        fprintf('\nFatal Error: BIN %g, Sequencer %g, from "%s", has a erroneous time condition range\n',...
                                                                                iBin, kSequencer, logEventSelector{jLogES})
                                                                        isparsednumerically = 0;  % Numeric parsing was not approved
                                                                        return
                                                                end

                                                                if countexp(e) > 1
                                                                        dispcond(condition,'Hey! you are using more than one definition of time')
                                                                end
                                                                storeTime      = cat(1,storeTime, [t1 t2]);
                                                                t1catch        = t1;
                                                                t2catch        = t2;
                                                                istimedetected = 1;
                                                        else
                                                                if captureCode ~= 1000000 && captureCode ~= 2000000 && captureCode ~= 3000000
                                                                        storeTime = cat(1,storeTime, [-1 -1]);
                                                                end
                                                        end
                                                        if ~isempty(captureCode)
                                                                if captureCode ~= 1000000 && captureCode ~= 2000000 && captureCode ~= 3000000
                                                                        storeCode = cat(2,storeCode, captureCode);
                                                                        if char(rtimes{n}(3))=='~' % There is negation
                                                                                storeSign = cat(2,storeSign, 0);
                                                                        else                       % There is no negation
                                                                                storeSign = cat(2,storeSign, 1);
                                                                        end
                                                                end
                                                        else
                                                                fprintf('Fatal Error: expression without code!!! \n');
                                                                isparsednumerically = 0;  % Numeric parsing was not approved
                                                                return
                                                        end
                                                        if ~isempty(captureFlag)
                                                                if captureFlag > 65535
                                                                        fprintf('Fatal Error: BIN %g. 16-bit Flag format was violated',iBin)
                                                                        isparsednumerically = 0;  % Numeric parsing was not approved
                                                                        return
                                                                else
                                                                        flagcatch      = captureFlag;
                                                                        fmaskcatch     = captFlagMask;
                                                                        isflagdetected = 1;
                                                                        if captureCode ~= 2000000
                                                                                storeFlag   = cat(2,storeFlag, captureFlag );
                                                                                storeFmask  = cat(2,storeFmask, captFlagMask );
                                                                        end
                                                                end
                                                        else
                                                                if captureCode ~= 1000000 && captureCode ~= 2000000 && captureCode ~= 3000000
                                                                        storeFlag   = cat(2,storeFlag, 0);
                                                                        storeFmask  = cat(2,storeFmask, 0 );
                                                                end
                                                        end
                                                        if ~isempty(captureWrite)
                                                                if captureWrite > 65535
                                                                        fprintf('Fatal Error: BIN %g. 16-bit Write format was violated',iBin)
                                                                        isparsednumerically = 0;  % Numeric parsing was not approved
                                                                        return
                                                                else
                                                                        Writecatch     = captureWrite;
                                                                        smaskcatch     = captWriteMask;
                                                                        isWritedetected  = 1;
                                                                        if captureCode ~= 3000000
                                                                                storeWrite   = cat(2,storeWrite, captureWrite);
                                                                                storeWmask   = cat(2,storeWmask, captWriteMask );
                                                                        end
                                                                end
                                                        else

                                                                if captureCode ~= 1000000 && captureCode ~= 2000000 && captureCode ~= 3000000
                                                                        storeWrite   = cat(2,storeWrite, 0);
                                                                        storeWmask   = cat(2,storeWmask, 0 );
                                                                end
                                                        end
                                                end
                                                auxstr = regexprep(auxstr, expp{e}, '');
                                        else
                                                countexp(e) = 0;  %for future application
                                        end
                                end
                                if istimedetected
                                        lco = size(storeCode,2);
                                        storeTime = repmat([t1catch t2catch],lco,1);
                                end
                                if isflagdetected
                                        lco = size(storeCode,2);
                                        storeFlag  = repmat(flagcatch,1,lco);
                                        storeFmask = repmat(fmaskcatch,1,lco);
                                end
                                if isWritedetected
                                        lco = size(storeCode,2);
                                        storeWrite = repmat(Writecatch,1,lco);
                                        storeWmask = repmat(smaskcatch,1,lco);
                                end

                                %
                                % Structure
                                % Sorting by eventcode from lesser to
                                % greater including its time interval, flags, and writes
                                %
                                [ValMatrix]  = cat(1,num2cell(storeCode), num2cell(storeSign), num2cell(storeTime'), num2cell(storeFlag),...
                                        num2cell(storeFmask), num2cell(storeWrite), num2cell(storeWmask))';

                                auxforsort   = ValMatrix(:,1);
                                auxforsort   = [auxforsort{:}];
                                [indx, indx] = sort(auxforsort);
                                [MatrixSorted] = ValMatrix(indx,:);
                                storeCode      = cell2mat(MatrixSorted(:,1)');
                                storeSign      = cell2mat(MatrixSorted(:,2)');
                                storeTime      = cell2mat(MatrixSorted(:,3:4));
                                storeFlag      = cell2mat(MatrixSorted(:,5)');
                                storeFmask     = cell2mat(MatrixSorted(:,6)');
                                storeWrite     = cell2mat(MatrixSorted(:,7)');
                                storeWmask     = cell2mat(MatrixSorted(:,8)');

                                % Bad values filter
                                ecodeneg = find(storeCode <= 0, 1);
                                etimeneg = find(storeTime ~= -1 & storeTime <= 0 , 1);

                                if ~isempty(ecodeneg) || ~isempty(etimeneg)
                                        fprintf('Fatal Error: BIN %g has a bad numeric expression for event code or time range\n',iBin)
                                        isparsednumerically = 0;  % Numeric parsing was not approved
                                        return
                                end
                                %
                                % Detect if there is at least one negation and if so, everything is negated.
                                nWishedCodes  = nnz(storeSign); % number of nonzero elements in storeSign (nWishedCodes).
                                nDifferentSign = length(storeSign)-nWishedCodes;

                                if ~allowMixedSigns
                                    if nDifferentSign ~= length(storeSign) && nDifferentSign ~= 0
                                        storeSign = storeSign*0;
                                    end
                                end
                                if istimedetected
                                        t1now  = storeTime(1,1);
                                        t2now  = storeTime(1,2);
                                        sense =  jLogES-2;

                                        if ~isempty(auxt1pre)
                                                if ((sense*t2now)<(sense*auxt2pre)) || ((sense*t1now)<(sense*auxt1pre))
                                                        fprintf('\nFatal Error: BIN %g, Sequencer %g, from "%s", has a time condition range LESSER than previous one\n',...
                                                                iBin, kSequencer, logEventSelector{jLogES})
                                                        isparsednumerically = 0;  % No paso el parsing numerico
                                                        return
                                                end
                                        end
                                        auxt1pre = t1now;
                                        auxt2pre = t2now;
                                end

                                % Build a datastructure for the bin
                                % descriptor values
                                dispcond( condition, 'Showing Values (of complex expressions):',...
                                        storeCode, storeSign, storeTime, storeFlag, storeWrite)
                                %******************************************************
                                BIN(iBin).(logEventSelector{jLogES})(kSequencer).eventcode    =   single(storeCode);
                                BIN(iBin).(logEventSelector{jLogES})(kSequencer).eventsign    =   single(storeSign);
                                BIN(iBin).(logEventSelector{jLogES})(kSequencer).timecode     =   single(storeTime);
                                BIN(iBin).(logEventSelector{jLogES})(kSequencer).flagcode     =   uint16(storeFlag);
                                BIN(iBin).(logEventSelector{jLogES})(kSequencer).flagmask     =   uint16(storeFmask);
                                BIN(iBin).(logEventSelector{jLogES})(kSequencer).writecode    =   uint16(storeWrite);
                                BIN(iBin).(logEventSelector{jLogES})(kSequencer).writemask    =   uint16(storeWmask);
                        end  % Sequencer's loop

                elseif   isempty(segmentedBrackets{:}) && ~isempty(spCodes{:})    % The sequencer is not numeric

                        if char(specialCodesToken{1,1}{1,1}(1)) == '~'
                                BIN(iBin).(logEventSelector{jLogES}).eventcode =   -13;  % Code is a non-value!
                                BIN(iBin).(logEventSelector{jLogES}).eventsign =   0;
                        else
                                BIN(iBin).(logEventSelector{jLogES}).eventcode =   -7;   % Code is a non-value!
                                BIN(iBin).(logEventSelector{jLogES}).eventsign =   1;
                        end

                        BIN(iBin).(logEventSelector{jLogES-1})            =  []; % delete the prehome
                        BIN(iBin).(logEventSelector{jLogES}).timecode     =  single([-1 -1]);
                        BIN(iBin).(logEventSelector{jLogES}).flagcode     =  uint16(0);
                        BIN(iBin).(logEventSelector{jLogES}).flagmask     =  uint16(65535);
                        BIN(iBin).(logEventSelector{jLogES}).writecode    =  uint16(0);
                        BIN(iBin).(logEventSelector{jLogES}).writemask    =  uint16(65535);
                        BIN(iBin).(logEventSelector{jLogES+1})            =  [];  % Delete the posthome
                        isworkingFine = 0;  % Don't continue with the post home because the prehome was rejected.

                else   % No numeric sequencer and no special sequencer (~* or *)
                        BIN(iBin).(logEventSelector{jLogES}) =  []; % If there is no expression for the field, then it will be empty
                end
                jLogES = jLogES + 1;  % Field Number (pre, at, and post)
        end   % LES's loop
        % name the bin been processed
        BIN(iBin).namebin  =   ['BIN ' num2str(iBin)];
end % Bin's loop


function test_bug2464

% MEM 1gb
% WALLTIME 00:10:00
% DEPENDENCY ft_selectdata

filename = dccnpath('/home/common/matlab/fieldtrip/data/test/bug2464.mat');
load(filename);

cfg = [];
cfg.foilim = [10 20];
sel = ft_selectdata(cfg, freq);

cfg = [];
cfg.frequency = [10 20];
sel2 = ft_selectdata(cfg, freq);

assert(isequal(rmfield(sel, 'cfg'), rmfield(sel2, 'cfg')));


function r8_big_test ( )

%*****************************************************************************80
%
%% R8_BIG_TEST tests R8_BIG.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    08 November 2014
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'R8_BIG_TEST\n' );
  fprintf ( 1, '  R8_BIG returns a "big" R8 value;\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  R8_BIG = %f\n', r8_big ( ) );

  return
end


% [y,npadl,npadu] = padgrab(x,padv,l1,u1,l2,u2,...)
function [y,npadl,npadu] = padgrab(x,padv,varargin)

% parse arguments
usagestring = 'Usage: padgrab(x,padv,l1,u1,l2,u2,...)';
nd1 = ndims(x);
if mod(numel(varargin),2) ~= 0 || isempty(varargin),
  error(usagestring);
end
isones = cellfun(@(x) x == 1, varargin(1:2:end-1)) & cellfun(@(x) x == 1, varargin(2:2:end));
sz = size(x);
isones(1:nd1) = isones(1:nd1) & sz == 1;
nd = find(~isones,1,'last');
if isempty(nd),
  nd = 1;
end
varargin = varargin(1:2*nd);
isrowvec = nd == 1 && nd1 == 2 && size(x,1) == 1;
if isrowvec,
  varargin = [{1,1},varargin];
  nd = 2;
end
if mod(nd,1) ~= 0 || nd > nd1,
  error(usagestring);
end
l = cell2mat(varargin(1:2:end));
u = cell2mat(varargin(2:2:end));
%if any(u < l),
%  error(usagestring);
%end
%sz = size(x);
if nd < nd1,
  x = reshape(x,[sz(1:nd-1),prod(sz(nd:end)),1]);
  sz = size(x);
end

l1 = max(min(l,sz),1);
u1 = max(min(u,sz),1);
a = cell(1,nd);
aisempty = false(1,nd);
for i = 1:nd,
  if sz(i) <= 0 || l(i) > u(i) || u(i) < 1 || l(i) > sz(i),
    a{i} = [];
    aisempty(i) = true;
  else
    a{i} = l1(i):u1(i);
  end
end
y = x(a{:});
npadl = l1-l+aisempty;
npadu = u-u1;
npadl = npadl + (npadu < 0).*npadu;

idxlow = u < 1;
if any(idxlow),
  npadl(idxlow) = u(idxlow) - l(idxlow) + 1;
  npadu(idxlow) = 0;
end
idxhigh = l > sz;
if any(idxhigh),
  npadu(idxhigh) = u(idxhigh) - l(idxhigh) + 1;
  npadl(idxhigh) = 0;
end

if any(npadl > 0),
  y = padarray(y,npadl,padv,'pre');
end
if any(npadu > 0),
  y = padarray(y,npadu,padv,'post');
end

% if dotranspose,
%   y = y';
% end


function stla_to_tri_surface_fast ( stla_file_name, node_file_name, ...
  triangle_file_name )

%*****************************************************************************80
%
%% STLA_TO_TRI_SURFACE_FAST converts an ASCII STL file to a TRI_SURFACE file.
%
%  Discussion:
%
%    This function makes use of the "fast" routines STLA_SIZE_FAST and
%    STLA_READ_FAST, which may be much faster when reading large files.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    28 September 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string STLA_FILE_NAME, the name of the ASCII STL file to be read.
%
%    Input, string NODE_FILE_NAME, the name of the TRI_SURFACE node file to
%    be written.
%
%    Input, string TRIANGLE_FILE_NAME, the name of the TRI_SURFACE triangle
%    file to be written.
%

%
%  Get the size of the STLA data.
%
  [ solid_num, node_num, triangle_num, text_num ] = stla_size_fast ( stla_file_name );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  STLA file "%s".\n', stla_file_name );
  fprintf ( 1, '  Number of solids   = %d\n', solid_num );
  fprintf ( 1, '  Number of nodes    = %d\n', node_num );
  fprintf ( 1, '  Number of faces    = %d\n', triangle_num );
  fprintf ( 1, '  Number of textures = %d\n', text_num );
%
%  Read the STLA data.
%
  [ node_xyz, triangle_node, triangle_normal ] = stla_read_fast ( stla_file_name, ...
    node_num, triangle_num );
%
%  Write the data to the TRI_SURFACE files.
%
  dim_num = size ( node_xyz, 1 );
  order_num = 3;

  tri_surface_write ( node_file_name, triangle_file_name, dim_num, node_num, ...
    order_num, triangle_num, node_xyz, triangle_node );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  TRI_SURFACE data written to:\n' );
  fprintf ( 1, '  node file     "%s".\n', node_file_name );
  fprintf ( 1, '  triangle_file "%s".\n', triangle_file_name );

  return
end
function i4mat_write0 ( output_filename, m, n, table )

%*****************************************************************************80
%
%% I4MAT_WRITE0 writes an I4MAT file with no header.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    20 July 2005
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string OUTPUT_FILENAME, the output filename.
%
%    Input, integer M, the spatial dimension.
%
%    Input, integer N, the number of points.
%
%    Input, integer TABLE(M,N), the points.
%
%    Input, logical HEADER, is TRUE if the header is to be included.
%

%
%  Open the file.
%
  output_unit = fopen ( output_filename, 'wt' );

  if ( output_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'I4MAT_WRITE0 - Error!\n' );
    fprintf ( 1, '  Could not open the output file.\n' );
    error ( 'I4MAT_WRITE0 - Error!' );
    return;
  end
%
%  Write the data.
%
  for j = 1 : n
    for i = 1 : m
      fprintf ( output_unit, '  %12d', round ( table(i,j) ) );
    end
    fprintf ( output_unit, '\n' );
  end
%
%  Close the file.
%
  fclose ( output_unit );

  return
end
function r8mat_write0 ( output_filename, m, n, table )

%*****************************************************************************80
%
%% R8MAT_WRITE0 writes an R8MAT file with no header.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    29 June 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string OUTPUT_FILENAME, the output filename.
%
%    Input, integer M, the spatial dimension.
%
%    Input, integer N, the number of points.
%
%    Input, real TABLE(M,N), the points.
%

%
%  Open the file.
%
  output_unit = fopen ( output_filename, 'wt' );

  if ( output_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'R8MAT_WRITE0 - Error!\n' );
    fprintf ( 1, '  Could not open the output file.\n' );
    error ( 'R8MAT_WRITE0 - Error!' );
    return;
  end
%
%  Write the data.
%
%  For greater precision, try:
%
%     fprintf ( output_unit, '  %24,16f', table(i,j) );
%
  for j = 1 : n
    for i = 1 : m
      fprintf ( output_unit, '  %14f', table(i,j) );
    end
    fprintf ( output_unit, '\n' );
  end
%
%  Close the file.
%
  fclose ( output_unit );

  return
end
function [ node_xyz, face_node, face_normal ] = stla_read_fast ( ...
  input_file_name, node_num, face_num )

%*****************************************************************************80
%
%% STLA_READ_FAST reads graphics information from an ASCII StereoLithography file.
%
%  Discussion:
%
%    This routine should be faster than STLA_READ, since it does little
%    error checking, and uses native MATLAB commands like SSCANF to
%    read the data directly.
%
%  Modified:
%
%    16 February 2007
%
%  Author:
%
%    Bill Seufzer,
%    NASA Langley
%
%  Reference:
%
%    3D Systems, Inc,
%    Stereolithography Interface Specification,
%    October 1989.
%
%  Parameters:
%
%    Input, string INPUT_FILE_NAME, the name of the input file.
%
%    Input, integer NODE_NUM, the number of vertices defined.
%
%    Input, integer FACE_NUM, the number of faces defined.
%
%    Output, real NODE_XYZ(3,NODE_NUM), the coordinates of points.
%
%    Output, integer FACE_NODE(3,FACE_NUM), the nodes that make up each face.
%
%    Output, real FACE_NORMAL(3,FACE_NUM), the normal vector
%    at each face.
%
  node_xyz = [];
  face_node = [];
  face_normal = [];
%
%  If no file input, try to get one from the user.
%
  if ( nargin < 1 )
    input_file_name = input ( 'Enter the name of the ASCII STL file.' );
    if ( isempty ( input_file_name ) )
      return
    end
  end
%
%  If no size input, scan the file.
%
  if ( nargin < 3 )
    [ solid_num, node_num, face_num, text_num ] = stla_size_fast ( ...
      input_file_name );
  end
%
%  Open the file.
%
  input_file_unit = fopen ( input_file_name, 'r' );

  if ( input_file_unit < 1 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'STLA_READ_FAST - Fatal error!\n' );
    fprintf ( 1, '  Could not open the file "%s".\n', input_file_name );
    error ( 'STLA_READ_FAST - Fatal error!' )
    return
  end
%
%  Allocate space.
%
  solid = 0;
  node = 0;
  face = 0;

  node_xyz = zeros(3,node_num);
  face_node = zeros(3,face_num);
  face_normal = zeros(3,face_num);
%
%  Read the text, one line at a time.
%
  while ( 1 )

    text = fgetl ( input_file_unit );
%
%  On end of input, FGETL returns a -1 instead of a character array.
%
    if ( ~ischar ( text ) )
      break
    end
%
%  Left justify the string (no initial blanks).
%  Lowercase the string.
%
    text = lower ( strjust ( text, 'left' ) );
%
%  Locate the first word by finding the indices of the whitespace characters.
%
    blanks = find ( isspace ( text ) == 1 );

    if ( isempty ( blanks ) )
      word1 = text;
    else
      word1 = text(1:blanks(1)-1);
    end
%
%  Action depends on initial keyword.
%
    switch word1

       case 'solid'

         solid = solid + 1;

       case 'facet'

         face = face + 1;
         face_normal(:,face) = sscanf ( text, '%*s %*s %f %f %f' );

       case 'vertex'

         node = node + 1;
         node_xyz(:,node) = sscanf ( text, '%*s %f %f %f' );

       case 'endloop'

         face_node(:,face) = [ node-2; node-1; node ];

       otherwise

     end

  end
%
%  Close the file.
%
  fclose ( input_file_unit );

  return
end
function [ solid_num, node_num, face_num, text_num ] = stla_size_fast ( ...
  input_file_name )

%*****************************************************************************80
%
%% STLA_SIZE_FAST determines sizes associated with an STLA file.
%
%  Discussion:
%
%    This routine assumes that the file is a legal STLA file.
%
%    To perform checks on the file, call STLA_CHECK first.
%
%    Note that the counts for the number of nodes and edges are
%    overestimates, since presumably, most nodes will be defined several
%    times, once for each face they are part of, and most edges will
%    be defined twice.
%
%  Modified:
%
%    16 February 2007
%
%  Author:
%
%    Bill Seufzer,
%    NASA, Langley
%
%  Reference:
%
%    3D Systems, Inc,
%    Stereolithography Interface Specification,
%    October 1989.
%
%  Parameters:
%
%    Input, string INPUT_FILE_NAME, the name of the input file.
%
%    Output, integer SOLID_NUM, the number of solids defined.
%    Presumably, this is 1.
%
%    Output, integer NODE_NUM, the number of vertices defined.
%
%    Output, integer FACE_NUM, the number of faces defined.
%
%    Output, integer TEXT_NUM, the number of lines of text.
%
  solid_num = -1;
  node_num = -1;
  face_num = -1;
  text_num = -1;
%
%  If no file input, try to get one from the user.
%
  if ( nargin < 1 )
    input_file_name = input ( 'Enter the name of the ASCII STL file.' );
    if ( isempty ( input_file_name ) )
      return
    end
  end

  input_file_unit = fopen ( input_file_name, 'r' );

  if ( input_file_unit < 1 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'STLA_SIZE_FAST - Fatal error!\n' );
    fprintf ( 1, '  Could not open the file "%s".\n', input_file_name );
    error ( 'STLA_SIZE_FAST - Fatal error!' )
    return
  end

  solid_num = 0;
  node_num = 0;
  face_num = 0;
  text_num = 0;
%
%  Read the text, one line at a time.
%
  while ( 1 )

    text = fgetl ( input_file_unit );
%
%  On end of input, FGETL returns a -1 instead of a character array.
%
    if ( ~ischar ( text ) )
      break
    end

    text_num = text_num + 1;
%
%  Left justify the string (no initial blanks).
%  Lowercase the string.
%
    text = lower ( strjust ( text, 'left' ) );
%
%  Locate the first word by finding the indices of the whitespace characters.
%
    blanks = find ( isspace ( text ) == 1 );
%
%  If there are no blanks, the first word is the whole string.
%  Otherwise, the first word is the string before the first blank.
%
    if ( isempty ( blanks ) )
      word1 = text;
    else
      word1 = text(1:blanks(1)-1);
    end
%
%  Count occurrences of "SOLID", "FACET" or "VERTEX".
%
    switch word1

      case 'solid'
        solid_num = solid_num + 1;
      case 'facet'
        face_num = face_num + 1;
      case 'vertex'
        node_num = node_num + 1;
      otherwise

    end

  end
%
%  Close the file.
%
  fclose ( input_file_unit );

  return
end
function timestamp ( )

%*****************************************************************************80
%
%% TIMESTAMP prints the current YMDHMS date as a timestamp.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
  t = now;
  c = datevec ( t );
  s = datestr ( c, 0 );
  fprintf ( 1, '%s\n', s );

  return
end
function tri_surface_write ( node_file_name, triangle_file_name, dim_num, ...
  node_num, order_num, triangle_num, node_xyz, triangle_node )

%*****************************************************************************80
%
%% TRI_SURFACE_WRITE writes graphics information to a pair of TRI_SURFACE files.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    08 August 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string NODE_FILE_NAME, the name of the node file.
%
%    Input, string TRIANGLE_FILE_NAME, the name of the triangle file.
%
%    Input, integer DIM_NUM, the spatial dimension.
%
%    Input, integer NODE_NUM, the number of points.
%
%    Input, integer ORDER_NUM, the order of the triangles.
%
%    Input, integer TRIANGLE_NUM, the number of triangles.
%
%    Input, real NODE_XYZ(DIM_NUM,NODE_NUM), the node coordinates.
%
%    Input, integer TRIANGLE_NODE(ORDER_NUM,TRIANGLE_NUM),
%    the nodes that form the triangles.
%
  r8mat_write0 ( node_file_name, dim_num, node_num, node_xyz );

  i4mat_write0 ( triangle_file_name, order_num, triangle_num, ...
    triangle_node );

  return
end


function [newModel,AddedExchRxn] = addExchangeRxn(model,metList,lb,ub)
%addExchangeRxn adds exchange reactions
%
% newModel = addExchangeRxn(model,metList,lb,ub)
%
%INPUTS
% model         Cobra model structure
% metList       List of metabolites
%
%OPTIONAL INPUTS
% lb            Array of lower bounds
% ub            Array of upper bounds
%
%OUTPUT
% newModel      COBRA model with added exchange reactions
%
% Ines Thiele 02/2009

if nargin < 3
    lb = ones(length(metList),1)*min(model.lb);
end
if nargin < 4
    ub = ones(length(metList),1)*max(model.ub);
end
Revs = zeros(length(metList),1);
Revs(lb<0) = 1;

newModel = model;
AddedExchRxn = '';
for i = 1 : length(metList)
    [newModel,rxnIDexists] = addReactionOri(newModel,strcat('EX_',metList{i}),metList(i),-1,Revs(i),...
        lb(i),ub(i));
    AddedExchRxn=[AddedExchRxn;strcat('EX_',metList(i))];
end


function isBelow = isVersionBelow(versionA, versionB)
% Checks if versionA is smaller than versionB
    vA         = versionArray(versionA);
    vB         = versionArray(versionB);
    n          = min(length(vA), length(vB));
    deltaAB    = vA(1:n) - vB(1:n);
    difference = find(deltaAB, 1, 'first');
    if isempty(difference)
        isBelow = false; % equal versions
    else
        isBelow = (deltaAB(difference) < 0);
    end
end
% ==============================================================================
function arr = versionArray(str)
% Converts a version string to an array.
    if ischar(str)
        % Translate version string from '2.62.8.1' to [2; 62; 8; 1].
        switch getEnvironment
            case 'MATLAB'
                split = regexp(str, '\.', 'split'); % compatibility MATLAB < R2013a
            case  'Octave'
                split = strsplit(str, '.');
            otherwise
                errorUnknownEnvironment();
        end
        arr = str2num(char(split)); %#ok
    else
        arr = str;
    end
    arr = arr(:)';
end
% ==============================================================================
function errorUnknownEnvironment()
error('matlab2tikz:unknownEnvironment',...
      'Unknown environment "%s". Need MATLAB(R) or Octave.', getEnvironment);
end
% ==============================================================================


function [C_e, C_d] = elec_distance_consec(dist_e, dist_d)

% elec_distance_consec - Identify distance between nearest neighbour electrodes
%
% Requires input data generated by 'elec_distance.m'
% Assumes using FUSA CNL electrode positions (Scan ECI-Cap)
%

% $Revision: 1.1 $ $Date: 2009-04-28 22:13:54 $

% Licence:  GNU GPL, no implied or express warranties
% History:  05/2000, Darren.Weber_at_radiology.ucsf.edu
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  fprintf('\n%s\n\n', 'Calculating consecutive electrode distances.');

  End_e = strvcat('3', '5', '7', '9', '13', '22', '30', '41', '49', '54', '59', '67', '78', '86', '97', '101', '108', '110', '115', '117', '120', '124');

  C_e = cell(0);
  C_d = [];

  for row = 1:length(dist_d)

     % Check that row in dist_d matrix is non-zero

     NonZeroColumns = find(dist_d(row,:));

     if ~isempty(NonZeroColumns)

	  % Calculate consecutive electrode distance,
	  % excluding end electrodes defined in End_e

		if( (row+1) <= length(dist_e) )

			e = str2num(char(dist_e(row,row+1)));

			if(strmatch(num2str(e(1)), End_e, 'exact'))

				% found end electrode, do nothing
			else

				C_d(end + 1) = dist_d(row,row+1);
                                C_e(end + 1) = {num2str(e(1))};
			end
		end
	end
  end
  clear r x;


function [Zi, h] = ft_plot_topo(chanX, chanY, dat, varargin)

% FT_PLOT_TOPO interpolates and plots the 2-D spatial topography of the
% potential or field distribution over the head
%
% Use as
%   ft_plot_topo(x, y, val, ...)
%
% Optional arguments should come in key-value pairs and can include
%   'gridscale'     = scalar, number of points along both directions for interpolation (default = 67)
%   'datmask'       = vector of same dimensions as val
%   'mask'          = cell-array with line segments that forms the mask (see FT_PREPARE_LAYOUT)
%   'outline'       = cell-array with line segments that for the outline (see  FT_PREPARE_LAYOUT)
%   'isolines'      = vector with values for isocontour lines (default = [])
%   'interplim'     = string, 'electrodes' or 'mask' (default = 'electrodes')
%   'interpmethod'  = string, 'nearest', 'linear', 'natural', 'cubic' or 'v4' (default = 'v4')
%   'style'         = can be 'surf', 'iso', 'isofill', 'surfiso', 'imsat', 'imsatiso', 'colormix'
%   'clim'          = [min max], limits for color scaling
%   'shading'       = string, 'none', 'flat', 'interp' (default = 'flat')
%   'parent'        = handle which is set as the parent for all plots
%   'tag'           = string, the name assigned to the object. All tags with the same name can be deleted in a figure, without deleting other parts of the figure.
%   'box'           = draw a box around the local axes, can be 'yes' or 'no'
%
% It is possible to plot the object in a local pseudo-axis (c.f. subplot), which is specfied as follows
%   'hpos'          = horizontal position of the lower left corner of the local axes
%   'vpos'          = vertical position of the lower left corner of the local axes
%   'width'         = width of the local axes
%   'height'        = height of the local axes
%   'hlim'          = horizontal scaling limits within the local axes
%   'vlim'          = vertical scaling limits within the local axes
%
% See also FT_PLOT_TOPO3D, FT_PLOT_LAYOUT, FT_TOPOPLOTER, FT_TOPOPLOTTFR

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

% these are for speeding up the plotting on subsequent calls
persistent previous_argin previous_maskimage

% get the optional input arguments
hpos          = ft_getopt(varargin, 'hpos',         0);
vpos          = ft_getopt(varargin, 'vpos',         0);
width         = ft_getopt(varargin, 'width',        []);
height        = ft_getopt(varargin, 'height',       []);
gridscale     = ft_getopt(varargin, 'gridscale',    67); % 67 in original
shading       = ft_getopt(varargin, 'shading',      'flat');
interplim     = ft_getopt(varargin, 'interplim',    'electrodes');
interpmethod  = ft_getopt(varargin, 'interpmethod', 'v4');
style         = ft_getopt(varargin, 'style',        'surfiso'); % can be 'surf', 'iso', 'isofill', 'surfiso', 'imsat', 'imsatiso', 'colormix'
tag           = ft_getopt(varargin, 'tag',          '');
isolines      = ft_getopt(varargin, 'isolines');
datmask       = ft_getopt(varargin, 'datmask');
mask          = ft_getopt(varargin, 'mask');
outline       = ft_getopt(varargin, 'outline');
clim          = ft_getopt(varargin, 'clim', []);
parent        = ft_getopt(varargin, 'parent', []);
box           = ft_getopt(varargin, 'box', false);

% convert the yes/no strings into boolean values
box = istrue(box);

% check for nans in the data, they can be still left incase people want to mask non channels.
if any(isnan(dat))
  ft_warning('the data passed to ft_plot_topo contains NaNs, these channels will be removed from the data to prevent interpolation errors, but will remain in the mask');
  flagNaN = true;
else
  flagNaN = false;
end
NaNind = isnan(dat);

% everything is added to the current figure
holdflag = ishold;
if ~holdflag
  hold on
end

% layout units can be arbitrary (e.g. pixels for .mat files)
% so we need to compute the right scaling factor
% create a matrix with all coordinates
% from positions, mask, and outline
allCoords = [chanX(:) chanY(:)];
if ~isempty(mask)
  for k = 1:numel(mask)
    allCoords = [allCoords; mask{k}];
  end
end
if ~isempty(outline)
  for k = 1:numel(outline)
    allCoords = [allCoords; outline{k}];
  end
end

naturalWidth = (max(allCoords(:, 1))-min(allCoords(:, 1)));
naturalHeight = (max(allCoords(:, 2))-min(allCoords(:, 2)));

if isempty(width) && isempty(height)
  xScaling = 1;
  yScaling = 1;
elseif isempty(width) && ~isempty(height)
  % height specified, auto-compute width while maintaining aspect ratio
  yScaling = height/naturalHeight;
  xScaling = yScaling;
elseif ~isempty(width) && isempty(height)
  % width specified, auto-compute height while maintaining aspect ratio
  xScaling = width/naturalWidth;
  yScaling = xScaling;
else
  % both width and height specified
  xScaling = width/naturalWidth;
  yScaling = height/naturalHeight;
end

% keep original channel positions
chanXorg = chanX;
chanYorg = chanY;
chanX = chanX(:) * xScaling + hpos;
chanY = chanY(:) * yScaling + vpos;

if strcmp(interplim, 'electrodes')
  hlim = [min(chanX) max(chanX)];
  vlim = [min(chanY) max(chanY)];
elseif (strcmp(interplim, 'mask') || strcmp(interplim, 'mask_individual')) && ~isempty(mask)
  hlim = [inf -inf];
  vlim = [inf -inf];
  for i=1:length(mask)
    hlim = [min([hlim(1); mask{i}(:, 1)*xScaling+hpos]) max([hlim(2); mask{i}(:, 1)*xScaling+hpos])];
    vlim = [min([vlim(1); mask{i}(:, 2)*yScaling+vpos]) max([vlim(2); mask{i}(:, 2)*yScaling+vpos])];
  end
else
  hlim = [min(chanX) max(chanX)];
  vlim = [min(chanY) max(chanY)];
end

% check if all mask point are inside the limits otherwise redefine mask
newpoints = [];
if length(mask)==1
  % which channels are outside
  inside  = inside_contour([chanX chanY], mask{1});
  outside = ~inside;
  newpoints = [chanX(outside) chanY(outside)];
end

% try to speed up the preparation of the mask on subsequent calls
%current_argin = {chanX, chanY, gridscale, mask, datmask}; % old: to be plotted channel positions must be the same
current_argin = {chanXorg, chanYorg, gridscale, mask, datmask, interplim}; % new: unscaled channel positions must be the same over calls
if isequal(current_argin, previous_argin)
  % don't construct the binary image, but reuse it from the previous call
  maskimage = previous_maskimage;
elseif ~isempty(mask)
  % convert the mask into an indexed image
  maskimage = zeros(gridscale); %false(gridscale);
  %hlim      = [min(chanX) max(chanX)];
  %vlim      = [min(chanY) max(chanY)];
  xi        = linspace(hlim(1), hlim(2), gridscale);   % x-axis for interpolation (row vector)
  yi        = linspace(vlim(1), vlim(2), gridscale);   % y-axis for interpolation (row vector)
  [Xi, Yi]   = meshgrid(xi', yi);
  if ~isempty(newpoints) && (hpos == 0 || vpos == 0)
    ft_warning('Some points fall outside the outline, please consider using another layout')
    % FIXME: I am not sure about it, to be tested!
    %     tmp = [mask{1};newpoints];
    %     indx = convhull(tmp(:, 1), tmp(:, 2));
    %     mask{1} = tmp(indx, :);
    % NOTE: if you set hpos and/or vpos, newpoints is not empty, but nothing
    % needs to be fixed (this fixme screws up things, then)
  end
  for i=1:length(mask)
    mask{i}(:, 1) = mask{i}(:, 1)*xScaling+hpos;
    mask{i}(:, 2) = mask{i}(:, 2)*yScaling+vpos;
    mask{i}(end+1, :) = mask{i}(1, :);                   % force them to be closed
    maskimage(inside_contour([Xi(:) Yi(:)], mask{i})) = i; %true;
  end

else
  maskimage = [];
end

% adjust maskimage to also mask channels as specified in maskdat
if ~isempty(datmask)
  xi           = linspace(hlim(1), hlim(2), gridscale);   % x-axis for interpolation (row vector)
  yi           = linspace(vlim(1), vlim(2), gridscale);   % y-axis for interpolation (row vector)
  maskimagetmp = griddata(chanX', chanY, double(datmask), xi', yi, 'nearest'); % interpolate the mask data
  if isempty(maskimage)
    maskimage = maskimagetmp;
  else
    maskimage = (maskimage + maskimagetmp) > 1.01;
  end
end

% take out NaN channels if interpmethod does not work with NaNs
if flagNaN && strcmp(interpmethod, 'v4')
  dat(NaNind) = [];
  chanX(NaNind) = [];
  chanY(NaNind) = [];
end

% convert chanX, chanY and dat to double
dat = double(dat);
chanX = double(chanX);
chanY = double(chanY);

%interpolate data
xi         = linspace(hlim(1), hlim(2), gridscale);       % x-axis for interpolation (row vector)
yi         = linspace(vlim(1), vlim(2), gridscale);       % y-axis for interpolation (row vector)

if ~ft_platform_supports('griddata-vector-input')
  % in GNU Octave, griddata does not support vector
  % positions; make a grid to get the locations in vector form
  [xi,yi]=meshgrid(xi,yi);
  xi=xi';
end

if ~isempty(maskimage) && strcmp(interplim, 'mask_individual')
  % do the interpolation for each set of electrodes within a mask, useful
  % for ECoG data with multiple grids, to avoid cross talk
  Zi = zeros(size(maskimage));
  for i=1:max(maskimage(:))
    chansel = inside_contour([chanX chanY], mask{i});
    [Xi, Yi, tmpZi]  = griddata(chanX(chansel)', chanY(chansel), dat(chansel), xi', yi, interpmethod);
    Zi(maskimage==i) = tmpZi(maskimage==i);
  end
else
  [Xi, Yi, Zi] = griddata(chanX', chanY, dat, xi', yi, interpmethod); % interpolate the topographic data
end

if ~isempty(maskimage)
  % apply mask to the data to hide parts of the interpolated data (outside the circle) and channels that were specified to be masked
  % this combines the input options mask and maskdat
  Zi(maskimage==0) = NaN;
end

% The topography should be plotted prior to the isolines to ensure that it is exported correctly, see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2496
if strcmp(style, 'surf') || strcmp(style, 'surfiso')

  deltax = xi(2)-xi(1); % length of grid entry
  deltay = yi(2)-yi(1); % length of grid entry
  h = surf(Xi-deltax/2, Yi-deltay/2, zeros(size(Zi)), Zi, 'EdgeColor', 'none', 'FaceColor', shading);
  set(h, 'tag', tag);
  if ~isempty(parent)
    set(h, 'Parent', parent);
  end

  % this is an alternative to using NaN values to hide parts of the interpolated data (outside the circle), but fails in eps files
  % the NaN solution is more robust and works for all renderers and file formats
  %   if ~isempty(maskimage)
  %     set(h, 'facealpha', 'flat');
  %     set(h, 'alphadatamapping', 'scaled');
  %     set(h, 'alphadata', maskimage);
  %   end

elseif strcmp(style, 'imsat') || strcmp(style, 'imsatiso')
  % Plot the surface in an alternate style (using imagesc and saturation masking) so that it can be nicely saved to a vectorized format

  % set mask and cdat, and check for clim
  if isempty(clim)
    ft_error('clim is required for style = ''imsat'' or style = ''imsatiso''')
  end

  cmap    = get(gcf, 'colormap');
  rgbcdat = cdat2rgb(Zi, cmap, clim, maskimage~=0);

  h = imagesc(xi, yi, rgbcdat, clim);
  set(h, 'tag', tag);

elseif strcmp(style, 'colormix')
  % Plot the surface in an alternate style (using imagesc and saturation masking) so that it can be nicely saved to a vectorized format

  % set mask and cdat, and check for clim
  if isempty(clim)
    error('clim is required for style = ''colormix''')
  end

  if ~isempty(datmask)
    % use maskimagetmp in combination with maskimage, maskimagetmp is
    % scaled between 0 and 1
    maskimagetmp = maskimagetmp./max(maskimagetmp(:));
    Zmask        = double(maskimage~=0);
    Zmask(Zmask>0) = maskimagetmp(Zmask>0);
  else
    Zmask        = double(maskimage~=0);
  end

  cmap    = get(gcf, 'colormap');
  rgbcdat = bg_rgba2rgb([1 1 1], Zi, cmap, clim, Zmask, 'rampup', [0 1]);

  h = imagesc(xi, yi, rgbcdat, clim);
  set(h,'tag',tag);

end

% Plot the outline of the head, ears and nose
for i=1:length(outline)
  xval = outline{i}(:, 1) * xScaling  + hpos;
  yval = outline{i}(:, 2) * yScaling + vpos;
  ft_plot_vector(xval, yval, 'Color', 'k', 'LineWidth', 2, 'tag', tag, 'parent', parent);
end

% Create isolines
if strcmp(style, 'iso') || strcmp(style, 'surfiso') ||  strcmp(style, 'imsatiso')
  if ~isempty(isolines)
    [cont, h] = contour(Xi, Yi, Zi, isolines, 'k');
    set(h, 'tag', tag);
    if ~isempty(parent)
      set(h, 'Parent', parent);
    end
  end
end

% Plot filled contours
if strcmp(style, 'isofill') && ~isempty(isolines)
  [cont, h] = contourf(Xi, Yi, Zi, isolines, 'k');
  set(h, 'tag', tag);
  if ~isempty(parent)
    set(h, 'Parent', parent);
  end
end

if box
  % this plots a box around the original hpos/vpos with appropriate width/height
  boxposition = zeros(1,4);
  boxposition(1) = hpos - width/2;
  boxposition(2) = hpos + width/2;
  boxposition(3) = vpos - height/2;
  boxposition(4) = vpos + height/2;
  ft_plot_box(boxposition);
end

% apply clim if it was given
if ~isempty(clim)
  caxis(clim)
end

% remember the current input arguments, so that they can be
% reused on a subsequent call in case the same input argument is given
previous_argin     = current_argin;
previous_maskimage = maskimage;

if ~holdflag
  hold off
end


function [y,newp,retcode]=sstate_file(obj,y,p,d,id) %#ok<INUSL>
% sstate_model -- shows the way of writing a RISE steady state file
%
% ::
%
%
%   [y,newp,retcode]=sstate_model(obj,y,p,d,id)
%
% Args:
%
%    - **obj** [rise|dsge]: model object (not always needed)
%
%    - **y** [vector]: endo_nbr x 1 vector of initial steady state
%
%    - **p** [struct]: parameter structure
%
%    - **d** [struct]: definitions
%
%    - **id** [vector]: location of the variables to calculate
%
% Returns:
%    :
%
%      CASE 1: one input argument
%
%    - **y** [cell array]: list of the variables for which the steady state
%    will be calculated within the steady state function
%
%    - **newp** [cell array]: List of the parameters calculated inside the
%    steady state function
%
%    - **retcode** [struct]: possible fields are "imposed", "unique", "loop".
%    The default value for all of those is false.
%      - "imposed": This tells RISE not to check that this is actually solves
%          the steady state. Hence, RISE will attempt to approximate the model
%          around the chosen point
%      - "unique": This tells RISE that the steady state is the same across
%          all regimes. RISE will call the function only once but instead of
%          using just any parameter vector, it will use the ergodic mean of
%          the parameter vector (mean across all regimes).
%      - "loop": This tells RISE that if the user was given the steady state
%          values for some of the variables, he would be able to compute the
%          steady state for the remaining variables. RISE will then exploit
%          this information to optimize over the variables that the user needs
%          for computing the steady state.
%
%      CASE 2: More than one input argument
%
%    - **y** []: endo_nbr x 1 vector of updated steady state
%
%    - **newp** [struct]: structure containing updated parameters if any
%
%    - **retcode** [0|number]: return 0 if there are no problems, else return
%      any number different from 0
%
% Note:
%
%    - If the user knows the steady state, it is always an advantage. If the
%    steady state is computed numerically, we don't know whether it is unique
%    or not. Not that it really matters but... some economists have a strong
%    aversion towards models with multiple equilibria.
%
%    - If the user does not know the solution for all the variables in the
%    steady state, it is a good idea to take a log-linear approximation for
%    the variables that potentially have a nonzero steady state. Hence the
%    user should give that information to RISE.
%
%    - One can potentially improve on the above point by explicit bounds on
%    the variables. But this is not implemented.
%
%    - An alternative that potentially avoids taking a loglinearization is to
%    to reset the values proposed by the optimizer whenever they are in a bad
%    region. It is unclear whether this always works.
%
%    - So be on the safe side, i.e. don't do like me: compute your steady
%    state analytically.
%
% Example:
%
%    See also:

retcode=0;
if nargin==1

    % list the variables for which we compute the steady state. Not all
    % variables need to be listed. The variables NOT in this list
    % automatically get a value of 0. RISE is responsible for calculating
    % the steady state of any variable it may have created. The user does
    % not have to worry about those.
    %----------------------------------------------------------------------
    y={'X','A','E','Z','V','MU','PAI','R','Q','LAMBDA','XI','C','M','Y',...
        'K','I','H','W','D','N','LC','LI','LM','LPI','LR'};

	% list of parameters herein calculated
	%-------------------------------------
	newp={};

    % flags on the calculation
    %--------------------------
    retcode=struct('unique',true,'imposed',true);
else
    % no parameters to update
    %-------------------------
    newp=[];

    % create definitions (auxiliary parameters) that are useful for solving
    % the steady state
    %----------------------------------------------------------------------
    z_ss=p.z_ss_trans*10000;
% 	phi_p = 100*abs(p.phi_p_trans);
% 	phi_k = 100*abs(p.phi_k_trans);
	mu_ss = 1 + p.mu_ss_trans;

    X=1;
    A=1;
    E=p.e_ss;
    Z=z_ss;
    V=1;
    % mu determined by policy
    MU=mu_ss;
    PAI=MU/p.g;
    R=MU/p.beta;
    Q=p.g/p.beta-1+p.delta;
    % lambda comes here
    l1ss=1/(p.theta/(p.theta-1)-(p.g-1+p.delta)*p.alpha/Q);
    l2ss=1/(1+E*(R/(R-1))^(p.gam-1));
    l3ss=(1-p.alpha)*Z*((p.theta-1)/p.theta)^(1/(1-p.alpha))*(p.alpha/Q)^(p.alpha/(1-p.alpha));
    LAMBDA=(p.eta+(1-p.alpha)*l1ss*l2ss)/l3ss;
    XI = (p.theta-1)/p.theta*LAMBDA;
    C = 1/(1+E*(R/(R-1))^(p.gam-1))*(1/LAMBDA);
    M = E*(R/(R-1))^p.gam*C;
    Y = 1/(1-(p.g-1+p.delta)*(p.theta-1)/p.theta*p.alpha/Q)*C;
    K = (p.theta-1)/p.theta*p.alpha*Y/Q;
    I = (p.g-1+p.delta)*K;
    H=1/Z*(Y/K^p.alpha)^(1/(1-p.alpha));
    W=(1-p.alpha)*(p.theta-1)/p.theta*Y/H;
    D = Y-W*H-Q*K;
    N=Y/H;
    LC=log(C);
    LI=log(I);
    LM=log(M);
    LPI=log(PAI);
    LR=log(R);
    ys=[X A E Z V MU PAI R Q LAMBDA XI C M Y K I H W D N LC LI LM LPI LR].';

    % check the validity of the calculations
    %----------------------------------------
    if ~utils.error.valid(ys)||any(abs(ys)>100000)
        retcode=1;
    else
        % push the calculations
        %----------------------
        y(id)=ys;
    end
end

end


function [surface_handles, ax] = canlab_canonical_brain_surface_cutaways(method_keyword, varargin)
% Create one of a number of pre-set 3D brain views, and return surface handles for rendering
%
% :Usage:
% ::
%
% [surface_handles, axis_handles] = canlab_canonical_brain_surface_cutaways(method_keyword, ['noverbose'])
%
% - Uses fmri_data.isosurface method, which is a flexible way of creating surfaces
% - You can then render activation blobs on these surfaces using the
%   surface() object methods for CANlab objects or cluster_surf
%
% - Uses a pre-set group-average anatomical image tuned for quality visual display
%   ('keuken_2014_enhanced_for_underlay.img') from Keuken et al. 7T atlas
%
%   Keuken et al. (2014). Quantifying inter-individual anatomical variability in the subcortex using 7T structural MRI
%   Forstmann et al. (2014). Forstmann, Birte U., Max C. Keuken, Andreas Schafer, Pierre-Louis Bazin, Anneke Alkemade, and Robert Turner. 2014. ?Multi-Modal Ultra-High Resolution Structural 7-Tesla MRI Data Repository.? Scientific Data 1 (December): 140050.
%
% - This function is called from addbrain, which has many options for
%   surface rendering.
%
% - fmri_data.isosurface() can be used to create many more custom surfaces
%   See this code for examples.
%
% :Inputs:
%
%   **method_keyword:** One of the following:
%     'left_cutaway'
%     'right_cutaway'
%     'left_insula_slab'
%     'right_insula_slab'
%     'accumbens_slab'
%
% :Outputs:
%   **A figure display with rendering**
%
%   **surface_handles:**
%        A vector of handles to surface objects (isosurfaces and isocaps)
%
%  % To recreate these isosurfaces, do this:
% anat = fmri_data(which('keuken_2014_enhanced_for_underlay.img'), 'noverbose');
% [isosurf, isocap] = deal({});
% [p, ~, isosurf{1}, isocap{1}] = isosurface(anat, 'thresh', 140, 'nosmooth', 'ylim', [-Inf -30]);
% [p2, ~, isosurf{2}, isocap{2}] = isosurface(anat, 'thresh', 140, 'nosmooth', 'xlim', [-Inf 0], 'YLim', [-30 Inf]);
%
% :See also:
%   fmri_data.isosurface, addbrain, cluster_cutaways, fmri_data.surface,
%   region.surface
%

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

% load this to create new isosurfaces, but not needed to load existing saved ones:
% anat = fmri_data(which('keuken_2014_enhanced_for_underlay.img'), 'noverbose');

ax = gca;

doverbose = true;
if any(strcmp(varargin, 'noverbose')), doverbose = false; end

anat.source_notes = {};
anat.source_notes{1, 1} = 'Anatomical image: Adapted from the 7T high-resolution atlas of Keuken, Forstmann et al.';
anat.source_notes{2, 1} = 'Keuken et al. (2014). Quantifying inter-individual anatomical variability in the subcortex using 7T structural MRI. ';
anat.source_notes{3, 1} = 'Forstmann, Birte U., Max C. Keuken, Andreas Schafer, Pierre-Louis Bazin, Anneke Alkemade, and Robert Turner. 2014. ?Multi-Modal Ultra-High Resolution Structural 7-Tesla MRI Data Repository.? Scientific Data 1 (December): 140050.';

switch method_keyword

    case {'cutaway' 'cutaways' 'left_cutaway'}

        % To recreate these isosurfaces, do this:
        %         [isosurf, isocap] = deal({});
        %         [p, ~, isosurf{1}, isocap{1}] = isosurface(anat, 'thresh', 140, 'nosmooth', 'ylim', [-Inf -30]);
        %         [p2, ~, isosurf{2}, isocap{2}] = isosurface(anat, 'thresh', 140, 'nosmooth', 'xlim', [-Inf 0], 'YLim', [-30 Inf]);
        %
        %         save('canlab_canonical_brain_surface_left_cutaway', 'isosurf', 'isocap');

        load('canlab_canonical_brain_surface_left_cutaway', 'isosurf', 'isocap');
        p = draw_isosurface_patches(isosurf, isocap, [.5 .5 .5]);

        p3 = addbrain('limbic hires');
        alpha 1
        delete(p3(3)); p3(3) = [];
        set(p3, 'FaceAlpha', .6, 'FaceColor', [.5 .5 .5]);

        set_slab_view_properties(p, [135 15])

        surface_handles = [p p3];

    case 'right_cutaway'

        %         [isosurf, isocap] = deal({});
        %         [p, ~, isosurf{1}, isocap{1}] = isosurface(anat, 'thresh', 140, 'nosmooth', 'ylim', [-Inf -30]);
        %         [p2, ~, isosurf{2}, isocap{2}] = isosurface(anat, 'thresh', 140, 'nosmooth', 'xlim', [0 Inf], 'yLim', [-30 Inf]);
        %         save('canlab_canonical_brain_surface_right_cutaway', 'isosurf', 'isocap');

        load('canlab_canonical_brain_surface_right_cutaway', 'isosurf', 'isocap');
        p = draw_isosurface_patches(isosurf, isocap, [.5 .5 .5]);

        p3 = addbrain('limbic hires');
        alpha 1
        delete(p3(3)); p3(3) = [];
        set(p3, 'FaceAlpha', .6, 'FaceColor', [.5 .5 .5]);

        set_slab_view_properties(p, [-137 14])

        surface_handles = [p p3];

    case 'left_insula_slab'

        %         [isosurf, isocap] = deal({});
        %         [p, ~, isosurf{1}, isocap{1}] = isosurface(anat, 'thresh', 140, 'nosmooth', 'xlim', [15 44], 'yLim', [-45 Inf]);
        %          save('canlab_canonical_brain_surface_left_insula', 'isosurf', 'isocap');
        %
        load('canlab_canonical_brain_surface_left_insula', 'isosurf', 'isocap');
        p = draw_isosurface_patches(isosurf, isocap, [.5 .5 .5]);

        set_slab_view_properties(p, [271 0])
        surface_handles = p;

    case 'right_insula_slab'

        %         [isosurf, isocap] = deal({});
        %         [p, ~, isosurf{1}, isocap{1}] = isosurface(anat, 'thresh', 140, 'nosmooth', 'xlim', [-15 -44], 'YLim', [-45 Inf]);
        %         save('canlab_canonical_brain_surface_right_insula', 'isosurf', 'isocap');
        %
        load('canlab_canonical_brain_surface_right_insula', 'isosurf', 'isocap');
        p = draw_isosurface_patches(isosurf, isocap, [.5 .5 .5]);

        set_slab_view_properties(p, [91 0])
        surface_handles = p;

    case 'accumbens_slab'

        %         [isosurf, isocap] = deal({});
        %         [p, ~, isosurf{1}, isocap{1}] = isosurface(anat, 'thresh', 140, 'nosmooth', 'yLim', [-18 8]);
        %         save('canlab_canonical_brain_surface_accumbens_slab', 'isosurf', 'isocap');
        % %
        load('canlab_canonical_brain_surface_accumbens_slab', 'isosurf', 'isocap');
        p = draw_isosurface_patches(isosurf, isocap, [.5 .5 .5]);

        set_slab_view_properties(p, [156 0])
        surface_handles = p;

    case 'coronal_slabs'

        % surface_handles = render_coronal_slabs(anat, 6);

        [surface_handles, ax] = draw_coronal_slab_patches('canlab_canonical_brain_surface_coronal_slabs6');

    case 'coronal_slabs_4'

        % surface_handles = render_coronal_slabs(anat, 4);

        [surface_handles, ax] = draw_coronal_slab_patches('canlab_canonical_brain_surface_coronal_slabs4');

    case 'coronal_slabs_5'

        % surface_handles = render_coronal_slabs(anat, 5);

        [surface_handles, ax] = draw_coronal_slab_patches('canlab_canonical_brain_surface_coronal_slabs5');

    otherwise
        error('illegal method keyword.');

end % switch

if doverbose
    disp(char(anat.source_notes));
end

end % main function

function set_slab_view_properties(p, az_el)

set(p, 'FaceAlpha', 1);
colormap(gca, gray);
axis vis3d image
view(az_el(1), az_el(2));
lightRestoreSingle;

end

function [p, isosurf, isocap] = render_coronal_slabs(anat, nslabs)
% Use this to create custom isosurface slabs

start_mm = -80;
end_mm = 50;
slab_thickness_mm = 20;

st = linspace(start_mm, end_mm - slab_thickness_mm, nslabs); % define starting points

axwid = 2*0.8 / (nslabs + 1);
xstart = .1;
ystart = .9 - axwid;
xpos = linspace(xstart, .65, nslabs);
ypos = linspace(ystart, .7 - axwid, nslabs);

p = {};

for i = 1:nslabs
    ax = axes('Position', [xpos(i) ypos(i) axwid axwid]);
    [p{i}, ~, isosurf{i}, isocap{i}] = isosurface(anat, 'thresh', 140, 'nosmooth', 'yLim', [st(i) st(i)+slab_thickness_mm]);
    set(ax, 'Color', 'none');
    set_slab_view_properties(p{i}, [135 12])
    axis off
    drawnow
end

p = cat(2, p{:});

% *pause and save file here if creating stock slabs*
end

function [p, ax] = draw_coronal_slab_patches(isosurfacefilename)
% Use this to draw patches from saved isosurface slabs

load(isosurfacefilename, 'isosurf', 'isocap')
nslabs = length(isosurf);

start_mm = -80;
end_mm = 50;
slab_thickness_mm = 20;

st = linspace(start_mm, end_mm - slab_thickness_mm, nslabs); % define starting points

axwid = 2*0.8 / (nslabs + 1);
xstart = .1;
ystart = .9 - axwid;
xpos = linspace(xstart, .65, nslabs);
ypos = linspace(ystart, .7 - axwid, nslabs);

p = {};

for i = 1:nslabs
    ax = axes('Position', [xpos(i) ypos(i) axwid axwid]);
    %[p{i}, ~, isosurf{i}, isocap{i}] = isosurface(anat, 'thresh', 140, 'nosmooth', 'yLim', [st(i) st(i)+slab_thickness_mm]);
    p{i} = draw_isosurface_patches(isosurf(i),  isocap(i), [.5 .5 .5]);
    set(ax, 'Color', 'none');
    set_slab_view_properties(p{i}, [135 12])
    axis off
    drawnow
end

p = cat(2, p{:});
end

function p = draw_isosurface_patches(my_isosurface,  my_isocap, mycolor)

p = [];

for i = 1:length(my_isosurface) % cell
    p(end + 1) = patch('Faces',my_isosurface{i}.faces,'Vertices',my_isosurface{i}.vertices,'FaceColor', mycolor, ...
        'EdgeColor','none','SpecularStrength', .2,'FaceAlpha', .3,'SpecularExponent', 200);
end

for i = 1:length(my_isocap) % cell
    p(end + 1) = patch(my_isocap{i}, 'FaceColor', 'interp','EdgeColor', 'none', 'FaceAlpha',1);
end

end


function [keyPresses , elapsedTime] = RobotHardKeyBoard(CommPort)
%function [keyPresses , elapsedTime] = RobotHardKeyBoard(CommPort);
%permits control of robot via numerical key pad on a physical key board
% Numerical keypad presets:
%8-moves Roomba forward 10cm
%5-moves Roomba backward 5cm
%4-turns Roomba left 15 degrees
%7-slightly turns Roomba left 5 degrees
%6-turns Roomba right 15 degrees
%9-slightly turns Roomba right 5 degrees

%Alphabetical key presets:
%y-moves Roomba forward 10cm
%h-moves Roomba backward 5cm
%g-turns Roomba left 15 degrees
%t-slightly turns Roomba left 5 degrees
%j-turns Roomba right 15 degrees
%u-slightly turns Roomba right 5 degrees
%
% q quits
%
% input is a number for the comm port ex.   use 1, for COM1
% if omitted, set to default to 9.
% outputs: keypresses = total number of key pressed  (q doesn't count, but
% all other keys, including inactive ones ex 'a' do
% elapsedTime time in seconds since first keypress. can be 0 if q pressed
% immediately
disp('Wait for robot beep...')
a = instrfind();
if ~isempty(a)
    fclose(a);
    pause(1);
    delete(a);
    pause(1);
end

if nargin==0
    CommPort = 9;
end

ser = RoombaInit(CommPort);

im = imread('KeyBoardControl.png');

%logging variables
keyPresses = [0 0];
startTime = [];
elapsedTime = [];
%-------------------------------------------
%        SWITCH SPEEDS AND ANGLES HERE
%
% bD=distance forward sD=distance backward
% sA=small turn angle bA=big turn angle
% sV=backwardspeed bV=forwardspeed
% sW=small angle speed bW=big angle speed
%
%-------------------------------------------
%
% speeds and angles
sV = .1; sD = 0.05; % vel in m/s angles in deg W is angluar speed but in m/s?
bV = .2; bD = 0.1;
sW = .05; sA = 5;
bW = .1; bA = 15;

% set up hidden key logger window
callstr = ['set(gcbf,''Userdata'',double(get(gcbf,''Currentcharacter''))) ; uiresume '];
fh = figure('keypressfcn',callstr, ...
    'windowstyle','modal',...
    'units', 'normalized',...
    'position',[.1 .1 .8 .8],...
    'Name','GETKEY', ...
    'userdata','timeout') ;
imshow(im);

disp('Starting Keyboard Mode.   Press q to quit.   ')

while(1)
  uiwait ;
  try
      %disp('here');  why does a single keypress appear to trigger two
      %events.   First with empty, then actual character????   JME 5/26
      k = char( get(fh,'Userdata') );

  catch
    k = nan ;
  end

  if ~isempty(k)&& k~='q'
    keyPresses(1) = keyPresses(1) +1;
    %disp(k)
  end
if isempty(startTime)
    startTime = tic;
end
%-------------------------------------
%       SWITCH KEYBOARD KEYS HERE
%-------------------------------------
if ~isempty(k)
switch k
    %2
    case {'5','h'}
        travelDist(ser, sV, -sD);
    case {'4','g'}
        turnAngle(ser, bW, bA);
    case {'6','j'}
        turnAngle(ser, bW, -bA);
    case {'7','t'}
        turnAngle(ser, sW, sA);
    case {'8','y'}
        travelDist(ser, bV, bD);
    case {'9','u'}
        turnAngle(ser, sW, -sA);
    case '0'
        elapsedTime = toc(startTime);
        fprintf('Sec:  %.2f,  Keystrokes: %d, NegKey: %d \n ', [elapsedTime keyPresses(1) keyPresses(2)]);
    case 'q'
        if ~isempty(startTime)
        elapsedTime = toc(startTime);
        else
            elapsedTime =0;
        end
        fprintf('Sec:  %.2f,  Keystrokes: %d, NegKey: %d \n ', [elapsedTime keyPresses(1) keyPresses(2)]);
        delete(fh);
        break
    otherwise
        disp('Otherwise')
        keyPresses(2) = keyPresses(2) +1;
end % end switch k
end % if ~isempty(k)
end % end while(1)


function plot_results(varargin)
%PLOT_RESULTS Plots all results for a given dataset.
%   Name-value pairs are supported, listed below.
%   E.g.: plot_results('dataset', 'imagenet', 'set', 'val')

  opts.dataset = 'cifar';  % choose dataset
  opts.set = 'train';  % train or val
  opts.var = 'err';  % err or obj (error/objective)
  opts.save = false;  % if true, saves as a PDF file in the base directory

  opts.baseDir = [vl_rootnn() '/data/curveball/<dataset>'];  % results location
  opts.subdir = '';  % optional subdirectory

  opts = vl_argparse(opts, varargin);

  % compose directory where experiments are located
  base = strrep(opts.baseDir, '<dataset>', opts.dataset);
  base = [base '/' opts.subdir];

  % list experiments (folders)
  folders = dir(base);

  figure(10);
  clf();
  hold('on');
  ax = gca();
  set(ax, 'lineStyleOrder', {'-','--','-.',':','*','+'});

  for i = 1:numel(folders)
    name = folders(i).name;

    if folders(i).isdir && ~strncmp(name, '.', 1)
      % try to load final results first
      filename = [base '/' name '/results.mat'];
      if ~exist(filename, 'file')
        % if it doesn't exist, look for the most recent checkpoint
        filename = models.checkpoint([base '/' name '/epoch-*.mat']);
      end

      if ~isempty(filename)
        % load result statistics
        data = load(filename, 'stats');

        % get the relevant curve
        values = data.stats.values(opts.set, opts.var);

        % display it
        plot(values, 'DisplayName', name, 'LineWidth',2);
      end
    end
  end

  % make plots look nice
  legend('show');
  grid('on');

  xlabel('Epochs');
  ylabel([opts.set ' ' opts.var]);

  % save to PDF
  if opts.save
    filename = [base '/results.pdf'];
    print(10, filename, '-dpdf');
  end
end


% Ryan Steindl based on Robotics Toolbox for MATLAB (v6 and v9)
%
% Copyright (C) 1993-2011, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for MATLAB (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com
function v = double(q)
%Quaternion.double Convert a quaternion object to a 4-element vector
%
% V = Q.double() is a 4-vector comprising the quaternion
% elements [s vx vy vz].

    v = [q.s q.v];
endfunction