<commit_before>/** @namespace

Lightweight JSONP fetcher - www.nonobstrusive.com
The JSONP namespace provides a lightweight JSONP implementation.  This code
is implemented as-is from the code released on www.nonobtrusive.com, as per the
blog post listed below.  Only two changes were made. First, rename the json function
to get around jslint warnings. Second, remove the params functionality from that
function (not needed for my implementation).

http://www.nonobtrusive.com/2010/05/20/lightweight-jsonp-without-any-3rd-party-libraries/
*/
GRUNT.JSONP = (function(){
    var counter = 0, head, query, key, jsonp, window = this;

    function load(url) {
        var script = document.createElement('script'),
            done = false;
        script.src = url;
        script.async = true;

        script.onload = script.onreadystatechange = function() {
            if ( !done && (!this.readyState || this.readyState === "loaded" || this.readyState === "complete") ) {
                done = true;
                script.onload = script.onreadystatechange = null;
                if ( script && script.parentNode ) {
                    script.parentNode.removeChild( script );
                }
            }
        };
        if ( !head ) {
            head = document.getElementsByTagName('head')[0];
        }
        head.appendChild( script );
    } // load

    function prepAndLoad(url, callback) {
        // apply either a ? or & to the url depending on whether we already have query params
        url += url.indexOf("?") >= 0 ? "&" : "?";

        jsonp = "json" + (++counter);
        window[ jsonp ] = function(data){
            callback(data);
            window[ jsonp ] = null;
            try {
                delete window[ jsonp ];
            } catch (e) {}
        };

        load(url + query + "callback=" + jsonp);
        return jsonp;
    } // jsonp

    return {
        get:prepAndLoad
    };

}());

/** @namespace

The XHR namespace provides functionality for issuing AJAX requests in a similar style
to the way jQuery does.  Why build a replacement for jQuery's ajax functionality you ask
(and a fair question, I might add)?  Basically, because I was writing a library that I
didn't want to have to rely on the presence of jQuery especially when the internals of the
way AJAX is handled changed between version 1.3.2 and 1.4.2. While not a big deal for
end users of jQuery it became a problem when you wanted to implement a replacement XHR
object.  So what does GRUNT XHR provide then?

TODO: add information here...
*/
GRUNT.XHR = (function() {
    // define some content types
    var CONTENT_TYPES = {
        HTML: "text/html",
        XML: "text/xml",
        TEXT: "text/plain",
        STREAM: "application/octet-stream"
    };

    // define some regular expressions to help determine the type of the request
    var REQUEST_URL_EXTENSIONS = {
        JSON: ['json'],
        PDON: ['pdon.txt']
    };

    var INDERMINATE_CONTENT_TYPES = ["TEXT", "STREAM"];

    // initialise some regexes
    var REGEX_URL = /^(\w+:)?\/\/([^\/?#]+)/;

    // define the variable content type processors
    var RESPONSE_TYPE_PROCESSORS = {
        XML: function(xhr, requestParams) {
            return xhr.responseXML;
        },

        JSON: function(xhr, requestParams) {
            // use the JSON object to convert the responseText to a JS object
            try {
                return JSON.parse(xhr.responseText);
            }
            catch (e) {
                GRUNT.Log.error("Error parsing JSON data: ", xhr.responseText);
                GRUNT.Log.exception(e);
            }

            return "";
        },

        PDON: function(xhr, requestParams) {
            return GRUNT.Data.parse({
                data: xhr.responseText,
                format: "PDON"
            });
        },

        DEFAULT: function(xhr, requestParam) {
            return xhr.responseText;
        }
    }; // CONTENT_TYPE_PROCESSORS

    // define headers
    var HEADERS = {
        CONTENT_TYPE: "Content-Type"
    };

    /**
    This function is used to determine the appropriate request type based on the extension
    of the url that was originally requested.  This function is only called in the case where
    an indeterminate type of content-type has been received from the server that has supplied the
    response (such as application/octet-stream).

    @private
    @param {XMLHttpRequest } xhr the XMLHttpRequest object
    @param requestParams the parameters that were passed to the xhr request
    @param fallbackType the type of request that we will fallback to
    */
    function getProcessorForRequestUrl(xhr, requestParams, fallbackType) {
        for (var requestType in REQUEST_URL_EXTENSIONS) {
            // iterate through the file extensions
            for (var ii = 0; ii < REQUEST_URL_EXTENSIONS[requestType].length; ii++) {
                var fileExt = REQUEST_URL_EXTENSIONS[requestType][ii];

                // if the request url ends with the specified file extension we have a match
                if (new RegExp(fileExt + "$", "i").test(requestParams.url)) {
                    return requestType;
                } // if
            } // for
        } // for

        return fallbackType ? fallbackType : "DEFAULT";
    } // getProcessorForRequestUrl

    function requestOK(xhr, requestParams) {
        return ((! xhr.status) && (location.protocol === "file:")) ||
            (xhr.status >= 200 && xhr.status < 300) ||
            (xhr.status === 304) ||
            (xhr.status === 1223) ||
            (xhr.status === 0);
    } // getStatus

    function processResponseData(xhr, requestParams) {
        // get the content type of the response
        var contentType = xhr.getResponseHeader(HEADERS.CONTENT_TYPE),
            processorId,
            matchedType = false;

        // GRUNT.Log.info("processing response data, content type = " + contentType);

        // determine the matching content type
        for (processorId in CONTENT_TYPES) {
            if (contentType && (contentType.indexOf(CONTENT_TYPES[processorId]) >= 0)) {
                matchedType = true;
                break;
            }
        } // for

        // if the match type was indeterminate, then look at the url of the request to
        // determine which is the best type to match on
        var indeterminate = (! matchedType);
        for (var ii = 0; ii < INDERMINATE_CONTENT_TYPES.length; ii++) {
            indeterminate = indeterminate || (INDERMINATE_CONTENT_TYPES[ii] == processorId);
        } // for

        if (indeterminate) {
            processorId = getProcessorForRequestUrl(xhr, requestParams, processorId);
        } // if

        try {
            // GRUNT.Log.info("using processor: " + processorId + " to process response");
            return RESPONSE_TYPE_PROCESSORS[processorId](xhr, requestParams);
        }
        catch (e) {
            GRUNT.Log.warn("error applying processor '" + processorId + "' to response type, falling back to default");
            return RESPONSE_TYPE_PROCESSORS.DEFAULT(xhr, requestParams);
        } // try..catch
    } // processResponseData

    // define self
    var module = GRUNT.newModule({
        id: "grunt.xhr",

        ajaxSettings: {
            xhr: null
        },

        ajax: function(params) {
            // given that I am having to write my own AJAX handling, I think it's safe to assume that I should
            // do that in the context of a try catch statement to catch the things that are going to go wrong...
            try {
                params = GRUNT.extend({
                    method: "GET",
                    data: null,
                    url: null,
                    async: true,
                    success: null,
                    handleResponse: null,
                    error: null,
                    contentType: "application/x-www-form-urlencoded"
                }, module.ajaxSettings, params);

                // determine if this is a remote request (as per the jQuery ajax calls)
                var parts = REGEX_URL.exec(params.url),
                    remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);

                // if we have data, then update the method to POST
                if (params.data) {
                    params.method = "POST";
                } // if

                // if the url is empty, then log an error
                if (! params.url) {
                    GRUNT.Log.warn("ajax request issued with no url - that ain't going to work...");
                    return;
                } // if

                // if the we have an xhr creator registered, then let it decide whether it wants to create the client
                var xhr = null;
                if (params.xhr) {
                    xhr = params.xhr(params);
                } // if

                // if the optional creator, didn't create the client, then create the default client
                if (! xhr) {
                    xhr = new XMLHttpRequest();
                } // if

                // GRUNT.Log.info("opening request: " + JSON.stringify(params));

                // open the request
                // TODO: support basic authentication
                xhr.open(params.method, params.url, params.async);

                // if we are sending data, then set the correct content type
                if (params.data) {
                    xhr.setRequestHeader("Content-Type", params.contentType);
                } // if

                // if this is not a remote request, the set the requested with header
                if (! remote) {
                    xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
                } // if

                xhr.onreadystatechange = function() {
                    if (this.readyState === 4) {
                        var responseData = null,
                            success = requestOK(this, params);

                        try {
                            // get and check the status
                            if (success) {
                                // process the response
                                if (params.handleResponse) {
                                    params.handleResponse(this);
                                }
                                else {
                                    responseData = processResponseData(this, params);
                                }
                            }
                            else if (params.error) {
                                params.error(this);
                            } // if..else
                        }
                        catch (e) {
                            GRUNT.Log.exception(e, "PROCESSING AJAX RESPONSE");
                        } // try..catch

                        // if the success callback is defined, then call it
                        // GRUNT.Log.info("received response, calling success handler: " + params.success);
                        if (success && responseData && params.success) {
                            params.success.call(this, responseData);
                        } // if
                    } // if
                }; // onreadystatechange

                // send the request
                // GRUNT.Log.info("sending request with data: " + module.param(params.data));
                xhr.send(params.method == "POST" ? module.param(params.data) : null);
            }
            catch (e) {
                GRUNT.Log.exception(e);
            } // try..catch
        }, // ajax

        param: function(data) {
            // iterate through the members of the data and convert to a paramstring
            var params = [];
            var addKeyVal = function (key, value) {
                // If value is a function, invoke it and return its value
                value = GRUNT.isFunction(value) ? value() : value;
                params[ params.length ] = encodeURIComponent(key) + "=" + encodeURIComponent(value);
            };

            // If an array was passed in, assume that it is an array of form elements.
            if (GRUNT.isArray(data)) {
                for (var ii = 0; ii < data.length; ii++) {
                    addKeyVal(data[ii].name, data[ii].value);
                } // for
            }
            else {
                for (var keyname in data) {
                    addKeyVal(keyname, data[keyname]);
                } // for
            } // if..else

            // Return the resulting serialization
            return params.join("&").replace(/%20/g, "+");
        }
    }); // self

    return module;
})();

<commit_msg>JSON Tweaks (again)<commit_after>/** @namespace

Lightweight JSONP fetcher - www.nonobstrusive.com
The JSONP namespace provides a lightweight JSONP implementation.  This code
is implemented as-is from the code released on www.nonobtrusive.com, as per the
blog post listed below.  Only two changes were made. First, rename the json function
to get around jslint warnings. Second, remove the params functionality from that
function (not needed for my implementation).

http://www.nonobtrusive.com/2010/05/20/lightweight-jsonp-without-any-3rd-party-libraries/
*/
GRUNT.JSONP = (function(){
    var counter = 0, head, query, key, jsonp, window = this;

    function load(url) {
        var script = document.createElement('script'),
            done = false;
        script.src = url;
        script.async = true;

        script.onload = script.onreadystatechange = function() {
            if ( !done && (!this.readyState || this.readyState === "loaded" || this.readyState === "complete") ) {
                done = true;
                script.onload = script.onreadystatechange = null;
                if ( script && script.parentNode ) {
                    script.parentNode.removeChild( script );
                }
            }
        };
        if ( !head ) {
            head = document.getElementsByTagName('head')[0];
        }
        head.appendChild( script );
    } // load

    function prepAndLoad(url, callback) {
        // apply either a ? or & to the url depending on whether we already have query params
        url += url.indexOf("?") >= 0 ? "&" : "?";

        jsonp = "json" + (++counter);
        window[ jsonp ] = function(data){
            callback(data);
            window[ jsonp ] = null;
            try {
                delete window[ jsonp ];
            } catch (e) {}
        };

        load(url + "callback=" + jsonp);
        return jsonp;
    } // jsonp

    return {
        get:prepAndLoad
    };

}());

/** @namespace

The XHR namespace provides functionality for issuing AJAX requests in a similar style
to the way jQuery does.  Why build a replacement for jQuery's ajax functionality you ask
(and a fair question, I might add)?  Basically, because I was writing a library that I
didn't want to have to rely on the presence of jQuery especially when the internals of the
way AJAX is handled changed between version 1.3.2 and 1.4.2. While not a big deal for
end users of jQuery it became a problem when you wanted to implement a replacement XHR
object.  So what does GRUNT XHR provide then?

TODO: add information here...
*/
GRUNT.XHR = (function() {
    // define some content types
    var CONTENT_TYPES = {
        HTML: "text/html",
        XML: "text/xml",
        TEXT: "text/plain",
        STREAM: "application/octet-stream"
    };

    // define some regular expressions to help determine the type of the request
    var REQUEST_URL_EXTENSIONS = {
        JSON: ['json'],
        PDON: ['pdon.txt']
    };

    var INDERMINATE_CONTENT_TYPES = ["TEXT", "STREAM"];

    // initialise some regexes
    var REGEX_URL = /^(\w+:)?\/\/([^\/?#]+)/;

    // define the variable content type processors
    var RESPONSE_TYPE_PROCESSORS = {
        XML: function(xhr, requestParams) {
            return xhr.responseXML;
        },

        JSON: function(xhr, requestParams) {
            // use the JSON object to convert the responseText to a JS object
            try {
                return JSON.parse(xhr.responseText);
            }
            catch (e) {
                GRUNT.Log.error("Error parsing JSON data: ", xhr.responseText);
                GRUNT.Log.exception(e);
            }

            return "";
        },

        PDON: function(xhr, requestParams) {
            return GRUNT.Data.parse({
                data: xhr.responseText,
                format: "PDON"
            });
        },

        DEFAULT: function(xhr, requestParam) {
            return xhr.responseText;
        }
    }; // CONTENT_TYPE_PROCESSORS

    // define headers
    var HEADERS = {
        CONTENT_TYPE: "Content-Type"
    };

    /**
    This function is used to determine the appropriate request type based on the extension
    of the url that was originally requested.  This function is only called in the case where
    an indeterminate type of content-type has been received from the server that has supplied the
    response (such as application/octet-stream).

    @private
    @param {XMLHttpRequest } xhr the XMLHttpRequest object
    @param requestParams the parameters that were passed to the xhr request
    @param fallbackType the type of request that we will fallback to
    */
    function getProcessorForRequestUrl(xhr, requestParams, fallbackType) {
        for (var requestType in REQUEST_URL_EXTENSIONS) {
            // iterate through the file extensions
            for (var ii = 0; ii < REQUEST_URL_EXTENSIONS[requestType].length; ii++) {
                var fileExt = REQUEST_URL_EXTENSIONS[requestType][ii];

                // if the request url ends with the specified file extension we have a match
                if (new RegExp(fileExt + "$", "i").test(requestParams.url)) {
                    return requestType;
                } // if
            } // for
        } // for

        return fallbackType ? fallbackType : "DEFAULT";
    } // getProcessorForRequestUrl

    function requestOK(xhr, requestParams) {
        return ((! xhr.status) && (location.protocol === "file:")) ||
            (xhr.status >= 200 && xhr.status < 300) ||
            (xhr.status === 304) ||
            (xhr.status === 1223) ||
            (xhr.status === 0);
    } // getStatus

    function processResponseData(xhr, requestParams) {
        // get the content type of the response
        var contentType = xhr.getResponseHeader(HEADERS.CONTENT_TYPE),
            processorId,
            matchedType = false;

        // GRUNT.Log.info("processing response data, content type = " + contentType);

        // determine the matching content type
        for (processorId in CONTENT_TYPES) {
            if (contentType && (contentType.indexOf(CONTENT_TYPES[processorId]) >= 0)) {
                matchedType = true;
                break;
            }
        } // for

        // if the match type was indeterminate, then look at the url of the request to
        // determine which is the best type to match on
        var indeterminate = (! matchedType);
        for (var ii = 0; ii < INDERMINATE_CONTENT_TYPES.length; ii++) {
            indeterminate = indeterminate || (INDERMINATE_CONTENT_TYPES[ii] == processorId);
        } // for

        if (indeterminate) {
            processorId = getProcessorForRequestUrl(xhr, requestParams, processorId);
        } // if

        try {
            // GRUNT.Log.info("using processor: " + processorId + " to process response");
            return RESPONSE_TYPE_PROCESSORS[processorId](xhr, requestParams);
        }
        catch (e) {
            GRUNT.Log.warn("error applying processor '" + processorId + "' to response type, falling back to default");
            return RESPONSE_TYPE_PROCESSORS.DEFAULT(xhr, requestParams);
        } // try..catch
    } // processResponseData

    // define self
    var module = GRUNT.newModule({
        id: "grunt.xhr",

        ajaxSettings: {
            xhr: null
        },

        ajax: function(params) {
            // given that I am having to write my own AJAX handling, I think it's safe to assume that I should
            // do that in the context of a try catch statement to catch the things that are going to go wrong...
            try {
                params = GRUNT.extend({
                    method: "GET",
                    data: null,
                    url: null,
                    async: true,
                    success: null,
                    handleResponse: null,
                    error: null,
                    contentType: "application/x-www-form-urlencoded"
                }, module.ajaxSettings, params);

                // determine if this is a remote request (as per the jQuery ajax calls)
                var parts = REGEX_URL.exec(params.url),
                    remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);

                // if we have data, then update the method to POST
                if (params.data) {
                    params.method = "POST";
                } // if

                // if the url is empty, then log an error
                if (! params.url) {
                    GRUNT.Log.warn("ajax request issued with no url - that ain't going to work...");
                    return;
                } // if

                // if the we have an xhr creator registered, then let it decide whether it wants to create the client
                var xhr = null;
                if (params.xhr) {
                    xhr = params.xhr(params);
                } // if

                // if the optional creator, didn't create the client, then create the default client
                if (! xhr) {
                    xhr = new XMLHttpRequest();
                } // if

                // GRUNT.Log.info("opening request: " + JSON.stringify(params));

                // open the request
                // TODO: support basic authentication
                xhr.open(params.method, params.url, params.async);

                // if we are sending data, then set the correct content type
                if (params.data) {
                    xhr.setRequestHeader("Content-Type", params.contentType);
                } // if

                // if this is not a remote request, the set the requested with header
                if (! remote) {
                    xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
                } // if

                xhr.onreadystatechange = function() {
                    if (this.readyState === 4) {
                        var responseData = null,
                            success = requestOK(this, params);

                        try {
                            // get and check the status
                            if (success) {
                                // process the response
                                if (params.handleResponse) {
                                    params.handleResponse(this);
                                }
                                else {
                                    responseData = processResponseData(this, params);
                                }
                            }
                            else if (params.error) {
                                params.error(this);
                            } // if..else
                        }
                        catch (e) {
                            GRUNT.Log.exception(e, "PROCESSING AJAX RESPONSE");
                        } // try..catch

                        // if the success callback is defined, then call it
                        // GRUNT.Log.info("received response, calling success handler: " + params.success);
                        if (success && responseData && params.success) {
                            params.success.call(this, responseData);
                        } // if
                    } // if
                }; // onreadystatechange

                // send the request
                // GRUNT.Log.info("sending request with data: " + module.param(params.data));
                xhr.send(params.method == "POST" ? module.param(params.data) : null);
            }
            catch (e) {
                GRUNT.Log.exception(e);
            } // try..catch
        }, // ajax

        param: function(data) {
            // iterate through the members of the data and convert to a paramstring
            var params = [];
            var addKeyVal = function (key, value) {
                // If value is a function, invoke it and return its value
                value = GRUNT.isFunction(value) ? value() : value;
                params[ params.length ] = encodeURIComponent(key) + "=" + encodeURIComponent(value);
            };

            // If an array was passed in, assume that it is an array of form elements.
            if (GRUNT.isArray(data)) {
                for (var ii = 0; ii < data.length; ii++) {
                    addKeyVal(data[ii].name, data[ii].value);
                } // for
            }
            else {
                for (var keyname in data) {
                    addKeyVal(keyname, data[keyname]);
                } // for
            } // if..else

            // Return the resulting serialization
            return params.join("&").replace(/%20/g, "+");
        }
    }); // self

    return module;
})();

<|endoftext|>


<commit_before>var XHR = Posterior.xhr = function(cfg) {
    return XHR.main(cfg);
},
htmlClass = D.documentElement.classList;

XHR.ctor = XMLHttpRequest;
XHR.main = function(cfg) {
    var xhr,
        promise;

    if (cfg.cache) {
        xhr = store(XHR.key(cfg));
        if (xhr) {
            promise = Promise.resolve(xhr);
        }
    }
    if (!promise) {
        xhr = new XHR.ctor();
        XHR.config(xhr, cfg);
        promise = XHR.promise(xhr, cfg);
        if (cfg.cache) {
            promise.then(function() {
                XHR.cache(xhr);
            });
        }
    }
    if (cfg.then) {
        promise = promise.then(cfg.then);
    }
    if (cfg.catch) {
        promise = promise.catch(cfg.catch);
    }
    promise.xhr = xhr;
    return promise;
};

XHR.config = function(xhr, cfg) {
    xhr.open(XHR.method(cfg),
             XHR.url(cfg),
             'async' in cfg ? cfg.async : true,
             cfg.username, cfg.password);
    xhr.cfg = cfg;
    cfg.xhr = xhr;
    for (var prop in cfg) {
        var value = cfg[prop];
        if (prop in xhr) {
            xhr[prop] = value;
        }
        if (typeof value === "function") {
            xhr.addEventListener(prop, value.bind(xhr));
        }
    }
    if (cfg.mimeType) {
        xhr.overrideMimeType(cfg.mimeType);
    }
    if (cfg.requestedWith !== false) {
        xhr.setRequestHeader('X-Requested-With', cfg.requestedWith || 'XMLHttpRequest');
    }
    if (cfg.headers) {
        for (var header in cfg.headers) {
            xhr.setRequestHeader(header, cfg.headers[header]);
        }
    }
    if (cfg.json !== false) {
        try {
            xhr.responseType = 'json';// unsupported by phantomjs (webkit)
        } catch (e) {}
        // don't append to existing headers
        if (!cfg.headers || !cfg.headers['Accept']) {
            xhr.setRequestHeader('Accept', 'application/json');
        }
        if (!cfg.headers || !cfg.headers['Content-Type']) {
            xhr.setRequestHeader('Content-Type', 'application/json');
        }
    }
};

XHR.method = function(cfg) {
    return XHR.methodMap[cfg.method] || cfg.method || 'GET';
};
XHR.methodMap = {
    PATCH: 'POST'
};

XHR.url = function(cfg) {
    var url = cfg.url,
        was;
    while (was !== url) {
        was = url;
        url = url.replace(/([\/\?\&]|^)[^\/\.\?\&]+[\/\?\&]?\.\.([\/\?\&]?)/, '$1');
    }
    return url;
};

XHR.promise = function(xhr, cfg) {
    return new Promise(function(resolve, reject) {
        var fail = function(e) {
            if (cfg.retry) {
                XHR.retry(cfg, cfg.retry, events, fail);
            } else {
                reject(xhr.error = e);
            }
        },
        events = {
            error: fail,
            timeout: fail,
            loadstart: XHR.start,
            loadend: XHR.end,
            load: XHR.load(cfg, resolve, fail)
        };
        XHR.run(xhr, cfg, events, fail);
    });
};

XHR.retry = function(cfg, retry, events, fail) {
    if (typeof retry !== 'object') {
        retry = cfg.retry = {};
    }
    retry.wait = 'wait' in retry ? retry.wait : 1000;
    retry.limit = 'limit' in retry ? retry.limit : 3;
    retry.count = 'count' in retry ? retry.count : 0;
    if (retry.limit > retry.count++) {
        setTimeout(function retryAfterWait() {
            var xhr = new XHR.ctor();
            XHR.config(xhr, cfg);
            XHR.run(xhr, cfg, events, fail);
        }, retry.wait *= 2);
    }
};

XHR.run = function(xhr, cfg, events, fail) {
    for (var event in events) {
        xhr.addEventListener(event, events[event]);
    }
    try {
        xhr.send(XHR.data(cfg));
    } catch (e) {
        fail(e);
    }
};

XHR.load = function(cfg, resolve, reject) {
    return function() {
        try {
            // cfg status code handling (e.g. {0: 200} for file://)
            var xhr = cfg.xhr,
                status = cfg[xhr.status] || xhr.status;
            if (typeof status === "function") {
                status = status(xhr) || xhr.status;
            }
            if (status >= 200 && status < 300) {
                if (cfg.json !== false && typeof xhr.response !== "object") {
                    XHR.forceJSONResponse(xhr);
                }
                var data = xhr.responseType ? xhr.response :
                           cfg.json !== false ? xhr.responseObject :
                           xhr.responseText;
                if (cfg.responseData && XHR.isData(data)) {
                    var ret = cfg.responseData.call(xhr, data);
                    data = ret === undefined ? data : ret;
                }
                resolve(XHR.isData(data) ? data : xhr);
            } else {
                reject(status);
            }
        } catch (e) {
            reject(e);
        }
    };
};

XHR.forceJSONResponse = function(xhr) {
    try {
        delete xhr.response;
        Object.defineProperty(xhr, 'response', { value: xhr.responseObject, enumerable: true, configurable: true });
    } catch (e) {}
};

XHR.isData = function(data) {
    // reject as impossible output by JSON.stringify, invalid input to JSON.parse
    return !(data === undefined || data === '');
};
XHR.data = function(cfg) {
    var data = cfg.data;
    if (cfg.requestData && XHR.isData(data)) {
        var ret = cfg.requestData(data);
        data = ret === undefined ? data : ret;// return new object or keep old
    }
    if (data !== undefined && typeof data !== "string") {
        data = JSON.stringify(data);
    }
    return data || '';
};

XHR.properties = {
    responseObject: {
        get: function() {
            var response = null;
            try {
                if (this.responseText) {
                    response = JSON.parse(this.responseText);
                }
            } catch (e) {}
            if (response === null && typeof this.response === 'object') {
                response = this.response;
            }
            Object.defineProperty(this, 'responseObject', {value:response});
            return response;
        },
        enumerable: true,
        configurable: true
    },
    responseHeaders: {
        get: function() {
            var headers = {},
                all = this.getAllResponseHeaders().trim().split('\n');
            for (var i=0,m=all.length, header; i<m; i++) {
                if ((header = all[i])) {
                    var parts = header.match(/^([\w\-]+):(.*)/);
                    if (parts.length === 3) {
                        headers[parts[1]] = parts[2].trim();
                    }
                }
            }
            Object.defineProperty(this, 'responseHeaders', {value:headers});
            return headers;
        },
        enumerable: true,
        configurable: true
    }
};
Object.defineProperties(XMLHttpRequest.prototype, XHR.properties);

XHR.active = 0;
XHR.activeClass = 'xhr-active';
XHR.start = function() {
    XHR.active++;
    htmlClass.add(XHR.activeClass);
};
XHR.end = function() {
    if (!--XHR.active) {
        htmlClass.remove(XHR.activeClass);
    }
};

XHR.key = function(cfg) {
    return XHR.url(cfg)+'|'+XHR.method(cfg)+'|'+XHR.data(cfg);
};
XHR.cache = function(xhr) {
    var cfg = xhr.cfg;
    store(XHR.key(cfg), XHR.safeCopy(xhr), cfg.cache);
    return xhr;
};
XHR.safeCopy = function(object, copied) {
    var copy = {};
    copied = copied || [];
    if (copied.indexOf(object) < 0) {
        copied.push(object);
        for (var name in object) {
            try {
                var value = object[name],
                    type = typeof value;
                if (type === 'function') {
                    value = undefined;
                } else if (type === 'object') {
                    value = XHR.safeCopy(value, copied);
                }
                if (value !== undefined) {
                    copy[name] = value;
                }
            } catch (e) {}
        }
        return copy;
    }
};
<commit_msg>configured catch fn gets XHR as 2nd arg and cfg as context, since the status code alone has limited use for error handling<commit_after>var XHR = Posterior.xhr = function(cfg) {
    return XHR.main(cfg);
},
htmlClass = D.documentElement.classList;

XHR.ctor = XMLHttpRequest;
XHR.main = function(cfg) {
    var xhr,
        promise;

    if (cfg.cache) {
        xhr = store(XHR.key(cfg));
        if (xhr) {
            promise = Promise.resolve(xhr);
        }
    }
    if (!promise) {
        xhr = new XHR.ctor();
        XHR.config(xhr, cfg);
        promise = XHR.promise(xhr, cfg);
        if (cfg.cache) {
            promise.then(function() {
                XHR.cache(xhr);
            });
        }
    }
    if (cfg.then) {
        promise = promise.then(cfg.then);
    }
    if (cfg.catch) {
        // call catch with cfg as context and xhr as second arg
        promise = promise.catch(function caught(error) {
            return cfg.catch.call(cfg, error, xhr);
        });
    }
    promise.xhr = xhr;
    return promise;
};

XHR.config = function(xhr, cfg) {
    xhr.open(XHR.method(cfg),
             XHR.url(cfg),
             'async' in cfg ? cfg.async : true,
             cfg.username, cfg.password);
    xhr.cfg = cfg;
    cfg.xhr = xhr;
    for (var prop in cfg) {
        var value = cfg[prop];
        if (prop in xhr) {
            xhr[prop] = value;
        }
        if (typeof value === "function") {
            xhr.addEventListener(prop, value.bind(xhr));
        }
    }
    if (cfg.mimeType) {
        xhr.overrideMimeType(cfg.mimeType);
    }
    if (cfg.requestedWith !== false) {
        xhr.setRequestHeader('X-Requested-With', cfg.requestedWith || 'XMLHttpRequest');
    }
    if (cfg.headers) {
        for (var header in cfg.headers) {
            xhr.setRequestHeader(header, cfg.headers[header]);
        }
    }
    if (cfg.json !== false) {
        try {
            xhr.responseType = 'json';// unsupported by phantomjs (webkit)
        } catch (e) {}
        // don't append to existing headers
        if (!cfg.headers || !cfg.headers['Accept']) {
            xhr.setRequestHeader('Accept', 'application/json');
        }
        if (!cfg.headers || !cfg.headers['Content-Type']) {
            xhr.setRequestHeader('Content-Type', 'application/json');
        }
    }
};

XHR.method = function(cfg) {
    return XHR.methodMap[cfg.method] || cfg.method || 'GET';
};
XHR.methodMap = {
    PATCH: 'POST'
};

XHR.url = function(cfg) {
    var url = cfg.url,
        was;
    while (was !== url) {
        was = url;
        url = url.replace(/([\/\?\&]|^)[^\/\.\?\&]+[\/\?\&]?\.\.([\/\?\&]?)/, '$1');
    }
    return url;
};

XHR.promise = function(xhr, cfg) {
    return new Promise(function(resolve, reject) {
        var fail = function(e) {
            if (cfg.retry) {
                XHR.retry(cfg, cfg.retry, events, fail);
            } else {
                reject(xhr.error = e);
            }
        },
        events = {
            error: fail,
            timeout: fail,
            loadstart: XHR.start,
            loadend: XHR.end,
            load: XHR.load(cfg, resolve, fail)
        };
        XHR.run(xhr, cfg, events, fail);
    });
};

XHR.retry = function(cfg, retry, events, fail) {
    if (typeof retry !== 'object') {
        retry = cfg.retry = {};
    }
    retry.wait = 'wait' in retry ? retry.wait : 1000;
    retry.limit = 'limit' in retry ? retry.limit : 3;
    retry.count = 'count' in retry ? retry.count : 0;
    if (retry.limit > retry.count++) {
        setTimeout(function retryAfterWait() {
            var xhr = new XHR.ctor();
            XHR.config(xhr, cfg);
            XHR.run(xhr, cfg, events, fail);
        }, retry.wait *= 2);
    }
};

XHR.run = function(xhr, cfg, events, fail) {
    for (var event in events) {
        xhr.addEventListener(event, events[event]);
    }
    try {
        xhr.send(XHR.data(cfg));
    } catch (e) {
        fail(e);
    }
};

XHR.load = function(cfg, resolve, reject) {
    return function() {
        try {
            // cfg status code handling (e.g. {0: 200} for file://)
            var xhr = cfg.xhr,
                status = cfg[xhr.status] || xhr.status;
            if (typeof status === "function") {
                status = status(xhr) || xhr.status;
            }
            if (status >= 200 && status < 300) {
                if (cfg.json !== false && typeof xhr.response !== "object") {
                    XHR.forceJSONResponse(xhr);
                }
                var data = xhr.responseType ? xhr.response :
                           cfg.json !== false ? xhr.responseObject :
                           xhr.responseText;
                if (cfg.responseData && XHR.isData(data)) {
                    var ret = cfg.responseData.call(xhr, data);
                    data = ret === undefined ? data : ret;
                }
                resolve(XHR.isData(data) ? data : xhr);
            } else {
                reject(status);
            }
        } catch (e) {
            reject(e);
        }
    };
};

XHR.forceJSONResponse = function(xhr) {
    try {
        delete xhr.response;
        Object.defineProperty(xhr, 'response', { value: xhr.responseObject, enumerable: true, configurable: true });
    } catch (e) {}
};

XHR.isData = function(data) {
    // reject as impossible output by JSON.stringify, invalid input to JSON.parse
    return !(data === undefined || data === '');
};
XHR.data = function(cfg) {
    var data = cfg.data;
    if (cfg.requestData && XHR.isData(data)) {
        var ret = cfg.requestData(data);
        data = ret === undefined ? data : ret;// return new object or keep old
    }
    if (data !== undefined && typeof data !== "string") {
        data = JSON.stringify(data);
    }
    return data || '';
};

XHR.properties = {
    responseObject: {
        get: function() {
            var response = null;
            try {
                if (this.responseText) {
                    response = JSON.parse(this.responseText);
                }
            } catch (e) {}
            if (response === null && typeof this.response === 'object') {
                response = this.response;
            }
            Object.defineProperty(this, 'responseObject', {value:response});
            return response;
        },
        enumerable: true,
        configurable: true
    },
    responseHeaders: {
        get: function() {
            var headers = {},
                all = this.getAllResponseHeaders().trim().split('\n');
            for (var i=0,m=all.length, header; i<m; i++) {
                if ((header = all[i])) {
                    var parts = header.match(/^([\w\-]+):(.*)/);
                    if (parts.length === 3) {
                        headers[parts[1]] = parts[2].trim();
                    }
                }
            }
            Object.defineProperty(this, 'responseHeaders', {value:headers});
            return headers;
        },
        enumerable: true,
        configurable: true
    }
};
Object.defineProperties(XMLHttpRequest.prototype, XHR.properties);

XHR.active = 0;
XHR.activeClass = 'xhr-active';
XHR.start = function() {
    XHR.active++;
    htmlClass.add(XHR.activeClass);
};
XHR.end = function() {
    if (!--XHR.active) {
        htmlClass.remove(XHR.activeClass);
    }
};

XHR.key = function(cfg) {
    return XHR.url(cfg)+'|'+XHR.method(cfg)+'|'+XHR.data(cfg);
};
XHR.cache = function(xhr) {
    var cfg = xhr.cfg;
    store(XHR.key(cfg), XHR.safeCopy(xhr), cfg.cache);
    return xhr;
};
XHR.safeCopy = function(object, copied) {
    var copy = {};
    copied = copied || [];
    if (copied.indexOf(object) < 0) {
        copied.push(object);
        for (var name in object) {
            try {
                var value = object[name],
                    type = typeof value;
                if (type === 'function') {
                    value = undefined;
                } else if (type === 'object') {
                    value = XHR.safeCopy(value, copied);
                }
                if (value !== undefined) {
                    copy[name] = value;
                }
            } catch (e) {}
        }
        return copy;
    }
};
<|endoftext|>


<commit_before>// xio.js
// http://github.com/stimpy77/xio.js
// version 0.1.0
// send feedback to jon@jondavis.net
(function ($) {

    (window || exports).Xio = function () {
        if (!$) throw "jQuery must be referenced before xio.js is loaded.";

        function formatKey(key) {
            if ($.type(key) == "array") {
                key = $.makeArray(key);
                for (var i in key) {
                    key[i] = key[i].toString();
                }
                key = key.join('-');
            }
            return key;
        }

        // localStorage
        function localSetDefinition(key, value) {
            key = formatKey(key);
            if (typeof (value) == "object") {
                value = stringify(value);
            }
            localStorage.setItem(key, value);
        }
        function localGetDefinition(key) {
            key = formatKey(key);
            var result = localStorage.getItem(key);
            if (result && ((result.indexOf("{") == 0 && result.indexOf("}") == result.length - 1) ||
                          (result.indexOf("[") == 0 && result.indexOf("]") == result.length - 1))) {
                try {
                    result = parseJSON(result);
                }
                catch (error) { }
            }
            return result !== undefined && result !== null
                ? synchronousPromiseResult({ success: function (callback) { callback.call(this, result); } })
                : synchronousPromiseResult({ error: function (callback) { callback.call(this, "Not found"); } });
        }

        function localDeleteDefinition(key) {
            key = formatKey(key);
            localStorage.removeItem(key);
        }

        // sessionStorage
        function sessionSetDefinition(key, value) {
            key = formatKey(key);
            if (typeof (value) == "object") {
                value = stringify(value);
            }
            sessionStorage.setItem(key, value);
        }

        function sessionGetDefinition(key) {
            key = formatKey(key);
            var result = sessionStorage.getItem(key);
            if (result && ((result.indexOf("{") == 0 && result.indexOf("}") == result.length - 1) ||
                          (result.indexOf("[") == 0 && result.indexOf("]") == result.length - 1))) {
                try {
                    result = parseJSON(result);
                }
                catch (error) { }
            }
            return result !== undefined && result !== null
                ? synchronousPromiseResult({ success: function (callback) { callback.call(this, result); } })
                : synchronousPromiseResult({ error: function (callback) { callback.call(this, "Not found"); } });
        }

        function sessionDeleteDefinition(key) {
            key = formatKey(key);
            sessionStorage.removeItem(key);
        }

        // cookie
        function cookieSetDefinition(key, value, expires, path, domain) {
            key = formatKey(key);
            if (typeof (value) == "object") {
                value = stringify(value);
            }
            if (window.location.href.indexOf("file:///") == 0) {
                throw "Cannot set a cookie on a local file system document. Use a web server.";
            }
            var cookie = encodeURIComponent(key) + "=" + encodeURIComponent(value);
            if (expires) {
                var expiry = expires;
                switch (expires.constructor) {
                    case Number:
                        expiry = expires === Infinity
                            ? ";expires=Fri, 31 Dec 9999 23:59:59 GMT"
                            : ";max-age=" + expiry
                    case Date:
                        expiry = ";expires=" + new Date(expires).toUTCString();
                        break;
                    case String:
                        expiry = ";expires=" + expires;
                        break;
                }
                cookie += expiry;
            }
            if (domain) {
                cookie += ";domain=" + encodeURIComponent(domain);
            }
            if (path) {
                cookie += ";path=" + path;
            }
            document.cookie = cookie;

            // parameter builder convenience functions
            return {
                expires: function (vexpires) {
                    cookieDeleteDefinition(key, path, domain);
                    return cookieSetDefinition(key, value, vexpires, path, domain);
                },
                path: function (vpath) {
                    cookieDeleteDefinition(key, path, domain);
                    return cookieSetDefinition(key, value, expires, vpath, domain);
                },
                domain: function (vdomain) {
                    cookieDeleteDefinition(key, path, domain);
                    return cookieSetDefinition(key, value, expires, path, vdomain);
                }
            };
        }

        function cookieDeleteDefinition(key, path, domain) {
            key = formatKey(key);
            cookieSetDefinition(key, "-", new Date("Jan 1, 1970"), path, domain);
        }

        function cookieGetDefinition(key) {
            key = formatKey(key);
            // from mozilla (!!)
            var result = decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
            if (result && ((result.indexOf("{") == 0 && result.indexOf("}") == result.length - 1) ||
                          (result.indexOf("[") == 0 && result.indexOf("]") == result.length - 1))) {
                try {
                    result = parseJSON(result);
                }
                catch (error) { }
            }
            return result
                ? synchronousPromiseResult({ success: function (callback) { callback.call(this, result); } })
                : synchronousPromiseResult({ error: function (callback) { callback.call(this, "Not found"); } });
        }

        function synchronousPromiseResult(promise) { // bit of a hack to make synchronous operations appear asynchronous
            promise = promise || {};
            var autocall = function (callback) { callback.call(this); return ret; }; // execute and return my psuedo-promise; also, this?
            var nocall = function () { return ret; }; // do nothing and return my pseudo-promise
            var wrapcall = function (callee) { // wrap the promise's handler to return my psuedo-promise
                return callee
                    ? function (usercallback) {
                        callee.call(this, usercallback); // this?
                        return ret;
                    }
                    : null;
            };
            promise.success = promise.success || nocall;
            var ret;
            ret = function () {
                var result;
                promise.success(function (value) {
                    result = value;
                    return ret;
                });
                if (result === undefined && promise.readyState === 4) {
                    switch (promise.getResponseHeader("Content-Type")) {
                        case "application/x-javascript":
                        case "application/json":
                            result = JSON.parse(promise.responseText);
                            break;
                        default:
                            result = promise.responseText;
                    }
                }
                return result;
            };
            ret.success = wrapcall(promise.success) || nocall;
            ret.error = wrapcall(promise.error) || nocall;
            ret.fail = wrapcall(promise.fail) || wrapcall(promise.error) || nocall;
            ret.done = wrapcall(promise.done) || autocall;
            ret.always = wrapcall(promise.always) || autocall;
            ret.complete = ret.always;
            return ret;
        }

        // put
        var putDefinitions = {
            local: localSetDefinition,
            session: sessionSetDefinition,
            cookie: cookieSetDefinition
        };

        // post
        var postDefinitions = {
            local: localSetDefinition,
            session: sessionSetDefinition,
            cookie: cookieSetDefinition
        };

        // set
        var setDefinitions = {
            local: localSetDefinition,
            session: sessionSetDefinition,
            cookie: cookieSetDefinition
        };

        // get
        var getDefinitions = {
            local: localGetDefinition,
            session: sessionGetDefinition,
            cookie: cookieGetDefinition
        };

        // delete
        var deleteDefinitions = {
            local: localDeleteDefinition,
            session: sessionDeleteDefinition,
            cookie: cookieDeleteDefinition
        };

        var verbHandles = {
            "put": putDefinitions,
            "set": setDefinitions,
            "get": getDefinitions,
            "delete": deleteDefinitions,
            "post": postDefinitions
        };

        // routing and actions
        var verbs = {
            "get": "GET",
            "post": "POST",
            "put": "PUT",
            "delete": "DELETE",
            "patch": "PATCH"
            // etc etc
        };
        var define = function (name, options) {
            var custom = {}, customqty;
            for (var v in verbs) {
                if (options[v] !== undefined && typeof (options[v]) == "function") {
                    custom[v] = options[v];
                    customqty++;
                }
            }
            if (!options.methods) {
                options.methods = customqty == 0 ? ["GET"] : [];
            }
            var retset = { options: options };
            // add autogenerated implementations
            for (var index in options.methods) {
                var actionVerb = options.methods[index];
                var verbmember = actionVerb.toLowerCase();
                var handlers = verbs[verbmember] ? verbHandles[verbmember] : null;
                if (handlers) {
                    if (handlers[name]) throw "A " + actionVerb + " route named \"" + name + "\" already exists.";
                    retset[verbmember] = handlers[name] = createRoutedHandler(actionVerb, options);
                }
            }
            // add custom implementations
            for (var v in custom) {
                if (custom.hasOwnProperty(v)) {
                    var actionVerb = verbs[v];
                    var verbmember = v;
                    var handlers = verbs[verbmember] ? verbHandles[verbmember] : null;
                    if (handlers) {
                        if (handlers[name]) throw "A " + actionVerb + " route named \"" + name + "\" already exists.";
                        retset[verbmember] = handlers[name] = createCustomHandler(actionVerb, custom[v], options);
                    }
                }
            }

            return retset;
        };

        function redefine(definition_name, /* optional */ verb, implementation, options) {
            if (typeof (verb) !== "string") {
                options = implementation;
                implementation = verb;
                verb = undefined;

                for (var v in verbs) {
                    if (verbHandles[v] && verbHandles[v][definition_name]) {
                        delete verbHandles[v][definition_name];
                    }
                }
                return define(definition_name, implementation || options);
            }

            else {
                verb = verb.toLowerCase();
                if (!verbs[verb] || !verbHandles[verb]) throw "Verb not supported: " + verb;
                var handleset = {};
                for (var v in verbs) {
                    if (verbHandles[v] && verbHandles[v][definition_name]) {
                        handleset[v] = verbHandles[v][definition_name];
                    }
                }
                if (typeof (implementation) == "function") {
                    var options = arguments.length > 3 ? arguments[3] : null;
                    handleset[verb] = verbHandles[verb][definition_name] = createCustomHandler(verb, implementation, options);
                    return handleset;
                }
                else {
                    throw "implementation argument must be a function if a verb is specified"
                }
            }
        }

        function isPromise(o) { // a bit of a hack? is this what constitutes a promise?
            if (typeof (o) !== "object") return false;
            if (!o.success || typeof (o.success) !== "function") return false;
            if (!o.complete || typeof (o.complete) !== "function") return false;
            return true;
        }

        function formatString(str) {
            if (/\{\d+\}/.test(str)) {
                for (var i = 1; i < arguments.length; i++) {
                    str = str.replace(new RegExp("\\{" + (i - 1) + "\\}", 'g'), arguments[i].toString() || "");
                }
            }
            return str;
        }

        function parseJSON(obj) {
            if (!JSON || !JSON.stringify) {
                throw "json2.js is required; please reference it.";
            }
            return JSON.parse(obj);
        }

        function stringify(obj) {
            if (!JSON || !JSON.stringify) {
                throw "json2.js is required; please reference it.";
            }
            return JSON.stringify(obj);
        }

        function createCustomHandler(verb, fn, options) {
            return function (key, data) {
                var catcherr;
                try {
                    var ret = fn.apply(this, arguments); // this?
                } catch (error) {
                    catcherr = error;
                    return synchronousPromiseResult({ error: function (callback) { callback.call(this, error); } }); // this?
                }

                if (isPromise(ret)) return ret;
                return synchronousPromiseResult({ success: function (callback) { callback.call(this, ret); } }); // this?

            };
        }

        function createRoutedHandler(verb, options) {

            return function (key, data) {

                options = options || {};
                var url = options.url;
                var args = [url];
                if (key === null || typeof (key) == "string" || typeof (key) == "number") args.push(key);
                else { // assume array of composite key items for formatter
                    for (var i in key) args.push(key[i]);
                }

                url = formatString.apply(null, args);
                var method = verb;

                // jquery implementation (todo: drop jquery dependency)
                var jqoptions = {};
                for (var p in options) {
                    if (options.hasOwnProperty(p) && p !== 'url' && p !== 'methods') {
                        jqoptions[p] = options[p];
                    }
                }
                jqoptions.type = method;
                data = data || jqoptions.data;
                //if (typeof(data) === "string" && data.indexOf("=") == -1) data = "value=" + data;
                if (typeof (data) == "object") data = stringify(data);
                jqoptions.data = data;
                if (options.async === false) {
                    // return immediately
                    var response = $.ajax(url, jqoptions);
                    return synchronousPromiseResult(response);
                }
                return $.ajax(url, jqoptions);
            };
        }
        return {

            // action implementations
            "get": getDefinitions,
            "post": postDefinitions,
            "put": putDefinitions,
            "set": setDefinitions,
            "delete": deleteDefinitions,

            "define": define,
            "redefine": redefine,

            // util
            "formatString": formatString,

            // reference
            "verbs": verbs
        };
    };

})(jQuery);
<commit_msg>Update xio.js<commit_after>// xio.js
// http://github.com/stimpy77/xio.js
// version 0.1.0
// send feedback to jon@jondavis.net
(function ($) {

    (window || exports).Xio = function () {
        if (!$) throw "jQuery must be referenced before xio.js is loaded.";

        function formatKey(key) {
            if ($.type(key) == "array") {
                key = $.makeArray(key);
                for (var i in key) {
                    key[i] = key[i].toString();
                }
                key = key.join('-');
            }
            return key;
        }

        // localStorage
        function localSetDefinition(key, value) {
            key = formatKey(key);
            if (typeof (value) == "object") {
                value = stringify(value);
            }
            localStorage.setItem(key, value);
        }
        function localGetDefinition(key) {
            key = formatKey(key);
            var result = localStorage.getItem(key);
            if (result && ((result.indexOf("{") == 0 && result.indexOf("}") == result.length - 1) ||
                          (result.indexOf("[") == 0 && result.indexOf("]") == result.length - 1))) {
                try {
                    result = parseJSON(result);
                }
                catch (error) { }
            }
            return result !== undefined && result !== null
                ? synchronousPromiseResult({ success: function (callback) { callback.call(this, result); } })
                : synchronousPromiseResult({ error: function (callback) { callback.call(this, "Not found"); } });
        }

        function localDeleteDefinition(key) {
            key = formatKey(key);
            localStorage.removeItem(key);
        }

        // sessionStorage
        function sessionSetDefinition(key, value) {
            key = formatKey(key);
            if (typeof (value) == "object") {
                value = stringify(value);
            }
            sessionStorage.setItem(key, value);
        }

        function sessionGetDefinition(key) {
            key = formatKey(key);
            var result = sessionStorage.getItem(key);
            if (result && ((result.indexOf("{") == 0 && result.indexOf("}") == result.length - 1) ||
                          (result.indexOf("[") == 0 && result.indexOf("]") == result.length - 1))) {
                try {
                    result = parseJSON(result);
                }
                catch (error) { }
            }
            return result !== undefined && result !== null
                ? synchronousPromiseResult({ success: function (callback) { callback.call(this, result); } })
                : synchronousPromiseResult({ error: function (callback) { callback.call(this, "Not found"); } });
        }

        function sessionDeleteDefinition(key) {
            key = formatKey(key);
            sessionStorage.removeItem(key);
        }

        // cookie
        function cookieSetDefinition(key, value, expires, path, domain) {
            key = formatKey(key);
            if (typeof (value) == "object") {
                value = stringify(value);
            }
            if (window.location.href.indexOf("file:///") == 0) {
                throw "Cannot set a cookie on a local file system document. Use a web server.";
            }
            var cookie = encodeURIComponent(key) + "=" + encodeURIComponent(value);
            if (expires) {
                var expiry = expires;
                switch (expires.constructor) {
                    case Number:
                        expiry = expires === Infinity
                            ? ";expires=Fri, 31 Dec 9999 23:59:59 GMT"
                            : ";max-age=" + expiry
                    case Date:
                        expiry = ";expires=" + new Date(expires).toUTCString();
                        break;
                    case String:
                        expiry = ";expires=" + expires;
                        break;
                }
                cookie += expiry;
            }
            if (domain) {
                cookie += ";domain=" + encodeURIComponent(domain);
            }
            if (path) {
                cookie += ";path=" + path;
            }
            document.cookie = cookie;

            // parameter builder convenience functions
            return {
                expires: function (vexpires) {
                    cookieDeleteDefinition(key, path, domain);
                    return cookieSetDefinition(key, value, vexpires, path, domain);
                },
                path: function (vpath) {
                    cookieDeleteDefinition(key, path, domain);
                    return cookieSetDefinition(key, value, expires, vpath, domain);
                },
                domain: function (vdomain) {
                    cookieDeleteDefinition(key, path, domain);
                    return cookieSetDefinition(key, value, expires, path, vdomain);
                }
            };
        }

        function cookieDeleteDefinition(key, path, domain) {
            key = formatKey(key);
            cookieSetDefinition(key, "-", new Date("Jan 1, 1970"), path, domain);
        }

        function cookieGetDefinition(key) {
            key = formatKey(key);
            // from mozilla (!!)
            var result = decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
            if (result && ((result.indexOf("{") == 0 && result.indexOf("}") == result.length - 1) ||
                          (result.indexOf("[") == 0 && result.indexOf("]") == result.length - 1))) {
                try {
                    result = parseJSON(result);
                }
                catch (error) { }
            }
            return result
                ? synchronousPromiseResult({ success: function (callback) { callback.call(this, result); } })
                : synchronousPromiseResult({ error: function (callback) { callback.call(this, "Not found"); } });
        }

        function synchronousPromiseResult(promise) { // bit of a hack to make synchronous operations appear asynchronous
            promise = promise || {};
            var ret;
            var autocall = function (callback) { callback.call(this); return ret; }; // execute and return my psuedo-promise; also, this?
            var nocall = function () { return ret; }; // do nothing and return my pseudo-promise
            var wrapcall = function (callee) { // wrap the promise's handler to return my psuedo-promise
                return callee
                    ? function (usercallback) {
                        callee.call(this, usercallback); // this?
                        return ret;
                    }
                    : null;
            };
            promise.success = promise.success || nocall;
            ret = function () {
                var result;
                promise.success(function (value) {
                    result = value;
                    return ret;
                });
                if (result === undefined && promise.readyState === 4) {
                    switch (promise.getResponseHeader("Content-Type")) {
                        case "application/x-javascript":
                        case "application/json":
                            result = JSON.parse(promise.responseText);
                            break;
                        default:
                            result = promise.responseText;
                    }
                }
                return result;
            };
            ret.success = wrapcall(promise.success) || nocall;
            ret.error = wrapcall(promise.error) || nocall;
            ret.fail = wrapcall(promise.fail) || wrapcall(promise.error) || nocall;
            ret.done = wrapcall(promise.done) || autocall;
            ret.always = wrapcall(promise.always) || autocall;
            ret.complete = ret.always;
            return ret;
        }

        // put
        var putDefinitions = {
            local: localSetDefinition,
            session: sessionSetDefinition,
            cookie: cookieSetDefinition
        };

        // post
        var postDefinitions = {
            local: localSetDefinition,
            session: sessionSetDefinition,
            cookie: cookieSetDefinition
        };

        // set
        var setDefinitions = {
            local: localSetDefinition,
            session: sessionSetDefinition,
            cookie: cookieSetDefinition
        };

        // get
        var getDefinitions = {
            local: localGetDefinition,
            session: sessionGetDefinition,
            cookie: cookieGetDefinition
        };

        // delete
        var deleteDefinitions = {
            local: localDeleteDefinition,
            session: sessionDeleteDefinition,
            cookie: cookieDeleteDefinition
        };

        var verbHandles = {
            "put": putDefinitions,
            "set": setDefinitions,
            "get": getDefinitions,
            "delete": deleteDefinitions,
            "post": postDefinitions
        };

        // routing and actions
        var verbs = {
            "get": "GET",
            "post": "POST",
            "put": "PUT",
            "delete": "DELETE",
            "patch": "PATCH"
            // etc etc
        };
        var define = function (name, options) {
            var custom = {}, customqty;
            for (var v in verbs) {
                if (options[v] !== undefined && typeof (options[v]) == "function") {
                    custom[v] = options[v];
                    customqty++;
                }
            }
            if (!options.methods) {
                options.methods = customqty == 0 ? ["GET"] : [];
            }
            var retset = { options: options };
            // add autogenerated implementations
            for (var index in options.methods) {
                var actionVerb = options.methods[index];
                var verbmember = actionVerb.toLowerCase();
                var handlers = verbs[verbmember] ? verbHandles[verbmember] : null;
                if (handlers) {
                    if (handlers[name]) throw "A " + actionVerb + " route named \"" + name + "\" already exists.";
                    retset[verbmember] = handlers[name] = createRoutedHandler(actionVerb, options);
                }
            }
            // add custom implementations
            for (var v in custom) {
                if (custom.hasOwnProperty(v)) {
                    var actionVerb = verbs[v];
                    var verbmember = v;
                    var handlers = verbs[verbmember] ? verbHandles[verbmember] : null;
                    if (handlers) {
                        if (handlers[name]) throw "A " + actionVerb + " route named \"" + name + "\" already exists.";
                        retset[verbmember] = handlers[name] = createCustomHandler(actionVerb, custom[v], options);
                    }
                }
            }

            return retset;
        };

        function redefine(definition_name, /* optional */ verb, implementation, options) {
            if (typeof (verb) !== "string") {
                options = implementation;
                implementation = verb;
                verb = undefined;

                for (var v in verbs) {
                    if (verbHandles[v] && verbHandles[v][definition_name]) {
                        delete verbHandles[v][definition_name];
                    }
                }
                return define(definition_name, implementation || options);
            }

            else {
                verb = verb.toLowerCase();
                if (!verbs[verb] || !verbHandles[verb]) throw "Verb not supported: " + verb;
                var handleset = {};
                for (var v in verbs) {
                    if (verbHandles[v] && verbHandles[v][definition_name]) {
                        handleset[v] = verbHandles[v][definition_name];
                    }
                }
                if (typeof (implementation) == "function") {
                    var options = arguments.length > 3 ? arguments[3] : null;
                    handleset[verb] = verbHandles[verb][definition_name] = createCustomHandler(verb, implementation, options);
                    return handleset;
                }
                else {
                    throw "implementation argument must be a function if a verb is specified"
                }
            }
        }

        function isPromise(o) { // a bit of a hack? is this what constitutes a promise?
            if (typeof (o) !== "object") return false;
            if (!o.success || typeof (o.success) !== "function") return false;
            if (!o.complete || typeof (o.complete) !== "function") return false;
            return true;
        }

        function formatString(str) {
            if (/\{\d+\}/.test(str)) {
                for (var i = 1; i < arguments.length; i++) {
                    str = str.replace(new RegExp("\\{" + (i - 1) + "\\}", 'g'), arguments[i].toString() || "");
                }
            }
            return str;
        }

        function parseJSON(obj) {
            if (!JSON || !JSON.stringify) {
                throw "json2.js is required; please reference it.";
            }
            return JSON.parse(obj);
        }

        function stringify(obj) {
            if (!JSON || !JSON.stringify) {
                throw "json2.js is required; please reference it.";
            }
            return JSON.stringify(obj);
        }

        function createCustomHandler(verb, fn, options) {
            return function (key, data) {
                var catcherr;
                try {
                    var ret = fn.apply(this, arguments); // this?
                } catch (error) {
                    catcherr = error;
                    return synchronousPromiseResult({ error: function (callback) { callback.call(this, error); } }); // this?
                }

                if (isPromise(ret)) return ret;
                return synchronousPromiseResult({ success: function (callback) { callback.call(this, ret); } }); // this?

            };
        }

        function createRoutedHandler(verb, options) {

            return function (key, data) {

                options = options || {};
                var url = options.url;
                var args = [url];
                if (key === null || typeof (key) == "string" || typeof (key) == "number") args.push(key);
                else { // assume array of composite key items for formatter
                    for (var i in key) args.push(key[i]);
                }

                url = formatString.apply(null, args);
                var method = verb;

                // jquery implementation (todo: drop jquery dependency)
                var jqoptions = {};
                for (var p in options) {
                    if (options.hasOwnProperty(p) && p !== 'url' && p !== 'methods') {
                        jqoptions[p] = options[p];
                    }
                }
                jqoptions.type = method;
                data = data || jqoptions.data;
                //if (typeof(data) === "string" && data.indexOf("=") == -1) data = "value=" + data;
                if (typeof (data) == "object") data = stringify(data);
                jqoptions.data = data;
                if (options.async === false) {
                    // return immediately
                    var response = $.ajax(url, jqoptions);
                    return synchronousPromiseResult(response);
                }
                return $.ajax(url, jqoptions);
            };
        }
        return {

            // action implementations
            "get": getDefinitions,
            "post": postDefinitions,
            "put": putDefinitions,
            "set": setDefinitions,
            "delete": deleteDefinitions,

            "define": define,
            "redefine": redefine,

            // util
            "formatString": formatString,

            // reference
            "verbs": verbs
        };
    };

})(jQuery);
<|endoftext|>


<commit_before>//workspace explorer
'use strict'
D.WSE=function(){
  var pending=this.pending={};this.dom=I.wse;this.dom.hidden=0
  this.dom.onclick=function(x){var t=x.target.closest('.jstree-anchor');if(!t)return
                               D.send('Edit',{win:0,pos:0,text:$e.jstree('get_path',t,'.')})
                               ;/^wse_leaf_/.test(t.id)||$e.jstree('refresh_node',t)}
  var $e=this.$e=$(this.dom).jstree({plugins:[],core:{animation:true,check_callback:true,data:function(x,f){
    var i=x.id==='#'?0:+x.id.replace(/\D+/g,'');pending[i]=f.bind(this);D.send('TreeList',{nodeId:i})
  }}})
}
D.WSE.prototype={
  replyTreeList:function(x){
    var f=this.pending[x.nodeId];if(!f)return
    f((x.nodeIds||[]).map(function(c,i){
      var t=Math.floor(x.classes[i]);return{text:x.names[i],children:!!c,id:'wse_'+(c||('leaf_'+x.nodeId+'_'+i)),
                                            icon:c?'':2<=t&&t<=4?'style/img/wse_nc'+t+'.png':'img/tb_ED.png'}
    }))
    delete this.pending[x.nodeId]
  },
  refresh:function(){this.$e.jstree('refresh')}
}
<commit_msg>fixed wrong path to tb_ED.png<commit_after>//workspace explorer
'use strict'
D.WSE=function(){
  var pending=this.pending={};this.dom=I.wse;this.dom.hidden=0
  this.dom.onclick=function(x){var t=x.target.closest('.jstree-anchor');if(!t)return
                               D.send('Edit',{win:0,pos:0,text:$e.jstree('get_path',t,'.')})
                               ;/^wse_leaf_/.test(t.id)||$e.jstree('refresh_node',t)}
  var $e=this.$e=$(this.dom).jstree({plugins:[],core:{animation:true,check_callback:true,data:function(x,f){
    var i=x.id==='#'?0:+x.id.replace(/\D+/g,'');pending[i]=f.bind(this);D.send('TreeList',{nodeId:i})
  }}})
}
D.WSE.prototype={
  replyTreeList:function(x){
    var f=this.pending[x.nodeId];if(!f)return
    f((x.nodeIds||[]).map(function(c,i){
      var t=Math.floor(x.classes[i]);return{text:x.names[i],children:!!c,id:'wse_'+(c||('leaf_'+x.nodeId+'_'+i)),
                                            icon:c?'':2<=t&&t<=4?'style/img/wse_nc'+t+'.png':'style/img/tb_ED.png'}
    }))
    delete this.pending[x.nodeId]
  },
  refresh:function(){this.$e.jstree('refresh')}
}
<|endoftext|>


<commit_before>var gulp = require('gulp');
var config = require('../gulp.config')();

function startBrowsersync(config) {
    var bs = require("browser-sync").create();
    bs.init(config);
    bs.reload();
}

/* Start live server dev mode */
gulp.task('serve-dev', ['sass', 'tsc-app', 'watch-ts', 'watch-sass'], function () {
    startBrowsersync(config.browserSync.dev);
});

/* Start live server production mode */
gulp.task('serve-build', ['build'], function () {
    startBrowsersync(config.browserSync.prod);
});<commit_msg>refactor serve.js<commit_after>var gulp = require('gulp');
var config = require('../gulp.config')();
var bs = require("browser-sync");

function startBrowsersync(config) {
    bsIns = bs.create();
    bsIns.init(config);
    bsIns.reload();
}

/* Start live server dev mode */
gulp.task('serve-dev', ['sass', 'tsc-app', 'watch-ts', 'watch-sass'], function () {
    startBrowsersync(config.browserSync.dev);
});

/* Start live server production mode */
gulp.task('serve-build', ['build'], function () {
    startBrowsersync(config.browserSync.prod);
});<|endoftext|>


<commit_before>'use strict'

const assert = require('assert');

const F = require('..');

describe('Either', () => {
    describe('call constructor', () => {
        describe('with left', () => {
            it('should work', () => {
                assert.doesNotThrow(() => new F.Either(5));
            });
        });

        describe('with left and right', () => {
            it('should work', () => {
                assert.doesNotThrow(() => new F.Either(5, 7));
            });
        });

        describe('without any value', () => {
            it('should throw', () => {
                assert.throws(() => new F.Either());
            });
        });
    });

    describe('create through factory method', () => {
        describe('with left', () => {
            it('should work', () => {
                assert.doesNotThrow(() => F.either(5));
            });
        });

        describe('with left and right', () => {
            it('should work', () => {
                assert.doesNotThrow(() => F.either(5, 7));
            });
        });

        describe('without any value', () => {
            it('should throw', () => {
                assert.throws(() => F.either());
            });
        });
    });

    describe('get value', () => {
        it('should return left', () => {
            assert.equal(F.either(5).value, 5);
        });
        it('should return right', () => {
            assert.equal(F.either(5, 7).value, 7);
        });
    });

    describe('call then', () => {
        describe('with transform', () => {
            it('should transform left', () => {
                assert.equal(F.either(5).then(a => a + 3), 8);
            });
            it('should transform right', () => {
                assert.equal(F.either(5, 7).then(a => a + 3), 10);
            });
        });

        describe('without transform', () => {
            it('should throw', () => {
                assert.throws(F.either(5).then);
            });
        });
    });
});
<commit_msg>Better either tests<commit_after>'use strict'

const assert = require('assert');
const co     = require('co');

const F = require('..');

const Either = F.Either;
const either = F.either;

describe('Either', () => {
    describe('call constructor', () => {
        describe('should work', () => {
            it('with left', () => {
                assert.doesNotThrow(() => new F.Either(5));
            });

            it('with left and right', () => {
                assert.doesNotThrow(() => new F.Either(5, 7));
            });
        });

        describe('should throw', () => {
            it('without any value', () => {
                assert.throws(() => new F.Either());
            });
        });
    });

    describe('create through factory method', () => {
        describe('should work', () => {
            it('with left', () => {
                assert.doesNotThrow(() => either(5));
            });

            it('with left and right', () => {
                assert.doesNotThrow(() => either(5, 7));
            });
        });

        describe('should throw', () => {
            it('without any value', () => {
                assert.throws(() => either());
            });
        });
    });

    describe('get value', () => {
        it('should return left', () => {
            assert.equal(either(5).value, 5);
        });
        it('should return right', () => {
            assert.equal(either(5, 7).value, 7);
        });
    });

    describe('call then', () => {
        describe('with transform', () => {
            it('should transform left', () => {
                assert.equal(either(5).then(a => a + 3), 8);
            });
            it('should transform right', () => {
                assert.equal(either(5, 7).then(a => a + 3), 10);
            });
        });

        describe('without transform', () => {
            it('should throw', () => {
                assert.throws(either(5).then);
            });
        });
    });

    describe('function*', () => {
        describe('should yield same value', () => {
            it('left', () => {
                return co(function* () {
                    return either(5);
                }).then(
                    val => assert.strictEqual(val, 5),
                    err => assert.ifError(err)
                );
            });

            it('right', () => {
                return co(function* () {
                    return either(5, 7);
                }).then(
                    val => assert.strictEqual(val, 7),
                    err => assert.ifError(err)
                );
            });
        });
    });
});
<|endoftext|>


<commit_before>tinyMCE.addI18n('de.advanced_dlg',{"link_list":"Linkliste","link_is_external":"Diese Adresse scheint ein externer Link zu sein. M\u00f6chten Sie das dazu ben\u00f6tigte \"http://\" voranstellen?","link_is_email":"Diese Adresse scheint eine E-Mail-Adresse zu sein. M\u00f6chten Sie das dazu ben\u00f6tigte \"mailto:\" voranstellen?","link_titlefield":"Titel","link_target_blank":"Neues Fenster \u00f6ffnen","link_target_same":"Im selben Fenster \u00f6ffnen","link_target":"Fenster","link_url":"Adresse","link_title":"Link einf\u00fcgen/ver\u00e4ndern","image_align_right":"Rechts","image_align_left":"Links","image_align_textbottom":"Unten im Text","image_align_texttop":"Oben im Text","image_align_bottom":"Unten","image_align_middle":"Mittig","image_align_top":"Oben","image_align_baseline":"Zeile","image_align":"Ausrichtung","image_hspace":"Horizontaler Abstand","image_vspace":"Vertikaler Abstand","image_dimensions":"Abmessungen","image_alt":"Alternativtext","image_list":"Bilderliste","image_border":"Rahmen","image_src":"Adresse","image_title":"Bild einf\u00fcgen/ver\u00e4ndern","charmap_title":"Sonderzeichen","colorpicker_name":"Name:","colorpicker_color":"Farbe:","colorpicker_named_title":"Benannte Farben","colorpicker_named_tab":"Benannte Farben","colorpicker_palette_title":"Farbpalette","colorpicker_palette_tab":"Palette","colorpicker_picker_title":"Farbwahl","colorpicker_picker_tab":"Farbwahl","colorpicker_title":"Farbe","code_wordwrap":"Automatischer Zeilenumbruch","code_title":"HTML-Quellcode bearbeiten","anchor_name":"Name des Ankers","anchor_title":"Anker einf\u00fcgen/ver\u00e4ndern","about_loaded":"Geladene Plugins","about_version":"Version","about_author":"Urheber","about_plugin":"Plugin","about_plugins":"Plugins","about_license":"Lizenzbedingungen","about_help":"Hilfe","about_general":"\u00dcber","about_title":"\u00dcber TinyMCE","charmap_usage":"Navigation mit linken und rechten Pfeilen.","anchor_invalid":"Bitte geben Sie einen g\u00fcltigen Namen f\u00fcr den Anker ein!","accessibility_help":"Eingabehilfe","accessibility_usage_title":"Allgemeine Verwendung"});<commit_msg>update to 3.5b3<commit_after>tinyMCE.addI18n('de.advanced_dlg',{"link_list":"Linkliste","link_is_external":"Diese Adresse scheint ein externer Link zu sein. M\u00f6chten Sie das dazu ben\u00f6tigte \"http://\" voranstellen?","link_is_email":"Diese Adresse scheint eine E-Mail-Adresse zu sein. M\u00f6chten Sie das dazu ben\u00f6tigte \"mailto:\" voranstellen?","link_titlefield":"Titel","link_target_blank":"Neues Fenster \u00f6ffnen","link_target_same":"Im selben Fenster \u00f6ffnen","link_target":"Fenster","link_url":"Adresse","link_title":"Link einf\u00fcgen/ver\u00e4ndern","image_align_right":"Rechts","image_align_left":"Links","image_align_textbottom":"Unten im Text","image_align_texttop":"Oben im Text","image_align_bottom":"Unten","image_align_middle":"Mittig","image_align_top":"Oben","image_align_baseline":"Zeile","image_align":"Ausrichtung","image_hspace":"Horizontaler Abstand","image_vspace":"Vertikaler Abstand","image_dimensions":"Abmessungen","image_alt":"Alternativtext","image_list":"Bilderliste","image_border":"Rahmen","image_src":"Adresse","image_title":"Bild einf\u00fcgen/ver\u00e4ndern","charmap_title":"Sonderzeichen","colorpicker_name":"Name:","colorpicker_color":"Farbe:","colorpicker_named_title":"Benannte Farben","colorpicker_named_tab":"Benannte Farben","colorpicker_palette_title":"Farbpalette","colorpicker_palette_tab":"Palette","colorpicker_picker_title":"Farbwahl","colorpicker_picker_tab":"Farbwahl","colorpicker_title":"Farbe","code_wordwrap":"Automatischer Zeilenumbruch","code_title":"HTML-Quellcode bearbeiten","anchor_name":"Name des Ankers","anchor_title":"Anker einf\u00fcgen/ver\u00e4ndern","about_loaded":"Geladene Plugins","about_version":"Version","about_author":"Urheber","about_plugin":"Plugin","about_plugins":"Plugins","about_license":"Lizenzbedingungen","about_help":"Hilfe","about_general":"\u00dcber","about_title":"\u00dcber TinyMCE","charmap_usage":"Navigation mit linken und rechten Pfeilen.","anchor_invalid":"Bitte geben Sie einen g\u00fcltigen Namen f\u00fcr den Anker ein!","accessibility_help":"Eingabehilfe","accessibility_usage_title":"Allgemeine Verwendung","invalid_color_value":"Ung\u00fcltige Farbangabe"});<|endoftext|>