Installieren lässt es sich, funktioniert aber nicht (mehr).
Gleiches gilt hier schon für die Fx Version 55.
 
															
		Installieren lässt es sich, funktioniert aber nicht (mehr).
Gleiches gilt hier schon für die Fx Version 55.
Also diese Version funktioniert hier im Nightly, aber nur mit Tampermonkey getestet:
Und im 55er eben mal mit Greasemonkey getestet, einwandfrei.
// ==UserScript==
    // @name          Shorten Title
    // @namespace     http://maltekraus.ma.funpic.de/Firefox/
    // @description   Kürzt den Titel der Themen im Firefox-Forum auf www.camp-firefox.de
    // @include       https://www.camp-firefox.de/forum/*
    // @Version       0.0.1
    // ==/UserScript==
    // Basiert auf Correct Title von Malte Kraus <http://firefox.maltekraus.de/greasemonkey/correct-title>
    (function()
    {
        var dividers = new Array();
        // you may want to change this to fit your needs:
        dividers[0] = " :: ";
        dividers[1] = " - ";
        //var title = "www.camp-firefox.de - Suchen";
        var title = document.title;
        var parts = new Array();
        for(var i = 0; i < dividers.length; i++)
        {
            if(title.indexOf(dividers[i]) > - 1)
            {
                parts[i] = title.substring(0, title.indexOf(dividers[i]));
                title = title.substring(title.indexOf(dividers[i]) + dividers[i].length, title.length);
            }
        }
        for(i = parts.length - 1; i >= 0; i--)
        {
            if(typeof parts[i] != "undefined")
           title = title;
        }
        //GM_log(title);
        document.title = title;
    })();Bitte mal testen.
Mfg.
Endor
Hier mit Violentmonkey lässt sich das Script nicht speichern und es kommt der Hinweis "Invalid Script"  
Das ging mir mit mehreren Scripten so, daher ist Violentmonkey bei mir wieder raus geflogen
und durch Tampermonkey ersetzt worden.
Mfg.
Endor
Son Schiet... Danke fürs Testen...
lässt sich das Script nicht speichern
Doch, lässt es sich, aber wie gesagt..keine Funktion mehr bzw. wird immer nur"Camp-Firefox" angezeigt, und nicht der Titel der Seite.
Das Script von Endor funktioniert hier im Fx 55 mit Greasemonkey auch nicht, gleiches Ergebnis.
[attachment=0]Screenshot (195).png[/attachment]
Verstehe ich da etwas falsch? In einem neuen Profil ohne Erweiterungen oder Scripte wird mir der Titel angezeigt (Nightly 57.0a1 (2017-09-06) (64-Bit)).
Verstehe ich da etwas falsch?
Nein, du sieht das richtig :wink:
Evtl. habe ich jetzt einen Gedankenfehler oder früher war es nicht so :-??
Aber im Code steht ja:
Kürzt den Titel der Themen im Firefox-Forum auf https://www.camp-firefox.de
Jetzt steht hier z:B. Camp-Firefox - An...
[attachment=0]Zwischenablage01.jpg[/attachment]
Und ich bin der Meinung früher stand da nur: Antwortfenster.
lässt sich das Script nicht speichern
Diesen Text einfügen:
// ==UserScript==
// @name Shorten Title
// @namespace Violentmonkey Scripts
// @match https://www.camp-firefox.de/forum/*
// @grant none
// ==/UserScript==
    // @namespace     http://maltekraus.ma.funpic.de/Firefox/
    // @description   Kürzt den Titel der Themen im Firefox-Forum auf www.camp-firefox.de
    // @Version       0.0.1
    // ==/UserScript==
    // Basiert auf Correct Title von Malte Kraus <http://firefox.maltekraus.de/greasemonkey/correct-title>
    (function()
    {
        var dividers = new Array();
        // you may want to change this to fit your needs:
        dividers[0] = " :: ";
        dividers[1] = " - ";
        //var title = "www.camp-firefox.de - Suchen";
        var title = document.title;
        var parts = new Array();
        for(var i = 0; i < dividers.length; i++)
        {
            if(title.indexOf(dividers[i]) > - 1)
            {
                parts[i] = title.substring(0, title.indexOf(dividers[i]));
                title = title.substring(title.indexOf(dividers[i]) + dividers[i].length, title.length);
            }
        }
        for(i = parts.length - 1; i >= 0; i--)
        {
            if(typeof parts[i] != "undefined")
           title = title;
        }
        //GM_log(title);
        document.title = title;
    })();Sieht dann so aus:
[attachment=1]Screenshot (197).png[/attachment]
Und ist damit auch aktiviert:
[attachment=0]Screenshot (198).png[/attachment]
Evtl. habe ich jetzt einen Gedankenfehler oder früher war es nicht so :-??
Früher war das nicht so. Ich habe dieses Script selbst lange genutzt, eben weil früher Camp Firefox - Titel des Threads im Tab stand. Warum das im Antwortfenster immer noch so ist oder ob früher wirklich nur Antwortfenster im Tab stand weiß ich nicht.
Ich habe da wohl etwas durcheinander gebracht...sorry :oops:
Mit akt. Script sieht das nämlich so aus :wink:
[attachment=0]Zwischenablage01.jpg[/attachment]
Also ich habe das Script jetzt mal bei mit bei Github hochgeladen.
Siehe hier: https://github.com/Endor8/userChr…entitle.user.js
Es lässt sich in Violentmonkey nun ganz normal installieren.
Der mag keine Leerzeichen am Anfang.
[Blockierte Grafik: https://i.imgur.com/9R5Or5O.png]
ohne Script
[Blockierte Grafik: https://i.imgur.com/FQYsZdr.png]
mit Script
Mfg.
Endor
Das Problem ist nur dass Du mit Script nicht mehr siehst welche Threads Du in verschiedenen Tabs offen hast.
[attachment=1]mit.png[/attachment]
Ohne Script siehst Du es.
[attachment=0]ohne.png[/attachment]
Ursprünglich war das Script dafür gedacht die Tabtitel so aussehen zu lassen wie auf dem 2. Screenshot.
Hallo Road-Runner
Ja du hast recht. Darum verwende ich das Script auch nicht.
Ich habe es nur auf Wunsch von Boersenfeger, mit Hilfe von 2002Andreas
so gemacht. Für mich wäre das nichts.
Mfg.
Endor
Kein Problem. Wenn Boersenfeger es so verwenden will habe ich sicher nichts dagegen einzuwenden.
Ich werde es testen.... eigentlich sollte der Titel des Beitrags angezeigt werden, ohne das Camp Firefox davor steht.....
...aber ich stelle gerade fest, das hier auf der Arbeit ganz ohne irgendwas, es so angezeigt wird, wie von mir gewünscht...  :-?? 
[attachment=0]Unbenannt.PNG[/attachment]
Ja so sieht es hier auch aus. Dafür braucht es kein Script.
Mfg.
Endor
Prima, hier zu Hause ists auch so.. dann wech damit..  
Dieses Script in Violentmonkey bewirkt bei Nutzung, das ich in Nightly aus dem Camp-Firefox-Forum ausgeloggt werde...
Liegts am Code oder an Violentmonkey?
// ==UserScript==
// @name           AutoPagerize
// @namespace      http://swdyh.yu.to/
// @description    loading next page and inserting into current page.
// @include        http://*
// @include        https://*
// @exclude        https://mail.google.com/*
// @exclude        http://b.hatena.ne.jp/*
// @exclude        http://www.facebook.com/plugins/like.php*
// @exclude        http://api.tweetmeme.com/button.js*
// @version        0.0.66
// @icon           http://autopagerize.net/img/icons/icon_032.png
// @grant          GM_getValue
// @grant          GM_setValue
// @grant          GM_addStyle
// @grant          GM_log
// @grant          GM_xmlhttpRequest
// @grant          GM_registerMenuCommand
// ==/UserScript==
//
// auther:  swdyh http://d.hatena.ne.jp/swdyh/
// version: 0.0.66 2012-08-31T18:23:34+09:00
//
// this script based on
// GoogleAutoPager(http://la.ma.la/blog/diary_200506231749.htm) and
// estseek autopager(http://la.ma.la/blog/diary_200601100209.htm).
// thanks to ma.la.
//
// Released under the GPL license
// http://www.gnu.org/copyleft/gpl.html
//
if (isGreasemonkey()) {
    var ep = getPref('exclude_patterns')
    if (ep && isExclude(ep)) {
        // FIXME
        // return
    }
}
else {
    gmCompatible()
}
var URL = 'http://autopagerize.net/'
var VERSION = '0.0.66'
var DEBUG = false
var AUTO_START = true
var CACHE_EXPIRE = 24 * 60 * 60 * 1000
var BASE_REMAIN_HEIGHT = 400
var FORCE_TARGET_WINDOW = getPref('force_target_window', true)
var XHR_TIMEOUT = 30 * 1000
var SITEINFO_IMPORT_URLS = [
    'http://wedata.net/databases/AutoPagerize/items.json',
]
var COLOR = {
    on: '#0f0',
    off: '#ccc',
    loading: '#0ff',
    terminated: '#00f',
    error: '#f0f'
}
var SITEINFO = [
    /* sample
    {
        url:          'http://(.*).google.+/(search).+',
        nextLink:     'id("navbar")//td[last()]/a',
        pageElement:  '//div[@id="res"]/div',
        exampleUrl:   'http://www.google.com/search?q=nsIObserver',
    },
    */
    /* template
    {
        url:          '',
        nextLink:     '',
        pageElement:  '',
        exampleUrl:   '',
    },
    */
]
var MICROFORMAT = {
    url:          '.*',
    nextLink:     '//a[@rel="next"] | //link[@rel="next"]',
    insertBefore: '//*[contains(@class, "autopagerize_insert_before")]',
    pageElement:  '//*[contains(@class, "autopagerize_page_element")]',
}
var AutoPager = function(info) {
    this.pageNum = 1
    this.info = info
    this.state = AUTO_START ? 'enable' : 'disable'
    var self = this
    var url = this.getNextURL(info.nextLink, document, location.href)
    if ( !url ) {
        debug("getNextURL returns null.", info.nextLink)
        return
    }
    if (info.insertBefore) {
        this.insertPoint = getFirstElementByXPath(info.insertBefore)
    }
    if (!this.insertPoint) {
        var lastPageElement = getElementsByXPath(info.pageElement).pop()
        if (lastPageElement) {
            this.insertPoint = lastPageElement.nextSibling ||
                lastPageElement.parentNode.appendChild(document.createTextNode(' '))
        }
    }
    if (!this.insertPoint) {
        debug("insertPoint not found.", lastPageElement, info.pageElement)
        return
    }
    this.requestURL = url
    this.loadedURLs = {}
    this.loadedURLs[location.href] = true
    var toggle = function() {self.stateToggle()}
    this.toggle = toggle
    GM_registerMenuCommand('AutoPagerize - on/off', toggle)
    this.scroll= function() { self.onScroll() }
    window.addEventListener("scroll", this.scroll, false)
    if (isFirefoxExtension()) {
        var div = document.createElement("div")
        div.setAttribute('id', 'autopagerize_icon')
        div.style.display = 'none'
        document.body.appendChild(div)
        this.icon = div
    }
    else if (isChromeExtension() || isSafariExtension() || isJetpack()) {
        var frame = document.createElement('iframe')
        frame.style.display = 'none'
        frame.style.position = 'fixed'
        frame.style.bottom = '0px'
        frame.style.left = '0px'
        frame.style.height = '25px'
        frame.style.border = '0px'
        frame.style.opacity = '0.8'
        frame.style.zIndex = '1000'
        frame.width = '100%'
        frame.scrolling = 'no'
        this.messageFrame = frame
        var u = settings['extension_path'] ?
            settings['extension_path'] + 'loading.html' :
            'http://autopagerize.net/files/loading.html'
        this.messageFrame.src = u
        document.body.appendChild(frame)
        if (isSafariExtension()) {
            safari.self.tab.dispatchMessage('launched', {url: location.href })
        }
        else if (isChromeExtension()) {
            chrome.extension.connect({name: "launched"}).postMessage()
        }
        if (isJetpack()) {
            postMessage({name: 'launched', data: location.href })
        }
   }
    else {
        this.initIcon()
        this.initHelp()
        GM_addStyle('@media print{#autopagerize_icon, #autopagerize_help {display: none !important;}}')
        GM_addStyle('hr.autopagerize_page_separator {clear: both;}')
        this.icon.addEventListener("mouseover", function() {
            self.viewHelp()
        }, true)
    }
    var scrollHeight = getScrollHeight()
    var bottom = getElementPosition(this.insertPoint).top ||
        this.getPageElementsBottom() ||
        (Math.round(scrollHeight * 0.8))
    this.remainHeight = scrollHeight - bottom + BASE_REMAIN_HEIGHT
    this.onScroll()
    var that = this
    document.addEventListener('AutoPagerizeToggleRequest', function() {
        that.toggle()
    }, false)
    document.addEventListener('AutoPagerizeUpdateIconRequest', function() {
        that.updateIcon()
    }, false)
    that.updateIcon()
}
AutoPager.prototype.getPageElementsBottom = function() {
    try {
        var elem = getElementsByXPath(this.info.pageElement).pop()
        return getElementBottom(elem)
    }
    catch(e) {}
}
AutoPager.prototype.initHelp = function() {
    var helpDiv = document.createElement('div')
    helpDiv.setAttribute('id', 'autopagerize_help')
    helpDiv.setAttribute('style', 'padding:5px;position:fixed;' +
                     'top:-200px;right:3px;font-size:10px;' +
                     'background:#fff;color:#000;border:1px solid #ccc;' +
                     'z-index:256;text-align:left;font-weight:normal;' +
                     'line-height:120%;font-family:verdana;')
    var toggleDiv = document.createElement('div')
    toggleDiv.setAttribute('style', 'margin:0 0 0 50px;')
    var a = document.createElement('a')
    a.setAttribute('class', 'autopagerize_link')
    a.innerHTML = 'on/off'
    a.href = 'javascript:void(0)'
    var self = this
    var toggle = function() {
        self.stateToggle()
        helpDiv.style.top = '-200px'
    }
    a.addEventListener('click', toggle, false)
    toggleDiv.appendChild(a)
    var s = '<div style="width:100px; float:left;">'
    for (var i in COLOR) {
        s += '<div style="float:left;width:1em;height:1em;' +
            'margin:0 3px;background-color:' + COLOR[i] + ';' +
            '"></div><div style="margin:0 3px">' + i + '</div>'
    }
    s += '</div>'
    var colorDiv = document.createElement('div')
    colorDiv.innerHTML = s
    helpDiv.appendChild(colorDiv)
    helpDiv.appendChild(toggleDiv)
    var versionDiv = document.createElement('div')
    versionDiv.setAttribute('style', 'clear:both;')
    versionDiv.innerHTML = '<a href="' + URL +
        '">AutoPagerize</a> ver ' + VERSION
    helpDiv.appendChild(versionDiv)
    document.body.appendChild(helpDiv)
    var proc = function(e) {
        var c_style = document.defaultView.getComputedStyle(helpDiv, '')
        var s = ['top', 'left', 'height', 'width'].map(function(i) {
            return parseInt(c_style.getPropertyValue(i)) })
        if (e.clientX < s[1] || e.clientX > (s[1] + s[3] + 11) ||
            e.clientY < s[0] || e.clientY > (s[0] + s[2] + 11)) {
                helpDiv.style.top = '-200px'
        }
    }
    helpDiv.addEventListener('mouseout', proc, false)
    this.helpLayer = helpDiv
    GM_addStyle('#autopagerize_help a { color: #0f0; text-decoration: underline;}')
}
AutoPager.prototype.viewHelp = function() {
    this.helpLayer.style.top = '3px'
}
AutoPager.prototype.onScroll = function() {
    var scrollHeight = Math.max(document.documentElement.scrollHeight,
                                document.body.scrollHeight)
    var remain = scrollHeight - window.innerHeight - window.scrollY
    if (this.state == 'enable' && remain < this.remainHeight) {
          this.request()
    }
}
AutoPager.prototype.stateToggle = function() {
    if (this.state == 'enable') {
        this.disable()
    }
    else {
        this.enable()
    }
}
AutoPager.prototype.enable = function() {
    this.state = 'enable'
    this.updateIcon()
}
AutoPager.prototype.disable = function() {
    this.state = 'disable'
    this.updateIcon()
}
AutoPager.prototype.updateIcon = function(state) {
    var st = state || this.state
    var rename = {'enable': 'on', 'disable': 'off' }
    if (rename[st]) {
        st = rename[st]
    }
    var color = COLOR[st]
    if (color) {
        if (isFirefoxExtension()) {
            chlorine.pageAction.update(color, location.href)
        }
        else if (isChromeExtension()) {
            chrome.extension.connect({name: "pageActionChannel"}).postMessage(color)
        }
        else if (isSafariExtension() || isJetpack()) {
        }
        else {
            this.icon.style.background = color
        }
    }
}
AutoPager.prototype.request = function() {
    if (!this.requestURL || this.lastRequestURL == this.requestURL) {
        return
    }
    this.lastRequestURL = this.requestURL
    var self = this
    var mime = 'text/html; charset=' + document.characterSet
    var headers = {}
    if (isSameDomain(this.requestURL)) {
        headers.Cookie = document.cookie
    }
    else {
        this.error()
        return
    }
    var opt = {
        method: 'get',
        url: this.requestURL,
        headers: headers,
        overrideMimeType: mime,
        onerror: function(res) {
            self.error()
        },
        onload: function(res) {
            if (res.finalUrl) {
                var url_s = res.finalUrl.split(/[\/\?]/)
                if (url_s[0] == location.protocol && location.host == url_s[2]) {
                    self.requestLoad.apply(self, [res])
                    return
                }
            }
            self.error()
        }
    }
    AutoPager.requestFilters.forEach(function(i) { i(opt) }, this)
    if (opt.stop) {
        this.requestURL = opt.url
    }
    else {
        this.showLoading(true)
        GM_xmlhttpRequest(opt)
    }
}
AutoPager.prototype.showLoading = function(sw) {
    if (sw) {
        this.updateIcon('loading')
        if (this.messageFrame && settings['display_message_bar']) {
            this.messageFrame.style.display = 'block'
        }
    }
    else {
        this.updateIcon('enable')
        if (this.messageFrame) {
            this.messageFrame.style.display = 'none'
        }
    }
}
AutoPager.prototype.requestLoad = function(res) {
    AutoPager.responseFilters.forEach(function(i) {
        i(res, this.requestURL)
    }, this)
    var htmlDoc = createHTMLDocumentByString(res.responseText)
    AutoPager.documentFilters.forEach(function(i) {
        i(htmlDoc, this.requestURL, this.info)
    }, this)
    try {
        var page = getElementsByXPath(this.info.pageElement, htmlDoc)
        var url = this.getNextURL(this.info.nextLink, htmlDoc, this.requestURL)
    }
    catch(e){
        log(e)
        this.error()
        return
    }
    if (!page || page.length < 1 ) {
        debug('pageElement not found.' , this.info.pageElement)
        this.terminate()
        return
    }
    if (this.loadedURLs[this.requestURL]) {
        debug('page is already loaded.', this.requestURL, this.info.nextLink)
        this.terminate()
        return
    }
    this.loadedURLs[this.requestURL] = true
    page = this.addPage(htmlDoc, page)
    AutoPager.filters.forEach(function(i) {
        i(page)
    })
    this.requestURL = url
    this.showLoading(false)
    this.onScroll()
    if (!url) {
        debug('nextLink not found.', this.info.nextLink, htmlDoc)
        this.terminate()
    }
    var ev = document.createEvent('Event')
    ev.initEvent('GM_AutoPagerizeNextPageLoaded', true, false)
    document.dispatchEvent(ev)
}
AutoPager.prototype.addPage = function(htmlDoc, page) {
    var HTML_NS  = 'http://www.w3.org/1999/xhtml'
    var hr = document.createElementNS(HTML_NS, 'hr')
    var p  = document.createElementNS(HTML_NS, 'p')
    hr.setAttribute('class', 'autopagerize_page_separator')
    p.setAttribute('class', 'autopagerize_page_info')
    var self = this
    if (page[0] && /tr/i.test(page[0].tagName)) {
        var insertParent = this.insertPoint.parentNode
        var colNodes = getElementsByXPath('child::tr[1]/child::*[self::td or self::th]', insertParent)
        var colums = 0
        for (var i = 0, l = colNodes.length; i < l; i++) {
            var col = colNodes[i].getAttribute('colspan')
            colums += parseInt(col, 10) || 1
        }
        var td = document.createElement('td')
        // td.appendChild(hr)
        td.appendChild(p)
        var tr = document.createElement('tr')
        td.setAttribute('colspan', colums)
        tr.appendChild(td)
        insertParent.insertBefore(tr, this.insertPoint)
    }
    else {
        this.insertPoint.parentNode.insertBefore(hr, this.insertPoint)
        this.insertPoint.parentNode.insertBefore(p, this.insertPoint)
    }
    p.innerHTML = 'page: <a class="autopagerize_link" href="' +
        this.requestURL.replace(/&/g, '&') + '">' + (++this.pageNum) + '</a>'
    return page.map(function(i) {
        var pe = document.importNode(i, true)
        self.insertPoint.parentNode.insertBefore(pe, self.insertPoint)
        var ev = document.createEvent('MutationEvent')
        ev.initMutationEvent('AutoPagerize_DOMNodeInserted', true, false,
                             self.insertPoint.parentNode, null,
                             self.requestURL, null, null)
        pe.dispatchEvent(ev)
        return pe
    })
}
AutoPager.prototype.initIcon = function() {
    var div = document.createElement("div")
    div.setAttribute('id', 'autopagerize_icon')
    with (div.style) {
        fontSize   = '12px'
        position   = 'fixed'
        top        = '3px'
        right      = '3px'
        background = COLOR['on']
        color      = '#fff'
        width = '10px'
        height = '10px'
        zIndex = '255'
        if (this.state != 'enable') {
            background = COLOR['off']
        }
    }
    document.body.appendChild(div)
    this.icon = div
}
AutoPager.prototype.getNextURL = function(xpath, doc, url) {
    var nextLink = getFirstElementByXPath(xpath, doc)
    if (nextLink) {
        var nextValue = nextLink.getAttribute('href') ||
            nextLink.getAttribute('action') || nextLink.value
        if (nextValue.match(/^http(s)?:/)) {
            return nextValue
        }
        else {
            var base = getFirstElementByXPath('//base[@href]', doc)
            return resolvePath(nextValue, (base ? base.href : url))
        }
    }
}
AutoPager.prototype.terminate = function() {
    window.removeEventListener('scroll', this.scroll, false)
    this.updateIcon('terminated')
    var self = this
    setTimeout(function() {
        if (self.icon) {
            self.icon.parentNode.removeChild(self.icon)
        }
        if (isSafariExtension()) {
            var mf = self.messageFrame
            mf.parentNode.removeChild(mf)
        }
    }, 1500)
}
AutoPager.prototype.error = function() {
    this.updateIcon('error')
    window.removeEventListener('scroll', this.scroll, false)
    if (isSafariExtension() || isChromeExtension() || isJetpack()) {
        var mf = this.messageFrame
        var u = settings['extension_path'] ?
            settings['extension_path'] + 'error.html' :
            'http://autopagerize.net/files/error.html'
        mf.src = u
        mf.style.display = 'block'
        setTimeout(function() {
            mf.parentNode.removeChild(mf)
        }, 3000)
    }
}
AutoPager.documentFilters = []
AutoPager.requestFilters = []
AutoPager.responseFilters = []
AutoPager.filters = []
var parseInfo = function(str) {
    var lines = str.split(/\r\n|\r|\n/)
    var re = /(^[^:]*?):(.*)$/
    var strip = function(str) {
        return str.replace(/^\s*/, '').replace(/\s*$/, '')
    }
    var info = {}
    for (var i = 0; i < lines.length; i++) {
        if (lines[i].match(re)) {
            info[RegExp.$1] = strip(RegExp.$2)
        }
    }
    var isValid = function(info) {
        var infoProp = ['url', 'nextLink', 'pageElement']
        for (var i = 0; i < infoProp.length; i++) {
            if (!info[infoProp[i]]) {
                return false
            }
        }
        return true
    }
    return isValid(info) ? info : null
}
var launchAutoPager = function(list) {
    if (list.length == 0) {
        return
    }
    for (var i = 0; i < list.length; i++) {
        try {
            if (ap) {
                return
            }
            else if (!location.href.match(list[i].url)) {
            }
            else if (!getFirstElementByXPath(list[i].nextLink)) {
                // FIXME microformats case detection.
                // limiting greater than 12 to filter microformats like SITEINFOs.
                if (list[i].url.length > 12 ) {
                    debug("nextLink not found.", list[i].nextLink)
                }
            }
            else if (!getFirstElementByXPath(list[i].pageElement)) {
                if (list[i].url.length > 12 ) {
                    debug("pageElement not found.", list[i].pageElement)
                }
            }
            else {
                ap = new AutoPager(list[i])
                return
            }
        }
        catch(e) {
            log(e)
            continue
        }
    }
}
var clearCache = function() {
    GM_setValue('cacheInfo', '')
}
var getCache = function() {
    try {
        return JSON.parse(GM_getValue('cacheInfo')) || {}
    }
    catch(e) {
        return {}
    }
}
var getCacheCallback = function(res, url) {
    if (res.status != 200) {
        return getCacheErrorCallback(url)
    }
    var info
    try {
        info = JSON.parse(res.responseText).map(function(i) { return i.data })
    }
    catch(e) {
        info = []
    }
    if (info.length > 0) {
        info = info.filter(function(i) { return ('url' in i) })
        info.sort(function(a, b) { return (b.url.length - a.url.length) })
        var r_keys = ['url', 'nextLink', 'insertBefore', 'pageElement']
        info = info.map(function(i) {
            var item = {}
            r_keys.forEach(function(key) {
                if (i[key]) {
                    item[key] = i[key]
                }
            })
            return item
        })
        cacheInfo[url] = {
            url: url,
            expire: new Date(new Date().getTime() + CACHE_EXPIRE),
            info: info
        }
        GM_setValue('cacheInfo', JSON.stringify(cacheInfo))
        launchAutoPager(info)
    }
    else {
        getCacheErrorCallback(url)
    }
}
var getCacheErrorCallback = function(url) {
    var expire = new Date(new Date().getTime() + CACHE_EXPIRE)
    if (cacheInfo[url]) {
        cacheInfo[url].expire = expire
        launchAutoPager(cacheInfo[url].info)
    }
    else {
        cacheInfo[url] = {
            url: url,
            expire: expire,
            info: []
        }
    }
    GM_setValue('cacheInfo', cacheInfo.toSource())
}
var linkFilter = function(doc, url) {
    var base = getFirstElementByXPath('//base[@href]', doc)
    var baseUrl = base ? base.href : url
    var isSameBase = isSameBaseUrl(location.href, baseUrl)
    if (!FORCE_TARGET_WINDOW && isSameBase) {
        return
    }
    var anchors = getElementsByXPath('descendant-or-self::a[@href]', doc)
    anchors.forEach(function(i) {
        var attrHref = i.getAttribute('href')
        if (FORCE_TARGET_WINDOW && !attrHref.match(/^#|^javascript:/) &&
            i.className.indexOf('autopagerize_link') < 0) {
            i.target = '_blank'
        }
        if (!isSameBase && !attrHref.match(/^#|^\w+:/)) {
            i.href = resolvePath(i.getAttribute('href'), baseUrl)
        }
    })
    if (!isSameBase) {
        var images = getElementsByXPath('descendant-or-self::img', doc)
        images.forEach(function(i) {
            i.src = resolvePath(i.getAttribute('src'), baseUrl)
        })
    }
}
AutoPager.documentFilters.push(linkFilter)
fixResolvePath()
if (typeof(window.AutoPagerize) == 'undefined') {
    window.AutoPagerize = {}
    window.AutoPagerize.addFilter = function(f) {
        AutoPager.filters.push(f)
    }
    window.AutoPagerize.addDocumentFilter = function(f) {
        AutoPager.documentFilters.push(f)
    }
    window.AutoPagerize.addResponseFilter = function(f) {
        AutoPager.responseFilters.push(f)
    }
    window.AutoPagerize.addRequestFilter = function(f) {
        AutoPager.requestFilters.push(f)
    }
    window.AutoPagerize.launchAutoPager = launchAutoPager
    var ev = document.createEvent('Event')
    ev.initEvent('GM_AutoPagerizeLoaded', true, false)
    document.dispatchEvent(ev)
}
var settings = {}
var ap = null
if (isChromeExtension()) {
    var port = chrome.extension.connect({name: "settingsChannel"})
    port.postMessage()
    port.onMessage.addListener(function(res) {
        settings = res
        if (res['exclude_patterns'] && isExclude(res['exclude_patterns'])) {
            return
        }
        launchAutoPager(SITEINFO)
        var port_ = chrome.extension.connect({name: "siteinfoChannel"})
        port_.postMessage({ url: location.href })
        port_.onMessage.addListener(function(res) {
            launchAutoPager(res)
            chrome.extension.onConnect.addListener(function(port) {
                if (port.name == "toggleRequestChannel") {
                    port.onMessage.addListener(function(msg) {
                        if (ap) {
                            ap.toggle()
                        }
                    })
                }
            })
        })
    })
}
else if (isSafariExtension()) {
    var re_exclude = /^(about:|safari-extension:)/
    if (!location.href.match(re_exclude)) {
        safari.self.addEventListener('message', function(event) {
            if (event.name === 'settings') {
                settings = event.message
                safari.self.tab.dispatchMessage('siteinfoChannel', {url: location.href })
            }
            else if (event.name === 'siteinfoChannel') {
                if (!settings['exclude_patterns'] || !isExclude(settings['exclude_patterns'])) {
                    launchAutoPager(SITEINFO)
                    launchAutoPager([MICROFORMAT])
                    launchAutoPager(event.message)
                }
            }
            else if (event.name === 'toggleRequestChannel') {
                if (ap) {
                    ap.toggle()
                }
            }
            else if (event.name === 'updateSettings') {
                settings = event.message
            }
        }, false)
        safari.self.tab.dispatchMessage('settings')
    }
}
else if (isJetpack()) {
    postMessage({ name: 'settings' })
    onMessage = function(message) {
        if (message.name == 'siteinfo') {
            // launchAutoPager(SITEINFO)
            launchAutoPager(message.data)
        }
        else if (message.name == 'settings') {
            settings = message.data
            if (settings['exclude_patterns'] && isExclude(settings['exclude_patterns'])) {
                // return
            }
            else  {
                postMessage({ name: 'siteinfo', url: location.href })
                launchAutoPager([MICROFORMAT])
            }
        }
    }
}
else {
    launchAutoPager(SITEINFO)
    GM_registerMenuCommand('AutoPagerize - clear cache', clearCache)
    var cacheInfo = getCache()
    var xhrStates = {}
    SITEINFO_IMPORT_URLS.forEach(function(i) {
        if (!cacheInfo[i] || new Date(cacheInfo[i].expire) < new Date()) {
            var opt = {
                method: 'get',
                url: i,
                onload: function(res) {
                    xhrStates[i] = 'loaded'
                    getCacheCallback(res, i)
                },
                onerror: function(res){
                    xhrStates[i] = 'error'
                    getCacheErrorCallback(i)
                },
            }
            xhrStates[i] = 'start'
            GM_xmlhttpRequest(opt)
            setTimeout(function() {
                if (xhrStates[i] == 'start') {
                    getCacheErrorCallback(i)
                }
            }, XHR_TIMEOUT)
        }
        else {
            launchAutoPager(cacheInfo[i].info)
        }
    })
    launchAutoPager([MICROFORMAT])
}
// new google search sucks!
if (location.href.match('^http://[^.]+\.google\.(?:[^.]{2,3}\.)?[^./]{2,3}/.*(&fp=)')) {
    var to = location.href.replace(/&fp=.*/, '')
    // console.log([location.href, to])
    location.href = to
}
// utility functions.
function createHTMLDocumentByString(str) {
    if (document.documentElement.nodeName != 'HTML') {
        return new DOMParser().parseFromString(str, 'application/xhtml+xml')
    }
    var html = strip_html_tag(str)
    var htmlDoc
    try {
        // We have to handle exceptions since Opera 9.6 throws
        // a NOT_SUPPORTED_ERR exception for |document.cloneNode(false)|
        // against the DOM 3 Core spec.
        htmlDoc = document.cloneNode(false)
        htmlDoc.appendChild(htmlDoc.importNode(document.documentElement, false))
    }
    catch(e) {
        htmlDoc = document.implementation.createDocument(null, 'html', null)
    }
    var fragment = createDocumentFragmentByString(html)
    try {
        fragment = htmlDoc.adoptNode(fragment)
    }
    catch(e) {
        fragment = htmlDoc.importNode(fragment, true)
    }
    htmlDoc.documentElement.appendChild(fragment)
    return htmlDoc
}
function getElementsByXPath(xpath, node) {
    var nodesSnapshot = getXPathResult(xpath, node,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE)
    var data = []
    for (var i = 0; i < nodesSnapshot.snapshotLength; i++) {
        data.push(nodesSnapshot.snapshotItem(i))
    }
    return data
}
function getFirstElementByXPath(xpath, node) {
    var result = getXPathResult(xpath, node,
        XPathResult.FIRST_ORDERED_NODE_TYPE)
    return result.singleNodeValue
}
function getXPathResult(xpath, node, resultType) {
    var node = node || document
    var doc = node.ownerDocument || node
    var resolver = doc.createNSResolver(node.documentElement || node)
    // Use |node.lookupNamespaceURI('')| for Opera 9.5
    // A workaround for bugs of Node.lookupNamespaceURI(null)
    // https://bugzilla.mozilla.org/show_bug.cgi?id=693615
    // https://bugzilla.mozilla.org/show_bug.cgi?id=694754
    var defaultNS = null
    try {
        // This follows the spec: http://www.w3.org/TR/DOM-Level-3-Core/namespaces-algorithms.html#lookupNamespaceURIAlgo
        if (node.nodeType == node.DOCUMENT_NODE) {
            defaultNS = node.documentElement.lookupNamespaceURI(null)
        }
        else {
            defaultNS = node.lookupNamespaceURI(null)
        }
    }
    catch(e) {}
    if (defaultNS) {
        const defaultPrefix = '__default__'
        xpath = addDefaultPrefix(xpath, defaultPrefix)
        var defaultResolver = resolver
        resolver = function (prefix) {
            return (prefix == defaultPrefix)
                ? defaultNS : defaultResolver.lookupNamespaceURI(prefix)
        }
    }
    return doc.evaluate(xpath, node, resolver, resultType, null)
}
function addDefaultPrefix(xpath, prefix) {
    const tokenPattern = /([A-Za-z_\u00c0-\ufffd][\w\-.\u00b7-\ufffd]*|\*)\s*(::?|\()?|(".*?"|'.*?'|\d+(?:\.\d*)?|\.(?:\.|\d+)?|[\)\]])|(\/\/?|!=|[<>]=?|[\(\[|,=+-])|([@$])/g
    const TERM = 1, OPERATOR = 2, MODIFIER = 3
    var tokenType = OPERATOR
    prefix += ':'
    function replacer(token, identifier, suffix, term, operator, modifier) {
        if (suffix) {
            tokenType =
                (suffix == ':' || (suffix == '::' &&
                 (identifier == 'attribute' || identifier == 'namespace')))
                ? MODIFIER : OPERATOR
        }
        else if (identifier) {
            if (tokenType == OPERATOR && identifier != '*') {
                token = prefix + token
            }
            tokenType = (tokenType == TERM) ? OPERATOR : TERM
        }
        else {
            tokenType = term ? TERM : operator ? OPERATOR : MODIFIER
        }
        return token
    }
    return xpath.replace(tokenPattern, replacer)
}
function createDocumentFragmentByString(str) {
    var range = document.createRange()
    range.setStartAfter(document.body)
    return range.createContextualFragment(str)
}
function log(message) {
    if (typeof console == 'object') {
        console.log(message)
    }
    else {
        GM_log(message)
    }
}
function debug() {
    if ( typeof DEBUG != 'undefined' && DEBUG ) {
        if (console.log.apply) {
            console.log.apply(console, arguments)
        }
        else {
            Function.prototype.apply.apply(console.log, [console, arguments])
        }
    }
}
function getElementPosition(elem) {
    var offsetTrail = elem
    var offsetLeft  = 0
    var offsetTop   = 0
    while (offsetTrail) {
        offsetLeft += offsetTrail.offsetLeft
        offsetTop  += offsetTrail.offsetTop
        offsetTrail = offsetTrail.offsetParent
    }
    offsetTop = offsetTop || null
    offsetLeft = offsetLeft || null
    return {left: offsetLeft, top: offsetTop}
}
function getElementBottom(elem) {
    var c_style = document.defaultView.getComputedStyle(elem, '')
    var height  = 0
    var prop    = ['height', 'borderTopWidth', 'borderBottomWidth',
                   'paddingTop', 'paddingBottom',
                   'marginTop', 'marginBottom']
    prop.forEach(function(i) {
        var h = parseInt(c_style[i])
        if (typeof h == 'number') {
            height += h
        }
    })
    var top = getElementPosition(elem).top
    return top ? (top + height) : null
}
function getScrollHeight() {
    return Math.max(document.documentElement.scrollHeight,
                                document.body.scrollHeight)
}
function isSameDomain(url) {
    if (url.match(/^\w+:/)) {
        var url_s = url.split(/[\/\?]/)
        return url_s[0] == location.protocol && location.host == url_s[2]
    }
    else {
        return true
    }
}
function isSameBaseUrl(urlA, urlB) {
    return (urlA.replace(/[^/]+$/, '') == urlB.replace(/[^/]+$/, ''))
}
function resolvePath(path, base) {
    if (path.match(/^https?:\/\//)) {
        return path
    }
    if (path.match(/^\?/)) {
        return base.replace(/\?.+$/, '') + path;
    }
    if (path.match(/^[^\/]/)) {
        return base.replace(/[^/]+$/, '') + path
    }
    else {
        return base.replace(/([^/]+:\/\/[^/]+)\/.*/, '\$1') + path
    }
}
function fixResolvePath() {
    if (resolvePath('', 'http://resolve.test/') == 'http://resolve.test/') {
        return
    }
    // A workaround for WebKit and Mozilla 1.9.2a1pre,
    // which don't support XML Base in HTML.
    // https://bugs.webkit.org/show_bug.cgi?id=17423
    // https://bugzilla.mozilla.org/show_bug.cgi?id=505783
    var XML_NS = 'http://www.w3.org/XML/1998/namespace'
    var baseElement = document.createElementNS(null, 'base')
    var pathElement = document.createElementNS(null, 'path')
    baseElement.appendChild(pathElement)
    resolvePath = function resolvePath_workaround(path, base) {
        baseElement.setAttributeNS(XML_NS, 'xml:base', base)
        pathElement.setAttributeNS(XML_NS, 'xml:base', path)
        return pathElement.baseURI
    }
}
function strip_html_tag(str) {
    var chunks = str.split(/(<html(?:[ \t\r\n][^>]*)?>)/)
    if (chunks.length >= 3) {
        chunks.splice(0, 2)
    }
    str = chunks.join('')
    chunks = str.split(/(<\/html[ \t\r\n]*>)/)
    if (chunks.length >= 3) {
        chunks.splice(chunks.length - 2)
    }
    return chunks.join('')
}
function getPref(key, defaultValue) {
    var value = GM_getValue(key)
    return (typeof value == 'undefined') ? defaultValue : value
}
function wildcard2regep(str) {
    return '^' + str.replace(/([-()\[\]{}+?.$\^|,:#<!\\])/g, '\\$1').replace(/\x08/g, '\\x08').replace(/\*/g, '.*')
}
function isExclude(patterns) {
    var rr = /^\/(.+)\/$/
    var eps = (patterns || '').split(/[\r\n ]+/)
    for (var i = 0; i < eps.length; i++) {
        var reg = null
        if (rr.test(eps[i])) {
            reg = eps[i].match(rr)[1]
        }
        else {
            reg = wildcard2regep(eps[i])
        }
        if (location.href.match(reg)) {
            return true
        }
    }
    return false
}
// obsolete
function isFirefoxExtension() {
    return (typeof chlorine == 'object')
}
function isChromeExtension() {
    return (typeof chrome == 'object') &&
        (typeof chrome.extension == 'object')
}
function isSafariExtension() {
    return (typeof safari == 'object') &&
        (typeof safari.extension == 'object')
}
function isGreasemonkey() {
    return (typeof GM_log == 'function')
}
function isJetpack() {
    // isFirefoxExtension is obsolete
    return (!isGreasemonkey() && !isSafariExtension() &&
            !isChromeExtension() && !isFirefoxExtension())
}
function gmCompatible() {
    GM_registerMenuCommand = function() {}
    GM_setValue = function() {}
    GM_getValue = function() {}
    GM_addStyle = function() {}
    uneval = function() {}
    fixResolvePath = function() {}
    resolvePath = function (path, base) { return path }
    if (isChromeExtension() || isSafariExtension()) {
        createHTMLDocumentByString = function(str) {
            if (document.documentElement.nodeName != 'HTML') {
                return new DOMParser().parseFromString(str, 'application/xhtml+xml')
            }
            // FIXME
            var html = str.replace(/<script(?:[ \t\r\n][^>]*)?>[\S\s]*?<\/script[ \t\r\n]*>|<\/?(?:i?frame|html|script|object)(?:[ \t\r\n][^<>]*)?>/gi, ' ')
            var htmlDoc = document.implementation.createHTMLDocument ?
                document.implementation.createHTMLDocument('apfc') :
                document.implementation.createDocument(null, 'html', null)
            var range = document.createRange()
            range.selectNodeContents(document.documentElement)
            htmlDoc.documentElement.appendChild(range.createContextualFragment(html))
            return htmlDoc
        }
    }
    return true
}
Liegts am Code oder an Violentmonkey?
Keine Probleme damit hier:
[attachment=0]Screenshot (259).png[/attachment]
// ==UserScript==
// @name AutoPagerize
// @namespace Violentmonkey Scripts
// @match *://*/*
// @grant none
// ==UserScript==
// @name           AutoPagerize
// @namespace      http://swdyh.yu.to/
// @description    loading next page and inserting into current page.
// @include        http://*
// @include        https://*
// @exclude        https://mail.google.com/*
// @exclude        http://b.hatena.ne.jp/*
// @exclude        http://www.facebook.com/plugins/like.php*
// @exclude        http://api.tweetmeme.com/button.js*
// @version        0.0.66
// @icon           http://autopagerize.net/img/icons/icon_032.png
// @grant          GM_getValue
// @grant          GM_setValue
// @grant          GM_addStyle
// @grant          GM_log
// @grant          GM_xmlhttpRequest
// @grant          GM_registerMenuCommand
// ==/UserScript==
//
// auther:  swdyh http://d.hatena.ne.jp/swdyh/
// version: 0.0.66 2012-08-31T18:23:34+09:00
//
// this script based on
// GoogleAutoPager(http://la.ma.la/blog/diary_200506231749.htm) and
// estseek autopager(http://la.ma.la/blog/diary_200601100209.htm).
// thanks to ma.la.
//
// Released under the GPL license
// http://www.gnu.org/copyleft/gpl.html
//
if (isGreasemonkey()) {
    var ep = getPref('exclude_patterns')
    if (ep && isExclude(ep)) {
        // FIXME
        // return
    }
}
else {
    gmCompatible()
}
var URL = 'http://autopagerize.net/'
var VERSION = '0.0.66'
var DEBUG = false
var AUTO_START = true
var CACHE_EXPIRE = 24 * 60 * 60 * 1000
var BASE_REMAIN_HEIGHT = 400
var FORCE_TARGET_WINDOW = getPref('force_target_window', true)
var XHR_TIMEOUT = 30 * 1000
var SITEINFO_IMPORT_URLS = [
    'http://wedata.net/databases/AutoPagerize/items.json',
]
var COLOR = {
    on: '#0f0',
    off: '#ccc',
    loading: '#0ff',
    terminated: '#00f',
    error: '#f0f'
}
var SITEINFO = [
    /* sample
    {
        url:          'http://(.*).google.+/(search).+',
        nextLink:     'id("navbar")//td[last()]/a',
        pageElement:  '//div[@id="res"]/div',
        exampleUrl:   'http://www.google.com/search?q=nsIObserver',
    },
    */
    /* template
    {
        url:          '',
        nextLink:     '',
        pageElement:  '',
        exampleUrl:   '',
    },
    */
]
var MICROFORMAT = {
    url:          '.*',
    nextLink:     '//a[@rel="next"] | //link[@rel="next"]',
    insertBefore: '//*[contains(@class, "autopagerize_insert_before")]',
    pageElement:  '//*[contains(@class, "autopagerize_page_element")]',
}
var AutoPager = function(info) {
    this.pageNum = 1
    this.info = info
    this.state = AUTO_START ? 'enable' : 'disable'
    var self = this
    var url = this.getNextURL(info.nextLink, document, location.href)
    if ( !url ) {
        debug("getNextURL returns null.", info.nextLink)
        return
    }
    if (info.insertBefore) {
        this.insertPoint = getFirstElementByXPath(info.insertBefore)
    }
    if (!this.insertPoint) {
        var lastPageElement = getElementsByXPath(info.pageElement).pop()
        if (lastPageElement) {
            this.insertPoint = lastPageElement.nextSibling ||
                lastPageElement.parentNode.appendChild(document.createTextNode(' '))
        }
    }
    if (!this.insertPoint) {
        debug("insertPoint not found.", lastPageElement, info.pageElement)
        return
    }
    this.requestURL = url
    this.loadedURLs = {}
    this.loadedURLs[location.href] = true
    var toggle = function() {self.stateToggle()}
    this.toggle = toggle
    GM_registerMenuCommand('AutoPagerize - on/off', toggle)
    this.scroll= function() { self.onScroll() }
    window.addEventListener("scroll", this.scroll, false)
    if (isFirefoxExtension()) {
        var div = document.createElement("div")
        div.setAttribute('id', 'autopagerize_icon')
        div.style.display = 'none'
        document.body.appendChild(div)
        this.icon = div
    }
    else if (isChromeExtension() || isSafariExtension() || isJetpack()) {
        var frame = document.createElement('iframe')
        frame.style.display = 'none'
        frame.style.position = 'fixed'
        frame.style.bottom = '0px'
        frame.style.left = '0px'
        frame.style.height = '25px'
        frame.style.border = '0px'
        frame.style.opacity = '0.8'
        frame.style.zIndex = '1000'
        frame.width = '100%'
        frame.scrolling = 'no'
        this.messageFrame = frame
        var u = settings['extension_path'] ?
            settings['extension_path'] + 'loading.html' :
            'http://autopagerize.net/files/loading.html'
        this.messageFrame.src = u
        document.body.appendChild(frame)
        if (isSafariExtension()) {
            safari.self.tab.dispatchMessage('launched', {url: location.href })
        }
        else if (isChromeExtension()) {
            chrome.extension.connect({name: "launched"}).postMessage()
        }
        if (isJetpack()) {
            postMessage({name: 'launched', data: location.href })
        }
   }
    else {
        this.initIcon()
        this.initHelp()
        GM_addStyle('@media print{#autopagerize_icon, #autopagerize_help {display: none !important;}}')
        GM_addStyle('hr.autopagerize_page_separator {clear: both;}')
        this.icon.addEventListener("mouseover", function() {
            self.viewHelp()
        }, true)
    }
    var scrollHeight = getScrollHeight()
    var bottom = getElementPosition(this.insertPoint).top ||
        this.getPageElementsBottom() ||
        (Math.round(scrollHeight * 0.8))
    this.remainHeight = scrollHeight - bottom + BASE_REMAIN_HEIGHT
    this.onScroll()
    var that = this
    document.addEventListener('AutoPagerizeToggleRequest', function() {
        that.toggle()
    }, false)
    document.addEventListener('AutoPagerizeUpdateIconRequest', function() {
        that.updateIcon()
    }, false)
    that.updateIcon()
}
AutoPager.prototype.getPageElementsBottom = function() {
    try {
        var elem = getElementsByXPath(this.info.pageElement).pop()
        return getElementBottom(elem)
    }
    catch(e) {}
}
AutoPager.prototype.initHelp = function() {
    var helpDiv = document.createElement('div')
    helpDiv.setAttribute('id', 'autopagerize_help')
    helpDiv.setAttribute('style', 'padding:5px;position:fixed;' +
                     'top:-200px;right:3px;font-size:10px;' +
                     'background:#fff;color:#000;border:1px solid #ccc;' +
                     'z-index:256;text-align:left;font-weight:normal;' +
                     'line-height:120%;font-family:verdana;')
    var toggleDiv = document.createElement('div')
    toggleDiv.setAttribute('style', 'margin:0 0 0 50px;')
    var a = document.createElement('a')
    a.setAttribute('class', 'autopagerize_link')
    a.innerHTML = 'on/off'
    a.href = 'javascript:void(0)'
    var self = this
    var toggle = function() {
        self.stateToggle()
        helpDiv.style.top = '-200px'
    }
    a.addEventListener('click', toggle, false)
    toggleDiv.appendChild(a)
    var s = '<div style="width:100px; float:left;">'
    for (var i in COLOR) {
        s += '<div style="float:left;width:1em;height:1em;' +
            'margin:0 3px;background-color:' + COLOR[i] + ';' +
            '"></div><div style="margin:0 3px">' + i + '</div>'
    }
    s += '</div>'
    var colorDiv = document.createElement('div')
    colorDiv.innerHTML = s
    helpDiv.appendChild(colorDiv)
    helpDiv.appendChild(toggleDiv)
    var versionDiv = document.createElement('div')
    versionDiv.setAttribute('style', 'clear:both;')
    versionDiv.innerHTML = '<a href="' + URL +
        '">AutoPagerize</a> ver ' + VERSION
    helpDiv.appendChild(versionDiv)
    document.body.appendChild(helpDiv)
    var proc = function(e) {
        var c_style = document.defaultView.getComputedStyle(helpDiv, '')
        var s = ['top', 'left', 'height', 'width'].map(function(i) {
            return parseInt(c_style.getPropertyValue(i)) })
        if (e.clientX < s[1] || e.clientX > (s[1] + s[3] + 11) ||
            e.clientY < s[0] || e.clientY > (s[0] + s[2] + 11)) {
                helpDiv.style.top = '-200px'
        }
    }
    helpDiv.addEventListener('mouseout', proc, false)
    this.helpLayer = helpDiv
    GM_addStyle('#autopagerize_help a { color: #0f0; text-decoration: underline;}')
}
AutoPager.prototype.viewHelp = function() {
    this.helpLayer.style.top = '3px'
}
AutoPager.prototype.onScroll = function() {
    var scrollHeight = Math.max(document.documentElement.scrollHeight,
                                document.body.scrollHeight)
    var remain = scrollHeight - window.innerHeight - window.scrollY
    if (this.state == 'enable' && remain < this.remainHeight) {
          this.request()
    }
}
AutoPager.prototype.stateToggle = function() {
    if (this.state == 'enable') {
        this.disable()
    }
    else {
        this.enable()
    }
}
AutoPager.prototype.enable = function() {
    this.state = 'enable'
    this.updateIcon()
}
AutoPager.prototype.disable = function() {
    this.state = 'disable'
    this.updateIcon()
}
AutoPager.prototype.updateIcon = function(state) {
    var st = state || this.state
    var rename = {'enable': 'on', 'disable': 'off' }
    if (rename[st]) {
        st = rename[st]
    }
    var color = COLOR[st]
    if (color) {
        if (isFirefoxExtension()) {
            chlorine.pageAction.update(color, location.href)
        }
        else if (isChromeExtension()) {
            chrome.extension.connect({name: "pageActionChannel"}).postMessage(color)
        }
        else if (isSafariExtension() || isJetpack()) {
        }
        else {
            this.icon.style.background = color
        }
    }
}
AutoPager.prototype.request = function() {
    if (!this.requestURL || this.lastRequestURL == this.requestURL) {
        return
    }
    this.lastRequestURL = this.requestURL
    var self = this
    var mime = 'text/html; charset=' + document.characterSet
    var headers = {}
    if (isSameDomain(this.requestURL)) {
        headers.Cookie = document.cookie
    }
    else {
        this.error()
        return
    }
    var opt = {
        method: 'get',
        url: this.requestURL,
        headers: headers,
        overrideMimeType: mime,
        onerror: function(res) {
            self.error()
        },
        onload: function(res) {
            if (res.finalUrl) {
                var url_s = res.finalUrl.split(/[\/\?]/)
                if (url_s[0] == location.protocol && location.host == url_s[2]) {
                    self.requestLoad.apply(self, [res])
                    return
                }
            }
            self.error()
        }
    }
    AutoPager.requestFilters.forEach(function(i) { i(opt) }, this)
    if (opt.stop) {
        this.requestURL = opt.url
    }
    else {
        this.showLoading(true)
        GM_xmlhttpRequest(opt)
    }
}
AutoPager.prototype.showLoading = function(sw) {
    if (sw) {
        this.updateIcon('loading')
        if (this.messageFrame && settings['display_message_bar']) {
            this.messageFrame.style.display = 'block'
        }
    }
    else {
        this.updateIcon('enable')
        if (this.messageFrame) {
            this.messageFrame.style.display = 'none'
        }
    }
}
AutoPager.prototype.requestLoad = function(res) {
    AutoPager.responseFilters.forEach(function(i) {
        i(res, this.requestURL)
    }, this)
    var htmlDoc = createHTMLDocumentByString(res.responseText)
    AutoPager.documentFilters.forEach(function(i) {
        i(htmlDoc, this.requestURL, this.info)
    }, this)
    try {
        var page = getElementsByXPath(this.info.pageElement, htmlDoc)
        var url = this.getNextURL(this.info.nextLink, htmlDoc, this.requestURL)
    }
    catch(e){
        log(e)
        this.error()
        return
    }
    if (!page || page.length < 1 ) {
        debug('pageElement not found.' , this.info.pageElement)
        this.terminate()
        return
    }
    if (this.loadedURLs[this.requestURL]) {
        debug('page is already loaded.', this.requestURL, this.info.nextLink)
        this.terminate()
        return
    }
    this.loadedURLs[this.requestURL] = true
    page = this.addPage(htmlDoc, page)
    AutoPager.filters.forEach(function(i) {
        i(page)
    })
    this.requestURL = url
    this.showLoading(false)
    this.onScroll()
    if (!url) {
        debug('nextLink not found.', this.info.nextLink, htmlDoc)
        this.terminate()
    }
    var ev = document.createEvent('Event')
    ev.initEvent('GM_AutoPagerizeNextPageLoaded', true, false)
    document.dispatchEvent(ev)
}
AutoPager.prototype.addPage = function(htmlDoc, page) {
    var HTML_NS  = 'http://www.w3.org/1999/xhtml'
    var hr = document.createElementNS(HTML_NS, 'hr')
    var p  = document.createElementNS(HTML_NS, 'p')
    hr.setAttribute('class', 'autopagerize_page_separator')
    p.setAttribute('class', 'autopagerize_page_info')
    var self = this
    if (page[0] && /tr/i.test(page[0].tagName)) {
        var insertParent = this.insertPoint.parentNode
        var colNodes = getElementsByXPath('child::tr[1]/child::*[self::td or self::th]', insertParent)
        var colums = 0
        for (var i = 0, l = colNodes.length; i < l; i++) {
            var col = colNodes[i].getAttribute('colspan')
            colums += parseInt(col, 10) || 1
        }
        var td = document.createElement('td')
        // td.appendChild(hr)
        td.appendChild(p)
        var tr = document.createElement('tr')
        td.setAttribute('colspan', colums)
        tr.appendChild(td)
        insertParent.insertBefore(tr, this.insertPoint)
    }
    else {
        this.insertPoint.parentNode.insertBefore(hr, this.insertPoint)
        this.insertPoint.parentNode.insertBefore(p, this.insertPoint)
    }
    p.innerHTML = 'page: <a class="autopagerize_link" href="' +
        this.requestURL.replace(/&/g, '&') + '">' + (++this.pageNum) + '</a>'
    return page.map(function(i) {
        var pe = document.importNode(i, true)
        self.insertPoint.parentNode.insertBefore(pe, self.insertPoint)
        var ev = document.createEvent('MutationEvent')
        ev.initMutationEvent('AutoPagerize_DOMNodeInserted', true, false,
                             self.insertPoint.parentNode, null,
                             self.requestURL, null, null)
        pe.dispatchEvent(ev)
        return pe
    })
}
AutoPager.prototype.initIcon = function() {
    var div = document.createElement("div")
    div.setAttribute('id', 'autopagerize_icon')
    with (div.style) {
        fontSize   = '12px'
        position   = 'fixed'
        top        = '3px'
        right      = '3px'
        background = COLOR['on']
        color      = '#fff'
        width = '10px'
        height = '10px'
        zIndex = '255'
        if (this.state != 'enable') {
            background = COLOR['off']
        }
    }
    document.body.appendChild(div)
    this.icon = div
}
AutoPager.prototype.getNextURL = function(xpath, doc, url) {
    var nextLink = getFirstElementByXPath(xpath, doc)
    if (nextLink) {
        var nextValue = nextLink.getAttribute('href') ||
            nextLink.getAttribute('action') || nextLink.value
        if (nextValue.match(/^http(s)?:/)) {
            return nextValue
        }
        else {
            var base = getFirstElementByXPath('//base[@href]', doc)
            return resolvePath(nextValue, (base ? base.href : url))
        }
    }
}
AutoPager.prototype.terminate = function() {
    window.removeEventListener('scroll', this.scroll, false)
    this.updateIcon('terminated')
    var self = this
    setTimeout(function() {
        if (self.icon) {
            self.icon.parentNode.removeChild(self.icon)
        }
        if (isSafariExtension()) {
            var mf = self.messageFrame
            mf.parentNode.removeChild(mf)
        }
    }, 1500)
}
AutoPager.prototype.error = function() {
    this.updateIcon('error')
    window.removeEventListener('scroll', this.scroll, false)
    if (isSafariExtension() || isChromeExtension() || isJetpack()) {
        var mf = this.messageFrame
        var u = settings['extension_path'] ?
            settings['extension_path'] + 'error.html' :
            'http://autopagerize.net/files/error.html'
        mf.src = u
        mf.style.display = 'block'
        setTimeout(function() {
            mf.parentNode.removeChild(mf)
        }, 3000)
    }
}
AutoPager.documentFilters = []
AutoPager.requestFilters = []
AutoPager.responseFilters = []
AutoPager.filters = []
var parseInfo = function(str) {
    var lines = str.split(/\r\n|\r|\n/)
    var re = /(^[^:]*?):(.*)$/
    var strip = function(str) {
        return str.replace(/^\s*/, '').replace(/\s*$/, '')
    }
    var info = {}
    for (var i = 0; i < lines.length; i++) {
        if (lines[i].match(re)) {
            info[RegExp.$1] = strip(RegExp.$2)
        }
    }
    var isValid = function(info) {
        var infoProp = ['url', 'nextLink', 'pageElement']
        for (var i = 0; i < infoProp.length; i++) {
            if (!info[infoProp[i]]) {
                return false
            }
        }
        return true
    }
    return isValid(info) ? info : null
}
var launchAutoPager = function(list) {
    if (list.length == 0) {
        return
    }
    for (var i = 0; i < list.length; i++) {
        try {
            if (ap) {
                return
            }
            else if (!location.href.match(list[i].url)) {
            }
            else if (!getFirstElementByXPath(list[i].nextLink)) {
                // FIXME microformats case detection.
                // limiting greater than 12 to filter microformats like SITEINFOs.
                if (list[i].url.length > 12 ) {
                    debug("nextLink not found.", list[i].nextLink)
                }
            }
            else if (!getFirstElementByXPath(list[i].pageElement)) {
                if (list[i].url.length > 12 ) {
                    debug("pageElement not found.", list[i].pageElement)
                }
            }
            else {
                ap = new AutoPager(list[i])
                return
            }
        }
        catch(e) {
            log(e)
            continue
        }
    }
}
var clearCache = function() {
    GM_setValue('cacheInfo', '')
}
var getCache = function() {
    try {
        return JSON.parse(GM_getValue('cacheInfo')) || {}
    }
    catch(e) {
        return {}
    }
}
var getCacheCallback = function(res, url) {
    if (res.status != 200) {
        return getCacheErrorCallback(url)
    }
    var info
    try {
        info = JSON.parse(res.responseText).map(function(i) { return i.data })
    }
    catch(e) {
        info = []
    }
    if (info.length > 0) {
        info = info.filter(function(i) { return ('url' in i) })
        info.sort(function(a, b) { return (b.url.length - a.url.length) })
        var r_keys = ['url', 'nextLink', 'insertBefore', 'pageElement']
        info = info.map(function(i) {
            var item = {}
            r_keys.forEach(function(key) {
                if (i[key]) {
                    item[key] = i[key]
                }
            })
            return item
        })
        cacheInfo[url] = {
            url: url,
            expire: new Date(new Date().getTime() + CACHE_EXPIRE),
            info: info
        }
        GM_setValue('cacheInfo', JSON.stringify(cacheInfo))
        launchAutoPager(info)
    }
    else {
        getCacheErrorCallback(url)
    }
}
var getCacheErrorCallback = function(url) {
    var expire = new Date(new Date().getTime() + CACHE_EXPIRE)
    if (cacheInfo[url]) {
        cacheInfo[url].expire = expire
        launchAutoPager(cacheInfo[url].info)
    }
    else {
        cacheInfo[url] = {
            url: url,
            expire: expire,
            info: []
        }
    }
    GM_setValue('cacheInfo', cacheInfo.toSource())
}
var linkFilter = function(doc, url) {
    var base = getFirstElementByXPath('//base[@href]', doc)
    var baseUrl = base ? base.href : url
    var isSameBase = isSameBaseUrl(location.href, baseUrl)
    if (!FORCE_TARGET_WINDOW && isSameBase) {
        return
    }
    var anchors = getElementsByXPath('descendant-or-self::a[@href]', doc)
    anchors.forEach(function(i) {
        var attrHref = i.getAttribute('href')
        if (FORCE_TARGET_WINDOW && !attrHref.match(/^#|^javascript:/) &&
            i.className.indexOf('autopagerize_link') < 0) {
            i.target = '_blank'
        }
        if (!isSameBase && !attrHref.match(/^#|^\w+:/)) {
            i.href = resolvePath(i.getAttribute('href'), baseUrl)
        }
    })
    if (!isSameBase) {
        var images = getElementsByXPath('descendant-or-self::img', doc)
        images.forEach(function(i) {
            i.src = resolvePath(i.getAttribute('src'), baseUrl)
        })
    }
}
AutoPager.documentFilters.push(linkFilter)
fixResolvePath()
if (typeof(window.AutoPagerize) == 'undefined') {
    window.AutoPagerize = {}
    window.AutoPagerize.addFilter = function(f) {
        AutoPager.filters.push(f)
    }
    window.AutoPagerize.addDocumentFilter = function(f) {
        AutoPager.documentFilters.push(f)
    }
    window.AutoPagerize.addResponseFilter = function(f) {
        AutoPager.responseFilters.push(f)
    }
    window.AutoPagerize.addRequestFilter = function(f) {
        AutoPager.requestFilters.push(f)
    }
    window.AutoPagerize.launchAutoPager = launchAutoPager
    var ev = document.createEvent('Event')
    ev.initEvent('GM_AutoPagerizeLoaded', true, false)
    document.dispatchEvent(ev)
}
var settings = {}
var ap = null
if (isChromeExtension()) {
    var port = chrome.extension.connect({name: "settingsChannel"})
    port.postMessage()
    port.onMessage.addListener(function(res) {
        settings = res
        if (res['exclude_patterns'] && isExclude(res['exclude_patterns'])) {
            return
        }
        launchAutoPager(SITEINFO)
        var port_ = chrome.extension.connect({name: "siteinfoChannel"})
        port_.postMessage({ url: location.href })
        port_.onMessage.addListener(function(res) {
            launchAutoPager(res)
            chrome.extension.onConnect.addListener(function(port) {
                if (port.name == "toggleRequestChannel") {
                    port.onMessage.addListener(function(msg) {
                        if (ap) {
                            ap.toggle()
                        }
                    })
                }
            })
        })
    })
}
else if (isSafariExtension()) {
    var re_exclude = /^(about:|safari-extension:)/
    if (!location.href.match(re_exclude)) {
        safari.self.addEventListener('message', function(event) {
            if (event.name === 'settings') {
                settings = event.message
                safari.self.tab.dispatchMessage('siteinfoChannel', {url: location.href })
            }
            else if (event.name === 'siteinfoChannel') {
                if (!settings['exclude_patterns'] || !isExclude(settings['exclude_patterns'])) {
                    launchAutoPager(SITEINFO)
                    launchAutoPager([MICROFORMAT])
                    launchAutoPager(event.message)
                }
            }
            else if (event.name === 'toggleRequestChannel') {
                if (ap) {
                    ap.toggle()
                }
            }
            else if (event.name === 'updateSettings') {
                settings = event.message
            }
        }, false)
        safari.self.tab.dispatchMessage('settings')
    }
}
else if (isJetpack()) {
    postMessage({ name: 'settings' })
    onMessage = function(message) {
        if (message.name == 'siteinfo') {
            // launchAutoPager(SITEINFO)
            launchAutoPager(message.data)
        }
        else if (message.name == 'settings') {
            settings = message.data
            if (settings['exclude_patterns'] && isExclude(settings['exclude_patterns'])) {
                // return
            }
            else  {
                postMessage({ name: 'siteinfo', url: location.href })
                launchAutoPager([MICROFORMAT])
            }
        }
    }
}
else {
    launchAutoPager(SITEINFO)
    GM_registerMenuCommand('AutoPagerize - clear cache', clearCache)
    var cacheInfo = getCache()
    var xhrStates = {}
    SITEINFO_IMPORT_URLS.forEach(function(i) {
        if (!cacheInfo[i] || new Date(cacheInfo[i].expire) < new Date()) {
            var opt = {
                method: 'get',
                url: i,
                onload: function(res) {
                    xhrStates[i] = 'loaded'
                    getCacheCallback(res, i)
                },
                onerror: function(res){
                    xhrStates[i] = 'error'
                    getCacheErrorCallback(i)
                },
            }
            xhrStates[i] = 'start'
            GM_xmlhttpRequest(opt)
            setTimeout(function() {
                if (xhrStates[i] == 'start') {
                    getCacheErrorCallback(i)
                }
            }, XHR_TIMEOUT)
        }
        else {
            launchAutoPager(cacheInfo[i].info)
        }
    })
    launchAutoPager([MICROFORMAT])
}
// new google search sucks!
if (location.href.match('^http://[^.]+\.google\.(?:[^.]{2,3}\.)?[^./]{2,3}/.*(&fp=)')) {
    var to = location.href.replace(/&fp=.*/, '')
    // console.log([location.href, to])
    location.href = to
}
// utility functions.
function createHTMLDocumentByString(str) {
    if (document.documentElement.nodeName != 'HTML') {
        return new DOMParser().parseFromString(str, 'application/xhtml+xml')
    }
    var html = strip_html_tag(str)
    var htmlDoc
    try {
        // We have to handle exceptions since Opera 9.6 throws
        // a NOT_SUPPORTED_ERR exception for |document.cloneNode(false)|
        // against the DOM 3 Core spec.
        htmlDoc = document.cloneNode(false)
        htmlDoc.appendChild(htmlDoc.importNode(document.documentElement, false))
    }
    catch(e) {
        htmlDoc = document.implementation.createDocument(null, 'html', null)
    }
    var fragment = createDocumentFragmentByString(html)
    try {
        fragment = htmlDoc.adoptNode(fragment)
    }
    catch(e) {
        fragment = htmlDoc.importNode(fragment, true)
    }
    htmlDoc.documentElement.appendChild(fragment)
    return htmlDoc
}
function getElementsByXPath(xpath, node) {
    var nodesSnapshot = getXPathResult(xpath, node,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE)
    var data = []
    for (var i = 0; i < nodesSnapshot.snapshotLength; i++) {
        data.push(nodesSnapshot.snapshotItem(i))
    }
    return data
}
function getFirstElementByXPath(xpath, node) {
    var result = getXPathResult(xpath, node,
        XPathResult.FIRST_ORDERED_NODE_TYPE)
    return result.singleNodeValue
}
function getXPathResult(xpath, node, resultType) {
    var node = node || document
    var doc = node.ownerDocument || node
    var resolver = doc.createNSResolver(node.documentElement || node)
    // Use |node.lookupNamespaceURI('')| for Opera 9.5
    // A workaround for bugs of Node.lookupNamespaceURI(null)
    // https://bugzilla.mozilla.org/show_bug.cgi?id=693615
    // https://bugzilla.mozilla.org/show_bug.cgi?id=694754
    var defaultNS = null
    try {
        // This follows the spec: http://www.w3.org/TR/DOM-Level-3-Core/namespaces-algorithms.html#lookupNamespaceURIAlgo
        if (node.nodeType == node.DOCUMENT_NODE) {
            defaultNS = node.documentElement.lookupNamespaceURI(null)
        }
        else {
            defaultNS = node.lookupNamespaceURI(null)
        }
    }
    catch(e) {}
    if (defaultNS) {
        const defaultPrefix = '__default__'
        xpath = addDefaultPrefix(xpath, defaultPrefix)
        var defaultResolver = resolver
        resolver = function (prefix) {
            return (prefix == defaultPrefix)
                ? defaultNS : defaultResolver.lookupNamespaceURI(prefix)
        }
    }
    return doc.evaluate(xpath, node, resolver, resultType, null)
}
function addDefaultPrefix(xpath, prefix) {
    const tokenPattern = /([A-Za-z_\u00c0-\ufffd][\w\-.\u00b7-\ufffd]*|\*)\s*(::?|\()?|(".*?"|'.*?'|\d+(?:\.\d*)?|\.(?:\.|\d+)?|[\)\]])|(\/\/?|!=|[<>]=?|[\(\[|,=+-])|([@$])/g
    const TERM = 1, OPERATOR = 2, MODIFIER = 3
    var tokenType = OPERATOR
    prefix += ':'
    function replacer(token, identifier, suffix, term, operator, modifier) {
        if (suffix) {
            tokenType =
                (suffix == ':' || (suffix == '::' &&
                 (identifier == 'attribute' || identifier == 'namespace')))
                ? MODIFIER : OPERATOR
        }
        else if (identifier) {
            if (tokenType == OPERATOR && identifier != '*') {
                token = prefix + token
            }
            tokenType = (tokenType == TERM) ? OPERATOR : TERM
        }
        else {
            tokenType = term ? TERM : operator ? OPERATOR : MODIFIER
        }
        return token
    }
    return xpath.replace(tokenPattern, replacer)
}
function createDocumentFragmentByString(str) {
    var range = document.createRange()
    range.setStartAfter(document.body)
    return range.createContextualFragment(str)
}
function log(message) {
    if (typeof console == 'object') {
        console.log(message)
    }
    else {
        GM_log(message)
    }
}
function debug() {
    if ( typeof DEBUG != 'undefined' && DEBUG ) {
        if (console.log.apply) {
            console.log.apply(console, arguments)
        }
        else {
            Function.prototype.apply.apply(console.log, [console, arguments])
        }
    }
}
function getElementPosition(elem) {
    var offsetTrail = elem
    var offsetLeft  = 0
    var offsetTop   = 0
    while (offsetTrail) {
        offsetLeft += offsetTrail.offsetLeft
        offsetTop  += offsetTrail.offsetTop
        offsetTrail = offsetTrail.offsetParent
    }
    offsetTop = offsetTop || null
    offsetLeft = offsetLeft || null
    return {left: offsetLeft, top: offsetTop}
}
function getElementBottom(elem) {
    var c_style = document.defaultView.getComputedStyle(elem, '')
    var height  = 0
    var prop    = ['height', 'borderTopWidth', 'borderBottomWidth',
                   'paddingTop', 'paddingBottom',
                   'marginTop', 'marginBottom']
    prop.forEach(function(i) {
        var h = parseInt(c_style[i])
        if (typeof h == 'number') {
            height += h
        }
    })
    var top = getElementPosition(elem).top
    return top ? (top + height) : null
}
function getScrollHeight() {
    return Math.max(document.documentElement.scrollHeight,
                                document.body.scrollHeight)
}
function isSameDomain(url) {
    if (url.match(/^\w+:/)) {
        var url_s = url.split(/[\/\?]/)
        return url_s[0] == location.protocol && location.host == url_s[2]
    }
    else {
        return true
    }
}
function isSameBaseUrl(urlA, urlB) {
    return (urlA.replace(/[^/]+$/, '') == urlB.replace(/[^/]+$/, ''))
}
function resolvePath(path, base) {
    if (path.match(/^https?:\/\//)) {
        return path
    }
    if (path.match(/^\?/)) {
        return base.replace(/\?.+$/, '') + path;
    }
    if (path.match(/^[^\/]/)) {
        return base.replace(/[^/]+$/, '') + path
    }
    else {
        return base.replace(/([^/]+:\/\/[^/]+)\/.*/, '\$1') + path
    }
}
function fixResolvePath() {
    if (resolvePath('', 'http://resolve.test/') == 'http://resolve.test/') {
        return
    }
    // A workaround for WebKit and Mozilla 1.9.2a1pre,
    // which don't support XML Base in HTML.
    // https://bugs.webkit.org/show_bug.cgi?id=17423
    // https://bugzilla.mozilla.org/show_bug.cgi?id=505783
    var XML_NS = 'http://www.w3.org/XML/1998/namespace'
    var baseElement = document.createElementNS(null, 'base')
    var pathElement = document.createElementNS(null, 'path')
    baseElement.appendChild(pathElement)
    resolvePath = function resolvePath_workaround(path, base) {
        baseElement.setAttributeNS(XML_NS, 'xml:base', base)
        pathElement.setAttributeNS(XML_NS, 'xml:base', path)
        return pathElement.baseURI
    }
}
function strip_html_tag(str) {
    var chunks = str.split(/(<html(?:[ \t\r\n][^>]*)?>)/)
    if (chunks.length >= 3) {
        chunks.splice(0, 2)
    }
    str = chunks.join('')
    chunks = str.split(/(<\/html[ \t\r\n]*>)/)
    if (chunks.length >= 3) {
        chunks.splice(chunks.length - 2)
    }
    return chunks.join('')
}
function getPref(key, defaultValue) {
    var value = GM_getValue(key)
    return (typeof value == 'undefined') ? defaultValue : value
}
function wildcard2regep(str) {
    return '^' + str.replace(/([-()\[\]{}+?.$\^|,:#<!\\])/g, '\\$1').replace(/\x08/g, '\\x08').replace(/\*/g, '.*')
}
function isExclude(patterns) {
    var rr = /^\/(.+)\/$/
    var eps = (patterns || '').split(/[\r\n ]+/)
    for (var i = 0; i < eps.length; i++) {
        var reg = null
        if (rr.test(eps[i])) {
            reg = eps[i].match(rr)[1]
        }
        else {
            reg = wildcard2regep(eps[i])
        }
        if (location.href.match(reg)) {
            return true
        }
    }
    return false
}
// obsolete
function isFirefoxExtension() {
    return (typeof chlorine == 'object')
}
function isChromeExtension() {
    return (typeof chrome == 'object') &&
        (typeof chrome.extension == 'object')
}
function isSafariExtension() {
    return (typeof safari == 'object') &&
        (typeof safari.extension == 'object')
}
function isGreasemonkey() {
    return (typeof GM_log == 'function')
}
function isJetpack() {
    // isFirefoxExtension is obsolete
    return (!isGreasemonkey() && !isSafariExtension() &&
            !isChromeExtension() && !isFirefoxExtension())
}
function gmCompatible() {
    GM_registerMenuCommand = function() {}
    GM_setValue = function() {}
    GM_getValue = function() {}
    GM_addStyle = function() {}
    uneval = function() {}
    fixResolvePath = function() {}
    resolvePath = function (path, base) { return path }
    if (isChromeExtension() || isSafariExtension()) {
        createHTMLDocumentByString = function(str) {
            if (document.documentElement.nodeName != 'HTML') {
                return new DOMParser().parseFromString(str, 'application/xhtml+xml')
            }
            // FIXME
            var html = str.replace(/<script(?:[ \t\r\n][^>]*)?>[\S\s]*?<\/script[ \t\r\n]*>|<\/?(?:i?frame|html|script|object)(?:[ \t\r\n][^<>]*)?>/gi, ' ')
            var htmlDoc = document.implementation.createHTMLDocument ?
                document.implementation.createHTMLDocument('apfc') :
                document.implementation.createDocument(null, 'html', null)
            var range = document.createRange()
            range.selectNodeContents(document.documentElement)
            htmlDoc.documentElement.appendChild(range.createContextualFragment(html))
            return htmlDoc
        }
    }
    return true
}