<commit_before>/*global document, location, io, XMLHttpRequest, setTimeout, setInterval, clearInterval, StyleFix, less, ActiveXObject*/
(function () {
    'use strict';

    var liveStyleOptions = {}; // The options will be injected by the server

    function log(msg) {
        if (liveStyleOptions.debug && window.console) {
            console.log(msg);
        }
    }

    if (!Array.prototype.indexOf) {
        Array.prototype.indexOf = function (o, from) {
            var i;
            for (i = from || 0; i < this.length; i += 1) {
                if (this[i] === o) {
                    return i;
                }
            }
            return -1;
        };
    }

    var pollTimeout = 2000,
        changedHrefsQueue = [], // Queue of incoming change events
        isBusyByHref = {},
        escapeRegExp = function (str) {
            return str.replace(/[\.\+\*\{\}\[\]\(\)\?\^\$]/g, '\\$&');
        },
        cleanHref = function (href) {
            if (!href) {
                return false;
            }
            var local = new RegExp(
                '^' + escapeRegExp(document.location.protocol + '//' + document.location.hostname + (document.location.port ? ':' + document.location.port : '')) + '/',
                'i'),
                proxy,
                remote = /:\/\/|^\/\//;

            // Skip things like chrome-extension://hmdcmlfkchdmnmnmheododdhjedfccka/inject/anchor-cursor-default.css?0.2.6
            if (/^[\w\-]+:/.test(href) && !/^https?:/.test(href)) {
                return false;
            }

            if (liveStyleOptions.proxy) {
                proxy = new RegExp('^' + escapeRegExp(liveStyleOptions.proxy), 'i');
                if (proxy.test(href)) {
                    return '/' + href.replace(proxy, '');
                }
            }

            if (!local.test(href) && (/^\/\//.test(href) || /^[a-z0-9\+]+:\/\//i.test(href))) {
                return false;
            }

            if (/^data:/.test(href)) {
                // AdBlock for Chrome injects these
                return false;
            }

            // Normalize to be root relative:
            href = href.replace(local, '').replace(/\?.*$/, '');
            if (!/^\//.test(href)) {
                href = location.pathname.replace(/[^\/]+$/, '') + href;
            }

            // Normalize: /foo/../bar => /bar
            while (/\/[^\/\.][^\/]*\/\.\.\//.test(href)) {
                href = href.replace(/\/[^\/\.][^\/]*\/\.\.\//, '/');
            }

            return href;
        },
        findCssIncludes = function () {
            var cssIncludes = [],
                links = document.getElementsByTagName('link'),
                styles = document.getElementsByTagName('style'),
                style,
                cssRule,
                i,
                href;

            // Link tags with rel="stylesheet"
            for (i = 0; i < links.length; i += 1) {
                if (/\bstylesheet\b/i.test(links[i].getAttribute('rel'))) {
                    href = cleanHref(links[i].getAttribute('href'));
                    if (href) {
                        cssIncludes.push({type: 'link', href: href, node: links[i]});
                    }
                }
            }

            // Look for .compilessinclude {src: url(...);} in non-inline stylesheets:
            for (i = 0 ; i < document.styleSheets.length ; i += 1) {
                var styleSheet = document.styleSheets[i];
                if (styleSheet.href) {
                    for (var j = 0 ; j < styleSheet.cssRules.length ; j += 1) {
                        cssRule = styleSheet.cssRules[j];
                        if (/^\.compilessinclude$/.test(cssRule.selectorText)) {
                            var urlToken = cssRule.style.getPropertyValue('src'),
                                matchUrlToken = urlToken.match(/^url\((['"]|)(.*?)\1\)$/);
                            if (matchUrlToken) {
                                href = cleanHref(styleSheet.href);
                                var watchHref = cleanHref(matchUrlToken[2]);
                                if (href && watchHref) {
                                    cssIncludes.push({type: 'link', href: href, watchHref: watchHref, node: styleSheet.ownerNode});
                                }
                            }
                        } else {
                            // These .compilessinclude rules always come first, so break on the first non-matching one:
                            break;
                        }
                    }
                }
            }

            // Style tags: @includes and inline prefixfree blocks
            for (i = 0 ; i < styles.length ; i += 1) {
                style = styles[i];

                if (typeof StyleFix !== 'undefined') {
                    // Prefixfree support
                    href = cleanHref(style.href || style.getAttribute('data-href'));
                    if (href) {
                        cssIncludes.push({type: 'prefixfree', href: href, node: style});
                    }
                }

                // @import
                style.innerHTML.replace(/@import\s+(?:'([^']+)'|"([^"]+)"|url\(([^\)]+)\))/g, function ($0, singleQuotedHref, doubleQuotedHref, urlParenthesesHref) {
                    if (urlParenthesesHref) {
                        urlParenthesesHref = urlParenthesesHref.replace(/^(['"])(.*)\1$/, '$2');
                    }
                    var href = cleanHref(singleQuotedHref || doubleQuotedHref || urlParenthesesHref);
                    if (href) {
                        cssIncludes.push({type: 'import', href: href, styleElement: style});
                    }
                });
            }

            return cssIncludes;
        },
        removeCacheBuster = function (href) {
            return href.replace(/[?&]livestyle=\d+/, '');
        },
        addCacheBuster = function (href) {
            return href + (href.indexOf('?') === -1 ? '?' : '&') + 'livestyle=' + new Date().getTime();
        },

        // Replaces a link tag with an updated version. Just replacing the href would cause FOUC.
        // We insert the new node before the old one and remove the old one after the new one has loaded.
        replaceLinkTag = function (node, href) {
            isBusyByHref[href] = (isBusyByHref[href] || 0) + 1;
            var parent = node.parentNode,
                newNode = node.cloneNode(true),
                monitor;

            newNode.removeAttribute('href');

            // The node must be added to the document before the href is set, otherwise IE9 won't
            // apply the styles.
            if (node.nextSibling) {
                parent.insertBefore(newNode, node.nextSibling);
            } else {
                parent.appendChild(newNode);
            }

            newNode.href = href;
            newNode.onload = function () {
                isBusyByHref[href] -= 1;
                if (node.parentNode) {
                    parent.removeChild(node);

                    clearInterval(monitor);
                }
                // There may be additional occurrences of this href in changedHrefsQueue that can be processed
                // now that the busy counter was decremented:
                processNextChangedHref();
            };
            monitor = setInterval(function () {
                try {
                    if (newNode.sheet && newNode.sheet.cssRules.length > 0) { // Throws an error if the stylesheet hasn't loaded
                        newNode.onload();
                    }
                } catch (err) {}
            }, 20);
        },
        replaceStyleTag = function (node, oldHref, href) {
            var parent = node.parentNode,
                newNode = node.cloneNode(),
                replacerRegexp = new RegExp("@import\\s+url\\([\"']?" + oldHref.replace(/[\?\[\]\(\)\{\}]/g, "\\$&") + "[\"']?\\)");

            newNode.textContent = node.textContent.replace(replacerRegexp, '@import url(\'' + addCacheBuster(href) + '\')');
            parent.insertBefore(newNode, node);
            parent.removeChild(node);
        },
        processNextChangedHref = function () {
            var i,
                href;
            // Find the first non-busy href in changedHrefsQueue:
            for (i = 0 ; i < changedHrefsQueue.length ; i += 1) {
                if (isBusyByHref[changedHrefsQueue[i]]) {
                    if (liveStyleOptions.debug) {
                        log("Postponing 'change' notification on stylesheet that's already being refreshed: " + changedHrefsQueue[i]);
                    }
                } else {
                    href = changedHrefsQueue.splice(i, 1)[0];
                    break;
                }
            }
            if (!href) {
                return;
            }

            var cssIncludes = findCssIncludes(),
                cssInclude,
                newHref,
                replacerRegExp;

            if (href === location.pathname) {
                location.reload(true);
            }

            for (i = 0; i < cssIncludes.length; i += 1) {
                cssInclude = cssIncludes[i];
                var matchAgainstHref = removeCacheBuster(cssInclude.watchHref || cssInclude.href);

                if (matchAgainstHref === href) {
                    log('Refreshing ' + cssInclude.href);
                    if (cssInclude.type === 'link') {
                        // Less.js support (https://github.com/cloudhead/less.js)
                        if (/\bstylesheet\/less\b/i.test(cssInclude.node.getAttribute('rel')) && typeof less !== 'undefined') {
                            // Sadly this method isn't accessible
                            // less.loadStyleSheet(cssInclude.node, function () {}, false, 0);
                            // So instead we'll just have to brutally refresh ALL less includes
                            less.refresh();
                        } else {
                            replaceLinkTag(cssInclude.node, cssInclude.href);
                        }
                    }

                    if (cssInclude.type === 'import') {
                        replaceStyleTag(cssInclude.styleElement, cssInclude.href, addCacheBuster(href));
                    }

                    if (cssInclude.type === 'prefixfree') {
                        // The next two lines are hacks to make Prefixfree think this is a link and not a style block
                        cssInclude.node.setAttribute('href', href); // No cache buster needed
                        cssInclude.node.rel = 'stylesheet';
                        StyleFix.link(cssInclude.node);
                    }

                    // Replacing the first occurrence should be good enough. Besides, the @import replacement code invalidates
                    // the rest of the cssIncludes in the same stylesheet.
                    break;
                }
            }
            processNextChangedHref(); // We consumed an item from changedHrefsQueue, keep going
        },
        startListening = function () {
            var socket = io.connect();

            socket.on('connect', function () {
                var hrefs = [],
                    watchNewStylesheets = function () {
                        var cssIncludes = findCssIncludes(),
                            toWatch = [],
                            href,
                            i;
                        //cssIncludes.unshift({ href: location.pathname }); // See https://github.com/One-com/livestyle/issues/11

                        for (i = 0; i < cssIncludes.length; i += 1) {
                            href = removeCacheBuster(cssIncludes[i].watchHref || cssIncludes[i].href);
                            if (hrefs.indexOf(href) === -1) {
                                hrefs.push(href);
                                toWatch.push(href);
                            }
                        }

                        if (toWatch.length !== 0) {
                            log('Subscribing to ' + toWatch.length + ' files:\n  ' + toWatch.join('\n  '));
                            socket.emit('watch', toWatch);
                        }
                    };

                watchNewStylesheets();
                setInterval(watchNewStylesheets, pollTimeout);
            }).on('change', function (href) {
                if (changedHrefsQueue.indexOf(href) === -1) {
                    changedHrefsQueue.push(href);
                    log('Received change notification for ' + href + ', queued');
                    processNextChangedHref();
                } else {
                    log('Received change notification for ' + href + ', skipped (already in queue)');
                }
            });
        },
        state = {},
        startPolling = function () {
            var getXHR = function () {
                    try {
                        return new XMLHttpRequest();
                    } catch (e1) {
                        try {
                            return new ActiveXObject("Msxml2.XMLHTTP.6.0");
                        } catch (e2) {
                            try {
                                return new ActiveXObject("Msxml2.XMLHTTP.3.0");
                            } catch (e3) {
                                try {
                                    return new ActiveXObject("Msxml2.XMLHTTP");
                                } catch (e4) {
                                    try {
                                        return new ActiveXObject("Microsoft.XMLHTTP");
                                    } catch (e5) {}
                                }
                            }
                        }
                    }

                    return null; // no XHR support
                },
                cssIncludes = findCssIncludes(),
                proceed = function () {
                    var cssInclude,
                        url,
                        xhr;

                    if (cssIncludes.length > 0) {
                        cssInclude = cssIncludes.shift();
                        url = removeCacheBuster(cssInclude.href);
                        xhr = getXHR();

                        xhr.onreadystatechange = function () {
                            var lastModified,
                                etag;

                            if (xhr.readyState === 4) {
                                if (xhr.status === 200) {
                                    lastModified = Date.parse(xhr.getResponseHeader("Last-Modified"));
                                    etag = xhr.getResponseHeader("ETag");

                                    if (!state[url] || state[url].lastModified < lastModified || state[url].etag !== etag) {
                                        state[url] = {
                                            lastModified: lastModified,
                                            etag: etag
                                        };
                                        refresh(url);
                                    }
                                }

                                proceed();
                            }
                        };
                        xhr.open('HEAD', addCacheBuster(url), true);
                        xhr.send(null);
                    } else {
                        setTimeout(startPolling, pollTimeout);
                    }
                };
            //cssIncludes.unshift({ href: location.pathname }); // See https://github.com/One-com/livestyle/issues/11
            proceed();
        };

    if (typeof io !== 'undefined') {
        log('socket.io present, connecting');
        startListening();
    } else {
        log('socket.io not present, falling back to polling mode');
        startPolling();
    }
}());
<commit_msg>Client, replaceLinkTag: Be even more careful when detecting that the new stylesheet has loaded and replacing the old link tag.<commit_after>/*global document, location, io, XMLHttpRequest, setTimeout, setInterval, clearInterval, StyleFix, less, ActiveXObject*/
(function () {
    'use strict';

    var liveStyleOptions = {}; // The options will be injected by the server

    function log(msg) {
        if (liveStyleOptions.debug && window.console) {
            console.log(msg);
        }
    }

    if (!Array.prototype.indexOf) {
        Array.prototype.indexOf = function (o, from) {
            var i;
            for (i = from || 0; i < this.length; i += 1) {
                if (this[i] === o) {
                    return i;
                }
            }
            return -1;
        };
    }

    var pollTimeout = 2000,
        changedHrefsQueue = [], // Queue of incoming change events
        isBusyByHref = {},
        escapeRegExp = function (str) {
            return str.replace(/[\.\+\*\{\}\[\]\(\)\?\^\$]/g, '\\$&');
        },
        cleanHref = function (href) {
            if (!href) {
                return false;
            }
            var local = new RegExp(
                '^' + escapeRegExp(document.location.protocol + '//' + document.location.hostname + (document.location.port ? ':' + document.location.port : '')) + '/',
                'i'),
                proxy,
                remote = /:\/\/|^\/\//;

            // Skip things like chrome-extension://hmdcmlfkchdmnmnmheododdhjedfccka/inject/anchor-cursor-default.css?0.2.6
            if (/^[\w\-]+:/.test(href) && !/^https?:/.test(href)) {
                return false;
            }

            if (liveStyleOptions.proxy) {
                proxy = new RegExp('^' + escapeRegExp(liveStyleOptions.proxy), 'i');
                if (proxy.test(href)) {
                    return '/' + href.replace(proxy, '');
                }
            }

            if (!local.test(href) && (/^\/\//.test(href) || /^[a-z0-9\+]+:\/\//i.test(href))) {
                return false;
            }

            if (/^data:/.test(href)) {
                // AdBlock for Chrome injects these
                return false;
            }

            // Normalize to be root relative:
            href = href.replace(local, '').replace(/\?.*$/, '');
            if (!/^\//.test(href)) {
                href = location.pathname.replace(/[^\/]+$/, '') + href;
            }

            // Normalize: /foo/../bar => /bar
            while (/\/[^\/\.][^\/]*\/\.\.\//.test(href)) {
                href = href.replace(/\/[^\/\.][^\/]*\/\.\.\//, '/');
            }

            return href;
        },
        findCssIncludes = function () {
            var cssIncludes = [],
                links = document.getElementsByTagName('link'),
                styles = document.getElementsByTagName('style'),
                style,
                cssRule,
                i,
                href;

            // Link tags with rel="stylesheet"
            for (i = 0; i < links.length; i += 1) {
                if (/\bstylesheet\b/i.test(links[i].getAttribute('rel'))) {
                    href = cleanHref(links[i].getAttribute('href'));
                    if (href) {
                        cssIncludes.push({type: 'link', href: href, node: links[i]});
                    }
                }
            }

            // Look for .compilessinclude {src: url(...);} in non-inline stylesheets:
            for (i = 0 ; i < document.styleSheets.length ; i += 1) {
                var styleSheet = document.styleSheets[i];
                if (styleSheet.href) {
                    for (var j = 0 ; j < styleSheet.cssRules.length ; j += 1) {
                        cssRule = styleSheet.cssRules[j];
                        if (/^\.compilessinclude$/.test(cssRule.selectorText)) {
                            var urlToken = cssRule.style.getPropertyValue('src'),
                                matchUrlToken = urlToken.match(/^url\((['"]|)(.*?)\1\)$/);
                            if (matchUrlToken) {
                                href = cleanHref(styleSheet.href);
                                var watchHref = cleanHref(matchUrlToken[2]);
                                if (href && watchHref) {
                                    cssIncludes.push({type: 'link', href: href, watchHref: watchHref, node: styleSheet.ownerNode});
                                }
                            }
                        } else {
                            // These .compilessinclude rules always come first, so break on the first non-matching one:
                            break;
                        }
                    }
                }
            }

            // Style tags: @includes and inline prefixfree blocks
            for (i = 0 ; i < styles.length ; i += 1) {
                style = styles[i];

                if (typeof StyleFix !== 'undefined') {
                    // Prefixfree support
                    href = cleanHref(style.href || style.getAttribute('data-href'));
                    if (href) {
                        cssIncludes.push({type: 'prefixfree', href: href, node: style});
                    }
                }

                // @import
                style.innerHTML.replace(/@import\s+(?:'([^']+)'|"([^"]+)"|url\(([^\)]+)\))/g, function ($0, singleQuotedHref, doubleQuotedHref, urlParenthesesHref) {
                    if (urlParenthesesHref) {
                        urlParenthesesHref = urlParenthesesHref.replace(/^(['"])(.*)\1$/, '$2');
                    }
                    var href = cleanHref(singleQuotedHref || doubleQuotedHref || urlParenthesesHref);
                    if (href) {
                        cssIncludes.push({type: 'import', href: href, styleElement: style});
                    }
                });
            }

            return cssIncludes;
        },
        removeCacheBuster = function (href) {
            return href.replace(/[?&]livestyle=\d+/, '');
        },
        addCacheBuster = function (href) {
            return href + (href.indexOf('?') === -1 ? '?' : '&') + 'livestyle=' + new Date().getTime();
        },

        // Replaces a link tag with an updated version. Just replacing the href would cause FOUC.
        // We insert the new node before the old one and remove the old one after the new one has loaded.
        replaceLinkTag = function (node, href) {
            isBusyByHref[href] = (isBusyByHref[href] || 0) + 1;
            var parent = node.parentNode,
                newNode = node.cloneNode(true),
                monitor;

            newNode.removeAttribute('href');

            // The node must be added to the document before the href is set, otherwise IE9 won't
            // apply the styles.
            if (node.nextSibling) {
                parent.insertBefore(newNode, node.nextSibling);
            } else {
                parent.appendChild(newNode);
            }

            newNode.href = href;
            newNode.onload = function () {
                newNode.onload = null;
                isBusyByHref[href] -= 1;
                if (node.parentNode) {
                    parent.removeChild(node);
                }
                if (monitor) {
                    clearInterval(monitor);
                    monitor = null;
                }
                // There may be additional occurrences of this href in changedHrefsQueue that can be processed
                // now that the busy counter was decremented:
                processNextChangedHref();
            };
            monitor = setInterval(function () {
                var isReady;
                try {
                    isReady = newNode.sheet && newNode.sheet.cssRules.length > 0; // Throws an error if the stylesheet hasn't loaded
                } catch (err) {}
                if (isReady) {
                    newNode.onload();
                }
            }, 20);
        },
        replaceStyleTag = function (node, oldHref, href) {
            var parent = node.parentNode,
                newNode = node.cloneNode(),
                replacerRegexp = new RegExp("@import\\s+url\\([\"']?" + oldHref.replace(/[\?\[\]\(\)\{\}]/g, "\\$&") + "[\"']?\\)");

            newNode.textContent = node.textContent.replace(replacerRegexp, '@import url(\'' + addCacheBuster(href) + '\')');
            parent.insertBefore(newNode, node);
            parent.removeChild(node);
        },
        processNextChangedHref = function () {
            var i,
                href;
            // Find the first non-busy href in changedHrefsQueue:
            for (i = 0 ; i < changedHrefsQueue.length ; i += 1) {
                if (isBusyByHref[changedHrefsQueue[i]]) {
                    if (liveStyleOptions.debug) {
                        log("Postponing 'change' notification on stylesheet that's already being refreshed: " + changedHrefsQueue[i]);
                    }
                } else {
                    href = changedHrefsQueue.splice(i, 1)[0];
                    break;
                }
            }
            if (!href) {
                return;
            }

            var cssIncludes = findCssIncludes(),
                cssInclude,
                newHref,
                replacerRegExp;

            if (href === location.pathname) {
                location.reload(true);
            }

            for (i = 0; i < cssIncludes.length; i += 1) {
                cssInclude = cssIncludes[i];
                var matchAgainstHref = removeCacheBuster(cssInclude.watchHref || cssInclude.href);

                if (matchAgainstHref === href) {
                    log('Refreshing ' + cssInclude.href);
                    if (cssInclude.type === 'link') {
                        // Less.js support (https://github.com/cloudhead/less.js)
                        if (/\bstylesheet\/less\b/i.test(cssInclude.node.getAttribute('rel')) && typeof less !== 'undefined') {
                            // Sadly this method isn't accessible
                            // less.loadStyleSheet(cssInclude.node, function () {}, false, 0);
                            // So instead we'll just have to brutally refresh ALL less includes
                            less.refresh();
                        } else {
                            replaceLinkTag(cssInclude.node, cssInclude.href);
                        }
                    }

                    if (cssInclude.type === 'import') {
                        replaceStyleTag(cssInclude.styleElement, cssInclude.href, addCacheBuster(href));
                    }

                    if (cssInclude.type === 'prefixfree') {
                        // The next two lines are hacks to make Prefixfree think this is a link and not a style block
                        cssInclude.node.setAttribute('href', href); // No cache buster needed
                        cssInclude.node.rel = 'stylesheet';
                        StyleFix.link(cssInclude.node);
                    }

                    // Replacing the first occurrence should be good enough. Besides, the @import replacement code invalidates
                    // the rest of the cssIncludes in the same stylesheet.
                    break;
                }
            }
            processNextChangedHref(); // We consumed an item from changedHrefsQueue, keep going
        },
        startListening = function () {
            var socket = io.connect();

            socket.on('connect', function () {
                var hrefs = [],
                    watchNewStylesheets = function () {
                        var cssIncludes = findCssIncludes(),
                            toWatch = [],
                            href,
                            i;
                        //cssIncludes.unshift({ href: location.pathname }); // See https://github.com/One-com/livestyle/issues/11

                        for (i = 0; i < cssIncludes.length; i += 1) {
                            href = removeCacheBuster(cssIncludes[i].watchHref || cssIncludes[i].href);
                            if (hrefs.indexOf(href) === -1) {
                                hrefs.push(href);
                                toWatch.push(href);
                            }
                        }

                        if (toWatch.length !== 0) {
                            log('Subscribing to ' + toWatch.length + ' files:\n  ' + toWatch.join('\n  '));
                            socket.emit('watch', toWatch);
                        }
                    };

                watchNewStylesheets();
                setInterval(watchNewStylesheets, pollTimeout);
            }).on('change', function (href) {
                if (changedHrefsQueue.indexOf(href) === -1) {
                    changedHrefsQueue.push(href);
                    log('Received change notification for ' + href + ', queued');
                    processNextChangedHref();
                } else {
                    log('Received change notification for ' + href + ', skipped (already in queue)');
                }
            });
        },
        state = {},
        startPolling = function () {
            var getXHR = function () {
                    try {
                        return new XMLHttpRequest();
                    } catch (e1) {
                        try {
                            return new ActiveXObject("Msxml2.XMLHTTP.6.0");
                        } catch (e2) {
                            try {
                                return new ActiveXObject("Msxml2.XMLHTTP.3.0");
                            } catch (e3) {
                                try {
                                    return new ActiveXObject("Msxml2.XMLHTTP");
                                } catch (e4) {
                                    try {
                                        return new ActiveXObject("Microsoft.XMLHTTP");
                                    } catch (e5) {}
                                }
                            }
                        }
                    }

                    return null; // no XHR support
                },
                cssIncludes = findCssIncludes(),
                proceed = function () {
                    var cssInclude,
                        url,
                        xhr;

                    if (cssIncludes.length > 0) {
                        cssInclude = cssIncludes.shift();
                        url = removeCacheBuster(cssInclude.href);
                        xhr = getXHR();

                        xhr.onreadystatechange = function () {
                            var lastModified,
                                etag;

                            if (xhr.readyState === 4) {
                                if (xhr.status === 200) {
                                    lastModified = Date.parse(xhr.getResponseHeader("Last-Modified"));
                                    etag = xhr.getResponseHeader("ETag");

                                    if (!state[url] || state[url].lastModified < lastModified || state[url].etag !== etag) {
                                        state[url] = {
                                            lastModified: lastModified,
                                            etag: etag
                                        };
                                        refresh(url);
                                    }
                                }

                                proceed();
                            }
                        };
                        xhr.open('HEAD', addCacheBuster(url), true);
                        xhr.send(null);
                    } else {
                        setTimeout(startPolling, pollTimeout);
                    }
                };
            //cssIncludes.unshift({ href: location.pathname }); // See https://github.com/One-com/livestyle/issues/11
            proceed();
        };

    if (typeof io !== 'undefined') {
        log('socket.io present, connecting');
        startListening();
    } else {
        log('socket.io not present, falling back to polling mode');
        startPolling();
    }
}());
<|endoftext|>


<commit_before>/**
 * Create a new pre-configured iframe.
 *
 * Options:
 *
 * visible: (boolean) Don't hide the iframe by default.
 * sandbox: (array) Sandbox properties.
 *
 * @param {Element} el DOM element where the iframe should be added on.
 * @param {String} id A unique name/id for the iframe.
 * @param {String} options Options.
 * @return {Object}
 * @api private
 */
function iframe(el, id, options) {
  'use strict';

  var i;

  options = options || {};
  options.sandbox = options.sandbox || [
    'allow-pointer-lock',
    'allow-same-origin',
    'allow-scripts',
    'allow-popups',
    'allow-forms'
  ];

  try {
    //
    // Internet Explorer 6/7 require a unique name attribute in order to work.
    // In addition to that, dynamic name attributes cannot be added using
    // `i.name` as it will just ignore it. Creating it using this oddly <iframe>
    // element fixes these issues.
    //
    i = document.createElement('<iframe name="'+ id +'">');
  } catch (e) {
    i = document.createElement('iframe');
    i.name = id;
  }

  //
  // The iframe needs to be added in to the DOM before we can modify it, make
  // sure it's remains unseen.
  //
  if (!options.visible) {
    i.style.top = i.style.left = -10000;
    i.style.position = 'absolute';
    i.style.display = 'none';
  }

  i.setAttribute('frameBorder', 0);

  if (options.sandbox.length) {
    i.setAttribute('sandbox', (options.sandbox).join(' '));
  }

  i.id = id;

  return {
    /**
     * Return the document which we can use to inject or modify the HTML.
     *
     * @returns {Document}
     * @api public
     */
    document: function doc() {
      return this.window().document;
    },

    /**
     * Return the global or the window from the iframe.
     *
     * @returns {Window}
     * @api public
     */
    window: function win() {
      return i.contentWindow || (i.contentDocument
        ? i.contentDocument.parentWindow || {}
        : {}
      );
    },

    /**
     * Add the iframe to the DOM, use insertBefore first child to avoid
     * `Operation Aborted` error in IE6.
     *
     * @api public
     */
    add: function add() {
      if (!this.attached()) {
        el.insertBefore(i, el.firstChild);
      }

      return this;
    },

    /**
     * Remove the iframe from the DOM.
     *
     * @api public
     */
    remove: function remove() {
      if (this.attached()) {
        el.removeChild(i);
      }

      return this;
    },

    /**
     * Checks if the iframe is currently attached to the DOM.
     *
     * @returns {Boolean} The container is attached to the mount point.
     * @api private
     */
    attached: function attached() {
      return !!document.getElementById(id);
    },

    /**
     * Reference to the iframe element.
     *
     * @type {HTMLIFRAMEElement}
     * @public
     */
    frame: i
  };
}

module.exports = iframe;
<commit_msg>[minor] Codestyle<commit_after>'use strict';

/**
 * Create a new pre-configured iframe.
 *
 * Options:
 *
 * visible: (boolean) Don't hide the iframe by default.
 * sandbox: (array) Sandbox properties.
 *
 * @param {Element} el DOM element where the iframe should be added on.
 * @param {String} id A unique name/id for the iframe.
 * @param {String} options Options.
 * @return {Object}
 * @api private
 */
module.exports = function iframe(el, id, options) {
  var i;

  options = options || {};
  options.sandbox = options.sandbox || [
    'allow-pointer-lock',
    'allow-same-origin',
    'allow-scripts',
    'allow-popups',
    'allow-forms'
  ];

  try {
    //
    // Internet Explorer 6/7 require a unique name attribute in order to work.
    // In addition to that, dynamic name attributes cannot be added using
    // `i.name` as it will just ignore it. Creating it using this oddly <iframe>
    // element fixes these issues.
    //
    i = document.createElement('<iframe name="'+ id +'">');
  } catch (e) {
    i = document.createElement('iframe');
    i.name = id;
  }

  //
  // The iframe needs to be added in to the DOM before we can modify it, make
  // sure it's remains unseen.
  //
  if (!options.visible) {
    i.style.top = i.style.left = -10000;
    i.style.position = 'absolute';
    i.style.display = 'none';
  }

  i.setAttribute('frameBorder', 0);

  if (options.sandbox.length) {
    i.setAttribute('sandbox', (options.sandbox).join(' '));
  }

  i.id = id;

  return {
    /**
     * Return the document which we can use to inject or modify the HTML.
     *
     * @returns {Document}
     * @api public
     */
    document: function doc() {
      return this.window().document;
    },

    /**
     * Return the global or the window from the iframe.
     *
     * @returns {Window}
     * @api public
     */
    window: function win() {
      return i.contentWindow || (i.contentDocument
        ? i.contentDocument.parentWindow || {}
        : {}
      );
    },

    /**
     * Add the iframe to the DOM, use insertBefore first child to avoid
     * `Operation Aborted` error in IE6.
     *
     * @api public
     */
    add: function add() {
      if (!this.attached()) {
        el.insertBefore(i, el.firstChild);
      }

      return this;
    },

    /**
     * Remove the iframe from the DOM.
     *
     * @api public
     */
    remove: function remove() {
      if (this.attached()) {
        el.removeChild(i);
      }

      return this;
    },

    /**
     * Checks if the iframe is currently attached to the DOM.
     *
     * @returns {Boolean} The container is attached to the mount point.
     * @api private
     */
    attached: function attached() {
      return !!document.getElementById(id);
    },

    /**
     * Reference to the iframe element.
     *
     * @type {HTMLIFRAMEElement}
     * @public
     */
    frame: i
  };
};
<|endoftext|>


<commit_before>/*
Script: Namespace.js
	Namespace utility

Copyright:
	Copyright (c) 2009 Maxime Bouroumeau-Fuseau

License:
	MIT-style license.

Version:
	1.0
*/
var Namespace = (function() {

	var _listeners = {};
	var _includedIdentifiers = [];

	/**
	 * Returns an object in an array unless the object is an array
	 *
	 * @param	mixed	obj
	 * @return	Array
	 */
	var _toArray = function(obj) {
		// checks if it's an array
		if (typeof(obj) == 'object' && obj.sort) {
			return obj;
		}
		return new Array(obj);
	};

	/**
	 * Creates an XMLHttpRequest object
	 *
	 * @return XMLHttpRequest
	 */
	var _createXmlHttpRequest = function() {
		var xhr;
		try { xhr = new XMLHttpRequest() } catch(e) {
			try { xhr = new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {
				try { xhr = new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {
					try { xhr = new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {
						try { xhr = new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {
							throw new Error( "This browser does not support XMLHttpRequest." )
						}
					}
				}
			}
		}
		return xhr;
	};

	/**
	 * Checks if an http request is successful based on its status code.
	 * Borrowed from dojo (http://www.dojotoolkit.org).
	 *
	 * @param	Integer	status 	Http status code
	 * @return	Boolean
	 */
	var _isHttpRequestSuccessful = function(status) {
		return (status >= 200 && status < 300) || 	// Boolean
				status == 304 || 						// allow any 2XX response code
				status == 1223 || 						// get it out of the cache
				(!status && (location.protocol == "file:" || location.protocol == "chrome:") ); // Internet Explorer mangled the status code
	};

	/**
	 * Creates a script tag with the specified data as content
	 *
	 * @param	String	data	The content of the script
	 */
	var _createScript = function(data) {
		var script = document.createElement('script');
		script.type = 'text/javascript';
		script.text = data;
		document.body.appendChild(script);
	};

	/**
	 * Dispatches an event
	 *
	 * @param	String	eventName
	 * @param	Object	properties
	 */
	var _dispatchEvent = function(eventName, properties) {
		if (!_listeners[eventName]) return;
		properties.event = eventName;
		for (var i = 0; i < _listeners[eventName].length; i++) {
			_listeners[eventName][i](properties);
		}
	};

	/**
	 * Creates an Object following the specified namespace identifier.
	 *
	 * @public
	 * @param 	String	identifier	The namespace string
	 * @param	Object	klasses		(OPTIONAL) An object which properties will be added to the namespace
	 * @return	Object				The most inner object
	 */
	var _namespace = function(identifier) {
		var klasses = arguments[1] || false;
		var ns = window;

		if (identifier != '') {
			var parts = identifier.split(Namespace.separator);
			for (var i = 0; i < parts.length; i++) {
				if (!ns[parts[i]]) {
					ns[parts[i]] = {};
				}
				ns = ns[parts[i]];
			}
		}

		if (klasses) {
			for (var klass in klasses) {
				ns[klass] = klasses[klass];
			}
		}

		_dispatchEvent('create', { 'identifier': identifier });
		return ns;
	};

	/**
	 * Checks if the specified identifier is defined
	 *
	 * @public
	 * @param 	String	identifier	The namespace string
	 * @return	Boolean
	 */
	_namespace.exist = function(identifier) {
		if (identifier == '') return true;

		var parts = identifier.split(Namespace.separator);
		var ns = window;
		for (var i = 0; i < parts.length; i++) {
			if (!ns[parts[i]]) {
				return false;
			}
			ns = ns[parts[i]];
		}

		return true;
	};

	/**
	 * Maps an identifier to a uri. Is public so it can be overriden by custom scripts.
	 *
	 * @public
	 * @param	String	identifier 	The namespace identifier
	 * @return	String				The uri
	 */
	_namespace.mapIdentifierToUri = function(identifier) {
		var regexp = new RegExp('\\' + Namespace.separator, 'g');
		return Namespace.baseUri + identifier.replace(regexp, '/') + '.js';
	};

	/**
	 * Loads a remote script atfer mapping the identifier to an uri
	 *
	 * @param	String		identifier			The namespace identifier
	 * @param	Function	successCallback		When set, the file will be loaded asynchronously. Will be called when the file is loaded
	 * @param	Function	errorCallback		Callback to be called when an error occurs
	 * @return	Boolean							Success of failure when loading synchronously
	 */
	_loadScript = function(identifier) {
		var successCallback = arguments[1] || false;
		var errorCallback = arguments[2] || false;
		var async = successCallback != false;
		var uri = _namespace.mapIdentifierToUri(identifier);
		var event = { 'identifier': identifier, 'uri': uri, 'async': async, 'callback': successCallback };

		var xhr = _createXmlHttpRequest();
		xhr.open("GET", uri, async);

		if (async) {
			xhr.onreadystatechange = function() {
				if (xhr.readyState == 4) {
					if (_isHttpRequestSuccessful(xhr.status || 0)) {
						_createScript(xhr.responseText);
						_dispatchEvent('include', event);
						successCallback();
						return;
					}
					event.status = xhr.status;
					_dispatchEvent('includeError', event);
					errorCallback && errorCallback();
				}
			};
		}

		xhr.send(null);

		if (!async) {
			if (_isHttpRequestSuccessful(xhr.status || 0)) {
				_createScript(xhr.responseText);
				_dispatchEvent('include', event);
				return true;
			}
			event.status = xhr.status;
			_dispatchEvent('includeError', event);
			return false;
		}
	};

	/**
	 * Includes a remote javascript file identified by the specified namespace string. The identifier
	 * must point to a class. Separators in the string will be converted to slashes and the .js extension will be appended.
	 *
	 * @public
	 * @param	String		identifier	The namespace string
	 * @param	Function	callback	(OPTIONAL) A function to call when the remote script has been included
	 */
	_namespace.include = function(identifier) {
		var successCallback = arguments[1] || false;
		var errorCallback = arguments[2] || false;

		// checks if the identifier is not already included
		if (_includedIdentifiers[identifier]) {
			successCallback && successCallback();
			return true;
		}

		if (successCallback) {
			_loadScript(identifier, function() {
				_includedIdentifiers[identifier] = true;
				successCallback();
			}, errorCallback);
		} else {
			if (_loadScript(identifier)) {
				_includedIdentifiers[identifier] = true;
				return true;
			}
			return false;
		}
	};

	/**
	 * Imports properties from the specified namespace to the global space (ie. under window)
	 *
	 * The identifier string can contain the * wildcard character as its last segment (eg: com.test.*)
	 * which will import all properties from the namespace.
	 *
	 * If not, the targeted namespace will be imported (ie. if com.test is imported, the test object
	 * will now be global). If the targeted object is not found, it will be included using include().
	 *
	 * @public
	 * @param	String		identifier 	The namespace string
	 * @param	Function	callback	(OPTIONAL) A function to call when the process is completed (including the include() if used)
	 * @param	Boolean		autoInclude	(OPTIONAL) Whether to automatically auto include the targeted object is not found. Default is Namespace.autoInclude
	 */
	_namespace.use = function(identifier) {
		var identifiers 		= _toArray(identifier);
		var callback 			= arguments[1] || false;
		var autoInclude 		= arguments.length > 2 ? arguments[2] : Namespace.autoInclude;
		var event				= { 'identifier': identifier };

		for (var i = 0; i < identifiers.length; i++) {
			identifier = identifiers[i];

			var parts = identifier.split(Namespace.separator);
			var target = parts.pop();
			var ns = _namespace(parts.join(Namespace.separator));

			if (target == '*') {
				// imports all objects from the identifier, can't use include() in that case
				for (var objectName in ns) {
					window[objectName] = ns[objectName];
				}
			} else {
				// imports only one object
				if (ns[target]) {
					// the object exists, import it
					window[target] = ns[target];
				} else {
					// the object does not exist
					if (autoInclude) {
						// try to auto include it
						if (callback) {
							_namespace.include(identifier, function() {
								window[target] = ns[target];

								if (i + 1 < identifiers.length) {
									// we continue to unpack the rest from here
									_namespace.unpack(identifiers.slice(i + 1), callback, autoInclude);
								} else {
									// no more identifiers to unpack
									_dispatchEvent('use', event);
									callback && callback();
								}
							});
							return;
						} else {
							_namespace.include(identifier);
							window[target] = ns[target];
						}
					}
				}
			}

		}

		// all identifiers have been unpacked
		_dispatchEvent('use', event);
		callback && callback();
	};

	/**
	 * Binds the include() and unpack() method to a specified identifier
	 *
	 * @public
	 * @param	String	identifier 	The namespace identifier
	 * @return	Object
	 */
	_namespace.from = function(identifier) {
		return {
			/**
			 * Includes the identifier specified in from()
			 *
			 * @see Namespace.include()
			 */
			include: function() {
				var callback = arguments[0] || false;
				_namespace.include(identifier, callback);
			},
			/**
			 * Includes the identifier specified in from() and unpack
			 * the specified indentifier in _identifier
			 *
			 * @see Namespace.use()
			 */
			use: function(_identifier) {
				var callback = arguments[1] || false;
				if (_identifier.charAt(0) == '.') {
					_identifier = identifier + _identifier;
				}

				if (callback) {
					_namespace.include(identifier, function() {
						_namespace.use(_identifier, callback, false);
					});
				} else {
					_namespace.include(identifier);
					_namespace.use(_identifier, callback, false);
				}
			}
		};
	};

	/**
	 * Registers a function to be called when the specified event is dispatched
	 *
	 * @param	String		eventName
	 * @param	Function	callback
	 */
	_namespace.addEventListener = function(eventName, callback) {
		if (!_listeners[eventName]) _listeners[eventName] = [];
		_listeners[eventName].push(callback);
	};

	/**
	 * Unregisters an event listener
	 *
	 * @param	String		eventName
	 * @param	Function	callback
	 */
	_namespace.removeEventListener = function(eventName, callback) {
		if (!_listeners[eventName]) return;
		for (var i = 0; i < _listeners[eventName].length; i++) {
			if (_listeners[eventName][i] == callback) {
				delete _listeners[eventName][i];
				return;
			}
		}
	};

	/**
	 * Adds methods to javascript native's object
	 * Inspired by http://thinkweb2.com/projects/prototype/namespacing-made-easy/
	 *
	 * @public
	 */
	_namespace.registerNativeExtensions = function() {
		/**
		 * @see Namespace()
		 */
		String.prototype.namespace = function() {
			var klasses = arguments[0] || {};
			return _namespace(this.valueOf(), klasses);
		};
		/**
		 * @see Namespace.include()
		 */
		String.prototype.include = function() {
			var callback = arguments[0] || false;
			return _namespace.include(this.valueOf(), callback);
		}
		/**
		 * @see Namespace.use()
		 */
		String.prototype.use = function() {
			var callback = arguments[0] || false;
			return _namespace.use(this.valueOf(), callback);
		}
		/**
		 * @see Namespace.from()
		 */
		String.prototype.from = function() {
			return _namespace.from(this.valueOf());
		}
		/**
		 * @see Namespace.use()
		 */
		Array.prototype.use = function() {
			var callback = arguments[0] || false;
			return _namespace.use(this, callback);
		}
	};

	return _namespace;
})();

/**
 * Namespace segment separator
 *
 * @var String
 */
Namespace.separator = '.';

/**
 * Base uri when using Namespace.include()
 * Must end with a slash
 *
 * @var String
 */
Namespace.baseUri = './';

/**
 * Whether to automatically call Namespace.include() when Namespace.import()
 * does not find the targeted object.
 *
 * @var Boolean
 */
Namespace.autoInclude = true;

<commit_msg>added Namespace.provide()<commit_after>/*
Script: Namespace.js
	Namespace utility

Copyright:
	Copyright (c) 2009 Maxime Bouroumeau-Fuseau

License:
	MIT-style license.

Version:
	1.0
*/
var Namespace = (function() {

	var _listeners = {};
	var _includedIdentifiers = [];

	/**
	 * Returns an object in an array unless the object is an array
	 *
	 * @param	mixed	obj
	 * @return	Array
	 */
	var _toArray = function(obj) {
		// checks if it's an array
		if (typeof(obj) == 'object' && obj.sort) {
			return obj;
		}
		return new Array(obj);
	};

	/**
	 * Creates an XMLHttpRequest object
	 *
	 * @return XMLHttpRequest
	 */
	var _createXmlHttpRequest = function() {
		var xhr;
		try { xhr = new XMLHttpRequest() } catch(e) {
			try { xhr = new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {
				try { xhr = new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {
					try { xhr = new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {
						try { xhr = new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {
							throw new Error( "This browser does not support XMLHttpRequest." )
						}
					}
				}
			}
		}
		return xhr;
	};

	/**
	 * Checks if an http request is successful based on its status code.
	 * Borrowed from dojo (http://www.dojotoolkit.org).
	 *
	 * @param	Integer	status 	Http status code
	 * @return	Boolean
	 */
	var _isHttpRequestSuccessful = function(status) {
		return (status >= 200 && status < 300) || 	// Boolean
				status == 304 || 						// allow any 2XX response code
				status == 1223 || 						// get it out of the cache
				(!status && (location.protocol == "file:" || location.protocol == "chrome:") ); // Internet Explorer mangled the status code
	};

	/**
	 * Creates a script tag with the specified data as content
	 *
	 * @param	String	data	The content of the script
	 */
	var _createScript = function(data) {
		var script = document.createElement('script');
		script.type = 'text/javascript';
		script.text = data;
		document.body.appendChild(script);
	};

	/**
	 * Dispatches an event
	 *
	 * @param	String	eventName
	 * @param	Object	properties
	 */
	var _dispatchEvent = function(eventName, properties) {
		if (!_listeners[eventName]) return;
		properties.event = eventName;
		for (var i = 0; i < _listeners[eventName].length; i++) {
			_listeners[eventName][i](properties);
		}
	};

	/**
	 * Creates an Object following the specified namespace identifier.
	 *
	 * @public
	 * @param 	String	identifier	The namespace string
	 * @param	Object	klasses		(OPTIONAL) An object which properties will be added to the namespace
	 * @return	Object				The most inner object
	 */
	var _namespace = function(identifier) {
		var klasses = arguments[1] || false;
		var ns = window;

		if (identifier != '') {
			var parts = identifier.split(Namespace.separator);
			for (var i = 0; i < parts.length; i++) {
				if (!ns[parts[i]]) {
					ns[parts[i]] = {};
				}
				ns = ns[parts[i]];
			}
		}

		if (klasses) {
			for (var klass in klasses) {
				ns[klass] = klasses[klass];
			}
		}

		_dispatchEvent('create', { 'identifier': identifier });
		return ns;
	};

	/**
	 * Checks if the specified identifier is defined
	 *
	 * @public
	 * @param 	String	identifier	The namespace string
	 * @return	Boolean
	 */
	_namespace.exist = function(identifier) {
		if (identifier == '') return true;

		var parts = identifier.split(Namespace.separator);
		var ns = window;
		for (var i = 0; i < parts.length; i++) {
			if (!ns[parts[i]]) {
				return false;
			}
			ns = ns[parts[i]];
		}

		return true;
	};

	/**
	 * Maps an identifier to a uri. Is public so it can be overriden by custom scripts.
	 *
	 * @public
	 * @param	String	identifier 	The namespace identifier
	 * @return	String				The uri
	 */
	_namespace.mapIdentifierToUri = function(identifier) {
		var regexp = new RegExp('\\' + Namespace.separator, 'g');
		return Namespace.baseUri + identifier.replace(regexp, '/') + '.js';
	};

	/**
	 * Loads a remote script atfer mapping the identifier to an uri
	 *
	 * @param	String		identifier			The namespace identifier
	 * @param	Function	successCallback		When set, the file will be loaded asynchronously. Will be called when the file is loaded
	 * @param	Function	errorCallback		Callback to be called when an error occurs
	 * @return	Boolean							Success of failure when loading synchronously
	 */
	_loadScript = function(identifier) {
		var successCallback = arguments[1] || false;
		var errorCallback = arguments[2] || false;
		var async = successCallback != false;
		var uri = _namespace.mapIdentifierToUri(identifier);
		var event = { 'identifier': identifier, 'uri': uri, 'async': async, 'callback': successCallback };

		var xhr = _createXmlHttpRequest();
		xhr.open("GET", uri, async);

		if (async) {
			xhr.onreadystatechange = function() {
				if (xhr.readyState == 4) {
					if (_isHttpRequestSuccessful(xhr.status || 0)) {
						_createScript(xhr.responseText);
						_dispatchEvent('include', event);
						successCallback();
						return;
					}
					event.status = xhr.status;
					_dispatchEvent('includeError', event);
					errorCallback && errorCallback();
				}
			};
		}

		xhr.send(null);

		if (!async) {
			if (_isHttpRequestSuccessful(xhr.status || 0)) {
				_createScript(xhr.responseText);
				_dispatchEvent('include', event);
				return true;
			}
			event.status = xhr.status;
			_dispatchEvent('includeError', event);
			return false;
		}
	};

	/**
	 * Includes a remote javascript file identified by the specified namespace string. The identifier
	 * must point to a class. Separators in the string will be converted to slashes and the .js extension will be appended.
	 *
	 * @public
	 * @param	String		identifier	The namespace string
	 * @param	Function	callback	(OPTIONAL) A function to call when the remote script has been included
	 */
	_namespace.include = function(identifier) {
		var successCallback = arguments[1] || false;
		var errorCallback = arguments[2] || false;

		// checks if the identifier is not already included
		if (_includedIdentifiers[identifier]) {
			successCallback && successCallback();
			return true;
		}

		if (successCallback) {
			_loadScript(identifier, function() {
				_includedIdentifiers[identifier] = true;
				successCallback();
			}, errorCallback);
		} else {
			if (_loadScript(identifier)) {
				_includedIdentifiers[identifier] = true;
				return true;
			}
			return false;
		}
	};

	/**
	 * Imports properties from the specified namespace to the global space (ie. under window)
	 *
	 * The identifier string can contain the * wildcard character as its last segment (eg: com.test.*)
	 * which will import all properties from the namespace.
	 *
	 * If not, the targeted namespace will be imported (ie. if com.test is imported, the test object
	 * will now be global). If the targeted object is not found, it will be included using include().
	 *
	 * @public
	 * @param	String		identifier 	The namespace string
	 * @param	Function	callback	(OPTIONAL) A function to call when the process is completed (including the include() if used)
	 * @param	Boolean		autoInclude	(OPTIONAL) Whether to automatically auto include the targeted object is not found. Default is Namespace.autoInclude
	 */
	_namespace.use = function(identifier) {
		var identifiers 		= _toArray(identifier);
		var callback 			= arguments[1] || false;
		var autoInclude 		= arguments.length > 2 ? arguments[2] : Namespace.autoInclude;
		var event				= { 'identifier': identifier };

		for (var i = 0; i < identifiers.length; i++) {
			identifier = identifiers[i];

			var parts = identifier.split(Namespace.separator);
			var target = parts.pop();
			var ns = _namespace(parts.join(Namespace.separator));

			if (target == '*') {
				// imports all objects from the identifier, can't use include() in that case
				for (var objectName in ns) {
					window[objectName] = ns[objectName];
				}
			} else {
				// imports only one object
				if (ns[target]) {
					// the object exists, import it
					window[target] = ns[target];
				} else {
					// the object does not exist
					if (autoInclude) {
						// try to auto include it
						if (callback) {
							_namespace.include(identifier, function() {
								window[target] = ns[target];

								if (i + 1 < identifiers.length) {
									// we continue to unpack the rest from here
									_namespace.unpack(identifiers.slice(i + 1), callback, autoInclude);
								} else {
									// no more identifiers to unpack
									_dispatchEvent('use', event);
									callback && callback();
								}
							});
							return;
						} else {
							_namespace.include(identifier);
							window[target] = ns[target];
						}
					}
				}
			}

		}

		// all identifiers have been unpacked
		_dispatchEvent('use', event);
		callback && callback();
	};

	/**
	 * Binds the include() and unpack() method to a specified identifier
	 *
	 * @public
	 * @param	String	identifier 	The namespace identifier
	 * @return	Object
	 */
	_namespace.from = function(identifier) {
		return {
			/**
			 * Includes the identifier specified in from()
			 *
			 * @see Namespace.include()
			 */
			include: function() {
				var callback = arguments[0] || false;
				_namespace.include(identifier, callback);
			},
			/**
			 * Includes the identifier specified in from() and unpack
			 * the specified indentifier in _identifier
			 *
			 * @see Namespace.use()
			 */
			use: function(_identifier) {
				var callback = arguments[1] || false;
				if (_identifier.charAt(0) == '.') {
					_identifier = identifier + _identifier;
				}

				if (callback) {
					_namespace.include(identifier, function() {
						_namespace.use(_identifier, callback, false);
					});
				} else {
					_namespace.include(identifier);
					_namespace.use(_identifier, callback, false);
				}
			}
		};
	};

	/**
	 * Registers a namespace so it won't be included
	 *
	 * Idea and code submitted by Nathan Smith (http://github.com/smith)
	 *
	 * @param	String		identifier
	 */
	_namespace.provide = function(identifier) {
		if (!(identifier in _includedIdentifiers)) {
			_dispatchEvent('provide', { 'identifier': identifier });
			_includedItentifiers[identifier] = true;
		}
	};

	/**
	 * Registers a function to be called when the specified event is dispatched
	 *
	 * @param	String		eventName
	 * @param	Function	callback
	 */
	_namespace.addEventListener = function(eventName, callback) {
		if (!_listeners[eventName]) _listeners[eventName] = [];
		_listeners[eventName].push(callback);
	};

	/**
	 * Unregisters an event listener
	 *
	 * @param	String		eventName
	 * @param	Function	callback
	 */
	_namespace.removeEventListener = function(eventName, callback) {
		if (!_listeners[eventName]) return;
		for (var i = 0; i < _listeners[eventName].length; i++) {
			if (_listeners[eventName][i] == callback) {
				delete _listeners[eventName][i];
				return;
			}
		}
	};

	/**
	 * Adds methods to javascript native's object
	 * Inspired by http://thinkweb2.com/projects/prototype/namespacing-made-easy/
	 *
	 * @public
	 */
	_namespace.registerNativeExtensions = function() {
		/**
		 * @see Namespace()
		 */
		String.prototype.namespace = function() {
			var klasses = arguments[0] || {};
			return _namespace(this.valueOf(), klasses);
		};
		/**
		 * @see Namespace.include()
		 */
		String.prototype.include = function() {
			var callback = arguments[0] || false;
			return _namespace.include(this.valueOf(), callback);
		}
		/**
		 * @see Namespace.use()
		 */
		String.prototype.use = function() {
			var callback = arguments[0] || false;
			return _namespace.use(this.valueOf(), callback);
		}
		/**
		 * @see Namespace.from()
		 */
		String.prototype.from = function() {
			return _namespace.from(this.valueOf());
		}
		/**
		 * @see Namespace.provide()
		 * Idea and code submitted by Nathan Smith (http://github.com/smith)
		 */
		String.prototype.provide = function() {
			return _namespace.provide(this.valueOf());
		}
		/**
		 * @see Namespace.use()
		 */
		Array.prototype.use = function() {
			var callback = arguments[0] || false;
			return _namespace.use(this, callback);
		}
	};

	return _namespace;
})();

/**
 * Namespace segment separator
 *
 * @var String
 */
Namespace.separator = '.';

/**
 * Base uri when using Namespace.include()
 * Must end with a slash
 *
 * @var String
 */
Namespace.baseUri = './';

/**
 * Whether to automatically call Namespace.include() when Namespace.import()
 * does not find the targeted object.
 *
 * @var Boolean
 */
Namespace.autoInclude = true;

<|endoftext|>


<commit_before>'use strict'

const fs = require('fs')
const gm = require('gm').subClass({imageMagick: true})
const aws = require('aws-sdk')
const mime = require('mime')
const BUCKET = process.env.BUCKET
const s3 = new aws.S3({apiVersion: '2006-03-01'})

exports.hasImage = function (Model, options) {
  let name = options.name
  let Name = name[0].toUpperCase() + name.slice(1)

  Model.prototype[`upload${Name}`] = function (file) {
    return new Upload(file, this, options).send()
  }
}

class Upload {

  constructor (file, model, options) {
    this.file = file
    this.model = model
    this.name = options.name
    this.sizes = Object.assign(options.sizes, {original: null})
  }

  get ext () {
    return mime.extension(this.mimetype)
  }

  get path () {
    return this.file.path
  }

  get mimetype () {
    return this.file.mimetype
  }

  s3Key (size) {
    return `${this.model.tableName}/${this.model.id}/${size}.${this.ext}`
  }

  cleanup () {
    fs.unlink(this.path)
  }

  send () {
    return Promise.all(
      Object.keys(this.sizes).map(this.put.bind(this))
    ).then(() => {
      this.cleanup()
      return this.model.update({
        [`${this.name}_updated_at`]: new Date(),
        [`${this.name}_ext`]: this.ext
      })
    }).catch((e) => {
      this.cleanup()
      throw e
    })
  }

  stream (size) {
    if (size === 'original') return fs.createReadStream(this.path)
    let width = this.sizes[size]
    return gm(this.path).resize(width, width).noProfile().stream(this.ext)
  }

  put (size) {
    return new Promise((resolve, reject) => {
      s3.upload({
        ACL: 'public-read',
        Body: this.stream(size),
        Bucket: BUCKET,
        CacheControl: `max-age=${60 * 60 * 24 * 7}, public`,
        ContentType: this.mimetype,
        Key: this.s3Key(size)
      }, e => e ? reject(e) : resolve())
    })
  }

}
<commit_msg>Image paths.<commit_after>'use strict'

const fs = require('fs')
const gm = require('gm').subClass({imageMagick: true})
const aws = require('aws-sdk')
const mime = require('mime')
const BUCKET = process.env.BUCKET
const s3 = new aws.S3({apiVersion: '2006-03-01'})

exports.hasImage = function (Model, options) {
  const name = options.name
  const Name = name[0].toUpperCase() + name.slice(1)

  Model.prototype[`upload${Name}`] = function (file) {
    return new Upload(file, this, options).send()
  }

  Model.prototype[`${name}Key`] = function (size) {
    const ext = this[`${name}_ext`]
    return `${this.tableName}/${this.id}/${name}/${size}.${ext}`
  }

  Model.prototype[`${name}Path`] = function (size) {
    const key = this[`${name}Key`](size)
    const updated_at = this[`${name}_updated_at`]
    return `/assets/${key}?${+updated_at}`
  }
}

class Upload {

  constructor (file, model, options) {
    this.file = file
    this.model = model
    this.name = options.name
    this.sizes = Object.assign(options.sizes, {original: null})
  }

  get ext () {
    return mime.extension(this.mimetype)
  }

  get path () {
    return this.file.path
  }

  get mimetype () {
    return this.file.mimetype
  }

  s3Key (size) {
    return `${this.model.tableName}/${this.model.id}/${this.name}/${size}.${this.ext}`
  }

  cleanup () {
    fs.unlink(this.path)
  }

  send () {
    return Promise.all(
      Object.keys(this.sizes).map(this.put.bind(this))
    ).then(() => {
      this.cleanup()
      return this.model.update({
        [`${this.name}_updated_at`]: new Date(),
        [`${this.name}_ext`]: this.ext
      })
    }).catch((e) => {
      this.cleanup()
      throw e
    })
  }

  stream (size) {
    if (size === 'original') return fs.createReadStream(this.path)
    let width = this.sizes[size]
    return gm(this.path).resize(width, width, '>').noProfile().stream(this.ext)
  }

  put (size) {
    return new Promise((resolve, reject) => {
      s3.upload({
        ACL: 'public-read',
        Body: this.stream(size),
        Bucket: BUCKET,
        CacheControl: `max-age=${60 * 60 * 24 * 7}, public`,
        ContentType: this.mimetype,
        Key: this.s3Key(size)
      }, e => e ? reject(e) : resolve())
    })
  }

}
<|endoftext|>


<commit_before>import CodeMirror, { Doc } from 'codemirror'

export function init (rootEl) {
  return CodeMirror(rootEl)
}

export function openDoc (cm, content) {
  const newDoc = Doc(content)
  cm.swapDoc(newDoc)
  return newDoc
}
<commit_msg>Configure CM with latex parser<commit_after>import CodeMirror, { Doc } from 'codemirror'

import LatexParser from './ide/editor/codemirror/parser'

export function init (rootEl) {
  CodeMirror.defineMode('latex', () => new LatexParser())
  CodeMirror.defineMIME('application/x-tex', 'latex')
  CodeMirror.defineMIME('application/x-latex', 'latex')

  return CodeMirror(rootEl, {
    mode: 'latex'
  })
}

export function openDoc (cm, content) {
  const newDoc = Doc(content, 'latex')
  cm.swapDoc(newDoc)
  return newDoc
}
<|endoftext|>


<commit_before>{
	"hi1": "KoolProxy是一款支持正则的代理软件，可以帮助你轻松的过滤你想屏蔽的网页或者网页的部分内容，支持https！",
	"hi2": "",
	"hi3": "",
	"rules":
	[
	[
		"视频规则",
		"https://rules.ngrok.wang/1.dat",
		"none",
		"2017-02-15 09:10:29"
	],
	[
		"静态规则",
		"https://rules.ngrok.wang/koolproxy.txt",
		"none",
		"2017-02-15 09:10:35"
	],
	[
		"视频规则(new)[请勿与上面的视频规则一起使用]",
		"http://entware.mirrors.ligux.com/koolproxy/1.dat",
		"none",
		"2017-3-9 16:31:12"
	],
	[
		"静态规则(new)[请勿与上面的静态规则一起使用]",
		"http://entware.mirrors.ligux.com/koolproxy/koolproxy.txt",
		"none",
		"2017-3-9 16:31:12"
	],
	[
		"防败家规则",
		"https://rules.ngrok.wang/no_shopping.txt",
		"none",
		"2017-02-15 09:10:35"
	]
	]
}
<commit_msg>Update shadowsocks_msg.json.js<commit_after>{
	"hi1": "说明说明：请在下面的账号设置表格中填入你的shadowsocks账号信息，选择好一个模式，点击提交后就能使用代理服务。",
	"hi2": "",
	"hi3": "",
	"rules":
	[
	[
		"视频规则",
		"https://rules.ngrok.wang/1.dat",
		"none",
		"2017-02-15 09:10:29"
	],
	[
		"静态规则",
		"https://rules.ngrok.wang/koolproxy.txt",
		"none",
		"2017-02-15 09:10:35"
	],
	[
		"视频规则(new)[请勿与上面的视频规则一起使用]",
		"http://entware.mirrors.ligux.com/koolproxy/1.dat",
		"none",
		"2017-3-9 16:31:12"
	],
	[
		"静态规则(new)[请勿与上面的静态规则一起使用]",
		"http://entware.mirrors.ligux.com/koolproxy/koolproxy.txt",
		"none",
		"2017-3-9 16:31:12"
	],
	[
		"防败家规则",
		"https://rules.ngrok.wang/no_shopping.txt",
		"none",
		"2017-02-15 09:10:35"
	]
	]
}
<|endoftext|>


<commit_before>/**
 * Spins up two web servers
 *   - http-server sends the static assets in dist and handles the /config.json endpoint
 *   - cors-proxy adds the necessary headers for xdomain access to the REST API
 */

var pkg = require('./package.json'),
    fs = require('fs'),
    morgan = require('morgan'),
    http = require('http'),
    https = require('https'),
    express = require('express'),
    finalhandler = require('finalhandler'),
    serveFavicon = require('serve-favicon'),
    corsAnywhere = require('cors-anywhere');

var COOPR_HOME = process.env.COOPR_HOME || (__dirname + '/../'),
    COOPR_SSL = ('true' === process.env.COOPR_SSL),
    COOPR_UI_PORT = ( COOPR_SSL
      ? parseInt(process.env.COOPR_UI_SSL_PORT || 8443, 10)
      : parseInt(process.env.COOPR_UI_PORT || 8080, 10)
    ),
    COOPR_UI_KEY_FILE = process.env.COOPR_UI_KEY_FILE || COOPR_HOME + 'cert/server.key',
    COOPR_UI_CERT_FILE = process.env.COOPR_UI_CERT_FILE || COOPR_HOME + 'cert/server.crt',
    COOPR_CORS_PORT = parseInt(process.env.COOPR_CORS_PORT || 8081, 10),
    COOPR_SERVER_URI = process.env.COOPR_SERVER_URI || 'http://127.0.0.1:55054';

COOPR_SERVER_URI = COOPR_SERVER_URI.replace('/localhost:', '\/127.0.0.1:')

var color = {
        hilite: function (v) {
            return '\x1B[7m' + v + '\x1B[27m';
        },
        green: function (v) {
            return '\x1B[40m\x1B[32m' + v + '\x1B[39m\x1B[49m';
        },
        pink: function (v) {
            return '\x1B[40m\x1B[35m' + v + '\x1B[39m\x1B[49m';
        }
    };

morgan.token('cooprcred', function (req, res) {
    return color.pink(req.headers['coopr-userid'] + '/' + req.headers['coopr-tenantid']);
});

var httpLabel = color.green('http'),
    corsLabel = color.pink('cors'),
    httpStaticLogger = morgan(httpLabel + ' :method :url :status'),
    httpIndexLogger = morgan(httpLabel + ' :method ' + color.hilite(':url') + ' :status'),
    corsLogger = morgan(corsLabel + ' :method :url :cooprcred :status', {
        skip: function (req, res) {
            return req.method === 'OPTIONS'
        }
    });

console.log(color.hilite(pkg.name) + ' v' + pkg.version + ' starting up...');

/**
 * Express application
 */

var app = express();

try { app.use(serveFavicon(__dirname + '/dist/assets/img/favicon.png')); }
catch(e) { console.error("Favicon missing! Did you run `gulp build`?"); }

// serve the config file
app.get('/config.js', function (req, res) {
    var data = JSON.stringify({
        // the following will be available in angular via the "MY_CONFIG" injectable

        COOPR_SERVER_URI: COOPR_SERVER_URI,
        COOPR_CORS_PORT: COOPR_CORS_PORT,
        authorization: req.headers.authorization

    });
    res.header({
        'Content-Type': 'text/javascript',
        'Cache-Control': 'no-store, must-revalidate'
    });
    res.send('angular.module("' + pkg.name + '.config", [])' +
        '.constant("MY_CONFIG",' + data + ');');
});

// serve static assets
app.use('/assets', [
  httpStaticLogger,
  express.static(__dirname + '/dist/assets', {
    index: false
  }),
  function(req, res) {
    finalhandler(req, res)(false); // 404
  }
]);

app.get('/robots.txt', [
    httpStaticLogger,
    function (req, res) {
        res.type('text/plain');
        res.send('User-agent: *\nDisallow: /');
    }
]);

// any other path, serve index.html
app.all('*', [
    httpIndexLogger,
    function (req, res) {
        res.sendFile(__dirname + '/dist/index.html');
    }
]);

/**
 * HTTP(S) server
 */
var server;
if (COOPR_SSL) {
    server = https.createServer({
        key: fs.readFileSync(COOPR_UI_KEY_FILE, 'utf-8'),
        cert: fs.readFileSync(COOPR_UI_CERT_FILE, 'utf-8')
    }, app);
}
else {
    server = http.createServer(app);
}

server.listen(COOPR_UI_PORT, null, null, function () {
    console.info(httpLabel + ' listening on port %s', COOPR_UI_PORT);
});

/**
 * CORS proxy
 */
corsAnywhere.createServer({
    requireHeader: ['x-requested-with'],
    removeHeaders: ['cookie', 'cookie2']
})
    .on('request', function (req, res) {
        corsLogger(req, res, function noop() {});
    })
    .listen(COOPR_CORS_PORT, '0.0.0.0', function () {
        console.info(corsLabel + ' listening on port %s', COOPR_CORS_PORT);
    });
<commit_msg>Hotfix<commit_after>/**
 * Spins up two web servers
 *   - http-server sends the static assets in dist and handles the /config.json endpoint
 *   - cors-proxy adds the necessary headers for xdomain access to the REST API
 */

var pkg = require('./package.json'),
    fs = require('fs'),
    morgan = require('morgan'),
    http = require('http'),
    https = require('https'),
    express = require('express'),
    finalhandler = require('finalhandler'),
    serveFavicon = require('serve-favicon'),
    corsAnywhere = require('cors-anywhere');

var COOPR_HOME = process.env.COOPR_HOME || (__dirname + '/../'),
    COOPR_SSL = ('true' === process.env.COOPR_SSL),
    COOPR_UI_PORT = ( COOPR_SSL
      ? parseInt(process.env.COOPR_UI_SSL_PORT || 8443, 10)
      : parseInt(process.env.COOPR_UI_PORT || 8080, 10)
    ),
    COOPR_UI_KEY_FILE = process.env.COOPR_UI_KEY_FILE || COOPR_HOME + 'cert/server.key',
    COOPR_UI_CERT_FILE = process.env.COOPR_UI_CERT_FILE || COOPR_HOME + 'cert/server.crt',
    COOPR_CORS_PORT = parseInt(process.env.COOPR_CORS_PORT || 8081, 10),
    COOPR_SERVER_URI = process.env.COOPR_SERVER_URI || 'http://127.0.0.1:55054';

COOPR_SERVER_URI = COOPR_SERVER_URI.replace('/localhost:', '/127.0.0.1:');

var color = {
        hilite: function (v) {
            return '\x1B[7m' + v + '\x1B[27m';
        },
        green: function (v) {
            return '\x1B[40m\x1B[32m' + v + '\x1B[39m\x1B[49m';
        },
        pink: function (v) {
            return '\x1B[40m\x1B[35m' + v + '\x1B[39m\x1B[49m';
        }
    };

morgan.token('cooprcred', function (req, res) {
    return color.pink(req.headers['coopr-userid'] + '/' + req.headers['coopr-tenantid']);
});

var httpLabel = color.green('http'),
    corsLabel = color.pink('cors'),
    httpStaticLogger = morgan(httpLabel + ' :method :url :status'),
    httpIndexLogger = morgan(httpLabel + ' :method ' + color.hilite(':url') + ' :status'),
    corsLogger = morgan(corsLabel + ' :method :url :cooprcred :status', {
        skip: function (req, res) {
            return req.method === 'OPTIONS'
        }
    });

console.log(color.hilite(pkg.name) + ' v' + pkg.version + ' starting up...');

/**
 * Express application
 */

var app = express();

try { app.use(serveFavicon(__dirname + '/dist/assets/img/favicon.png')); }
catch(e) { console.error("Favicon missing! Did you run `gulp build`?"); }

// serve the config file
app.get('/config.js', function (req, res) {
    var data = JSON.stringify({
        // the following will be available in angular via the "MY_CONFIG" injectable

        COOPR_SERVER_URI: COOPR_SERVER_URI,
        COOPR_CORS_PORT: COOPR_CORS_PORT,
        authorization: req.headers.authorization

    });
    res.header({
        'Content-Type': 'text/javascript',
        'Cache-Control': 'no-store, must-revalidate'
    });
    res.send('angular.module("' + pkg.name + '.config", [])' +
        '.constant("MY_CONFIG",' + data + ');');
});

// serve static assets
app.use('/assets', [
  httpStaticLogger,
  express.static(__dirname + '/dist/assets', {
    index: false
  }),
  function(req, res) {
    finalhandler(req, res)(false); // 404
  }
]);

app.get('/robots.txt', [
    httpStaticLogger,
    function (req, res) {
        res.type('text/plain');
        res.send('User-agent: *\nDisallow: /');
    }
]);

// any other path, serve index.html
app.all('*', [
    httpIndexLogger,
    function (req, res) {
        res.sendFile(__dirname + '/dist/index.html');
    }
]);

/**
 * HTTP(S) server
 */
var server;
if (COOPR_SSL) {
    server = https.createServer({
        key: fs.readFileSync(COOPR_UI_KEY_FILE, 'utf-8'),
        cert: fs.readFileSync(COOPR_UI_CERT_FILE, 'utf-8')
    }, app);
}
else {
    server = http.createServer(app);
}

server.listen(COOPR_UI_PORT, null, null, function () {
    console.info(httpLabel + ' listening on port %s', COOPR_UI_PORT);
});

/**
 * CORS proxy
 */
corsAnywhere.createServer({
    requireHeader: ['x-requested-with'],
    removeHeaders: ['cookie', 'cookie2']
})
    .on('request', function (req, res) {
        corsLogger(req, res, function noop() {});
    })
    .listen(COOPR_CORS_PORT, '0.0.0.0', function () {
        console.info(corsLabel + ' listening on port %s', COOPR_CORS_PORT);
    });
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * JSON Parser.
 */
var JSONParser = SkipGrammar.create({
  __proto__: grammar,

  START: copyInput(sym('objAsString')),

  objAsString: copyInput(sym('obj')),

  obj: seq1(1, '{', repeat(sym('pair'), ','), '}'),
    pair: seq(sym('key'), ':', sym('value')),

      key: alt(
        sym('symbol'),
        sym('string')),

        symbol: noskip(str(seq(sym('char'), str(repeat(sym('alpha')))))),
          char: alt(range('a','z'), range('A','Z'), '_', '$'),
          alpha: alt(sym('char'), range('0', '9')),

  // TODO(kgr): This should just be 'alt' but that isn't working for some
  // unknown reason. Probably related to SkipGrammar.  Fix and change to
  // just 'alt'.
  value: simpleAlt(
    sym('function literal'),
    sym('expr'),
    sym('number'),
    sym('string'),
    sym('obj'),
    sym('bool'),
    sym('array')
  ),

  expr: str(seq(
    sym('symbol'), optional(str(alt(
      seq('.', sym('expr')),
      seq('(', str(repeat(sym('value'), ',')), ')')))))),

  number: noskip(seq(
    optional('-'),
    repeat(range('0', '9'), null, 1),
    optional(seq('.', repeat(range('0', '9')))))),

  string: noskip(alt(
    sym('single quoted string'),
    sym('double quoted string'))),

    'double quoted string': seq1(1, '"', str(repeat(sym('double quoted char'))), '"'),
    'double quoted char': alt(
      sym('escape char'),
      literal('\\"', '"'),
      notChar('"')),

    'single quoted string': seq1(1, "'", str(repeat(sym('single quoted char'))), "'"),
    'single quoted char': alt(
      sym('escape char'),
      literal("\\'", "'"),
      notChar("'")),

    'escape char': alt(
      literal('\\\\', '\\'),
      literal('\\n', '\n')),

  bool: alt(
    literal('true', true),
    literal('false', false)),

  array: seq1(1, '[', repeat(sym('value'), ','), ']'),

  'function literal': seq(
    'function',
    optional(sym('symbol')),
    '(',
    repeat(sym('symbol'), ','),
    ')',
    '{',
    repeat(notChar('}')), // TODO(kgr): this is a very cheap/limited hack, replace with real JS grammar.
//    repeat(sym('value'), ';'), // TODO(kgr): replace with 'statement'.
    '}')

}.addActions({
  obj: function(v) {
    var m = {};
    for ( var i = 0 ; i < v.length ; i++ ) m[v[i][0]] = v[i][2];
    return m;
  }
}), repeat0(alt(' ', '\t', '\n', '\r')));

/*
TODO: move to FUNTest
var res = JSONParser.parseString('{a:1,b:"2",c:false,d:f(),e:g(1,2),f:h.j.k(1),g:[1,"a",false,[]]}');
console.log(res);
*/<commit_msg>Slight performance improvement.<commit_after>/**
 * @license
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * JSON Parser.
 */
var JSONParser = SkipGrammar.create({
  __proto__: grammar,

  START: copyInput(sym('objAsString')),

  objAsString: copyInput(sym('obj')),

  obj: seq1(1, '{', repeat(sym('pair'), ','), '}'),
    pair: seq(sym('key'), ':', sym('value')),

      key: alt(
        sym('symbol'),
        sym('string')),

        symbol: noskip(str(seq(sym('char'), str(repeat(sym('alpha')))))),
          char: alt(range('a','z'), range('A','Z'), '_', '$'),
          // Slightly faster to inline sym('char') until AltParser does it automatically
          alpha: alt(range('a','z'), range('A','Z'), '_', '$', /* sym('char') */ range('0', '9')),

  // TODO(kgr): This should just be 'alt' but that isn't working for some
  // unknown reason. Probably related to SkipGrammar.  Fix and change to
  // just 'alt'.
  value: simpleAlt(
    sym('function literal'),
    sym('expr'),
    sym('number'),
    sym('string'),
    sym('obj'),
    sym('bool'),
    sym('array')
  ),

  expr: str(seq(
    sym('symbol'), optional(str(alt(
      seq('.', sym('expr')),
      seq('(', str(repeat(sym('value'), ',')), ')')))))),

  number: noskip(seq(
    optional('-'),
    repeat(range('0', '9'), null, 1),
    optional(seq('.', repeat(range('0', '9')))))),

  string: noskip(alt(
    sym('single quoted string'),
    sym('double quoted string'))),

    'double quoted string': seq1(1, '"', str(repeat(sym('double quoted char'))), '"'),
    'double quoted char': alt(
      sym('escape char'),
      literal('\\"', '"'),
      notChar('"')),

    'single quoted string': seq1(1, "'", str(repeat(sym('single quoted char'))), "'"),
    'single quoted char': alt(
      sym('escape char'),
      literal("\\'", "'"),
      notChar("'")),

    'escape char': alt(
      literal('\\\\', '\\'),
      literal('\\n', '\n')),

  bool: alt(
    literal('true', true),
    literal('false', false)),

  array: seq1(1, '[', repeat(sym('value'), ','), ']'),

  'function literal': seq(
    'function',
    optional(sym('symbol')),
    '(',
    repeat(sym('symbol'), ','),
    ')',
    '{',
    repeat(notChar('}')), // TODO(kgr): this is a very cheap/limited hack, replace with real JS grammar.
//    repeat(sym('value'), ';'), // TODO(kgr): replace with 'statement'.
    '}')

}.addActions({
  obj: function(v) {
    var m = {};
    for ( var i = 0 ; i < v.length ; i++ ) m[v[i][0]] = v[i][2];
    return m;
  }
}), repeat0(alt(' ', '\t', '\n', '\r')));

/*
TODO: move to FUNTest
var res = JSONParser.parseString('{a:1,b:"2",c:false,d:f(),e:g(1,2),f:h.j.k(1),g:[1,"a",false,[]]}');
console.log(res);
*/<|endoftext|>


<commit_before>'use strict';

const core = require('./core.js');
const fd = require('./field.js');
const serv = require('./../services/services.js');
const servWeather = require('./../services/weatherService.js');
const db = require('./../AslanDBConnector.js');
/*
*   Fonction qui traite les réponses de type bonjour
*/
function processingGrettings(information, response) {
	if(information != undefined && response != undefined && information.first_name != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{prenom}") != -1) {
			var answer = fd.replaceField(response.result.fulfillment.speech, "{prenom}", information.first_name);
			core.prepareMessage(answer);
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingHour(response) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined
		&& response.result.parameters.ville != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{heure}") != -1) {
			console.log(response.result.parameters.ville);
			serv.getTimeAt(response.result.parameters.ville, function(hour) {
				var answer = fd.replaceField(response.result.fulfillment.speech, "{heure}",hour);
				answer = fd.replaceField(answer,
					"{\"ville\":[\"" + response.result.parameters.ville + "\"]}", response.result.parameters.ville);
				core.prepareMessage(answer);
			});
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingFountain(response) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined
		&& response.result.parameters.location != undefined) {
		serv.nearestFontaines(response.result.parameters.location, 20, function(foutains) {
			message["attachment"] = foutains;
			core.prepareMessage(message);
		});
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingCitizen(response) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined
		&& response.result.parameters.ville != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{heure}") != -1) {
			console.log(response.result.parameters.ville);
			serv.getTimeAt(response.result.parameters.ville, function(hour) {
				var answer = fd.replaceField(response.result.fulfillment.speech, "{heure}",hour);
				answer = fd.replaceField(answer,
					"{\"ville\":[\"" + response.result.parameters.ville + "\"]}", response.result.parameters.ville);
				console.log(answer);
				core.prepareMessage(answer);
			});
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingDate(response) {

}

function processingWeather(response, location) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{meteo}") != -1) {
			var coord = "";
			if(location) {

			} else if(response.result.parameters.ville != undefined){
				coord = response.result.parameters.ville;
			}
			serv.JSONP_LocalWeather(coord, formattedDate(), function(data) {
				var weather = data.current_condition['0'].lang_fr + ", " + data.current_condition['0'].temp_C + "°";
				var answer = fd.replaceField(response.result.fulfillment.speech, "{meteo}", weather);
				if(response.result.parameters.ville != undefined){
					answer = fd.replaceField(answer,
						"{\"ville\":[\"" + response.result.parameters.ville + "\"]}", response.result.parameters.ville);
				}
				core.prepareMessage(answer);
			});
		} else {
			core.prepareMessage(response.result.fulfillment.speech);
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingRestaurant(response, location) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{location:[]") != -1) {
			db.insertData("conversation", object, function(err, data) {
				console.log(err);
			});
			core.prepareMessage(response.result.fulfillment.speech);
		} else if (fields.indexOf("{restaurants}") != -1 && location != null){
			/*serv.getTimeAt(response.result.parameters.ville, function(hour) {
				var answer = fd.replaceField(response.result.fulfillment.speech, "{heure}",hour);
				answer = fd.replaceField(answer,
					"{\"ville\":[\"" + response.result.parameters.ville + "\"]}", response.result.parameters.ville);
				console.log(answer);
				core.prepareMessage(answer);
			});*/
		} else {
			core.prepareMessage(response.result.fulfillment.speech);
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function formattedDate(d = new Date) {
  let month = String(d.getMonth() + 1);
  let day = String(d.getDate());
  const year = String(d.getFullYear());

  if (month.length < 2) month = '0' + month;
  if (day.length < 2) day = '0' + day;

  return `${year}-${month}-${day}/`;
}
exports.processingGrettings = processingGrettings;
exports.processingHour = processingHour;
exports.processingFountain = processingFountain;
exports.processingCitizen = processingCitizen;
exports.processingDate = processingDate;
exports.processingWeather = processingWeather;
exports.processingRestaurant = processingRestaurant;<commit_msg>Fix bugs<commit_after>'use strict';

const core = require('./core.js');
const fd = require('./field.js');
const serv = require('./../services/services.js');
const servWeather = require('./../services/weatherService.js');
const db = require('./../AslanDBConnector.js');
/*
*   Fonction qui traite les réponses de type bonjour
*/
function processingGrettings(information, response) {
	if(information != undefined && response != undefined && information.first_name != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{prenom}") != -1) {
			var answer = fd.replaceField(response.result.fulfillment.speech, "{prenom}", information.first_name);
			core.prepareMessage(answer);
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingHour(response) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined
		&& response.result.parameters.ville != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{heure}") != -1) {
			console.log(response.result.parameters.ville);
			serv.getTimeAt(response.result.parameters.ville, function(hour) {
				var answer = fd.replaceField(response.result.fulfillment.speech, "{heure}",hour);
				answer = fd.replaceField(answer,
					"{\"ville\":[\"" + response.result.parameters.ville + "\"]}", response.result.parameters.ville);
				core.prepareMessage(answer);
			});
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingFountain(response) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined
		&& response.result.parameters.location != undefined) {
		serv.nearestFontaines(response.result.parameters.location, 20, function(foutains) {
			message["attachment"] = foutains;
			core.prepareMessage(message);
		});
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingCitizen(response) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined
		&& response.result.parameters.ville != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{heure}") != -1) {
			console.log(response.result.parameters.ville);
			serv.getTimeAt(response.result.parameters.ville, function(hour) {
				var answer = fd.replaceField(response.result.fulfillment.speech, "{heure}",hour);
				answer = fd.replaceField(answer,
					"{\"ville\":[\"" + response.result.parameters.ville + "\"]}", response.result.parameters.ville);
				console.log(answer);
				core.prepareMessage(answer);
			});
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingDate(response) {

}

function processingWeather(response, location) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{meteo}") != -1) {
			var coord = "";
			if(location) {

			} else if(response.result.parameters.ville != undefined){
				coord = response.result.parameters.ville;
			}
			servWeather.JSONP_LocalWeather(coord, formattedDate(), function(data) {
				var weather = data.current_condition['0'].lang_fr + ", " + data.current_condition['0'].temp_C + "°";
				var answer = fd.replaceField(response.result.fulfillment.speech, "{meteo}", weather);
				if(response.result.parameters.ville != undefined){
					answer = fd.replaceField(answer,
						"{\"ville\":[\"" + response.result.parameters.ville + "\"]}", response.result.parameters.ville);
				}
				core.prepareMessage(answer);
			});
		} else {
			core.prepareMessage(response.result.fulfillment.speech);
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function processingRestaurant(response, location) {
	if(response != undefined && response.result != undefined && response.result.parameters != undefined) {
		var fields = fd.extractFields(response.result.fulfillment.speech);
		console.log(fields);
		if(fields.indexOf("{location:[]") != -1) {
			db.insertData("conversation", object, function(err, data) {
				console.log(err);
			});
			core.prepareMessage(response.result.fulfillment.speech);
		} else if (fields.indexOf("{restaurants}") != -1 && location != null){
			/*serv.getTimeAt(response.result.parameters.ville, function(hour) {
				var answer = fd.replaceField(response.result.fulfillment.speech, "{heure}",hour);
				answer = fd.replaceField(answer,
					"{\"ville\":[\"" + response.result.parameters.ville + "\"]}", response.result.parameters.ville);
				console.log(answer);
				core.prepareMessage(answer);
			});*/
		} else {
			core.prepareMessage(response.result.fulfillment.speech);
		}
	} else {
		core.prepareMessage(response.result.fulfillment.speech);
	}
}

function formattedDate(d = new Date) {
  let month = String(d.getMonth() + 1);
  let day = String(d.getDate());
  const year = String(d.getFullYear());

  if (month.length < 2) month = '0' + month;
  if (day.length < 2) day = '0' + day;

  return `${year}-${month}-${day}/`;
}
exports.processingGrettings = processingGrettings;
exports.processingHour = processingHour;
exports.processingFountain = processingFountain;
exports.processingCitizen = processingCitizen;
exports.processingDate = processingDate;
exports.processingWeather = processingWeather;
exports.processingRestaurant = processingRestaurant;<|endoftext|>