<commit_before>/*!
 * CMS.API.Helpers
 * Multiple helpers used accross all CMS features
 */

//##############################################################################
// COMPATIBILITY

// ensuring django namespace is set correctly
window.django = window.django || undefined;

// ensuring jQuery namespace is set correctly
window.jQuery = (window.django && window.django.jQuery) ? window.django.jQuery : window.jQuery || undefined;

// ensuring Class namespace is set correctly
window.Class = window.Class || undefined;

// ensuring CMS namespace is set correctly
/**
 * @module CMS
 */
var CMS = {
    $: (typeof window.jQuery === 'function') ? window.jQuery : undefined,
    Class: (typeof window.Class === 'function') ? window.Class : undefined,
    /**
     * @module CMS
     * @submodule CMS.API
     */
    API: {},
    /**
     * Provides key codes for common keys.
     *
     * @module CMS
     * @submodule CMS.KEYS
     * @example
     *     if (e.keyCode === CMS.KEYS.ENTER) { ... };
     */
    KEYS: {
        SHIFT: 16,
        TAB: 9,
        UP: 38,
        DOWN: 40,
        ENTER: 13,
        SPACE: 32,
        ESC: 27,
        CMD_LEFT: 91,
        CMD_RIGHT: 93,
        CMD_FIREFOX: 224,
        CTRL: 17
    }
};

//##############################################################################
// CMS.API
(function ($) {
    'use strict';
    // shorthand for jQuery(document).ready();
    $(function () {
        /**
         * Provides various helpers that are mixed in all CMS classes.
         *
         * @class Helpers
         * @static
         * @module CMS
         * @submodule CMS.API
         * @namespace CMS.API
         */
        CMS.API.Helpers = {

            /**
             * Redirects to a specific url or reloads browser.
             *
             * @method reloadBrowser
             * @param {String} url where to redirect. if equal to `REFRESH_PAGE` will reload page instead
             * @param {Number} timeout=0 timeout in ms
             * @param {Boolean} ajax if set to true first initiates **synchronous**
             *     ajax request to figure out if the browser should reload current page,
             *     move to another one, or do nothing.
             */
            reloadBrowser: function (url, timeout, ajax) {
                var that = this;
                // is there a parent window?
                var parent = (window.parent) ? window.parent : window;

                // if there is an ajax reload, prioritize
                if (ajax) {
                    parent.CMS.API.locked = true;
                    // check if the url has changed, if true redirect to the new path
                    // this requires an ajax request
                    $.ajax({
                        async: false,
                        type: 'GET',
                        url: parent.CMS.config.request.url,
                        data: {
                            model: parent.CMS.config.request.model,
                            pk: parent.CMS.config.request.pk
                        },
                        success: function (response) {
                            parent.CMS.API.locked = false;

                            if (response === '' && !url) {
                                // cancel if response is empty
                                return false;
                            } else if (parent.location.pathname !== response && response !== '') {
                                // api call to the backend to check if the current path is still the same
                                that.reloadBrowser(response);
                            } else if (url === 'REFRESH_PAGE') {
                                // if on_close provides REFRESH_PAGE, only do a reload
                                that.reloadBrowser();
                            } else if (url) {
                                // on_close can also provide a url, reload to the new destination
                                that.reloadBrowser(url);
                            }
                        }
                    });

                    // cancel further operations
                    return false;
                }

                // add timeout if provided
                parent.setTimeout(function () {
                    if (url && url !== parent.location.href) {
                        // location.reload() takes precedence over this, so we
                        // don't want to reload the page if we need a redirect
                        parent.location.href = url;
                    } else {
                        // ensure page is always reloaded #3413
                        parent.location.reload();
                    }
                }, timeout || 0);
            },

            /**
             * Assigns an event handler to forms located in the toolbar
             * to prevent multiple submissions.
             *
             * @method preventSubmit
             */
            preventSubmit: function () {
                var forms = $('.cms-toolbar').find('form');
                forms.submit(function () {
                    // show loader
                    CMS.API.Toolbar.showLoader();
                    // we cannot use disabled as the name action will be ignored
                    $('input[type="submit"]').on('click', function (e) {
                        e.preventDefault();
                    }).css('opacity', 0.5);
                });
            },

            /**
             * Sets csrf token header on ajax requests.
             *
             * @method csrf
             * @param {String} csrf_token
             */
            csrf: function (csrf_token) {
                $.ajaxSetup({
                    beforeSend: function (xhr) {
                        xhr.setRequestHeader('X-CSRFToken', csrf_token);
                    }
                });
            },

            /**
             * Sends or retrieves a JSON from localStorage
             * or the session (through synchronous ajax request)
             * if localStorage is not available.
             *
             * @method setSettings
             * @param settings
             */
            setSettings: function (settings) {
                // merge settings
                settings = JSON.stringify($.extend({}, CMS.config.settings, settings));
                // set loader
                if (CMS.API.Toolbar) {
                    CMS.API.Toolbar.showLoader();
                }

                // use local storage or session
                if (this._isStorageSupported) {
                    // save within local storage
                    localStorage.setItem('cms_cookie', settings);
                    if (CMS.API.Toolbar) {
                        CMS.API.Toolbar.hideLoader();
                    }
                } else {
                    // save within session
                    CMS.API.locked = true;

                    $.ajax({
                        async: false,
                        type: 'POST',
                        url: CMS.config.urls.settings,
                        data: {
                            csrfmiddlewaretoken: this.config.csrf,
                            settings: settings
                        },
                        success: function (data) {
                            CMS.API.locked = false;
                            // determine if logged in or not
                            settings = (data) ? JSON.parse(data) : CMS.config.settings;
                            if (CMS.API.Toolbar) {
                                CMS.API.Toolbar.hideLoader();
                            }
                        },
                        error: function (jqXHR) {
                            CMS.API.Messages.open({
                                message: jqXHR.response + ' | ' + jqXHR.status + ' ' + jqXHR.statusText,
                                error: true
                            });
                        }
                    });
                }

                // save settings
                CMS.settings = JSON.parse(settings);

                // ensure new settings are returned
                return CMS.settings;
            },

            /**
             * Gets user settings (from JSON or the session)
             * in the same way as setSettings sets them.
             *
             * @method getSettings
             */
            getSettings: function () {
                var settings;
                // set loader
                if (CMS.API.Toolbar) {
                    CMS.API.Toolbar.showLoader();
                }

                // use local storage or session
                if (this._isStorageSupported) {
                    // get from local storage
                    settings = JSON.parse(localStorage.getItem('cms_cookie'));
                    if (CMS.API.Toolbar) {
                        CMS.API.Toolbar.hideLoader();
                    }
                } else {
                    CMS.API.locked = true;
                    // get from session
                    $.ajax({
                        async: false,
                        type: 'GET',
                        url: CMS.config.urls.settings,
                        success: function (data) {
                            CMS.API.locked = false;
                            // determine if logged in or not
                            settings = (data) ? JSON.parse(data) : CMS.config.settings;
                            if (CMS.API.Toolbar) {
                                CMS.API.Toolbar.hideLoader();
                            }
                        },
                        error: function (jqXHR) {
                            CMS.API.Messages.open({
                                message: jqXHR.response + ' | ' + jqXHR.status + ' ' + jqXHR.statusText,
                                error: true
                            });
                        }
                    });
                }

                if (!settings) {
                    settings = this.setSettings(CMS.config.settings);
                }

                // save settings
                CMS.settings = settings;

                // ensure new settings are returned
                return CMS.settings;
            },

            /**
             * Modifies the url with new params and sanitises
             * the ampersand within the url for #3404.
             *
             * @method makeURL
             * @param {String} url original url
             * @param {String[]} [params] array of `param=value` strings to update the url
             */
            makeURL: function makeURL(url, params) {
                var arr = [];
                var keys = [];
                var values = [];
                var tmp = '';
                var urlArray = [];
                var urlParams = [];
                var origin = url;

                // return url if there is no param
                if (!(url.split('?').length <= 1 || window.JSON === undefined)) {
                    // setup local vars
                    urlArray = url.split('?');
                    urlParams = urlArray[1].split('&');
                    origin = urlArray[0];
                }

                // loop through the available params
                $.each(urlParams, function (index, param) {
                    arr.push({
                        param: param.split('=')[0],
                        value: param.split('=')[1]
                    });
                });
                // loop through the new params
                if (params && params.length) {
                    $.each(params, function (index, param) {
                        arr.push({
                            param: param.split('=')[0],
                            value: param.split('=')[1]
                        });
                    });
                }

                // merge manually because jquery...
                $.each(arr, function (index, item) {
                    var i = $.inArray(item.param, keys);

                    if (i === -1) {
                        keys.push(item.param);
                        values.push(item.value);
                    } else {
                        values[i] = item.value;
                    }
                });

                // merge new url
                $.each(keys, function (index, key) {
                    tmp += '&' + key + '=' + values[index];
                });
                tmp = tmp.replace('&', '?');
                url = origin + tmp;
                url = url.replace('&', '&');

                return url;
            },

            /**
             * Creates a debounced function that delays invoking `func`
             * until after `wait` milliseconds have elapsed since
             * the last time the debounced function was invoked.
             * Optionally can be invoked first time immediately.
             *
             * @method debounce
             * @param {Function} func function to debounce
             * @param {Number} wait time in ms to wait
             * @param {Object} [opts]
             * @param {Boolean} [opts.immediate] trigger func immediately?
             * @return {Function}
             */
            debounce: function debounce(func, wait, opts) {
                var timeout;
                return function () {
                    var context = this, args = arguments;
                    var later = function () {
                        timeout = null;
                        if (!opts || !opts.immediate) {
                            func.apply(context, args);
                        }
                    };
                    var callNow = opts && opts.immediate && !timeout;
                    clearTimeout(timeout);
                    timeout = setTimeout(later, wait);
                    if (callNow) {
                        func.apply(context, args);
                    }
                };
            },

            /**
             * Returns a function that when invoked, will only be triggered
             * at most once during a given window of time. Normally, the
             * throttled function will run as much as it can, without ever
             * going more than once per `wait` duration, but if you’d like to
             * disable the execution on the leading edge, pass `{leading: false}`.
             * To disable execution on the trailing edge, ditto.
             *
             * @method throttle
             * @param {Function} func function to throttle
             * @param {Number} wait time window
             * @param {Object} [opts]
             * @param {Boolean} [opts.leading=true] execute on the leading edge
             * @param {Boolean} [opts.trailing=true] execute on the trailing edge
             * @return {Function}
             */
            throttle: function throttle(func, wait, opts) {
                var context, args, result;
                var timeout = null;
                var previous = 0;
                if (!opts) {
                    opts = {};
                }
                var later = function () {
                    previous = opts.leading === false ? 0 : $.now();
                    timeout = null;
                    result = func.apply(context, args);
                    if (!timeout) {
                        context = args = null;
                    }
                };
                return function () {
                    var now = $.now();
                    if (!previous && opts.leading === false) {
                        previous = now;
                    }
                    var remaining = wait - (now - previous);
                    context = this;
                    args = arguments;
                    if (remaining <= 0 || remaining > wait) {
                        if (timeout) {
                            clearTimeout(timeout);
                            timeout = null;
                        }
                        previous = now;
                        result = func.apply(context, args);
                        if (!timeout) {
                            context = args = null;
                        }
                    } else if (!timeout && opts.trailing !== false) {
                        timeout = setTimeout(later, remaining);
                    }
                    return result;
                };
            },

            /**
             * Browsers allow to "Prevent this page form creating additional
             * dialogs." checkbox which prevents further input from confirm messages.
             * This method falls back to "true" once the user chooses this option.
             *
             * @method secureConfirm
             * @param {String} message to be displayed
             * @return {Boolean}
             */
            secureConfirm: function secureConfirm(message) {
                var start = Number(new Date());
                var result = confirm(message);
                var end = Number(new Date());

                return (end < (start + 10) || result === true);
            },

            /**
             * Is localStorage truly supported?
             * Check is taken from modernizr.
             *
             * @property _isStorageSupported
             * @private
             * @type {Boolean}
             */
            _isStorageSupported: (function localStorageCheck() {
                var mod = 'modernizr';
                try {
                    localStorage.setItem(mod, mod);
                    localStorage.removeItem(mod);
                    return true;
                } catch (e) {
                    return false;
                }
            }())
        };

        // autoinits
        CMS.API.Helpers.preventSubmit();

    });
})(CMS.$);
<commit_msg>fix nonexistent csrf token<commit_after>/*!
 * CMS.API.Helpers
 * Multiple helpers used accross all CMS features
 */

//##############################################################################
// COMPATIBILITY

// ensuring django namespace is set correctly
window.django = window.django || undefined;

// ensuring jQuery namespace is set correctly
window.jQuery = (window.django && window.django.jQuery) ? window.django.jQuery : window.jQuery || undefined;

// ensuring Class namespace is set correctly
window.Class = window.Class || undefined;

// ensuring CMS namespace is set correctly
/**
 * @module CMS
 */
var CMS = {
    $: (typeof window.jQuery === 'function') ? window.jQuery : undefined,
    Class: (typeof window.Class === 'function') ? window.Class : undefined,
    /**
     * @module CMS
     * @submodule CMS.API
     */
    API: {},
    /**
     * Provides key codes for common keys.
     *
     * @module CMS
     * @submodule CMS.KEYS
     * @example
     *     if (e.keyCode === CMS.KEYS.ENTER) { ... };
     */
    KEYS: {
        SHIFT: 16,
        TAB: 9,
        UP: 38,
        DOWN: 40,
        ENTER: 13,
        SPACE: 32,
        ESC: 27,
        CMD_LEFT: 91,
        CMD_RIGHT: 93,
        CMD_FIREFOX: 224,
        CTRL: 17
    }
};

//##############################################################################
// CMS.API
(function ($) {
    'use strict';
    // shorthand for jQuery(document).ready();
    $(function () {
        /**
         * Provides various helpers that are mixed in all CMS classes.
         *
         * @class Helpers
         * @static
         * @module CMS
         * @submodule CMS.API
         * @namespace CMS.API
         */
        CMS.API.Helpers = {

            /**
             * Redirects to a specific url or reloads browser.
             *
             * @method reloadBrowser
             * @param {String} url where to redirect. if equal to `REFRESH_PAGE` will reload page instead
             * @param {Number} timeout=0 timeout in ms
             * @param {Boolean} ajax if set to true first initiates **synchronous**
             *     ajax request to figure out if the browser should reload current page,
             *     move to another one, or do nothing.
             */
            reloadBrowser: function (url, timeout, ajax) {
                var that = this;
                // is there a parent window?
                var parent = (window.parent) ? window.parent : window;

                // if there is an ajax reload, prioritize
                if (ajax) {
                    parent.CMS.API.locked = true;
                    // check if the url has changed, if true redirect to the new path
                    // this requires an ajax request
                    $.ajax({
                        async: false,
                        type: 'GET',
                        url: parent.CMS.config.request.url,
                        data: {
                            model: parent.CMS.config.request.model,
                            pk: parent.CMS.config.request.pk
                        },
                        success: function (response) {
                            parent.CMS.API.locked = false;

                            if (response === '' && !url) {
                                // cancel if response is empty
                                return false;
                            } else if (parent.location.pathname !== response && response !== '') {
                                // api call to the backend to check if the current path is still the same
                                that.reloadBrowser(response);
                            } else if (url === 'REFRESH_PAGE') {
                                // if on_close provides REFRESH_PAGE, only do a reload
                                that.reloadBrowser();
                            } else if (url) {
                                // on_close can also provide a url, reload to the new destination
                                that.reloadBrowser(url);
                            }
                        }
                    });

                    // cancel further operations
                    return false;
                }

                // add timeout if provided
                parent.setTimeout(function () {
                    if (url && url !== parent.location.href) {
                        // location.reload() takes precedence over this, so we
                        // don't want to reload the page if we need a redirect
                        parent.location.href = url;
                    } else {
                        // ensure page is always reloaded #3413
                        parent.location.reload();
                    }
                }, timeout || 0);
            },

            /**
             * Assigns an event handler to forms located in the toolbar
             * to prevent multiple submissions.
             *
             * @method preventSubmit
             */
            preventSubmit: function () {
                var forms = $('.cms-toolbar').find('form');
                forms.submit(function () {
                    // show loader
                    CMS.API.Toolbar.showLoader();
                    // we cannot use disabled as the name action will be ignored
                    $('input[type="submit"]').on('click', function (e) {
                        e.preventDefault();
                    }).css('opacity', 0.5);
                });
            },

            /**
             * Sets csrf token header on ajax requests.
             *
             * @method csrf
             * @param {String} csrf_token
             */
            csrf: function (csrf_token) {
                $.ajaxSetup({
                    beforeSend: function (xhr) {
                        xhr.setRequestHeader('X-CSRFToken', csrf_token);
                    }
                });
            },

            /**
             * Sends or retrieves a JSON from localStorage
             * or the session (through synchronous ajax request)
             * if localStorage is not available.
             *
             * @method setSettings
             * @param settings
             */
            setSettings: function (settings) {
                // merge settings
                settings = JSON.stringify($.extend({}, CMS.config.settings, settings));
                // set loader
                if (CMS.API.Toolbar) {
                    CMS.API.Toolbar.showLoader();
                }

                // use local storage or session
                if (this._isStorageSupported) {
                    // save within local storage
                    localStorage.setItem('cms_cookie', settings);
                    if (CMS.API.Toolbar) {
                        CMS.API.Toolbar.hideLoader();
                    }
                } else {
                    // save within session
                    CMS.API.locked = true;

                    $.ajax({
                        async: false,
                        type: 'POST',
                        url: CMS.config.urls.settings,
                        data: {
                            csrfmiddlewaretoken: CMS.config.csrf,
                            settings: settings
                        },
                        success: function (data) {
                            CMS.API.locked = false;
                            // determine if logged in or not
                            settings = (data) ? JSON.parse(data) : CMS.config.settings;
                            if (CMS.API.Toolbar) {
                                CMS.API.Toolbar.hideLoader();
                            }
                        },
                        error: function (jqXHR) {
                            CMS.API.Messages.open({
                                message: jqXHR.response + ' | ' + jqXHR.status + ' ' + jqXHR.statusText,
                                error: true
                            });
                        }
                    });
                }

                // save settings
                CMS.settings = JSON.parse(settings);

                // ensure new settings are returned
                return CMS.settings;
            },

            /**
             * Gets user settings (from JSON or the session)
             * in the same way as setSettings sets them.
             *
             * @method getSettings
             */
            getSettings: function () {
                var settings;
                // set loader
                if (CMS.API.Toolbar) {
                    CMS.API.Toolbar.showLoader();
                }

                // use local storage or session
                if (this._isStorageSupported) {
                    // get from local storage
                    settings = JSON.parse(localStorage.getItem('cms_cookie'));
                    if (CMS.API.Toolbar) {
                        CMS.API.Toolbar.hideLoader();
                    }
                } else {
                    CMS.API.locked = true;
                    // get from session
                    $.ajax({
                        async: false,
                        type: 'GET',
                        url: CMS.config.urls.settings,
                        success: function (data) {
                            CMS.API.locked = false;
                            // determine if logged in or not
                            settings = (data) ? JSON.parse(data) : CMS.config.settings;
                            if (CMS.API.Toolbar) {
                                CMS.API.Toolbar.hideLoader();
                            }
                        },
                        error: function (jqXHR) {
                            CMS.API.Messages.open({
                                message: jqXHR.response + ' | ' + jqXHR.status + ' ' + jqXHR.statusText,
                                error: true
                            });
                        }
                    });
                }

                if (!settings) {
                    settings = this.setSettings(CMS.config.settings);
                }

                // save settings
                CMS.settings = settings;

                // ensure new settings are returned
                return CMS.settings;
            },

            /**
             * Modifies the url with new params and sanitises
             * the ampersand within the url for #3404.
             *
             * @method makeURL
             * @param {String} url original url
             * @param {String[]} [params] array of `param=value` strings to update the url
             */
            makeURL: function makeURL(url, params) {
                var arr = [];
                var keys = [];
                var values = [];
                var tmp = '';
                var urlArray = [];
                var urlParams = [];
                var origin = url;

                // return url if there is no param
                if (!(url.split('?').length <= 1 || window.JSON === undefined)) {
                    // setup local vars
                    urlArray = url.split('?');
                    urlParams = urlArray[1].split('&');
                    origin = urlArray[0];
                }

                // loop through the available params
                $.each(urlParams, function (index, param) {
                    arr.push({
                        param: param.split('=')[0],
                        value: param.split('=')[1]
                    });
                });
                // loop through the new params
                if (params && params.length) {
                    $.each(params, function (index, param) {
                        arr.push({
                            param: param.split('=')[0],
                            value: param.split('=')[1]
                        });
                    });
                }

                // merge manually because jquery...
                $.each(arr, function (index, item) {
                    var i = $.inArray(item.param, keys);

                    if (i === -1) {
                        keys.push(item.param);
                        values.push(item.value);
                    } else {
                        values[i] = item.value;
                    }
                });

                // merge new url
                $.each(keys, function (index, key) {
                    tmp += '&' + key + '=' + values[index];
                });
                tmp = tmp.replace('&', '?');
                url = origin + tmp;
                url = url.replace('&', '&');

                return url;
            },

            /**
             * Creates a debounced function that delays invoking `func`
             * until after `wait` milliseconds have elapsed since
             * the last time the debounced function was invoked.
             * Optionally can be invoked first time immediately.
             *
             * @method debounce
             * @param {Function} func function to debounce
             * @param {Number} wait time in ms to wait
             * @param {Object} [opts]
             * @param {Boolean} [opts.immediate] trigger func immediately?
             * @return {Function}
             */
            debounce: function debounce(func, wait, opts) {
                var timeout;
                return function () {
                    var context = this, args = arguments;
                    var later = function () {
                        timeout = null;
                        if (!opts || !opts.immediate) {
                            func.apply(context, args);
                        }
                    };
                    var callNow = opts && opts.immediate && !timeout;
                    clearTimeout(timeout);
                    timeout = setTimeout(later, wait);
                    if (callNow) {
                        func.apply(context, args);
                    }
                };
            },

            /**
             * Returns a function that when invoked, will only be triggered
             * at most once during a given window of time. Normally, the
             * throttled function will run as much as it can, without ever
             * going more than once per `wait` duration, but if you’d like to
             * disable the execution on the leading edge, pass `{leading: false}`.
             * To disable execution on the trailing edge, ditto.
             *
             * @method throttle
             * @param {Function} func function to throttle
             * @param {Number} wait time window
             * @param {Object} [opts]
             * @param {Boolean} [opts.leading=true] execute on the leading edge
             * @param {Boolean} [opts.trailing=true] execute on the trailing edge
             * @return {Function}
             */
            throttle: function throttle(func, wait, opts) {
                var context, args, result;
                var timeout = null;
                var previous = 0;
                if (!opts) {
                    opts = {};
                }
                var later = function () {
                    previous = opts.leading === false ? 0 : $.now();
                    timeout = null;
                    result = func.apply(context, args);
                    if (!timeout) {
                        context = args = null;
                    }
                };
                return function () {
                    var now = $.now();
                    if (!previous && opts.leading === false) {
                        previous = now;
                    }
                    var remaining = wait - (now - previous);
                    context = this;
                    args = arguments;
                    if (remaining <= 0 || remaining > wait) {
                        if (timeout) {
                            clearTimeout(timeout);
                            timeout = null;
                        }
                        previous = now;
                        result = func.apply(context, args);
                        if (!timeout) {
                            context = args = null;
                        }
                    } else if (!timeout && opts.trailing !== false) {
                        timeout = setTimeout(later, remaining);
                    }
                    return result;
                };
            },

            /**
             * Browsers allow to "Prevent this page form creating additional
             * dialogs." checkbox which prevents further input from confirm messages.
             * This method falls back to "true" once the user chooses this option.
             *
             * @method secureConfirm
             * @param {String} message to be displayed
             * @return {Boolean}
             */
            secureConfirm: function secureConfirm(message) {
                var start = Number(new Date());
                var result = confirm(message);
                var end = Number(new Date());

                return (end < (start + 10) || result === true);
            },

            /**
             * Is localStorage truly supported?
             * Check is taken from modernizr.
             *
             * @property _isStorageSupported
             * @private
             * @type {Boolean}
             */
            _isStorageSupported: (function localStorageCheck() {
                var mod = 'modernizr';
                try {
                    localStorage.setItem(mod, mod);
                    localStorage.removeItem(mod);
                    return true;
                } catch (e) {
                    return false;
                }
            }())
        };

        // autoinits
        CMS.API.Helpers.preventSubmit();

    });
})(CMS.$);
<|endoftext|>


<commit_before>// These are variables the popup is going to want to access...
var spell_formname, spell_fieldname, spell_full;

// Spell check the specified field in the specified form.
function spellCheck(formName, fieldName, bFull = true)
{
	// Grab the (hidden) spell checking form.
	var spellform = document.forms.spell_form;

	// Register the name of the editing form for future reference.
	spell_formname = formName;
	spell_fieldname = fieldName;
	spell_full = bFull;

	// This should match a word (most of the time).
	var regexpWordMatch = /(?:<[^>]+>)|(?:\[[^ ][^\]]*\])|(?:&[^; ]+;)|(?:[^0-9\s\]\[{};:"\\|,<.>\/?`~!@#$%^&*()_+=]+)/g;

	// These characters can appear within words.
	var aWordCharacters = ['-', '\''];

	var aWords = new Array(), aResult = new Array();
	var sText = (spell_full) ? $('#' + fieldName).data("sceditor").getText() : document.forms[formName][fieldName].value;
	var bInCode = false;
	var iOffset1, iOffset2;

	// Loop through all words.
	while ((aResult = regexpWordMatch.exec(sText)) && typeof(aResult) != 'undefined')
	{
		iOffset1 = 0;
		iOffset2 = aResult[0].length - 1;

		// Strip the dashes and hyphens from the begin of the word.
		while (in_array(aResult[0].charAt(iOffset1), aWordCharacters) && iOffset1 < iOffset2)
			iOffset1++;

		// Strip the dashes and hyphens from the end of the word.
		while (in_array(aResult[0].charAt(iOffset2), aWordCharacters) && iOffset1 < iOffset2)
			iOffset2--;

		// I guess there's only dashes and hyphens in this word...
		if (iOffset1 == iOffset2)
			continue;

		// Ignore code blocks.
		if (aResult[0].substr(0, 5).toLowerCase() == '[code')
			bInCode = true;

		// Glad we're out of that code block!
		else if (bInCode && aResult[0].substr(0, 7).toLowerCase() == '[/code]')
			bInCode = false;

		// Now let's get to business.
		else if (!bInCode && !in_array(aResult[0].charAt(0), ['[', '<']) && aResult[0].toUpperCase() != aResult[0])
			aWords[aWords.length] = aResult[0].substr(iOffset1, iOffset2 - iOffset1 + 1) + '|' + (iOffset1 + sText.substr(0, aResult.index).length) + '|' + (iOffset2 + sText.substr(0, aResult.index).length);
	}

	// Open the window...
	openSpellWin(640, 480);

	// Pass the data to a form...
	spellform.spellstring.value = aWords.join('\n');
	spellform.fulleditor.value = spell_full ? 'true' : 'false';

	//  and go!
	spellform.submit();

	return true;
}

// Private functions -------------------------------

// Globals...
var wordindex = -1, offsetindex = 0;
var ignoredWords = [];

// A "misspelled word" object.
function misp(word, start, end, suggestions)
{
	// The word, start index, end index, and array of suggestions.
	this.word = word;
	this.start = start;
	this.end = end;
	this.suggestions = suggestions;
}

// Replace the word in the misps array at the "wordindex" index.  The
// misps array is generated by a PHP script after the string to be spell
// checked is evaluated with pspell.
function replaceWord()
{
	var strstart = "";
	var strend;

	// If this isn't the beginning of the string then get all of the string
	// that is before the word we are replacing.
	if (misps[wordindex].start != 0)
		strstart = mispstr.slice(0, misps[wordindex].start + offsetindex);

	// Get the end of the string after the word we are replacing.
	strend = mispstr.slice(misps[wordindex].end + 1 + offsetindex);

	// Rebuild the string with the new word.
	mispstr = strstart + document.forms.spellingForm.changeto.value + strend;

	// Update offsetindex to compensate for replacing a word with a word
	// of a different length.
	offsetindex += document.forms.spellingForm.changeto.value.length - misps[wordindex].word.length;

	// Update the word so future replaceAll calls don't change it.
	misps[wordindex].word = document.forms.spellingForm.changeto.value;

	nextWord(false);
}

// Replaces all instances of currently selected word with contents chosen by user.
// Note: currently only replaces words after highlighted word.  I think we can re-index
// all words at replacement or ignore time to have it wrap to the beginning if we want
// to.
function replaceAll()
{
	var strend;
	var idx;
	var origword;
	var localoffsetindex = offsetindex;

	origword = misps[wordindex].word;

	// Re-index everything past the current word.
	for (idx = wordindex; idx < misps.length; idx++)
	{
		misps[idx].start += localoffsetindex;
		misps[idx].end += localoffsetindex;
	}

	localoffsetindex = 0;

	for (idx = 0; idx < misps.length; idx++)
	{
		if (misps[idx].word == origword)
		{
			var strstart = "";
			if (misps[idx].start != 0)
				strstart = mispstr.slice(0, misps[idx].start + localoffsetindex);

			// Get the end of the string after the word we are replacing.
			strend = mispstr.slice(misps[idx].end + 1 + localoffsetindex);

			// Rebuild the string with the new word.
			mispstr = strstart + document.forms.spellingForm.changeto.value + strend;

			// Update offsetindex to compensate for replacing a word with a word
			// of a different length.
			localoffsetindex += document.forms.spellingForm.changeto.value.length - misps[idx].word.length;
		}

		// We have to re-index everything after replacements.
		misps[idx].start += localoffsetindex;
		misps[idx].end += localoffsetindex;
	}

	// Add the word to the ignore array.
	ignoredWords[origword] = true;

	// Reset offsetindex since we re-indexed.
	offsetindex = 0;

	nextWord(false);
}

// Highlight the word that was selected using the nextWord function.
function highlightWord()
{
	var strstart = "";
	var strend;

	// If this isn't the beginning of the string then get all of the string
	// that is before the word we are replacing.
	if (misps[wordindex].start != 0)
		strstart = mispstr.slice(0, misps[wordindex].start + offsetindex);

	// Get the end of the string after the word we are replacing.
	strend = mispstr.slice(misps[wordindex].end + 1 + offsetindex);

	// Rebuild the string with a span wrapped around the misspelled word
	// so we can highlight it in the div the user is viewing the string in.
	var divptr, newValue;
	divptr = document.getElementById("spellview");

	newValue = htmlspecialchars(strstart) + '' + misps[wordindex].word + '' + htmlspecialchars(strend);
	setInnerHTML(divptr, newValue.replace(/_\|_/g, '
'));

	// We could use scrollIntoView, but it's just not that great anyway.
	var spellview_height = typeof(document.getElementById("spellview").currentStyle) != "undefined" ? parseInt(document.getElementById("spellview").currentStyle.height) : document.getElementById("spellview").offsetHeight;
	var word_position = document.getElementById("h1").offsetTop;
	var current_position = document.getElementById("spellview").scrollTop;

	// The spellview is not tall enough!  Scroll down!
	if (spellview_height <= (word_position + current_position))
		document.getElementById("spellview").scrollTop = word_position + current_position - spellview_height + 32;
}

// Display the next misspelled word to the user and populate the suggested spellings box.
function nextWord(ignoreall)
{
	// Push ignored word onto ignoredWords array.
	if (ignoreall)
		ignoredWords[misps[wordindex].word] = true;

	// Update the index of all words we have processed...
	// This must be done to accomodate the replaceAll function.
	if (wordindex >= 0)
	{
		misps[wordindex].start += offsetindex;
		misps[wordindex].end += offsetindex;
	}

	// Increment the counter for the array of misspelled words.
	wordindex++;

	// Draw it and quit if there are no more misspelled words to evaluate.
	if (misps.length <= wordindex)
	{
		var divptr;
		divptr = document.getElementById("spellview");
		setInnerHTML(divptr, htmlspecialchars(mispstr).replace(/_\|_/g, "
"));

		while (document.forms.spellingForm.suggestions.options.length > 0)
			document.forms.spellingForm.suggestions.options[0] = null;

		alert(txt['done']);
		document.forms.spellingForm.change.disabled = true;
		document.forms.spellingForm.changeall.disabled = true;
		document.forms.spellingForm.ignore.disabled = true;
		document.forms.spellingForm.ignoreall.disabled = true;

		// Put line feeds back...
		mispstr = mispstr.replace(/_\|_/g, "\n");

		// Get a handle to the field we need to re-populate.
		if (spell_full)
			window.opener.spellCheckSetText(mispstr, spell_fieldname);
		else
		{
			window.opener.document.forms[spell_formname][spell_fieldname].value = mispstr;
			if (!window.opener.spellCheckDone)
				window.opener.document.forms[spell_formname][spell_fieldname].focus();
			else
				window.opener.spellCheckDone();
		}

		window.close();
		return true;
	}

	// Check to see if word is supposed to be ignored.
	if (typeof(ignoredWords[misps[wordindex].word]) != "undefined")
	{
		nextWord(false);
		return false;
	}

	// Clear out the suggestions box!
	while (document.forms.spellingForm.suggestions.options.length > 0)
		document.forms.spellingForm.suggestions.options[0] = null;

	// Re-populate the suggestions box if there are any suggested spellings for the word.
	if (misps[wordindex].suggestions.length)
	{
		for (var sugidx = 0; sugidx < misps[wordindex].suggestions.length; sugidx++)
		{
			var newopt = new Option(misps[wordindex].suggestions[sugidx], misps[wordindex].suggestions[sugidx]);
			document.forms.spellingForm.suggestions.options[sugidx] = newopt;

			if (sugidx == 0)
			{
				newopt.selected = true;
				document.forms.spellingForm.changeto.value = newopt.value;
				document.forms.spellingForm.changeto.select();
			}
		}
	}

	if (document.forms.spellingForm.suggestions.options.length == 0)
		document.forms.spellingForm.changeto.value = "";

	highlightWord();

	return false;
}

// convert characters to HTML equivalents
function htmlspecialchars(thetext)
{
	thetext = thetext.replace(/\</g, "<");
	thetext = thetext.replace(/\>/g, ">");
	thetext = thetext.replace(/\n/g, "
");
	thetext = thetext.replace(/\ \ /g, "  ");

	return thetext;
}

// Open a new window
function openSpellWin(width, height)
{
	window.open("", "spellWindow", "toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=no,width=" + width + ",height=" + height);
}

// get the sceditor text
function spellCheckGetText(editorID)
{
	return $("#" + editorID).data("sceditor").getText();
}

// set the sceditor text
function spellCheckSetText(text, editorID)
{
	$("#" + editorID).data("sceditor").InsertText(text, true);
	if (!$("#" + editorID).data("sceditor").inSourceMode)
		$("#" + editorID).data("sceditor").toggleSourceMode();
}<commit_msg>! JavaScript doesn't support argument defaults like PHP does<commit_after>// These are variables the popup is going to want to access...
var spell_formname, spell_fieldname, spell_full;

// Spell check the specified field in the specified form.
function spellCheck(formName, fieldName, bFull)
{
	// Grab the (hidden) spell checking form.
	var spellform = document.forms.spell_form;

	// Register the name of the editing form for future reference.
	spell_formname = formName;
	spell_fieldname = fieldName;
	spell_full = bFull || true;

	// This should match a word (most of the time).
	var regexpWordMatch = /(?:<[^>]+>)|(?:\[[^ ][^\]]*\])|(?:&[^; ]+;)|(?:[^0-9\s\]\[{};:"\\|,<.>\/?`~!@#$%^&*()_+=]+)/g;

	// These characters can appear within words.
	var aWordCharacters = ['-', '\''];

	var aWords = new Array(), aResult = new Array();
	var sText = (spell_full) ? $('#' + fieldName).data("sceditor").getText() : document.forms[formName][fieldName].value;
	var bInCode = false;
	var iOffset1, iOffset2;

	// Loop through all words.
	while ((aResult = regexpWordMatch.exec(sText)) && typeof(aResult) != 'undefined')
	{
		iOffset1 = 0;
		iOffset2 = aResult[0].length - 1;

		// Strip the dashes and hyphens from the begin of the word.
		while (in_array(aResult[0].charAt(iOffset1), aWordCharacters) && iOffset1 < iOffset2)
			iOffset1++;

		// Strip the dashes and hyphens from the end of the word.
		while (in_array(aResult[0].charAt(iOffset2), aWordCharacters) && iOffset1 < iOffset2)
			iOffset2--;

		// I guess there's only dashes and hyphens in this word...
		if (iOffset1 == iOffset2)
			continue;

		// Ignore code blocks.
		if (aResult[0].substr(0, 5).toLowerCase() == '[code')
			bInCode = true;

		// Glad we're out of that code block!
		else if (bInCode && aResult[0].substr(0, 7).toLowerCase() == '[/code]')
			bInCode = false;

		// Now let's get to business.
		else if (!bInCode && !in_array(aResult[0].charAt(0), ['[', '<']) && aResult[0].toUpperCase() != aResult[0])
			aWords[aWords.length] = aResult[0].substr(iOffset1, iOffset2 - iOffset1 + 1) + '|' + (iOffset1 + sText.substr(0, aResult.index).length) + '|' + (iOffset2 + sText.substr(0, aResult.index).length);
	}

	// Open the window...
	openSpellWin(640, 480);

	// Pass the data to a form...
	spellform.spellstring.value = aWords.join('\n');
	spellform.fulleditor.value = spell_full ? 'true' : 'false';

	//  and go!
	spellform.submit();

	return true;
}

// Private functions -------------------------------

// Globals...
var wordindex = -1, offsetindex = 0;
var ignoredWords = [];

// A "misspelled word" object.
function misp(word, start, end, suggestions)
{
	// The word, start index, end index, and array of suggestions.
	this.word = word;
	this.start = start;
	this.end = end;
	this.suggestions = suggestions;
}

// Replace the word in the misps array at the "wordindex" index.  The
// misps array is generated by a PHP script after the string to be spell
// checked is evaluated with pspell.
function replaceWord()
{
	var strstart = "";
	var strend;

	// If this isn't the beginning of the string then get all of the string
	// that is before the word we are replacing.
	if (misps[wordindex].start != 0)
		strstart = mispstr.slice(0, misps[wordindex].start + offsetindex);

	// Get the end of the string after the word we are replacing.
	strend = mispstr.slice(misps[wordindex].end + 1 + offsetindex);

	// Rebuild the string with the new word.
	mispstr = strstart + document.forms.spellingForm.changeto.value + strend;

	// Update offsetindex to compensate for replacing a word with a word
	// of a different length.
	offsetindex += document.forms.spellingForm.changeto.value.length - misps[wordindex].word.length;

	// Update the word so future replaceAll calls don't change it.
	misps[wordindex].word = document.forms.spellingForm.changeto.value;

	nextWord(false);
}

// Replaces all instances of currently selected word with contents chosen by user.
// Note: currently only replaces words after highlighted word.  I think we can re-index
// all words at replacement or ignore time to have it wrap to the beginning if we want
// to.
function replaceAll()
{
	var strend;
	var idx;
	var origword;
	var localoffsetindex = offsetindex;

	origword = misps[wordindex].word;

	// Re-index everything past the current word.
	for (idx = wordindex; idx < misps.length; idx++)
	{
		misps[idx].start += localoffsetindex;
		misps[idx].end += localoffsetindex;
	}

	localoffsetindex = 0;

	for (idx = 0; idx < misps.length; idx++)
	{
		if (misps[idx].word == origword)
		{
			var strstart = "";
			if (misps[idx].start != 0)
				strstart = mispstr.slice(0, misps[idx].start + localoffsetindex);

			// Get the end of the string after the word we are replacing.
			strend = mispstr.slice(misps[idx].end + 1 + localoffsetindex);

			// Rebuild the string with the new word.
			mispstr = strstart + document.forms.spellingForm.changeto.value + strend;

			// Update offsetindex to compensate for replacing a word with a word
			// of a different length.
			localoffsetindex += document.forms.spellingForm.changeto.value.length - misps[idx].word.length;
		}

		// We have to re-index everything after replacements.
		misps[idx].start += localoffsetindex;
		misps[idx].end += localoffsetindex;
	}

	// Add the word to the ignore array.
	ignoredWords[origword] = true;

	// Reset offsetindex since we re-indexed.
	offsetindex = 0;

	nextWord(false);
}

// Highlight the word that was selected using the nextWord function.
function highlightWord()
{
	var strstart = "";
	var strend;

	// If this isn't the beginning of the string then get all of the string
	// that is before the word we are replacing.
	if (misps[wordindex].start != 0)
		strstart = mispstr.slice(0, misps[wordindex].start + offsetindex);

	// Get the end of the string after the word we are replacing.
	strend = mispstr.slice(misps[wordindex].end + 1 + offsetindex);

	// Rebuild the string with a span wrapped around the misspelled word
	// so we can highlight it in the div the user is viewing the string in.
	var divptr, newValue;
	divptr = document.getElementById("spellview");

	newValue = htmlspecialchars(strstart) + '' + misps[wordindex].word + '' + htmlspecialchars(strend);
	setInnerHTML(divptr, newValue.replace(/_\|_/g, '
'));

	// We could use scrollIntoView, but it's just not that great anyway.
	var spellview_height = typeof(document.getElementById("spellview").currentStyle) != "undefined" ? parseInt(document.getElementById("spellview").currentStyle.height) : document.getElementById("spellview").offsetHeight;
	var word_position = document.getElementById("h1").offsetTop;
	var current_position = document.getElementById("spellview").scrollTop;

	// The spellview is not tall enough!  Scroll down!
	if (spellview_height <= (word_position + current_position))
		document.getElementById("spellview").scrollTop = word_position + current_position - spellview_height + 32;
}

// Display the next misspelled word to the user and populate the suggested spellings box.
function nextWord(ignoreall)
{
	// Push ignored word onto ignoredWords array.
	if (ignoreall)
		ignoredWords[misps[wordindex].word] = true;

	// Update the index of all words we have processed...
	// This must be done to accomodate the replaceAll function.
	if (wordindex >= 0)
	{
		misps[wordindex].start += offsetindex;
		misps[wordindex].end += offsetindex;
	}

	// Increment the counter for the array of misspelled words.
	wordindex++;

	// Draw it and quit if there are no more misspelled words to evaluate.
	if (misps.length <= wordindex)
	{
		var divptr;
		divptr = document.getElementById("spellview");
		setInnerHTML(divptr, htmlspecialchars(mispstr).replace(/_\|_/g, "
"));

		while (document.forms.spellingForm.suggestions.options.length > 0)
			document.forms.spellingForm.suggestions.options[0] = null;

		alert(txt['done']);
		document.forms.spellingForm.change.disabled = true;
		document.forms.spellingForm.changeall.disabled = true;
		document.forms.spellingForm.ignore.disabled = true;
		document.forms.spellingForm.ignoreall.disabled = true;

		// Put line feeds back...
		mispstr = mispstr.replace(/_\|_/g, "\n");

		// Get a handle to the field we need to re-populate.
		if (spell_full)
			window.opener.spellCheckSetText(mispstr, spell_fieldname);
		else
		{
			window.opener.document.forms[spell_formname][spell_fieldname].value = mispstr;
			if (!window.opener.spellCheckDone)
				window.opener.document.forms[spell_formname][spell_fieldname].focus();
			else
				window.opener.spellCheckDone();
		}

		window.close();
		return true;
	}

	// Check to see if word is supposed to be ignored.
	if (typeof(ignoredWords[misps[wordindex].word]) != "undefined")
	{
		nextWord(false);
		return false;
	}

	// Clear out the suggestions box!
	while (document.forms.spellingForm.suggestions.options.length > 0)
		document.forms.spellingForm.suggestions.options[0] = null;

	// Re-populate the suggestions box if there are any suggested spellings for the word.
	if (misps[wordindex].suggestions.length)
	{
		for (var sugidx = 0; sugidx < misps[wordindex].suggestions.length; sugidx++)
		{
			var newopt = new Option(misps[wordindex].suggestions[sugidx], misps[wordindex].suggestions[sugidx]);
			document.forms.spellingForm.suggestions.options[sugidx] = newopt;

			if (sugidx == 0)
			{
				newopt.selected = true;
				document.forms.spellingForm.changeto.value = newopt.value;
				document.forms.spellingForm.changeto.select();
			}
		}
	}

	if (document.forms.spellingForm.suggestions.options.length == 0)
		document.forms.spellingForm.changeto.value = "";

	highlightWord();

	return false;
}

// convert characters to HTML equivalents
function htmlspecialchars(thetext)
{
	thetext = thetext.replace(/\</g, "<");
	thetext = thetext.replace(/\>/g, ">");
	thetext = thetext.replace(/\n/g, "
");
	thetext = thetext.replace(/\ \ /g, "  ");

	return thetext;
}

// Open a new window
function openSpellWin(width, height)
{
	window.open("", "spellWindow", "toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=no,width=" + width + ",height=" + height);
}

// get the sceditor text
function spellCheckGetText(editorID)
{
	return $("#" + editorID).data("sceditor").getText();
}

// set the sceditor text
function spellCheckSetText(text, editorID)
{
	$("#" + editorID).data("sceditor").InsertText(text, true);
	if (!$("#" + editorID).data("sceditor").inSourceMode)
		$("#" + editorID).data("sceditor").toggleSourceMode();
}<|endoftext|>


<commit_before>const filesystem = require('fs')
const fs = require('fs').promises
const events = require('events')
const Queue = require('avenue')
const path = require('path')
const assert = require('assert')
const coalesce = require('extant')

const LEVEL = { ENOENT: 'debug' }

class Watcher extends events.EventEmitter {
    constructor (destructible, hash, directory) {
        super()
        this._queue = new Queue
        this._hash = hash
        this._pids = []
        this._processes = {}
        this._directory = directory
        this._watcher = filesystem.watch(directory)
        this._watcher.on('change', (eventType, filename) => {
            this._queue.push({ method: 'changed', eventType, filename })
        })
        this._watcher.on('error', this.emit.bind(this, 'error'))
        destructible.durable('shift', this._shift(this._queue.shifter()))
        destructible.destruct(() => this._watcher.close())
        destructible.destruct(() => this._queue.push(null))
    }

    killed (pid) {
        this._queue.push({ method: 'killed', pid })
    }

    _safeParse (json, eventType, filename) {
        try {
            return JSON.parse(json)
        } catch (error) {
            assert(error instanceof SyntaxError, 'syntax error expected')
            this.emit('notice', {
                level: 'warn', label: 'json',
                directory: this._directory,
                eventType, filename, json
            })
        }
    }

    async _killed () {
        if (this._pids.length != 0) {
            const dir = await fs.readdir(this._directory)
            const extant = {}
            for (const filename of dir) {
                const pid = /(\d+)-[0-9a-f]{1,8}\.json$/.exec(filename)
                if (pid == null) {
                    this.emit('notice', {
                        level: 'warn', label: 'filename',
                        directory: this._directory, filename, eventType: 'pid'
                    })
                    continue
                }
                extant[pid[1]] = true
            }
            let i = 0, I = this._pids.length
            while (i < I) {
                const pid = this._pids[i]
                if (extant[pid]) {
                    i++
                } else {
                    this._pids.splice(i, 1)
                    I--
                    this.emit('data', { pid, body: { method: 'eos' } })
                }
            }
        }
    }

    async _changed (eventType, filename) {
        await this._killed()
        const hash = /-([0-9a-f]{1,8})\.json$/.exec(filename)
        if (hash == null) {
            this.emit('notice', {
                level: 'warn', label: 'filename',
                directory: this._directory,
                eventType, filename
            })
            return
        }
        let buffer = null
        try {
            buffer = await fs.readFile(path.resolve(this._directory, filename))
        } catch (error) {
            this.emit('notice', {
                level: coalesce(LEVEL[error.code], 'warn'),
                label: 'read',
                directory: this._directory,
                eventType, filename, message: error.message, code: error.code
            })
        }
        try {
            await fs.unlink(path.resolve(this._directory, filename))
        } catch (error) {
            this.emit('notice', {
                level: coalesce(LEVEL[error.code], 'warn'),
                label: 'unlink',
                directory: this._directory,
                eventType, filename, message: error.message, code: error.code
            })
            return
        }
        const expected = parseInt(hash[1], 16)
        const actual = this._hash.call(null, buffer)
        if (actual != expected) {
            this.emit('notice', {
                level: 'warn', label: 'checksum',
                directory: this._directory, eventType, filename,
                actual: (+actual).toString(16), expected: (+expected).toString(16)
            })
            return
        }
        const json = this._safeParse(buffer.toString(), eventType, filename)
        if (json != null) {
            this.emit('data', json)
        }
    }

    async _shift (shifter) {
        for await (const entry of shifter.iterator()) {
            switch (entry.method) {
            case 'killed':
                this._pids.push(entry.pid)
                await this._killed()
                break
            case 'changed':
                await this._changed(entry.eventType, entry.filename)
                break
            }
        }
    }
}

module.exports = Watcher
<commit_msg>Watcher drains on destroy.<commit_after>const filesystem = require('fs')
const fs = require('fs').promises
const events = require('events')
const Queue = require('avenue')
const path = require('path')
const assert = require('assert')
const coalesce = require('extant')

const LEVEL = { ENOENT: 'debug' }

class Watcher extends events.EventEmitter {
    constructor (destructible, hash, directory) {
        super()
        this.destroyed = false
        this._queue = new Queue
        this._hash = hash
        this._pids = []
        this._processes = {}
        this._directory = directory
        this._watcher = filesystem.watch(directory)
        this._watcher.on('change', (eventType, filename) => {
            this._queue.push({ method: 'changed', eventType, filename })
        })
        this._watcher.on('error', this.emit.bind(this, 'error'))
        destructible.durable('shift', this._shift(this._queue.shifter()))
        destructible.destruct(() => this.destroyed = true)
        destructible.destruct(() => this._checkClose())
    }

    killed (pid) {
        this._queue.push({ method: 'killed', pid })
    }

    _safeParse (json, eventType, filename) {
        try {
            return JSON.parse(json)
        } catch (error) {
            assert(error instanceof SyntaxError, 'syntax error expected')
            this.emit('notice', {
                level: 'warn', label: 'json',
                directory: this._directory,
                eventType, filename, json
            })
        }
    }

    async _killed () {
        if (this._pids.length != 0) {
            const dir = await fs.readdir(this._directory)
            const extant = {}
            for (const filename of dir) {
                const pid = /(\d+)-[0-9a-f]{1,8}\.json$/.exec(filename)
                if (pid == null) {
                    this.emit('notice', {
                        level: 'warn', label: 'filename',
                        directory: this._directory, filename, eventType: 'pid'
                    })
                    continue
                }
                extant[pid[1]] = true
            }
            let i = 0, I = this._pids.length
            while (i < I) {
                const pid = this._pids[i]
                if (extant[pid]) {
                    i++
                } else {
                    this._pids.splice(i, 1)
                    I--
                    this.emit('data', { pid, body: { method: 'eos' } })
                }
            }
        }
    }

    async _checkClose () {
        const dir = await fs.readdir(this._directory)
        if (dir.length == 0) {
            this._watcher.close()
            this._queue.push(null)
        }
    }

    async _changed (eventType, filename) {
        await this._killed()
        const hash = /-([0-9a-f]{1,8})\.json$/.exec(filename)
        if (hash == null) {
            this.emit('notice', {
                level: 'warn', label: 'filename',
                directory: this._directory,
                eventType, filename
            })
            return
        }
        let buffer = null
        try {
            buffer = await fs.readFile(path.resolve(this._directory, filename))
        } catch (error) {
            this.emit('notice', {
                level: coalesce(LEVEL[error.code], 'warn'),
                label: 'read',
                directory: this._directory,
                eventType, filename, message: error.message, code: error.code
            })
        }
        try {
            await fs.unlink(path.resolve(this._directory, filename))
        } catch (error) {
            this.emit('notice', {
                level: coalesce(LEVEL[error.code], 'warn'),
                label: 'unlink',
                directory: this._directory,
                eventType, filename, message: error.message, code: error.code
            })
            return
        }
        if (this.destroyed) {
            await this._checkClose()
        }
        const expected = parseInt(hash[1], 16)
        const actual = this._hash.call(null, buffer)
        if (actual != expected) {
            this.emit('notice', {
                level: 'warn', label: 'checksum',
                directory: this._directory, eventType, filename,
                actual: (+actual).toString(16), expected: (+expected).toString(16)
            })
            return
        }
        const json = this._safeParse(buffer.toString(), eventType, filename)
        if (json != null) {
            this.emit('data', json)
        }
    }

    async _shift (shifter) {
        for await (const entry of shifter.iterator()) {
            switch (entry.method) {
            case 'killed':
                this._pids.push(entry.pid)
                await this._killed()
                break
            case 'changed':
                await this._changed(entry.eventType, entry.filename)
                break
            }
        }
    }
}

module.exports = Watcher
<|endoftext|>


<commit_before>/**
 * Initialize services module
 */

angular.module('app.services', [
  'app.config',
  'ngResource',
  'JsCollection'
]).factory('device', function ($window) {

  var service = {
    init: function () {
      service._isSmartphone = false
      if ($window.device && $window.device.platform) {
        if ($window.device.platform === 'iOS') {
          service.isIOS = true;
          //$window.StatusBar.hide();
          ionic.Platform.fullScreen(true);
          service._isSmartphone = true
        }
        if ($window.device.name) {
          var name = $window.device.name.toUpperCase();
          service.isIPad = name.search('IPAD') !== -1;
          if(service.isIPad)
            service._isSmartphone = true
        }

        if ($window.device.platform === 'Android') {
          service.isAndroid = true;
          service.isAndroid2 = $window.device.version[0] === '2';
          service._isSmartphone = true
        }
      }
    },

    isSmartphone : function(){
      this.init()
      return this._isSmartphone
    }
  };

  return service;
}).factory('navigateTo', function ($location) {

  var activityRoutes = {
    'question': '/questions/',
    'user-petition': '/user-petition/',
    'post': '/post/',
    'leader-news': '/question/news/',
    'petition': '/petition/',
    'payment-request': '/payment-polls/payment-request/',
    'leader-event': '/leader-event/',
    'crowdfunding-payment-request': '/payment-polls/crowdfunding-payment-request/'
  };

  var targetRoutes = {
    'group_question': '/questions/',
    'representative_question': '/questions/',
    'superuser_question': '/questions/',
    'quorum': '/petition/',
    'open letter': '/petition/',
    'long petition': '/petition/',
    'group_petition': '/question/leader-petition/',
    'group_news': '/question/news/',
    'representative_news': '/question/news/',
    'representative_petition': '/question/leader-petition/',
    'representative_payment_request': '/payment-polls/payment-request/',
    'group_payment_request': '/payment-polls/payment-request/',
    'representative_payment_request_crowdfunding': '/payment-polls/crowdfunding-payment-request/',
    'group_payment_request_crowdfunding': '/payment-polls/crowdfunding-payment-request/',
    'representative_event': '/leader-event/',
    'group_event': '/leader-event/',
    'group': '/group/',
    'user': '/influence/profile/'
  };

  var calls = {
    'path': function () {
      $location.path('/' + _(arguments).compact().join('/'));
    },
    'influence-profile': function (id) {
      if (id) {
        $location.path('/influence/profile/' + id);
      }
    },
    'discussion': function (questionId, commentId) {
      if (commentId) {
        $location.path('/discussion/' + questionId + '/' + commentId);
      } else {
        $location.path('/discussion/' + questionId);
      }
    },
    'owner-profile': function (user) {
      if ('representative' === user.type) {
        $location.path('/representative/' + (user.id ? user.id : 0) + '/' + (user.storage_id ? user.storage_id : 0));
      } else if ('group' === user.type) {
        $location.path('/group/' + user.id);
      } else if ('user' === user.type) {
        $location.path('/influence/profile/' + user.id);
      }
    },
    'group-profile': function (group) {
      $location.path('/group/' + group.id);
    },
    'group-members': function (group) {
      $location.path('/group-members/' + group.id);
    },
    'group-join': function (group) {
      $location.path('/group/join/' + group.id);
    },
    'activity': function (activity, focus) {
      var activityType = activity.get('entity').type
      var activityID = activity.get('entity').id

      var activityRoute = activityRoutes[activityType]
      if(activityRoute == null)
        console.error('undefined route for activity type: '+activityType)
      var path = activityRoute + activityID;
      if (focus) {
        $location.path(path).search('focus', focus);
      } else {
        $location.path(path);
      }
    },
    'target': function (type, id) {
      $location.path(targetRoutes[type] + id);
    }
  };

  return function () {
    if (calls[arguments[0]]) {
      calls[arguments[0]].apply(this, _.rest(arguments));
    }
  };
}).value('homeCtrlParams', {
  activitiesCount: 0,
  filter: {
    groups: [],
    selectedGroup: null
  }
});<commit_msg>fix #303: clicking social activity item does not enters Post and UserPetition detail<commit_after>/**
 * Initialize services module
 */

angular.module('app.services', [
  'app.config',
  'ngResource',
  'JsCollection'
]).factory('device', function ($window) {

  var service = {
    init: function () {
      service._isSmartphone = false
      if ($window.device && $window.device.platform) {
        if ($window.device.platform === 'iOS') {
          service.isIOS = true;
          //$window.StatusBar.hide();
          ionic.Platform.fullScreen(true);
          service._isSmartphone = true
        }
        if ($window.device.name) {
          var name = $window.device.name.toUpperCase();
          service.isIPad = name.search('IPAD') !== -1;
          if(service.isIPad)
            service._isSmartphone = true
        }

        if ($window.device.platform === 'Android') {
          service.isAndroid = true;
          service.isAndroid2 = $window.device.version[0] === '2';
          service._isSmartphone = true
        }
      }
    },

    isSmartphone : function(){
      this.init()
      return this._isSmartphone
    }
  };

  return service;
}).factory('navigateTo', function ($location) {

  var activityRoutes = {
    'question': '/questions/',
    'user-petition': '/user-petition/',
    'post': '/post/',
    'leader-news': '/question/news/',
    'petition': '/petition/',
    'payment-request': '/payment-polls/payment-request/',
    'leader-event': '/leader-event/',
    'crowdfunding-payment-request': '/payment-polls/crowdfunding-payment-request/'
  };

  var targetRoutes = {
    'group_question': '/questions/',
    'representative_question': '/questions/',
    'superuser_question': '/questions/',
    'quorum': '/petition/',
    'open letter': '/petition/',
    'long petition': '/petition/',
    'group_petition': '/question/leader-petition/',
    'group_news': '/question/news/',
    'representative_news': '/question/news/',
    'representative_petition': '/question/leader-petition/',
    'representative_payment_request': '/payment-polls/payment-request/',
    'group_payment_request': '/payment-polls/payment-request/',
    'representative_payment_request_crowdfunding': '/payment-polls/crowdfunding-payment-request/',
    'group_payment_request_crowdfunding': '/payment-polls/crowdfunding-payment-request/',
    'representative_event': '/leader-event/',
    'group_event': '/leader-event/',
    'group': '/group/',
    'user': '/influence/profile/',
    'user-petition': '/user-petition/',
    'post': '/post/'
  };

  var calls = {
    'path': function () {
      $location.path('/' + _(arguments).compact().join('/'));
    },
    'influence-profile': function (id) {
      if (id) {
        $location.path('/influence/profile/' + id);
      }
    },
    'discussion': function (questionId, commentId) {
      if (commentId) {
        $location.path('/discussion/' + questionId + '/' + commentId);
      } else {
        $location.path('/discussion/' + questionId);
      }
    },
    'owner-profile': function (user) {
      if ('representative' === user.type) {
        $location.path('/representative/' + (user.id ? user.id : 0) + '/' + (user.storage_id ? user.storage_id : 0));
      } else if ('group' === user.type) {
        $location.path('/group/' + user.id);
      } else if ('user' === user.type) {
        $location.path('/influence/profile/' + user.id);
      }
    },
    'group-profile': function (group) {
      $location.path('/group/' + group.id);
    },
    'group-members': function (group) {
      $location.path('/group-members/' + group.id);
    },
    'group-join': function (group) {
      $location.path('/group/join/' + group.id);
    },
    'activity': function (activity, focus) {
      var activityType = activity.get('entity').type
      var activityID = activity.get('entity').id

      var activityRoute = activityRoutes[activityType]
      if(activityRoute == null)
        console.error('undefined route for activity type: '+activityType)
      var path = activityRoute + activityID;
      if (focus) {
        $location.path(path).search('focus', focus);
      } else {
        $location.path(path);
      }
    },
    'target': function (type, id) {
      $location.path(targetRoutes[type] + id);
    }
  };

  return function () {
    if (calls[arguments[0]]) {
      calls[arguments[0]].apply(this, _.rest(arguments));
    }
  };
}).value('homeCtrlParams', {
  activitiesCount: 0,
  filter: {
    groups: [],
    selectedGroup: null
  }
});<|endoftext|>


<commit_before>angular.module('mapasculturais.services', [])

.factory('BlankFactory', [function(){

}])

.service('BlankService', [function(){

}])

.service('MenuState', ['$rootScope', function($rootScope) {
    $rootScope.activeMenu = 'events';
    this.activeMenu = function(activeMenu){
        $rootScope.activeMenu = activeMenu;
    };
}])

.service('ConfigState', function($localStorage, $location) {
    this.dataSources = {
        'spcultura': {
            prefix: 'spcultura',
            name: 'SpCultura',
            url: 'http://spcultura.prefeitura.sp.gov.br/',
            map: {
                latutude: -23.5408,
                longitude: -46.6400,
                zoom: 11
            }
        },
        estadodacultura: {
            prefix: 'estadodacultura',
            name: 'SP Estado da Cultura',
            url: 'http://estadodacultura.sp.gov.br/',
            map: {
                latutude: -22.61401087437029,
                longitude: -49.2132568359375,
                zoom: 7
            }
        },
        ceara: {
            prefix: 'ceara',
            name: 'Mapa Cultural do Ceará',
            url: 'http://mapa.cultura.ce.gov.br/',
            map: {
                latutude: -5.063586123720585,
                longitude: -39.4134521484375,
                zoom: 7
            }
        },
        blumenau: {
            prefix: 'blumenau',
            name: 'Blumenau Mais Cultura',
            url: 'http://blumenaumaiscultura.com.br/',
            map: {
                latutude: -26.883952223378103,
                longitude: -49.08708572387695,
                zoom: 12
            }
        },
        bh: {
            prefix: 'bh',
            name: 'Mapeamento Cultural de BH',
            url: 'http://mapeamentoculturalbh.pbh.gov.br/',
            map: {
                latutude: -19.919614676628896,
                longitude: -43.97294998168945,
                zoom: 12
            }
        },
        mapasmt: {
            prefix: 'mapasmt',
            name: 'Mapas MT',
            url: 'https://mapas.cultura.mt.gov.br/',
            map: {
                latutude: -13.549881446917126,
                longitude: -56.085205078125,
                zoom: 6
            }
        },
        /* precisa atualizar o mapas para funcionar
        lugaresdacultura: {
            prefix: 'lugaresdacultura',
            name: 'Lugares da Cultura',
            url: 'http://lugaresdacultura.org.br/',
            map: {
                latutude: -23.105628416305972,
                longitude: -45.84800720214843,
                zoom: 10
            }
        }, */
    };

    this.defineDataSource = function(prefix){
        $localStorage.config.dataSource = prefix;

        this.dataSource = this.dataSources[prefix];
    }

    if($localStorage.config){
        this.dataSource = this.dataSources[$localStorage.config.dataSource];
    } else {
        $localStorage.config = {};

        this.defineDataSource(this.dataSources[Object.keys(this.dataSources)[0]].prefix);
    }
})

.service('FavoriteEvents', ['$localStorage', 'ConfigState', function($localStorage, config) {

    var self = this
    this.favorites = [];

    var sync = function() {
        while (self.favorites.length > 0){
            self.favorites.pop();
        }
        for (var key in $localStorage.favoriteEvents) {
            var event = $localStorage.favoriteEvents[key];
            event.start = moment(event.start);
            event.end = moment(event.end);
            self.favorites.push(event);
        }
    }

    if (!$localStorage.favoriteEvents) {
        $localStorage.favoriteEvents = {}
    } else {
        sync();
    }

    var getKey = function(event) {
        var key = moment(event.start.toString()).format('X') + '|' + event.occurrence_id;
        return config.dataSource.prefix + ':' + key;

    }

    this.favorite = function(event) {
        if (!event.favorite) {
            event.favorite = true;
            $localStorage.favoriteEvents[getKey(event)] = event;
        } else {
            event.favorite = false;
            delete $localStorage.favoriteEvents[getKey(event)]
        }
        sync()
    }

    this.isFavorite = function(event) {
        return !!$localStorage.favoriteEvents[getKey(event)]
    }

    this.clear = function(){
        $localStorage.favoriteEvents = {};
        sync();
    }

}])

.service('MapState', function(ConfigState){
    // return function(mapTypeId, center){
    var center = new plugin.google.maps.LatLng(ConfigState.dataSource.map.latitude, ConfigState.dataSource.map.longitude);
    this.options = {
        'backgroundColor': 'transparent',
        'mapType': plugin.google.maps.MapTypeId.ROADMAP,
        'controls': {
            'myLocationButton': true,
            'indoorPicker': true,
            'zoom': true
        },
        'gestures': {
            'scroll': true,
            'tilt': true,
            'rotate': false,
            'zoom': true
        },
        'camera': {
            'latLng': center,
            'zoom': ConfigState.dataSource.map.zoom,
        }
    };
    this.markers = [];
        // map options that will be kept in memory ;)
    // }
})<commit_msg>fix typo in position<commit_after>angular.module('mapasculturais.services', [])

.factory('BlankFactory', [function(){

}])

.service('BlankService', [function(){

}])

.service('MenuState', ['$rootScope', function($rootScope) {
    $rootScope.activeMenu = 'events';
    this.activeMenu = function(activeMenu){
        $rootScope.activeMenu = activeMenu;
    };
}])

.service('ConfigState', function($localStorage, $location) {
    this.dataSources = {
        'spcultura': {
            prefix: 'spcultura',
            name: 'SpCultura',
            url: 'http://spcultura.prefeitura.sp.gov.br/',
            map: {
                latitude: -23.5408,
                longitude: -46.6400,
                zoom: 11
            }
        },
        estadodacultura: {
            prefix: 'estadodacultura',
            name: 'SP Estado da Cultura',
            url: 'http://estadodacultura.sp.gov.br/',
            map: {
                latitude: -22.61401087437029,
                longitude: -49.2132568359375,
                zoom: 7
            }
        },
        ceara: {
            prefix: 'ceara',
            name: 'Mapa Cultural do Ceará',
            url: 'http://mapa.cultura.ce.gov.br/',
            map: {
                latitude: -5.063586123720585,
                longitude: -39.4134521484375,
                zoom: 7
            }
        },
        blumenau: {
            prefix: 'blumenau',
            name: 'Blumenau Mais Cultura',
            url: 'http://blumenaumaiscultura.com.br/',
            map: {
                latitude: -26.883952223378103,
                longitude: -49.08708572387695,
                zoom: 12
            }
        },
        bh: {
            prefix: 'bh',
            name: 'Mapeamento Cultural de BH',
            url: 'http://mapeamentoculturalbh.pbh.gov.br/',
            map: {
                latitude: -19.919614676628896,
                longitude: -43.97294998168945,
                zoom: 12
            }
        },
        mapasmt: {
            prefix: 'mapasmt',
            name: 'Mapas MT',
            url: 'https://mapas.cultura.mt.gov.br/',
            map: {
                latitude: -13.549881446917126,
                longitude: -56.085205078125,
                zoom: 6
            }
        },
        mapasgovbr: {
            prefix: 'mapasgovbr',
            name: 'Mapas.cultura.gov.br',
            url: 'http://mapas.cultura.gov.br/',
            map: {
                latitude: -15.792253570362446,
                longitude: -47.900390625,
                zoom: 5
            }
        },
        /* precisa atualizar o mapas para funcionar
        lugaresdacultura: {
            prefix: 'lugaresdacultura',
            name: 'Lugares da Cultura',
            url: 'http://lugaresdacultura.org.br/',
            map: {
                latitude: -23.105628416305972,
                longitude: -45.84800720214843,
                zoom: 10
            }
        }, */
    };

    this.defineDataSource = function(prefix){
        $localStorage.config.dataSource = prefix;

        this.dataSource = this.dataSources[prefix];
    }

    if($localStorage.config){
        this.dataSource = this.dataSources[$localStorage.config.dataSource];
    } else {
        $localStorage.config = {};

        this.defineDataSource(this.dataSources[Object.keys(this.dataSources)[0]].prefix);
    }
})

.service('FavoriteEvents', ['$localStorage', 'ConfigState', function($localStorage, config) {

    var self = this
    this.favorites = [];

    var sync = function() {
        while (self.favorites.length > 0){
            self.favorites.pop();
        }
        for (var key in $localStorage.favoriteEvents) {
            var event = $localStorage.favoriteEvents[key];
            event.start = moment(event.start);
            event.end = moment(event.end);
            self.favorites.push(event);
        }
    }

    if (!$localStorage.favoriteEvents) {
        $localStorage.favoriteEvents = {}
    } else {
        sync();
    }

    var getKey = function(event) {
        var key = moment(event.start.toString()).format('X') + '|' + event.occurrence_id;
        return config.dataSource.prefix + ':' + key;

    }

    this.favorite = function(event) {
        if (!event.favorite) {
            event.favorite = true;
            $localStorage.favoriteEvents[getKey(event)] = event;
        } else {
            event.favorite = false;
            delete $localStorage.favoriteEvents[getKey(event)]
        }
        sync()
    }

    this.isFavorite = function(event) {
        return !!$localStorage.favoriteEvents[getKey(event)]
    }

    this.clear = function(){
        $localStorage.favoriteEvents = {};
        sync();
    }

}])

.service('MapState', function(ConfigState){
    // return function(mapTypeId, center){
    var center = new plugin.google.maps.LatLng(ConfigState.dataSource.map.latitude, ConfigState.dataSource.map.longitude);
    this.options = {
        'backgroundColor': 'transparent',
        'mapType': plugin.google.maps.MapTypeId.ROADMAP,
        'controls': {
            'myLocationButton': true,
            'indoorPicker': true,
            'zoom': true
        },
        'gestures': {
            'scroll': true,
            'tilt': true,
            'rotate': false,
            'zoom': true
        },
        'camera': {
            'latLng': center,
            'zoom': ConfigState.dataSource.map.zoom,
        }
    };
    this.markers = [];
        // map options that will be kept in memory ;)
    // }
})
<|endoftext|>


<commit_before>const assert = require('assert');

const PalindromeSwapper = (str) => {
  const inputArray = str.split('');
  const strLen = inputArray.length;
  const palTester = (arr) => {
    const len = arr.length;
    for (let i = 0; i < len; i += 1) {
      if (arr[i] !== arr[len - (1 + i)]) {
        return false;
      }
    }
    return true;
  };

  for (let i = 0; i < strLen - 1; i += 1) {
    const newArray = Array.from(inputArray);
    newArray.splice(i, 2, newArray[i + 1], newArray[i]);
    if (palTester(newArray)) {
      return newArray.join('');
    }

    // console.log('PalindromeSwapper');
  }
  return -1;
};

const in1 = 'anna'; // input
const expect1 = 'anna'; // output
const test1 = PalindromeSwapper(in1);
assert.strictEqual(test1, expect1, `should be ${expect1}`);
// console.log(test1);

// const in2 = 'kayak'; // input
// const expect2 = 'kayak'; // output
// const test2 = PalindromeSwapper(in2);
// assert.strictEqual(test2, expect2, `should be ${expect2}`);
// console.log(test2);
<commit_msg>wip-fix test<commit_after>const assert = require('assert');

const PalindromeSwapper = (str) => {
  const inputArray = str.split('');
  const strLen = inputArray.length;
  const palTester = (arr) => {
    const len = arr.length;
    for (let i = 0; i < len; i += 1) {
      if (arr[i] !== arr[len - (1 + i)]) {
        return false;
      }
    }
    return true;
  };

  for (let i = 0; i < strLen - 1; i += 1) {
    const newArray = Array.from(inputArray);
    newArray.splice(i, 2, newArray[i + 1], newArray[i]);
    if (palTester(newArray)) {
      return newArray.join('');
    }

    // console.log('PalindromeSwapper');
  }
  return -1;
};

const in1 = 'anna'; // input
const expect1 = 'anna'; // output
const test1 = PalindromeSwapper(in1);
assert.strictEqual(test1, expect1, `should be ${expect1}`);
// console.log(test1);

const in2 = 'kayak'; // input
const expect2 = 'kayak'; // output
const test2 = PalindromeSwapper(in2);
assert.strictEqual(test2, expect2, `should be ${expect2}`);
// console.log(test2);
<|endoftext|>


<commit_before>// Chris Samuel
// ksamuel.chris@gmail.com
/*
JavaSCript uses lexical scoping which  means thats function are executed using
the variable scope that is in effect when they are invoked. All JavaScript functions
are closures:

they are objects and they have a scope chain associated with them.

Github: alayode

*/

var ARMORY = (function(){
  var weaponList =  [ 'Excalibur','Ice Brand','Ragnarok','Save the Queen' ];
  var armorList  =  [ 'Rainbow Cloak','Doublet','Lizard Jerkin','Chain Mail' ];

  var removeWeapon = function(){
    //revmove weapon from the armory
  };
  var replaceWeapon = function(){
    //add a weapon to the weaponList
  };
  var removeArmor = function(){
    //remove a weapons from the armorList
  };
  var replaceArmor = function(){
    //add armor to the armorList
  };

  return{
    makeWeaponRequest: function(){
    //create a object that would be accessible to the global scope.
    console.log('Weapon Request Acknowledge!');
  },
    makeArmorRequest: function(){
      // create a object that also be available to the global scope once the function is called.
    }
  };
})();
<commit_msg>added a variable called weapon that will pass the weapons for requesting<commit_after>// Chris Samuel
// ksamuel.chris@gmail.com
/*
JavaSCript uses lexical scoping which  means thats function are executed using
the variable scope that is in effect when they are invoked. All JavaScript functions
are closures:

they are objects and they have a scope chain associated with them.

Github: alayode

*/

var ARMORY = (function(){
  var weaponList =  [ 'Excalibur','Ice Brand','Ragnarok','Save the Queen' ];
  var armorList  =  [ 'Rainbow Cloak','Doublet','Lizard Jerkin','Chain Mail' ];

  var removeWeapon = function(weapon){
    //revmove weapon from the armory
    // weaponList.slice()
    console.log(weapon);
  };
  var replaceWeapon = function(){
    //add a weapon to the weaponList
  };
  var removeArmor = function(){
    //remove a weapons from the armorList
  };
  var replaceArmor = function(){
    //add armor to the armorList
  };

  return{
    makeWeaponRequest: function(weapon){
    //create a object that would be accessible to the global scope.
    console.log('Weapon Request Acknowledge!');
    removeWeapon(weapon)

  },
    makeArmorRequest: function(){
      // create a object that also be available to the global scope once the function is called.
      console.log('Armor Request Acknowledge!')
    }
  };
})();

ARMORY.makeWeaponRequest('Excalibur');
// ARMORY.makeArmorRequest();
<|endoftext|>


<commit_before>#!/usr/bin/env node

// Load modules
var lfcli = require('./lfcli.js');

lfcli.query('/info', function(res) {
	console.log('Core Version: ' + res.core_version);
	console.log('API Version:  ' + res.api_version);
});

lfcli.query('/member_count', function(res) {
	console.log('Members: ' + res.total_count);
});

lfcli.query('/member', function(res) {
	var i;
	var members = res.result;
	for(i = 0; i < members.length; ++i) {
		var member = members[i];
		console.log('Member: ' + member.name);
	}
});

lfcli.query('/policy', function(res) {
	var i;
	var policies = res.result;
	console.log('Policies: ' + policies.length);
	for(i = 0; i < policies.length; ++i) {
		var policy = policies[i];
		console.log('Policy: ' + policy.name);
	}
});

lfcli.query('/unit', function(res) {
	var i;
	var units = res.result;
	console.log('Units: ' + units.length);
	for(i = 0; i < units.length; ++i) {
		var unit = units[i];
		console.log('Unit: ' + unit.name);
	}
});

lfcli.query('/area', function(res) {
	var i;
	var areas = res.result;
	console.log('Areas: ' + areas.length);
	for(i = 0; i < areas.length; ++i) {
		var area = areas[i];
		console.log('Area: ' + area.name);
	}
});

lfcli.query('/issue', function(res) {
	var i;
	var issues = res.result;
	console.log('Issues: ' + issues.length);
	for(i = 0; i < issues.length; ++i) {
		var issue = issues[i];
		console.log('Issue: ' + issue.state);
	}
});

lfcli.query('/initiative', function(res) {
	var i;
	var initiatives = res.result;
	console.log('Initiatives: ' + initiatives.length);
	for(i = 0; i < initiatives.length; ++i) {
		var initiative = initiatives[i];
		console.log('Initiative: ' + initiative.name);
	}
});
<commit_msg>Choose query via command line.<commit_after>#!/usr/bin/env node

// Load modules
var lfcli = require('./lfcli.js');

// Define all actions
actions = {};

actions.info = function() {
	lfcli.query('/info', function(res) {
		console.log('Core Version: ' + res.core_version);
		console.log('API Version:  ' + res.api_version);
	});
};
actions.info.help = 'Get general information on the server.';

actions.member_count = function() {
	lfcli.query('/member_count', function(res) {
		console.log('Members: ' + res.total_count);
	});
};
actions.member_count.help = 'Get the number of members registered.';

actions.members = function() {
	lfcli.query('/member', function(res) {
		var i;
		var members = res.result;
		for(i = 0; i < members.length; ++i) {
			var member = members[i];
			console.log('Member: ' + member.name);
		}
	});
};
actions.members.help = 'Get member list.';

actions.policies = function() {
	lfcli.query('/policy', function(res) {
		var i;
		var policies = res.result;
		console.log('Policies: ' + policies.length);
		for(i = 0; i < policies.length; ++i) {
			var policy = policies[i];
			console.log('Policy: ' + policy.name);
		}
	});
};
actions.policies.help = 'Get list of policies';

actions.units = function() {
	lfcli.query('/unit', function(res) {
		var i;
		var units = res.result;
		console.log('Units: ' + units.length);
		for(i = 0; i < units.length; ++i) {
			var unit = units[i];
			console.log('Unit: ' + unit.name);
		}
	});
};
actions.units.help = 'Get list of units';

actions.areas = function() {
	lfcli.query('/area', function(res) {
		var i;
		var areas = res.result;
		console.log('Areas: ' + areas.length);
		for(i = 0; i < areas.length; ++i) {
			var area = areas[i];
			console.log('Area: ' + area.name);
		}
	});
};
actions.areas.help = 'Get list of areas';

actions.issues = function() {
	lfcli.query('/issue', function(res) {
		var i;
		var issues = res.result;
		console.log('Issues: ' + issues.length);
		for(i = 0; i < issues.length; ++i) {
			var issue = issues[i];
			console.log('Issue: ' + issue.state);
		}
	});
};
actions.issues.help = 'Get list of issues';

actions.initiatives = function() {
	lfcli.query('/initiative', function(res) {
		var i;
		var initiatives = res.result;
		console.log('Initiatives: ' + initiatives.length);
		for(i = 0; i < initiatives.length; ++i) {
			var initiative = initiatives[i];
			console.log('Initiative: ' + initiative.name);
		}
	});
};
actions.initiatives.help = 'Get list of initiatives';

actions.help = function() {
	console.log('Invocation: apicli.js [action]');
	console.log('\nAvailable actions:');
	for(action in actions) {
		if(actions.hasOwnProperty(action)) {
			console.log('  ' + action + ': ' + actions[action].help);
		}
	}
};
actions.help.help = 'Show this help';

// specify what to do if no argument is given
actions.default = actions.help;

// Get arguments from Script
if(process.argv.length > 2) {
	var argument = process.argv[2];
	if(actions.hasOwnProperty(argument) && typeof(actions[argument]) == 'function') {
		actions[argument]();
	} else {
		actions.help();
	}
} else {
	actions.default();
}
<|endoftext|>