/* RED.nodes.registerType("email-listen",EmailInNode,{
credentials: {
userid: { type:"text" },
password: { type: "password" },
global: { type:"boolean" }
}
}); 
__DOCSPLACEHOLDER__

@param {any} params __DOCSPLACEHOLDER__
971122
function ListenToEmail(params) {
        RED.nodes.createNode(this, params);
        this.name = params.name;
        this.waitfor = params.waitfor;
        let node = this;
        this.on('input', function(msg) {
            if (msg.error) {
                // FIXME: Add error handling here
            } else {
                node.log('ListenToEmail');
                // node.log(JSON.stringify(params));
                retryParams = params;
                emailInNode(node, params, msg);
            }
        });
        this.on('close', function() {
            if (node.interval_id != null) {
                clearInterval(node.interval_id);
            }
            if (imap) {
                imap.destroy();
            }
        });

        // Repeat interval
        if (!isNaN(params.repeat) && params.repeat > 0) {
            node.interval_id = setInterval(function() {
                if (retryParams) {
                    console.log('>Calling node emit input');
                    node.emit('input', retryParams);
                }
            }, params.repeat * 1000);
        }
    }
368742
function (node, options) {

        var errors = [],
            messages = {},
            formData = {},
            delegateSuffix = ".vd", // validation.delegate
            resetSuffix = ".vr";    // validation.resetError

        window.Validation.hasScrolled = false;

        /**
         * Extends user-defined "options.message" into the default Validation "_message".
         */
        function extendRules() {
            options.rules = $.extend(
                true,
                {},
                _rules,
                options.rules
            );
        }

        /**
         * Extends user-defined "options.message" into the default Validation "_message".
         */
        function extendMessages() {
            options.messages = $.extend(
                true,
                {},
                _messages,
                options.messages
            );
        }

        /**
         * Extends user-defined "options" into the default Validation "_options".
         * Notes:
         *  - preventExtensions prevents from modifying the Validation "_options" object structure
         *  - filter through the "_supported" to delete unsupported "options"
         */
        function extendOptions() {

            if (!(options instanceof Object)) {
                options = {};
            }

            var tpmOptions = Object.preventExtensions($.extend(true, {}, _options));

            for (var method in options) {

                if (!options.hasOwnProperty(method) || method === "debug") {
                    continue;
                }

                if (~["labels", "messages", "rules"].indexOf(method) && options[method] instanceof Object) {
                    tpmOptions[method] = options[method];
                    continue;
                }

                if (!_options[method] || !(options[method] instanceof Object)) {

                    // {debug}
                    options.debug && window.Debug.log({
                        'node': node,
                        'function': 'extendOptions()',
                        'arguments': '{' + method + ': ' + JSON.stringify(options[method]) + '}',
                        'message': 'WARNING - ' + method + ' - invalid option'
                    });
                    // {/debug}

                    continue;
                }

                for (var type in options[method]) {
                    if (!options[method].hasOwnProperty(type)) {
                        continue;
                    }

                    if (!_options[method][type] || !(options[method][type] instanceof Object)) {

                        // {debug}
                        options.debug && window.Debug.log({
                            'node': node,
                            'function': 'extendOptions()',
                            'arguments': '{' + type + ': ' + JSON.stringify(options[method][type]) + '}',
                            'message': 'WARNING - ' + type + ' - invalid option'
                        });
                        // {/debug}

                        continue;
                    }

                    for (var option in options[method][type]) {
                        if (!options[method][type].hasOwnProperty(option)) {
                            continue;
                        }

                        if (_supported[method] &&
                            _supported[method][type] &&
                            _supported[method][type][option] &&
                            $.inArray(options[method][type][option], _supported[method][type][option]) === -1) {

                            // {debug}
                            options.debug && window.Debug.log({
                                'node': node,
                                'function': 'extendOptions()',
                                'arguments': '{' + option + ': ' + JSON.stringify(options[method][type][option]) + '}',
                                'message': 'WARNING - ' + option.toString() + ': ' + JSON.stringify(options[method][type][option]) + ' - unsupported option'
                            });
                            // {/debug}

                            delete options[method][type][option];
                        }

                    }
                    if (tpmOptions[method] && tpmOptions[method][type]) {
                        tpmOptions[method][type] = $.extend(Object.preventExtensions(tpmOptions[method][type]), options[method][type]);
                    }
                }
            }

            // {debug}
            if (options.debug && $.inArray(options.debug, _supported.debug !== -1)) {
                tpmOptions.debug = options.debug;
            }
            // {/debug}

            // @TODO Would there be a better fix to solve event conflict?
            if (tpmOptions.dynamic.settings.trigger) {
                if (tpmOptions.dynamic.settings.trigger === "keypress" && tpmOptions.submit.settings.clear === "keypress") {
                    tpmOptions.dynamic.settings.trigger = "keydown";
                }
            }

            options = tpmOptions;

        }

        /**
         * Delegates the dynamic validation on data-validation and data-validation-regex attributes based on trigger.
         *
         * @returns {Boolean} false if the option is not set
         */
        function delegateDynamicValidation() {

            if (!options.dynamic.settings.trigger) {
                return false;
            }

            // {debug}
            options.debug && window.Debug.log({
                'node': node,
                'function': 'delegateDynamicValidation()',
                'message': 'OK - Dynamic Validation activated on ' + node.length + ' form(s)'
            });
            // {/debug}

            if (!node.find('[' + _data.validation + '],[' + _data.regex + ']')[0]) {

                // {debug}
                options.debug && window.Debug.log({
                    'node': node,
                    'function': 'delegateDynamicValidation()',
                    'arguments': 'node.find([' + _data.validation + '],[' + _data.regex + '])',
                    'message': 'ERROR - [' + _data.validation + '] not found'
                });
                // {/debug}

                return false;
            }

            var event = options.dynamic.settings.trigger + delegateSuffix;
            if (options.dynamic.settings.trigger !== "focusout") {
                event += " change" + delegateSuffix + " paste" + delegateSuffix;
            }

            $.each(
                node.find('[' + _data.validation + '],[' + _data.regex + ']'),
                function (index, input) {

                    $(input).unbind(event).on(event, function (e) {

                        if ($(this).is(':disabled')) {
                            return false;
                        }

                        //e.preventDefault();

                        var input = this,
                            keyCode = e.keyCode || null;

                        _typeWatch(function () {

                            if (!validateInput(input)) {

                                displayOneError(input.name);
                                _executeCallback(options.dynamic.callback.onError, [node, input, keyCode, errors[input.name]]);

                            } else {

                                _executeCallback(options.dynamic.callback.onSuccess, [node, input, keyCode]);

                            }

                            _executeCallback(options.dynamic.callback.onComplete, [node, input, keyCode]);

                        }, options.dynamic.settings.delay);

                    });
                }
            );
        }

        /**
         * Delegates the submit validation on data-validation and data-validation-regex attributes based on trigger.
         * Note: Disable the form submit function so the callbacks are not by-passed
         */
        function delegateValidation() {

            _executeCallback(options.submit.callback.onInit, [node]);

            var event = options.submit.settings.trigger + '.vd';

            // {debug}
            options.debug && window.Debug.log({
                'node': node,
                'function': 'delegateValidation()',
                'message': 'OK - Validation activated on ' + node.length + ' form(s)'
            });
            // {/debug}

            if (!node.find(options.submit.settings.button)[0]) {

                // {debug}
                options.debug && window.Debug.log({
                    'node': node,
                    'function': 'delegateValidation()',
                    'arguments': '{button: ' + options.submit.settings.button + '}',
                    'message': 'ERROR - node.find("' + options.submit.settings.button + '") not found'
                });
                // {/debug}

                return false;

            }

            node.on("submit", false);
            node.find(options.submit.settings.button).off('.vd').on(event, function (e) {

                e.preventDefault();

                resetErrors();

                _executeCallback(options.submit.callback.onValidate, [node]);

                if (!validateForm()) {

                    displayErrors();
                    _executeCallback(options.submit.callback.onError, [node, errors, formData]);

                } else {

                    _executeCallback(options.submit.callback.onBeforeSubmit, [node]);

                    if (typeof options.submit.callback.onSubmit === "function") {
                        if (_executeCallback(options.submit.callback.onSubmit, [node, formData]) === true) {
                            submitForm();
                        }
                    } else {
                        submitForm();
                    }

                    _executeCallback(options.submit.callback.onAfterSubmit, [node]);

                }

                // {debug}
                options.debug && window.Debug.print();
                // {/debug}

                return false;

            });

        }

        /**
         * For every "data-validation" & "data-pattern" attributes that are not disabled inside the jQuery "node" object
         * the "validateInput" function will be called.
         *
         * @returns {Boolean} true if no error(s) were found (valid form)
         */
        function validateForm() {

            var isValid = isEmpty(errors);

            formData = {};

            $.each(
                node.find('input:not([type="submit"]), select, textarea').not(':disabled'),
                function(index, input) {

                    input = $(input);

                    var value = _getInputValue(input[0]),
                        inputName = input.attr('name');

                    if (inputName) {
                        if (/\[]$/.test(inputName)) {
                            inputName = inputName.replace(/\[]$/, '');
                            if (!(formData[inputName] instanceof Array)) {
                                formData[inputName] = [];
                            }
                            formData[inputName].push(value)
                        } else {
                            formData[inputName] = value;
                        }
                    }

                    if (!!input.attr(_data.validation) || !!input.attr(_data.regex)) {
                        if (!validateInput(input[0], value)) {
                            isValid = false;
                        }
                    }
                }
            );

            prepareFormData();

            return isValid;

        }

        /**
         * Loop through formData and build an object
         *
         * @returns {Object} data
         */
        function prepareFormData() {

            var data = {},
                matches,
                index;

            for (var i in formData) {
                if (!formData.hasOwnProperty(i)) continue;

                index = 0;
                matches = i.split(/\[(.+?)]/g);

                var tmpObject = {},
                    tmpArray = [];

                for (var k = matches.length - 1; k >= 0; k--) {
                    if (matches[k] === "") {
                        matches.splice(k, 1);
                        continue;
                    }

                    if (tmpArray.length < 1) {
                        tmpObject[matches[k]] = Number(formData[i]) || formData[i];
                    } else {
                        tmpObject = {};
                        tmpObject[matches[k]] = tmpArray[tmpArray.length - 1];
                    }
                    tmpArray.push(tmpObject)

                }

                data = $.extend(true, data, tmpObject);

            }

            formData = data;

        }

        /**
         * Prepare the information from the data attributes
         * and call the "validateRule" function.
         *
         * @param {Object} input Reference of the input element
         *
         * @returns {Boolean} true if no error(s) were found (valid input)
         */
        function validateInput(input, value) {

            var inputName = $(input).attr('name'),
                value = value || _getInputValue(input);

            if (!inputName) {

                // {debug}
                options.debug && window.Debug.log({
                    'node': node,
                    'function': 'validateInput()',
                    'arguments': '$(input).attr("name")',
                    'message': 'ERROR - Missing input [name]'
                });
                // {/debug}

                return false;
            }

            var matches = inputName.replace(/]$/, '').split(/]\[|[[\]]/g),
                inputShortName = window.Validation.labels[inputName] ||
                    options.labels[inputName] ||
                    $(input).attr(_data.label) ||
                    matches[matches.length - 1],

                validationArray = $(input).attr(_data.validation),
                validationMessage = $(input).attr(_data.validationMessage),
                validationRegex = $(input).attr(_data.regex),
                validationRegexReverse = !($(input).attr(_data.regexReverse) === undefined),
                validationRegexMessage = $(input).attr(_data.regexMessage),

                validateOnce = false;

            if (validationArray) {
                validationArray = _api._splitValidation(validationArray);
            }

            // Validates the "data-validation"
            if (validationArray instanceof Array && validationArray.length > 0) {

                // "OPTIONAL" input will not be validated if it's empty
                if ($.trim(value) === '' && ~validationArray.indexOf('OPTIONAL')) {
                    return true;
                }

                $.each(validationArray, function (i, rule) {

                    if (validateOnce === true) {
                        return true;
                    }

                    try {

                        validateRule(value, rule);

                    } catch (error) {

                        if (validationMessage || !options.submit.settings.allErrors) {
                            validateOnce = true;
                        }

                        error[0] = validationMessage || error[0];

                        registerError(inputName, error[0].replace('$', inputShortName).replace('%', error[1]));

                    }

                });

            }

            // Validates the "data-validation-regex"
            if (validationRegex) {

                var rule = _buildRegexFromString(validationRegex);

                // Do not block validation if a regexp is bad, only skip it
                if (!(rule instanceof RegExp)) {
                    return true;
                }

                try {

                    validateRule(value, rule, validationRegexReverse);

                } catch (error) {

                    error[0] = validationRegexMessage || error[0];

                    registerError(inputName, error[0].replace('$', inputShortName));

                }

            }

            return !errors[inputName] || errors[inputName] instanceof Array && errors[inputName].length === 0;

        }

        /**
         * Validate an input value against one rule.
         * If a "value-rule" mismatch occurs, an error is thrown to the caller function.
         *
         * @param {String} value
         * @param {*} rule
         * @param {Boolean} [reversed]
         *
         * @returns {*} Error if a mismatch occurred.
         */
        function validateRule(value, rule, reversed) {

            // Validate for "data-validation-regex" and "data-validation-regex-reverse"
            if (rule instanceof RegExp) {
                var isValid = rule.test(value);

                if (reversed) {
                    isValid = !isValid;
                }

                if (!isValid) {
                    throw [options.messages['default'], ''];
                }
                return;
            }

            if (options.rules[rule]) {
                if (!options.rules[rule].test(value)) {
                    throw [options.messages[rule], ''];
                }
                return;
            }

            // Validate for comparison "data-validation"
            var comparison = rule.match(options.rules.COMPARISON);

            if (!comparison || comparison.length !== 4) {

                // {debug}
                options.debug && window.Debug.log({
                    'node': node,
                    'function': 'validateRule()',
                    'arguments': 'value: ' + value + ' rule: ' + rule,
                    'message': 'WARNING - Invalid comparison'
                });
                // {/debug}

                return;
            }

            var type = comparison[1],
                operator = comparison[2],
                compared = comparison[3],
                comparedValue;

            switch (type) {

                // Compare input "Length"
                case "L":

                    // Only numeric value for "L" are allowed
                    if (isNaN(compared)) {

                        // {debug}
                        options.debug && window.Debug.log({
                            'node': node,
                            'function': 'validateRule()',
                            'arguments': 'compare: ' + compared + ' rule: ' + rule,
                            'message': 'WARNING - Invalid rule, "L" compare must be numeric'
                        });
                        // {/debug}

                        return false;

                    } else {

                        if (!value || eval(value.length + operator + parseFloat(compared)) === false) {
                            throw [options.messages[operator], compared];
                        }

                    }

                    break;

                // Compare input "Value"
                case "V":
                default:

                    // Compare Field values
                    if (isNaN(compared)) {

                        comparedValue = node.find('[name="' + compared + '"]').val();
                        if (!comparedValue) {

                            // {debug}
                            options.debug && window.Debug.log({
                                'node': node,
                                'function': 'validateRule()',
                                'arguments': 'compare: ' + compared + ' rule: ' + rule,
                                'message': 'WARNING - Unable to find compared field [name="' + compared + '"]'
                            });
                            // {/debug}

                            return false;
                        }

                        if (!value || !eval('"' + encodeURIComponent(value) + '"' + operator + '"' + encodeURIComponent(comparedValue) + '"')) {
                            throw [options.messages[operator].replace(' characters', ''), compared];
                        }

                    } else {
                        // Compare numeric value
                        if (!value || isNaN(value) || !eval(value + operator + parseFloat(compared))) {
                            throw [options.messages[operator].replace(' characters', ''), compared];
                        }

                    }
                    break;

            }

        }

        /**
         * Register an error into the global "error" variable.
         *
         * @param {String} inputName Input where the error occurred
         * @param {String} error Description of the error to be displayed
         */
        function registerError(inputName, error) {

            if (!errors[inputName]) {
                errors[inputName] = [];
            }

            error = error.capitalize();

            var hasError = false;
            for (var i = 0; i < errors[inputName].length; i++) {
                if (errors[inputName][i] === error) {
                    hasError = true;
                    break;
                }
            }

            if (!hasError) {
                errors[inputName].push(error);
            }

        }

        /**
         * Display a single error based on "inputName" key inside the "errors" global array.
         * The input, the label and the "inputContainer" will be given the "errorClass" and other
         * settings will be considered.
         *
         * @param {String} inputName Key used for search into "errors"
         *
         * @returns {Boolean} false if an unwanted behavior occurs
         */
        function displayOneError(inputName) {

            var input,
                inputId,
                errorContainer,
                label,
                html = '<div class="' + options.submit.settings.errorListClass + '" ' + _data.errorList + '><ul></ul></div>',
                group,
                groupInput;

            if (!errors.hasOwnProperty(inputName)) {
                return false;
            }

            input = node.find('[name="' + inputName + '"]');

            label = null;

            if (!input[0]) {

                // {debug}
                options.debug && window.Debug.log({
                    'node': node,
                    'function': 'displayOneError()',
                    'arguments': '[name="' + inputName + '"]',
                    'message': 'ERROR - Unable to find input by name "' + inputName + '"'
                });
                // {/debug}

                return false;
            }

            group = input.attr(_data.group);

            if (group) {

                groupInput = node.find('[name="' + inputName + '"]');
                label = node.find('[id="' + group + '"]');

                if (label[0]) {
                    label.addClass(options.submit.settings.errorClass);
                    errorContainer = label;
                }

                //node.find('[' + _data.group + '="' + group + '"]').addClass(options.submit.settings.errorClass)

            } else {

                input.addClass(options.submit.settings.errorClass);

                if (options.submit.settings.inputContainer) {
                    input.parentsUntil(node, options.submit.settings.inputContainer).addClass(options.submit.settings.errorClass);
                }

                inputId = input.attr('id');

                if (inputId) {
                    label = node.find('label[for="' + inputId + '"]')[0];
                }

                if (!label) {
                    label = input.parentsUntil(node, 'label')[0];
                }

                if (label) {
                    label = $(label);
                    label.addClass(options.submit.settings.errorClass);
                }
            }

            if (options.submit.settings.display === 'inline') {
                if (options.submit.settings.errorListContainer) {
                    errorContainer = input.parentsUntil(node, options.submit.settings.errorListContainer);
                } else {
                    errorContainer = errorContainer || input.parent();
                }
            } else if (options.submit.settings.display === 'block') {
                errorContainer = node;
            }

            // Prevent double error list if the previous one has not been cleared.
            if (options.submit.settings.display === 'inline' && errorContainer.find('[' + _data.errorList + ']')[0]) {
                return false;
            }

            if (options.submit.settings.display === "inline" ||
                (options.submit.settings.display === "block" && !errorContainer.find('[' + _data.errorList + ']')[0])
            ) {
                if (options.submit.settings.insertion === 'append') {
                    errorContainer.append(html);
                } else if (options.submit.settings.insertion === 'prepend') {
                    errorContainer.prepend(html);
                }
            }

            for (var i = 0; i < errors[inputName].length; i++) {
                if (options.submit.settings.errorTemplate) {
                    errorContainer.find('[' + _data.errorList + '] ul')
                        .append('<li>' + options.submit.settings.errorTemplate.replace('{{validation-message}}', errors[inputName][i]) + '</li>');
                } else {
                    errorContainer.find('[' + _data.errorList + '] ul').append('<li>' + errors[inputName][i] + '</li>');
                }
            }

            if (options.submit.settings.clear || options.dynamic.settings.trigger) {

                if (group && groupInput) {
                    input = groupInput;
                }

                var event = "coucou" + resetSuffix;
                if (options.submit.settings.clear) {
                    event += " " + options.submit.settings.clear + resetSuffix;
                    if (~['radio', 'checkbox'].indexOf(input[0].type)) {
                        event += " change" + resetSuffix;
                    }
                }
                if (options.dynamic.settings.trigger) {
                    event += " " + options.dynamic.settings.trigger + resetSuffix;
                    if (options.dynamic.settings.trigger !== "focusout" && !~['radio', 'checkbox'].indexOf(input[0].type)) {
                        event += " change" + resetSuffix + " paste" + resetSuffix;
                    }
                }

                input.unbind(event).on(event, function (a, b, c, d, e) {

                    return function () {
                        if (e) {
                            if ($(c).hasClass(options.submit.settings.errorClass)) {
                                resetOneError(a, b, c, d, e);
                            }
                        } else if ($(b).hasClass(options.submit.settings.errorClass)) {
                            resetOneError(a, b, c, d);
                        }
                    };

                }(inputName, input, label, errorContainer, group));
            }

            if (options.submit.settings.scrollToError && !window.Validation.hasScrolled) {

                window.Validation.hasScrolled = true;

                var offset = parseFloat(options.submit.settings.scrollToError.offset) || 0,
                    duration = parseFloat(options.submit.settings.scrollToError.duration) || 500,
                    handle = (options.submit.settings.display === 'block') ? errorContainer : input;

                $('html, body').animate({
                    scrollTop: handle.offset().top + offset
                }, duration);

            }

        }

        /**
         * Display all of the errors
         */
        function displayErrors() {

            for (var inputName in errors) {
                if (!errors.hasOwnProperty(inputName)) continue;
                displayOneError(inputName);
            }

        }

        /**
         * Remove an input error.
         *
         * @param {String} inputName Key reference to delete the error from "errors" global variable
         * @param {Object} input jQuery object of the input
         * @param {Object} label jQuery object of the input's label
         * @param {Object} container jQuery object of the "errorList"
         * @param {String} [group] Name of the group if any (ex: used on input radio)
         */
        function resetOneError(inputName, input, label, container, group) {

            delete errors[inputName];

            if (container) {

                //window.Validation.hasScrolled = false;

                if (options.submit.settings.inputContainer) {
                    (group ? label : input).parentsUntil(node, options.submit.settings.inputContainer).removeClass(options.submit.settings.errorClass);
                }

                label && label.removeClass(options.submit.settings.errorClass);

                input.removeClass(options.submit.settings.errorClass);

                if (options.submit.settings.display === 'inline') {
                    container.find('[' + _data.errorList + ']').remove();
                }

            } else {

                if (!input) {
                    input = node.find('[name="' + inputName + '"]');

                    if (!input[0]) {

                        // {debug}
                        options.debug && window.Debug.log({
                            'node': node,
                            'function': 'resetOneError()',
                            'arguments': '[name="' + inputName + '"]',
                            'message': 'ERROR - Unable to find input by name "' + inputName + '"'
                        });
                        // {/debug}

                        return false;
                    }
                }

                input.trigger('coucou' + resetSuffix);
            }

        }

        /**
         * Remove all of the input error(s) display.
         */
        function resetErrors() {

            errors = [];
            window.Validation.hasScrolled = false;

            node.find('[' + _data.errorList + ']').remove();
            node.find('.' + options.submit.settings.errorClass).removeClass(options.submit.settings.errorClass);

        }

        /**
         * Submits the form once it succeeded the validation process.
         * Note:
         * - This function will be overridden if "options.submit.settings.onSubmit" is defined
         * - The node can't be submitted by jQuery since it has been disabled, use the form native submit function instead
         */
        function submitForm() {

            node[0].submit()

        }

        /**
         * Destroy the Validation instance
         *
         * @returns {Boolean}
         */
        function destroy() {

            resetErrors();
            node.find('[' + _data.validation + '],[' + _data.regex + ']').off(delegateSuffix + ' ' + resetSuffix);

            node.find(options.submit.settings.button).off(delegateSuffix).on('click' + delegateSuffix, function () {
                $(this).closest('form')[0].submit();
            });

            //delete window.Validation.form[node.selector];

            return true;

        }

        /**
         * @private
         * Helper to get the value of an regular, radio or chackbox input
         *
         * @param input
         *
         * @returns {String} value
         */
        var _getInputValue = function (input) {

            var value;

            // Get the value or state of the input based on its type
            switch ($(input).attr('type')) {
                case 'checkbox':
                    value = ($(input).is(':checked')) ? 1 : '';
                    break;
                case 'radio':
                    value = node.find('input[name="' + $(input).attr('name') + '"]:checked').val() || '';
                    break;
                default:
                    value = $(input).val();
                    break;
            }

            return value;

        };

        /**
         * @private
         * Execute function once the timer is reached.
         * If the function is recalled before the timer ends, the first call will be canceled.
         */
        var _typeWatch = (function () {
            var timer = 0;
            return function (callback, ms) {
                clearTimeout(timer);
                timer = setTimeout(callback, ms);
            };
        })();

        /**
         * @private
         * Executes an anonymous function or a string reached from the window scope.
         *
         * @example
         * Note: These examples works with every callbacks (onInit, onError, onSubmit, onBeforeSubmit & onAfterSubmit)
         *
         * // An anonymous function inside the "onInit" option
         * onInit: function() { console.log(':D'); };
         *
         * * // myFunction() located on window.coucou scope
         * onInit: 'window.coucou.myFunction'
         *
         * // myFunction(a,b) located on window.coucou scope passing 2 parameters
         * onInit: ['window.coucou.myFunction', [':D', ':)']];
         *
         * // Anonymous function to execute a local function
         * onInit: function () { myFunction(':D'); }
         *
         * @param {String|Array} callback The function to be called
         * @param {Array} [extraParams] In some cases the function can be called with Extra parameters (onError)
         *
         * @returns {Boolean}
         */
        var _executeCallback = function (callback, extraParams) {

            if (!callback) {
                return false;
            }

            var _callback;

            if (typeof callback === "function") {

                _callback = callback;

            } else if (typeof callback === "string" || callback instanceof Array) {

                _callback = window;

                if (typeof callback === "string") {
                    callback = [callback, []];
                }

                var _exploded = callback[0].split('.'),
                    _params = callback[1],
                    _isValid = true,
                    _splitIndex = 0;

                while (_splitIndex < _exploded.length) {

                    if (typeof _callback !== 'undefined') {
                        _callback = _callback[_exploded[_splitIndex++]];
                    } else {
                        _isValid = false;
                        break;
                    }
                }

                if (!_isValid || typeof _callback !== "function") {

                    // {debug}
                    options.debug && window.Debug.log({
                        'node': node,
                        'function': '_executeCallback()',
                        'arguments': JSON.stringify(callback),
                        'message': 'WARNING - Invalid callback function"'
                    });
                    // {/debug}

                    return false;
                }

            }

            return _callback.apply(this, $.merge(_params || [], (extraParams) ? extraParams : []));

        };

        /**
         * @private
         * Constructs Validation
         */
        this.__construct = function () {

            extendOptions();
            extendRules();
            extendMessages();

            delegateDynamicValidation();
            delegateValidation();

            // {debug}
            options.debug && window.Debug.print();
            // {/debug}

        }();

        return {

            /**
             * @public
             * Register error
             *
             * @param inputName
             * @param error
             */
            registerError: registerError,

            /**
             * @public
             * Display one error
             *
             * @param inputName
             */
            displayOneError: displayOneError,

            /**
             * @public
             * Display all errors
             */
            displayErrors: displayErrors,

            /**
             * @public
             * Remove one error
             */
            resetOneError: resetOneError,

            /**
             * @public
             * Remove all errors
             */
            resetErrors: resetErrors,

            /**
             * @public
             * Destroy the Validation instance
             */
            destroy: destroy

        };

    }
1069637
protected void serializeDocType(DocumentType node, boolean bStart)
        throws SAXException {
        // The DocType and internalSubset can not be modified in DOM and is
        // considered to be well-formed as the outcome of successful parsing.
        String docTypeName = node.getNodeName();
        String publicId = node.getPublicId();
        String systemId = node.getSystemId();
        String internalSubset = node.getInternalSubset();

        //DocumentType nodes are never passed to the filter
        
        if (internalSubset != null && !"".equals(internalSubset)) {

            if (bStart) {
                try {
                    // The Serializer does not provide a way to write out the
                    // DOCTYPE internal subset via an event call, so we write it
                    // out here.
                    Writer writer = fSerializer.getWriter();
                    StringBuffer dtd = new StringBuffer();

                    dtd.append("<!DOCTYPE ");
                    dtd.append(docTypeName);
                    if (null != publicId) {
                        dtd.append(" PUBLIC \"");
                        dtd.append(publicId);
                        dtd.append('\"');
                    }

                    if (null != systemId) {
                        if (null == publicId) {
                            dtd.append(" SYSTEM \"");
                        } else {
                            dtd.append(" \"");
                        }    
                        dtd.append(systemId);
                        dtd.append('\"');
                    }
                    
                    dtd.append(" [ ");
                    
                    dtd.append(fNewLine);
                    dtd.append(internalSubset);
                    dtd.append("]>");
                    dtd.append(new String(fNewLine));
                    
                    writer.write(dtd.toString());
                    writer.flush();
                    
                } catch (IOException e) {
                    throw new SAXException(Utils.messages.createMessage(
                            MsgKey.ER_WRITING_INTERNAL_SUBSET, null), e);
                }
            } // else if !bStart do nothing
            
        } else {
            
            if (bStart) {
                if (fLexicalHandler != null) {
                    fLexicalHandler.startDTD(docTypeName, publicId, systemId);
                }
            } else {
                if (fLexicalHandler != null) {
                    fLexicalHandler.endDTD();
                }
            }
        }
    }
1368294
private void validateTypeAnnotations(Node n, JSDocInfo info) {
    if (info != null && info.hasType()) {
      boolean valid = false;
      switch (n.getToken()) {
        // Function declarations are valid
        case FUNCTION:
          valid = NodeUtil.isFunctionDeclaration(n);
          break;
        // Object literal properties, catch declarations and variable
        // initializers are valid.
        case NAME:
          valid = isTypeAnnotationAllowedForName(n);
          break;
        case ARRAY_PATTERN:
        case OBJECT_PATTERN:
          // allow JSDoc like
          //   function f(/** !Object */ {x}) {}
          //   function f(/** !Array */ [x]) {}
          valid = n.getParent().isParamList();
          break;
        // Casts, exports, and Object literal properties are valid.
        case CAST:
        case EXPORT:
        case STRING_KEY:
        case GETTER_DEF:
        case SETTER_DEF:
          valid = true;
          break;
        // Declarations are valid iff they only contain simple names
        //   /** @type {number} */ var x = 3; // ok
        //   /** @type {number} */ var {x} = obj; // forbidden
        case VAR:
        case LET:
        case CONST:
          valid = !NodeUtil.isDestructuringDeclaration(n);
          break;
        // Property assignments are valid, if at the root of an expression.
        case ASSIGN: {
          Node lvalue = n.getFirstChild();
          valid = n.getParent().isExprResult()
              && (lvalue.isGetProp()
                  || lvalue.isGetElem()
                  || lvalue.matchesQualifiedName("exports"));
          break;
        }
        case GETPROP:
          valid = n.getParent().isExprResult() && n.isQualifiedName();
          break;
        case CALL:
          valid = info.isDefine();
          break;
        default:
          break;
      }

      if (!valid) {
        reportMisplaced(n, "type", "Type annotations are not allowed here. "
            + "Are you missing parentheses?");
      }
    }
  }
222783
public void onDocumentType (@Nonnull final String sQualifiedElementName,
                              @Nullable final String sPublicID,
                              @Nullable final String sSystemID)
  {
    ValueEnforcer.notNull (sQualifiedElementName, "QualifiedElementName");

    final String sDocType = getDocTypeXMLRepresentation (m_eXMLVersion,
                                                         m_aXMLWriterSettings.getIncorrectCharacterHandling (),
                                                         sQualifiedElementName,
                                                         sPublicID,
                                                         sSystemID);
    _append (sDocType);
    newLine ();
  }
595371
function formatType(node) {
  let result;

  if (!node) {
    return [t('any')];
  }

  switch (node.type) {
    case Syntax.NullableLiteral:
      return [t('?')];
    case Syntax.AllLiteral:
      return [t('any')];
    case Syntax.NullLiteral:
      return [t('null')];
    case Syntax.VoidLiteral:
      return [t('void')];
    case Syntax.UndefinedLiteral:
      return [t('undefined')];
    case Syntax.NameExpression:
      return [t(node.name)];
    case Syntax.ParameterType:
      result = [];

      if (node.name) {
        result.push(c(node.name), t(': '));
      }

      return result.concat(formatType(node.expression));

    case Syntax.TypeApplication:
      return formatType(node.expression).concat(
        commaList(node.applications, '<', '>'),
      );
    case Syntax.UnionType:
      return commaList(node.elements, '(', ')', ' | ');

    case Syntax.ArrayType:
      return commaList(node.elements, '[', ']');
    case Syntax.RecordType:
      return commaList(node.fields, '{', '}');

    case Syntax.FieldType:
      if (node.value) {
        return [t(node.key + ': ')].concat(formatType(node.value));
      }
      return [t(node.key)];

    case Syntax.FunctionType:
      result = [t('function(')];

      if (node['this']) {
        if (node['new']) {
          result.push(t('new: '));
        } else {
          result.push(t('this: '));
        }

        result = result.concat(formatType(node['this']));

        if (node.params.length !== 0) {
          result.push(t(', '));
        }
      }

      result = result.concat(commaList(node.params, '', ')'));

      if (node.result) {
        result = result.concat([t(': ')].concat(formatType(node.result)));
      }
      return result;

    case Syntax.RestType:
      // note that here we diverge from doctrine itself, which
      // lets the expression be omitted.
      return [t('...'), ...formatType(node.expression)];
    case Syntax.OptionalType:
      if (node.default) {
        return [
          ...formatType(node.expression),
          t('?'),
          t('= ' + c(node.default)),
        ];
      }
      return [...formatType(node.expression), t('?')];
    case Syntax.NonNullableType:
      return node.prefix
        ? [t('?'), ...formatType(node.expression)]
        : [...formatType(node.expression), t('?')];
    case Syntax.NullableType:
      return [...formatType(node.expression), t('?')];
    case Syntax.StringLiteralType:
      return [c(JSON.stringify(node.value))];
    case Syntax.NumericLiteralType:
    case Syntax.BooleanLiteralType:
      return [c(String(node.value))];

    default:
      throw new Error('Unknown type ' + node.type);
  }
}
359509
private void checkValueType(TemplateParam param, SoyValue value, TemplateNode node) {
    if (!TofuTypeChecks.isInstance(param.type(), value, node.getSourceLocation())) {
      // should this be a soydataexception?
      throw RenderException.createWithSource(
          "Parameter type mismatch: attempt to bind value '"
              + (value instanceof UndefinedData ? "(undefined)" : value)
              + "' (a "
              + value.getClass().getSimpleName()
              + ") to parameter '"
              + param.name()
              + "' which has a declared type of '"
              + param.type()
              + "'.",
          node);
    }
  }
998770
function(params) {
			$.extend(globalConfig, params || {});

			this.startAll(document.documentElement);

			this.fire('init');
			initialized = true;
		}
124323
function setDocType($iframe, doctype){
                var win, doc;
                win = $iframe.get(0);
                win = win.contentWindow || win.contentDocument || win;
                doc = win.document || win.contentDocument || win;
                doc.open();
                doc.write(doctype);
                doc.close();
            }
39757
function addParamsEx(node, parent, isDirective, isSubTag) {
  var exPropsName = 'paramsEx';

  if (!parent[exPropsName]) {
    var exPropsNode;

    if (isDirective || isSubTag) {
      exPropsNode = {
        type: 'nj_ex',
        ex: 'props',
        content: [node]
      };
    } else {
      exPropsNode = node;
    }

    exPropsNode.parentType = parent.type;
    parent[exPropsName] = exPropsNode;
  } else {
    arrayPush(parent[exPropsName].content, isDirective || isSubTag ? [node] : node.content);
  }
}
229316
def _docstring_parameter(obj_type, subset=False):   # pylint: disable=no-self-argument
        """"""
        docstring = (
            "Flexibly search the JSS for objects of type {}.\n\n\tArgs:\n\t\t"
            "Data: Allows different types to conduct different types of "
            "searches. Argument of type:\n\t\t\tNone (or Provide no argument) "
            "to search for all objects.\n\t\t\tInt to search for an object by "
            "ID.\n\t\t\tString to search for an object by name.\n\t\t\t"
            "xml.etree.ElementTree.Element to create a new object from the "
            "Element's data.{}\n\n\tReturns:\n\t\tJSSObjectList for empty "
            "data arguments.\n\t\tReturns an object of type {} for searches "
            "and new objects.\n\t\t(FUTURE) Will return None if nothing is "
            "found that match the search criteria.\n\n\tRaises:\n\t\t"
            "JSSGetError for nonexistent objects.")

        if subset:
            subset_string = (
                "\n\t\tsubset: A list of XML subelement tags to request\n"
                "\t\t\t(e.g. ['general', 'purchasing']), OR an '&' \n\t\t\t"
                "delimited string (e.g. 'general&purchasing').")
        else:
            subset_string = ""

        def dec(obj):
            """Dynamically decorate a docstring."""
            class_name = str(obj_type)[:-2].rsplit(".")[-1]
            updated_docstring = docstring.format(class_name, subset_string,
                                                 class_name)
            obj.__doc__ = obj.__doc__.format(
                dynamic_docstring=updated_docstring)
            return obj
        return dec
1322997
private void validateReturnJsDoc(Node n, JSDocInfo info) {
    if (!n.isReturn() || info == null) {
      return;
    }
    // @type is handled in validateTypeAnnotations method.
    if (info.containsDeclaration() && !info.hasType()) {
      report(n, JSDOC_ON_RETURN);
    }
  }
708490
function Node(config) {
    RED.nodes.createNode(this,config);
    var node = this,
      message = '';

    this.on('input', function (msg) {
      node.status({});

      payloadCheck(msg)
      .then(function(){
        return wordcountCheck(msg, config);
      })
      .then(function(){
        return credentialsCheck(node);
      })
      .then(function(){
        return setEndPoint(config);
      })
      .then(function(){
        return prepareParams(msg, config);
      })
      .then(function(params){

        node.status({fill:'blue', shape:'dot', text:'requesting'});
        return executeService(msg, params);
      })
      .then(function(){
        node.status({});
        node.send(msg);
      })
      .catch(function(err){
        payloadutils.reportError(node, msg, err);
        node.send(msg);
      });
    });
  }
114895
function ReadPDFNode(params) {
        // FIXME:Cleanup
        // console.log('ReadPDFNode Called');
        let node = this;
        node.log(JSON.stringify(params));
        RED.nodes.createNode(this, params);
        this.name = params.name;
        this.location = params.location;
        this.locationType = params.locationType;
        this.preprocess = params.preprocess;
        this.store = params.store;
        this.storeType = params.storeType;
        this.waitfor = params.waitfor;

        this.on('input', function(msg) {
            if (msg.error) {
                // FIXME: Add error handling here
            } else {
                node.actionType = 'read';
                node.log('ReadPDFNode Received Input');
                // node.log(JSON.stringify(params));
                node.log(JSON.stringify(msg));
                getPdfAsJson(node, msg);
            }
        });
    }
354666
private String getParameterJSDocName(Node paramNode, int paramIndex) {
    Node nameNode = null;
    if (paramNode != null) {
      checkArgument(paramNode.getParent().isParamList(), paramNode);
      if (paramNode.isRest()) {
        // use `restParam` of `...restParam`
        // restParam might still be a destructuring pattern
        paramNode = paramNode.getOnlyChild();
      } else if (paramNode.isDefaultValue()) {
        // use `defaultParam` of `defaultParam = something`
        // defaultParam might still be a destructuring pattern
        paramNode = paramNode.getFirstChild();
      }
      if (paramNode.isName()) {
        nameNode = paramNode;
      } else {
        checkState(paramNode.isObjectPattern() || paramNode.isArrayPattern(), paramNode);
        nameNode = null; // must generate a fake name
      }
    }
    if (nameNode == null) {
      return "p" + paramIndex;
    } else {
      checkState(nameNode.isName(), nameNode);
      return nameNode.getString();
    }
  }
110194
function makeRoleMembershipDoc (docId, docSource) {
  return {
    roleId: docSource.templateRoleId,
    memberType: 'role',
    memberId: docSource.roleMemberId
  }
}
677086
function(node, propertyType) {
			var context = this,
				children = [],
				out = [],
				child,
				x,
				i;

			children = modules.domUtils.getChildren( node );

			x = 0;
			i = children.length;
			while(x < i) {
				child = children[x];
				var value = null;
				if(modules.domUtils.hasAttributeValue(child, 'class', 'value')) {
					switch(propertyType) {
					case 'p':
						value = context.getPValue(child, false);
						break;
					case 'u':
						value = context.getUValue(child, false);
						break;
					case 'dt':
						value = context.getDTValue(child, '', null, false);
						break;
					}
					if(value) {
						out.push(modules.utils.trim(value));
					}
				}
				x++;
			}
			if(out.length > 0) {
				if(propertyType === 'p') {
					return modules.text.parseText( this.document, out.join(''), this.options.textFormat);
				}
				if(propertyType === 'u') {
					return out.join('');
				}
				if(propertyType === 'dt') {
					var format = 'microformat2';
					return modules.dates.concatFragments(out,format).toString(format);
				}
			} else {
				return null;
			}
		}