├── HACKING ├── README ├── icons ├── readability-128.png ├── readability-16.png ├── readability-48.png ├── readability-toolbar.png └── small-tile.png ├── manifest.json ├── readability ├── arc90-logo-large.png ├── arc90-logo-small.png ├── arc90lab-logo-small.png ├── email-head.gif ├── email-readability.gif ├── footer-arc90.png ├── footer-readability.png ├── footer-thanks.png ├── footer.png ├── kindling-logo-small.gif ├── read-email.png ├── read-kindle.png ├── read-print.png ├── read-refresh.png ├── readability-drag.png ├── readability-logo-small.png ├── readability-orig.js ├── readability-print.css ├── readability-x.js ├── readability.css ├── readability.js ├── readability.png ├── title-small.png ├── title.png ├── twitter.png └── typekit-icon.png └── redux ├── background.html ├── background.js ├── contentscript.js ├── example.html ├── jquery-1.4.2.js ├── options.css ├── options.html ├── options.js └── underscore-0.6.js /HACKING: -------------------------------------------------------------------------------- 1 | SOME TIPS ON HOW TO IMPROVE READABILITY 2 | ======================================= 3 | 4 | 5 | IMPORTANT 6 | --------- 7 | 8 | Readability Redux is just a wrapper around Readability. If you want to 9 | improve css styling, add new fonts or whatnot, consider contributing 10 | to the original Readability project[1]. 11 | 12 | 13 | Layout 14 | ------ 15 | 16 | Okay, having that sorted out, let's look how RR is organized: 17 | 18 | / - some boilerplate files, like the one you're reading right now 19 | /icon*.png - icon files. Accepted dimensions are 16x16, 19x19, 48x48 and 128x128. 20 | /readability - "stock" Readability files 21 | /readability.js - original Readability script 22 | /readability-x.js - Readability that works with selections ("experimental") 23 | /redux - extension-specific files 24 | /background.js - background page 25 | /contentscript.js - content script (launched with every tab) 26 | /options.* - options page 27 | /example.html - example text shown in the options page 28 | 29 | Innards 30 | ------- 31 | 32 | There are three extensions scripts: background.js, options.js and contentscript.js. 33 | All communication happens through message passing. 34 | 35 | Note that background.js accepts messages sent by another extensions. 36 | 37 | Here are the interactions between those 3 scripts: 38 | 39 | + background.js - main pivot of the extension 40 | Messages accepted: 41 | + {"type": "javascript"} - returns a javascript code that readabilizes a document. 42 | You can pass an additional parameter "settings" with 43 | which you can customize the script. For the accepted 44 | format, see what getSettings spews out. 45 | + {"type": "getSettings"} - gets settings object. (see source for more) 46 | + {"type": "setSettings"} - analogous 47 | + {"type": "render", "tab_id": 123} - launches Redability in the given tab. 48 | If tab_id is ommitted, sender.tab.id 49 | is assumed. 50 | 51 | Actions performed: 52 | + When browser button or context menu item is clicked, sends "render" message 53 | to the proper context script. 54 | + When settings are changed (through setSettings) sends "newSettings" message 55 | to all its content scripts. 56 | 57 | + options.js 58 | Actions performed: 59 | + Communicates with the background.js through "getSettings"/"setSettings". 60 | 61 | + contentscript.js 62 | Messages accepted: 63 | + {"type": "render"} - launches Readability in the tab. 64 | + {"type": "newSettings"} - updates internal settings storage used for 65 | key shortcuts. 66 | 67 | Actions performed: 68 | + When correct key shortcut is pressed, Readablity is launched. 69 | + When Readability is launched, uses "javascript" message to get the 70 | code from background.js 71 | 72 | 73 | [1]: http://code.google.com/p/arc90labs-readability/ 74 | 75 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ================= 2 | READABILITY REDUX 3 | ================= 4 | 5 | Give your browsing an edge! Readability is a tool designed by Arc90. 6 | In their words: 7 | "Readability is a simple tool that makes reading on the Web more 8 | enjoyable by removing the cluter around what you're reading." 9 | 10 | Readability Redux is an extension for Google Chrome that brings you 11 | the support for Arc90's Readability. Check it out yourself. 12 | 13 | ------------ 14 | Installation 15 | ------------ 16 | 17 | Visit https://chrome.google.com/extensions/detail/jggheggpdocamneaacmfoipeehedigia 18 | 19 | Sources here are for development purposes. 20 | 21 | ---------- 22 | Changelog 23 | ---------- 24 | 25 | 1.3.4 (2011.12.25) 26 | + Added missing icons to the repo 27 | 28 | 1.3.3 (2011.12.25) 29 | + Updated to Readability r164 30 | + Removed needless console comments 31 | + Analytics 32 | 33 | 1.3.2 (2011.01.25) 34 | + New icon set by Pete Fairhurst. 35 | 36 | 1.3.1 (2010.08.15) 37 | + As context menu functionality isn't supported in stable Google Chrome, I had to remove it. 38 | + Minor bugfix. 39 | 40 | 1.3 (2010.08.14) 41 | + Now works with local files (if it isn't working, check out chrome://extensions and set "Allow access to file URLs") 42 | + Support for context menus (sadly they don't work with local files, and the hack I've used with the browser action is moot here) 43 | + Key shortcut updates should take an effect immediately after saving. 44 | + RR can be launched from another extensions (see HACKING). 45 | + A lil' code reorganization. 46 | 47 | 1.2.1 (2010.08.09) 48 | + Support for Readability 1.7.1 (multi-page support) 49 | 50 | 1.2 (2010.06.15) 51 | + Support for Readability 1.6 r147 (links-to-footnotes conversion) 52 | + Keyboard shortcuts, finally! 53 | 54 | 1.1.2 (2010.03.15) 55 | + Support for Readability 1.5.0 r137 56 | 57 | 1.1.1 (2010.03.01) 58 | + Fixed typo in options 59 | 60 | 1.1 61 | + Support for Readability 1.5 62 | + Preview is now in an iframe 63 | 64 | 1.0.1 65 | + Code overhaul, options are now based on jQuery + Underscore 66 | + Hosted on GitHub 67 | 68 | 1.0 69 | + Initial release 70 | 71 | ------------ 72 | Contributing 73 | ------------ 74 | 75 | If you want improve on css styling (or anything else in readability/ folder), 76 | talk to original Readability authors instead. 77 | 78 | In any case, see HACKING for more info. 79 | 80 | ---------------- 81 | Acknowledgements 82 | ---------------- 83 | 84 | + Ilsi 50Mhz - for applying Readability to a selection. 85 | + Ed Marshall (logic) - for updating RR to Readability 1.7.1 (RR 1.2.1). 86 | + Pete Fairhurst - for the new icon set. 87 | 88 | -------------------------------------------------------------------------------- /icons/readability-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/icons/readability-128.png -------------------------------------------------------------------------------- /icons/readability-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/icons/readability-16.png -------------------------------------------------------------------------------- /icons/readability-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/icons/readability-48.png -------------------------------------------------------------------------------- /icons/readability-toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/icons/readability-toolbar.png -------------------------------------------------------------------------------- /icons/small-tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/icons/small-tile.png -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Readability Redux", 3 | "version": "1.3.4", 4 | "description": "Readability for Chrome. Now fully customizable!", 5 | "background_page": "redux/background.html", 6 | "browser_action": { "default_icon": "icons/readability-toolbar.png" }, 7 | "icons": { 8 | "16": "icons/readability-16.png", 9 | "48": "icons/readability-48.png", 10 | "128": "icons/readability-128.png" 11 | }, 12 | "permissions": [ "tabs", "http://*/*", "https://*/*"], 13 | "options_page": "redux/options.html", 14 | "content_scripts": [ { "matches": ["http://*/*", "https://*/*", "ftp://*/*", "file://*/*"], "js": ["redux/contentscript.js"] } ] 15 | } 16 | -------------------------------------------------------------------------------- /readability/arc90-logo-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/arc90-logo-large.png -------------------------------------------------------------------------------- /readability/arc90-logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/arc90-logo-small.png -------------------------------------------------------------------------------- /readability/arc90lab-logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/arc90lab-logo-small.png -------------------------------------------------------------------------------- /readability/email-head.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/email-head.gif -------------------------------------------------------------------------------- /readability/email-readability.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/email-readability.gif -------------------------------------------------------------------------------- /readability/footer-arc90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/footer-arc90.png -------------------------------------------------------------------------------- /readability/footer-readability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/footer-readability.png -------------------------------------------------------------------------------- /readability/footer-thanks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/footer-thanks.png -------------------------------------------------------------------------------- /readability/footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/footer.png -------------------------------------------------------------------------------- /readability/kindling-logo-small.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/kindling-logo-small.gif -------------------------------------------------------------------------------- /readability/read-email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/read-email.png -------------------------------------------------------------------------------- /readability/read-kindle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/read-kindle.png -------------------------------------------------------------------------------- /readability/read-print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/read-print.png -------------------------------------------------------------------------------- /readability/read-refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/read-refresh.png -------------------------------------------------------------------------------- /readability/readability-drag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/readability-drag.png -------------------------------------------------------------------------------- /readability/readability-logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/readability-logo-small.png -------------------------------------------------------------------------------- /readability/readability-orig.js: -------------------------------------------------------------------------------- 1 | /*jslint undef: true, nomen: true, eqeqeq: true, plusplus: true, newcap: true, immed: true, browser: true, devel: true, passfail: false */ 2 | /*global window: false, readConvertLinksToFootnotes: false, readStyle: false, readSize: false, readMargin: false, Typekit: false, ActiveXObject: false */ 3 | 4 | var dbg = (typeof console !== 'undefined') ? function(s) { 5 | console.log("Readability: " + s); 6 | } : function() {}; 7 | 8 | /* 9 | * Readability. An Arc90 Lab Experiment. 10 | * Website: http://lab.arc90.com/experiments/readability 11 | * Source: http://code.google.com/p/arc90labs-readability 12 | * 13 | * "Readability" is a trademark of Arc90 Inc and may not be used without explicit permission. 14 | * 15 | * Copyright (c) 2010 Arc90 Inc 16 | * Readability is licensed under the Apache License, Version 2.0. 17 | **/ 18 | var readability = { 19 | version: '1.7.1', 20 | emailSrc: 'http://lab.arc90.com/experiments/readability/email.php', 21 | iframeLoads: 0, 22 | convertLinksToFootnotes: false, 23 | reversePageScroll: false, /* If they hold shift and hit space, scroll up */ 24 | frameHack: false, /** 25 | * The frame hack is to workaround a firefox bug where if you 26 | * pull content out of a frame and stick it into the parent element, the scrollbar won't appear. 27 | * So we fake a scrollbar in the wrapping div. 28 | **/ 29 | biggestFrame: false, 30 | bodyCache: null, /* Cache the body HTML in case we need to re-use it later */ 31 | flags: 0x1 | 0x2 | 0x4, /* Start with all flags set. */ 32 | 33 | /* constants */ 34 | FLAG_STRIP_UNLIKELYS: 0x1, 35 | FLAG_WEIGHT_CLASSES: 0x2, 36 | FLAG_CLEAN_CONDITIONALLY: 0x4, 37 | 38 | maxPages: 30, /* The maximum number of pages to loop through before we call it quits and just show a link. */ 39 | parsedPages: {}, /* The list of pages we've parsed in this call of readability, for autopaging. As a key store for easier searching. */ 40 | pageETags: {}, /* A list of the ETag headers of pages we've parsed, in case they happen to match, we'll know it's a duplicate. */ 41 | 42 | /** 43 | * All of the regular expressions in use within readability. 44 | * Defined up here so we don't instantiate them repeatedly in loops. 45 | **/ 46 | regexps: { 47 | unlikelyCandidates: /combx|comment|community|disqus|extra|foot|header|menu|remark|rss|shoutbox|sidebar|sponsor|ad-break|agegate|pagination|pager|popup|tweet|twitter/i, 48 | okMaybeItsACandidate: /and|article|body|column|main|shadow/i, 49 | positive: /article|body|content|entry|hentry|main|page|pagination|post|text|blog|story/i, 50 | negative: /combx|comment|com-|contact|foot|footer|footnote|masthead|media|meta|outbrain|promo|related|scroll|shoutbox|sidebar|sponsor|shopping|tags|tool|widget/i, 51 | extraneous: /print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single/i, 52 | divToPElements: /<(a|blockquote|dl|div|img|ol|p|pre|table|ul)/i, 53 | replaceBrs: /(]*>[ \n\r\t]*){2,}/gi, 54 | replaceFonts: /<(\/?)font[^>]*>/gi, 55 | trim: /^\s+|\s+$/g, 56 | normalize: /\s{2,}/g, 57 | killBreaks: /((\s| ?)*){1,}/g, 58 | videos: /http:\/\/(www\.)?(youtube|vimeo)\.com/i, 59 | skipFootnoteLink: /^\s*(\[?[a-z0-9]{1,2}\]?|^|edit|citation needed)\s*$/i, 60 | nextLink: /(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i, // Match: next, continue, >, >>, » but not >|, »| as those usually mean last. 61 | prevLink: /(prev|earl|old|new|<|«)/i 62 | }, 63 | 64 | /** 65 | * Runs readability. 66 | * 67 | * Workflow: 68 | * 1. Prep the document by removing script tags, css, etc. 69 | * 2. Build readability's DOM tree. 70 | * 3. Grab the article content from the current dom tree. 71 | * 4. Replace the current DOM tree with the new one. 72 | * 5. Read peacefully. 73 | * 74 | * @return void 75 | **/ 76 | init: function() { 77 | /* Before we do anything, remove all scripts that are not readability. */ 78 | window.onload = window.onunload = function() {}; 79 | 80 | readability.removeScripts(document); 81 | 82 | if(document.body && !readability.bodyCache) { 83 | readability.bodyCache = document.body.innerHTML; 84 | 85 | } 86 | /* Make sure this document is added to the list of parsed pages first, so we don't double up on the first page */ 87 | readability.parsedPages[window.location.href.replace(/\/$/, '')] = true; 88 | 89 | /* Pull out any possible next page link first */ 90 | var nextPageLink = readability.findNextPageLink(document.body); 91 | 92 | readability.prepDocument(); 93 | 94 | /* Build readability's DOM tree */ 95 | var overlay = document.createElement("DIV"); 96 | var innerDiv = document.createElement("DIV"); 97 | var articleTools = readability.getArticleTools(); 98 | var articleTitle = readability.getArticleTitle(); 99 | var articleContent = readability.grabArticle(); 100 | var articleFooter = readability.getArticleFooter(); 101 | 102 | if(!articleContent) { 103 | articleContent = document.createElement("DIV"); 104 | articleContent.id = "readability-content"; 105 | articleContent.innerHTML = [ 106 | "

Sorry, readability was unable to parse this page for content. If you feel like it should have been able to, please let us know by submitting an issue.

", 107 | (readability.frameHack ? "

It appears this page uses frames. Unfortunately, browser security properties often cause Readability to fail on pages that include frames. You may want to try running readability itself on this source page: " + readability.biggestFrame.src + "

" : ""), 108 | "

Also, please note that Readability does not play very nicely with front pages. Readability is intended to work on articles with a sizable chunk of text that you'd like to read comfortably. If you're using Readability on a landing page (like nytimes.com for example), please click into an article first before using Readability.

" 109 | ].join(''); 110 | 111 | nextPageLink = null; 112 | } 113 | 114 | overlay.id = "readOverlay"; 115 | innerDiv.id = "readInner"; 116 | 117 | /* Apply user-selected styling */ 118 | document.body.className = readStyle; 119 | document.dir = readability.getSuggestedDirection(articleTitle.innerHTML); 120 | 121 | if (readStyle === "style-athelas" || readStyle === "style-apertura"){ 122 | overlay.className = readStyle + " rdbTypekit"; 123 | } 124 | else { 125 | overlay.className = readStyle; 126 | } 127 | innerDiv.className = readMargin + " " + readSize; 128 | 129 | if(typeof(readConvertLinksToFootnotes) !== 'undefined' && readConvertLinksToFootnotes === true) { 130 | readability.convertLinksToFootnotes = true; 131 | } 132 | 133 | /* Glue the structure of our document together. */ 134 | innerDiv.appendChild( articleTitle ); 135 | innerDiv.appendChild( articleContent ); 136 | innerDiv.appendChild( articleFooter ); 137 | overlay.appendChild( articleTools ); 138 | overlay.appendChild( innerDiv ); 139 | 140 | /* Clear the old HTML, insert the new content. */ 141 | document.body.innerHTML = ""; 142 | document.body.insertBefore(overlay, document.body.firstChild); 143 | document.body.removeAttribute('style'); 144 | 145 | if(readability.frameHack) 146 | { 147 | var readOverlay = document.getElementById('readOverlay'); 148 | readOverlay.style.height = '100%'; 149 | readOverlay.style.overflow = 'auto'; 150 | } 151 | 152 | /** 153 | * If someone tries to use Readability on a site's root page, give them a warning about usage. 154 | **/ 155 | if((window.location.protocol + "//" + window.location.host + "/") === window.location.href) 156 | { 157 | articleContent.style.display = "none"; 158 | var rootWarning = document.createElement('p'); 159 | rootWarning.id = "readability-warning"; 160 | rootWarning.innerHTML = "Readability was intended for use on individual articles and not home pages. " + 161 | "If you'd like to try rendering this page anyway, click here to continue."; 162 | 163 | innerDiv.insertBefore( rootWarning, articleContent ); 164 | } 165 | 166 | readability.postProcessContent(articleContent); 167 | 168 | window.scrollTo(0, 0); 169 | 170 | /* If we're using the Typekit library, select the font */ 171 | if (readStyle === "style-athelas" || readStyle === "style-apertura") { 172 | readability.useRdbTypekit(); 173 | } 174 | 175 | if (nextPageLink) { 176 | /** 177 | * Append any additional pages after a small timeout so that people 178 | * can start reading without having to wait for this to finish processing. 179 | **/ 180 | window.setTimeout(function() { 181 | readability.appendNextPage(nextPageLink); 182 | }, 500); 183 | } 184 | 185 | /** Smooth scrolling **/ 186 | document.onkeydown = function(e) { 187 | var code = (window.event) ? event.keyCode : e.keyCode; 188 | if (code === 16) { 189 | readability.reversePageScroll = true; 190 | return; 191 | } 192 | 193 | if (code === 32) { 194 | readability.curScrollStep = 0; 195 | var windowHeight = window.innerHeight ? window.innerHeight : (document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight); 196 | 197 | if(readability.reversePageScroll) { 198 | readability.scrollTo(readability.scrollTop(), readability.scrollTop() - (windowHeight - 50), 20, 10); 199 | } 200 | else { 201 | readability.scrollTo(readability.scrollTop(), readability.scrollTop() + (windowHeight - 50), 20, 10); 202 | } 203 | 204 | return false; 205 | } 206 | }; 207 | 208 | document.onkeyup = function(e) { 209 | var code = (window.event) ? event.keyCode : e.keyCode; 210 | if (code === 16) { 211 | readability.reversePageScroll = false; 212 | return; 213 | } 214 | }; 215 | }, 216 | 217 | /** 218 | * Run any post-process modifications to article content as necessary. 219 | * 220 | * @param Element 221 | * @return void 222 | **/ 223 | postProcessContent: function(articleContent) { 224 | if(readability.convertLinksToFootnotes && !window.location.href.match(/wikipedia\.org/g)) { 225 | readability.addFootnotes(articleContent); 226 | } 227 | 228 | readability.fixImageFloats(articleContent); 229 | }, 230 | 231 | /** 232 | * Some content ends up looking ugly if the image is too large to be floated. 233 | * If the image is wider than a threshold (currently 55%), no longer float it, 234 | * center it instead. 235 | * 236 | * @param Element 237 | * @return void 238 | **/ 239 | fixImageFloats: function (articleContent) { 240 | var imageWidthThreshold = Math.min(articleContent.offsetWidth, 800) * 0.55, 241 | images = articleContent.getElementsByTagName('img'); 242 | 243 | for(var i=0, il = images.length; i < il; i+=1) { 244 | var image = images[i]; 245 | 246 | if(image.offsetWidth > imageWidthThreshold) { 247 | image.className += " blockImage"; 248 | } 249 | } 250 | }, 251 | 252 | /** 253 | * Get the article tools Element that has buttons like reload, print, email. 254 | * 255 | * @return void 256 | **/ 257 | getArticleTools: function () { 258 | var articleTools = document.createElement("DIV"); 259 | 260 | articleTools.id = "readTools"; 261 | articleTools.innerHTML = 262 | "Reload Original Page" + 263 | "Print Page" + 264 | "Email Page"; 265 | 266 | return articleTools; 267 | }, 268 | 269 | /** 270 | * retuns the suggested direction of the string 271 | * 272 | * @return "rtl" || "ltr" 273 | **/ 274 | getSuggestedDirection: function(text) { 275 | function sanitizeText() { 276 | return text.replace(/@\w+/, ""); 277 | } 278 | 279 | function countMatches(match) { 280 | var matches = text.match(new RegExp(match, "g")); 281 | return matches !== null ? matches.length : 0; 282 | } 283 | 284 | function isRTL() { 285 | var count_heb = countMatches("[\\u05B0-\\u05F4\\uFB1D-\\uFBF4]"); 286 | var count_arb = countMatches("[\\u060C-\\u06FE\\uFB50-\\uFEFC]"); 287 | 288 | // if 20% of chars are Hebrew or Arbic then direction is rtl 289 | return (count_heb + count_arb) * 100 / text.length > 20; 290 | } 291 | 292 | text = sanitizeText(text); 293 | return isRTL() ? "rtl" : "ltr"; 294 | }, 295 | 296 | 297 | /** 298 | * Get the article title as an H1. 299 | * 300 | * @return void 301 | **/ 302 | getArticleTitle: function () { 303 | var curTitle = "", 304 | origTitle = ""; 305 | 306 | try { 307 | curTitle = origTitle = document.title; 308 | 309 | if(typeof curTitle !== "string") { /* If they had an element with id "title" in their HTML */ 310 | curTitle = origTitle = readability.getInnerText(document.getElementsByTagName('title')[0]); 311 | } 312 | } 313 | catch(e) {} 314 | 315 | if(curTitle.match(/ [\|\-] /)) 316 | { 317 | curTitle = origTitle.replace(/(.*)[\|\-] .*/gi,'$1'); 318 | 319 | if(curTitle.split(' ').length < 3) { 320 | curTitle = origTitle.replace(/[^\|\-]*[\|\-](.*)/gi,'$1'); 321 | } 322 | } 323 | else if(curTitle.indexOf(': ') !== -1) 324 | { 325 | curTitle = origTitle.replace(/.*:(.*)/gi, '$1'); 326 | 327 | if(curTitle.split(' ').length < 3) { 328 | curTitle = origTitle.replace(/[^:]*[:](.*)/gi,'$1'); 329 | } 330 | } 331 | else if(curTitle.length > 150 || curTitle.length < 15) 332 | { 333 | var hOnes = document.getElementsByTagName('h1'); 334 | if(hOnes.length === 1) 335 | { 336 | curTitle = readability.getInnerText(hOnes[0]); 337 | } 338 | } 339 | 340 | curTitle = curTitle.replace( readability.regexps.trim, "" ); 341 | 342 | if(curTitle.split(' ').length <= 4) { 343 | curTitle = origTitle; 344 | } 345 | 346 | var articleTitle = document.createElement("H1"); 347 | articleTitle.innerHTML = curTitle; 348 | 349 | return articleTitle; 350 | }, 351 | 352 | /** 353 | * Get the footer with the readability mark etc. 354 | * 355 | * @return void 356 | **/ 357 | getArticleFooter: function () { 358 | var articleFooter = document.createElement("DIV"); 359 | 360 | /** 361 | * For research purposes, generate an img src that contains the chosen readstyle etc, 362 | * so we can generate aggregate stats and change styles based on them in the future 363 | **/ 364 | // var statsQueryParams = "?readStyle=" + encodeURIComponent(readStyle) + "&readMargin=" + encodeURIComponent(readMargin) + "&readSize=" + encodeURIComponent(readSize); 365 | /* TODO: attach this to an image */ 366 | 367 | articleFooter.id = "readFooter"; 368 | articleFooter.innerHTML = [ 369 | "", 370 | ""].join(''); 381 | 382 | return articleFooter; 383 | }, 384 | 385 | /** 386 | * Prepare the HTML document for readability to scrape it. 387 | * This includes things like stripping javascript, CSS, and handling terrible markup. 388 | * 389 | * @return void 390 | **/ 391 | prepDocument: function () { 392 | /** 393 | * In some cases a body element can't be found (if the HTML is totally hosed for example) 394 | * so we create a new body node and append it to the document. 395 | */ 396 | if(document.body === null) 397 | { 398 | var body = document.createElement("body"); 399 | try { 400 | document.body = body; 401 | } 402 | catch(e) { 403 | document.documentElement.appendChild(body); 404 | dbg(e); 405 | } 406 | } 407 | 408 | document.body.id = "readabilityBody"; 409 | 410 | var frames = document.getElementsByTagName('frame'); 411 | if(frames.length > 0) 412 | { 413 | var bestFrame = null; 414 | var bestFrameSize = 0; /* The frame to try to run readability upon. Must be on same domain. */ 415 | var biggestFrameSize = 0; /* Used for the error message. Can be on any domain. */ 416 | for(var frameIndex = 0; frameIndex < frames.length; frameIndex+=1) 417 | { 418 | var frameSize = frames[frameIndex].offsetWidth + frames[frameIndex].offsetHeight; 419 | var canAccessFrame = false; 420 | try { 421 | var frameBody = frames[frameIndex].contentWindow.document.body; 422 | canAccessFrame = true; 423 | } 424 | catch(eFrames) { 425 | dbg(eFrames); 426 | } 427 | 428 | if(frameSize > biggestFrameSize) { 429 | biggestFrameSize = frameSize; 430 | readability.biggestFrame = frames[frameIndex]; 431 | } 432 | 433 | if(canAccessFrame && frameSize > bestFrameSize) 434 | { 435 | readability.frameHack = true; 436 | 437 | bestFrame = frames[frameIndex]; 438 | bestFrameSize = frameSize; 439 | } 440 | } 441 | 442 | if(bestFrame) 443 | { 444 | var newBody = document.createElement('body'); 445 | newBody.innerHTML = bestFrame.contentWindow.document.body.innerHTML; 446 | newBody.style.overflow = 'scroll'; 447 | document.body = newBody; 448 | 449 | var frameset = document.getElementsByTagName('frameset')[0]; 450 | if(frameset) { 451 | frameset.parentNode.removeChild(frameset); } 452 | } 453 | } 454 | 455 | /* Remove all stylesheets */ 456 | for (var k=0;k < document.styleSheets.length; k+=1) { 457 | if (document.styleSheets[k].href !== null && document.styleSheets[k].href.lastIndexOf("readability") === -1) { 458 | document.styleSheets[k].disabled = true; 459 | } 460 | } 461 | 462 | /* Remove all style tags in head (not doing this on IE) - TODO: Why not? */ 463 | var styleTags = document.getElementsByTagName("style"); 464 | for (var st=0;st < styleTags.length; st+=1) { 465 | styleTags[st].textContent = ""; 466 | } 467 | 468 | /* Turn all double br's into p's */ 469 | /* Note, this is pretty costly as far as processing goes. Maybe optimize later. */ 470 | document.body.innerHTML = document.body.innerHTML.replace(readability.regexps.replaceBrs, '

').replace(readability.regexps.replaceFonts, '<$1span>'); 471 | }, 472 | 473 | /** 474 | * For easier reading, convert this document to have footnotes at the bottom rather than inline links. 475 | * @see http://www.roughtype.com/archives/2010/05/experiments_in.php 476 | * 477 | * @return void 478 | **/ 479 | addFootnotes: function(articleContent) { 480 | var footnotesWrapper = document.getElementById('readability-footnotes'), 481 | articleFootnotes = document.getElementById('readability-footnotes-list'); 482 | 483 | if(!footnotesWrapper) { 484 | footnotesWrapper = document.createElement("DIV"); 485 | footnotesWrapper.id = 'readability-footnotes'; 486 | footnotesWrapper.innerHTML = '

References

'; 487 | footnotesWrapper.style.display = 'none'; /* Until we know we have footnotes, don't show the references block. */ 488 | 489 | articleFootnotes = document.createElement('ol'); 490 | articleFootnotes.id = 'readability-footnotes-list'; 491 | 492 | footnotesWrapper.appendChild(articleFootnotes); 493 | 494 | var readFooter = document.getElementById('readFooter'); 495 | 496 | if(readFooter) { 497 | readFooter.parentNode.insertBefore(footnotesWrapper, readFooter); 498 | } 499 | } 500 | 501 | var articleLinks = articleContent.getElementsByTagName('a'); 502 | var linkCount = articleFootnotes.getElementsByTagName('li').length; 503 | for (var i = 0; i < articleLinks.length; i+=1) 504 | { 505 | var articleLink = articleLinks[i], 506 | footnoteLink = articleLink.cloneNode(true), 507 | refLink = document.createElement('a'), 508 | footnote = document.createElement('li'), 509 | linkDomain = footnoteLink.host ? footnoteLink.host : document.location.host, 510 | linkText = readability.getInnerText(articleLink); 511 | 512 | if(articleLink.className && articleLink.className.indexOf('readability-DoNotFootnote') !== -1 || linkText.match(readability.regexps.skipFootnoteLink)) { 513 | continue; 514 | } 515 | 516 | linkCount+=1; 517 | 518 | /** Add a superscript reference after the article link */ 519 | refLink.href = '#readabilityFootnoteLink-' + linkCount; 520 | refLink.innerHTML = '[' + linkCount + ']'; 521 | refLink.className = 'readability-DoNotFootnote'; 522 | try { refLink.style.color = 'inherit'; } catch(e) {} /* IE7 doesn't like inherit. */ 523 | 524 | if(articleLink.parentNode.lastChild === articleLink) { 525 | articleLink.parentNode.appendChild(refLink); 526 | } else { 527 | articleLink.parentNode.insertBefore(refLink, articleLink.nextSibling); 528 | } 529 | 530 | articleLink.name = 'readabilityLink-' + linkCount; 531 | try { articleLink.style.color = 'inherit'; } catch(err) {} /* IE7 doesn't like inherit. */ 532 | 533 | footnote.innerHTML = "^ "; 534 | 535 | footnoteLink.innerHTML = (footnoteLink.title ? footnoteLink.title : linkText); 536 | footnoteLink.name = 'readabilityFootnoteLink-' + linkCount; 537 | 538 | footnote.appendChild(footnoteLink); 539 | footnote.innerHTML = footnote.innerHTML + " (" + linkDomain + ")"; 540 | 541 | articleFootnotes.appendChild(footnote); 542 | } 543 | 544 | if(linkCount > 0) { 545 | footnotesWrapper.style.display = 'block'; 546 | } 547 | }, 548 | 549 | useRdbTypekit: function () { 550 | var rdbHead = document.getElementsByTagName('head')[0]; 551 | var rdbTKScript = document.createElement('script'); 552 | var rdbTKCode = null; 553 | 554 | var rdbTKLink = document.createElement('a'); 555 | rdbTKLink.setAttribute('class','rdbTK-powered'); 556 | rdbTKLink.setAttribute('title','Fonts by Typekit'); 557 | rdbTKLink.innerHTML = "Fonts by Typekit"; 558 | 559 | if (readStyle === "style-athelas") { 560 | rdbTKCode = "sxt6vzy"; 561 | dbg("Using Athelas Theme"); 562 | 563 | rdbTKLink.setAttribute('href','http://typekit.com/?utm_source=readability&utm_medium=affiliate&utm_campaign=athelas'); 564 | rdbTKLink.setAttribute('id','rdb-athelas'); 565 | document.getElementById("rdb-footer-right").appendChild(rdbTKLink); 566 | } 567 | if (readStyle === "style-apertura") { 568 | rdbTKCode = "bae8ybu"; 569 | dbg("Using Inverse Theme"); 570 | 571 | rdbTKLink.setAttribute('href','http://typekit.com/?utm_source=readability&utm_medium=affiliate&utm_campaign=inverse'); 572 | rdbTKLink.setAttribute('id','rdb-inverse'); 573 | document.getElementById("rdb-footer-right").appendChild(rdbTKLink); 574 | } 575 | 576 | /** 577 | * Setting new script tag attributes to pull Typekits libraries 578 | **/ 579 | rdbTKScript.setAttribute('type','text/javascript'); 580 | rdbTKScript.setAttribute('src',"http://use.typekit.com/" + rdbTKCode + ".js"); 581 | rdbTKScript.setAttribute('charset','UTF-8'); 582 | rdbHead.appendChild(rdbTKScript); 583 | 584 | /** 585 | * In the future, maybe try using the following experimental Callback function?: 586 | * http://gist.github.com/192350 587 | * & 588 | * http://getsatisfaction.com/typekit/topics/support_a_pre_and_post_load_callback_function 589 | **/ 590 | var typekitLoader = function() { 591 | dbg("Looking for Typekit."); 592 | if(typeof Typekit !== "undefined") { 593 | try { 594 | dbg("Caught typekit"); 595 | Typekit.load(); 596 | clearInterval(window.typekitInterval); 597 | } catch(e) { 598 | dbg("Typekit error: " + e); 599 | } 600 | } 601 | }; 602 | 603 | window.typekitInterval = window.setInterval(typekitLoader, 100); 604 | }, 605 | 606 | /** 607 | * Prepare the article node for display. Clean out any inline styles, 608 | * iframes, forms, strip extraneous

tags, etc. 609 | * 610 | * @param Element 611 | * @return void 612 | **/ 613 | prepArticle: function (articleContent) { 614 | readability.cleanStyles(articleContent); 615 | readability.killBreaks(articleContent); 616 | 617 | /* Clean out junk from the article content */ 618 | readability.cleanConditionally(articleContent, "form"); 619 | readability.clean(articleContent, "object"); 620 | readability.clean(articleContent, "h1"); 621 | 622 | /** 623 | * If there is only one h2, they are probably using it 624 | * as a header and not a subheader, so remove it since we already have a header. 625 | ***/ 626 | if(articleContent.getElementsByTagName('h2').length === 1) { 627 | readability.clean(articleContent, "h2"); 628 | } 629 | readability.clean(articleContent, "iframe"); 630 | 631 | readability.cleanHeaders(articleContent); 632 | 633 | /* Do these last as the previous stuff may have removed junk that will affect these */ 634 | readability.cleanConditionally(articleContent, "table"); 635 | readability.cleanConditionally(articleContent, "ul"); 636 | readability.cleanConditionally(articleContent, "div"); 637 | 638 | /* Remove extra paragraphs */ 639 | var articleParagraphs = articleContent.getElementsByTagName('p'); 640 | for(var i = articleParagraphs.length-1; i >= 0; i-=1) { 641 | var imgCount = articleParagraphs[i].getElementsByTagName('img').length; 642 | var embedCount = articleParagraphs[i].getElementsByTagName('embed').length; 643 | var objectCount = articleParagraphs[i].getElementsByTagName('object').length; 644 | 645 | if(imgCount === 0 && embedCount === 0 && objectCount === 0 && readability.getInnerText(articleParagraphs[i], false) === '') { 646 | articleParagraphs[i].parentNode.removeChild(articleParagraphs[i]); 647 | } 648 | } 649 | 650 | try { 651 | articleContent.innerHTML = articleContent.innerHTML.replace(/]*>\s*

topCandidate.readability.contentScore) { 852 | topCandidate = candidates[c]; } 853 | } 854 | 855 | /** 856 | * If we still have no top candidate, just use the body as a last resort. 857 | * We also have to copy the body node so it is something we can modify. 858 | **/ 859 | if (topCandidate === null || topCandidate.tagName === "BODY") 860 | { 861 | topCandidate = document.createElement("DIV"); 862 | topCandidate.innerHTML = page.innerHTML; 863 | page.innerHTML = ""; 864 | page.appendChild(topCandidate); 865 | readability.initializeNode(topCandidate); 866 | } 867 | 868 | /** 869 | * Now that we have the top candidate, look through its siblings for content that might also be related. 870 | * Things like preambles, content split by ads that we removed, etc. 871 | **/ 872 | var articleContent = document.createElement("DIV"); 873 | if (isPaging) { 874 | articleContent.id = "readability-content"; 875 | } 876 | var siblingScoreThreshold = Math.max(10, topCandidate.readability.contentScore * 0.2); 877 | var siblingNodes = topCandidate.parentNode.childNodes; 878 | 879 | 880 | for(var s=0, sl=siblingNodes.length; s < sl; s+=1) { 881 | var siblingNode = siblingNodes[s]; 882 | var append = false; 883 | 884 | /** 885 | * Fix for odd IE7 Crash where siblingNode does not exist even though this should be a live nodeList. 886 | * Example of error visible here: http://www.esquire.com/features/honesty0707 887 | **/ 888 | if(!siblingNode) { 889 | continue; 890 | } 891 | 892 | dbg("Looking at sibling node: " + siblingNode + " (" + siblingNode.className + ":" + siblingNode.id + ")" + ((typeof siblingNode.readability !== 'undefined') ? (" with score " + siblingNode.readability.contentScore) : '')); 893 | dbg("Sibling has score " + (siblingNode.readability ? siblingNode.readability.contentScore : 'Unknown')); 894 | 895 | if(siblingNode === topCandidate) 896 | { 897 | append = true; 898 | } 899 | 900 | var contentBonus = 0; 901 | /* Give a bonus if sibling nodes and top candidates have the example same classname */ 902 | if(siblingNode.className === topCandidate.className && topCandidate.className !== "") { 903 | contentBonus += topCandidate.readability.contentScore * 0.2; 904 | } 905 | 906 | if(typeof siblingNode.readability !== 'undefined' && (siblingNode.readability.contentScore+contentBonus) >= siblingScoreThreshold) 907 | { 908 | append = true; 909 | } 910 | 911 | if(siblingNode.nodeName === "P") { 912 | var linkDensity = readability.getLinkDensity(siblingNode); 913 | var nodeContent = readability.getInnerText(siblingNode); 914 | var nodeLength = nodeContent.length; 915 | 916 | if(nodeLength > 80 && linkDensity < 0.25) 917 | { 918 | append = true; 919 | } 920 | else if(nodeLength < 80 && linkDensity === 0 && nodeContent.search(/\.( |$)/) !== -1) 921 | { 922 | append = true; 923 | } 924 | } 925 | 926 | if(append) { 927 | dbg("Appending node: " + siblingNode); 928 | 929 | var nodeToAppend = null; 930 | if(siblingNode.nodeName !== "DIV" && siblingNode.nodeName !== "P") { 931 | /* We have a node that isn't a common block level element, like a form or td tag. Turn it into a div so it doesn't get filtered out later by accident. */ 932 | 933 | dbg("Altering siblingNode of " + siblingNode.nodeName + ' to div.'); 934 | nodeToAppend = document.createElement("DIV"); 935 | try { 936 | nodeToAppend.id = siblingNode.id; 937 | nodeToAppend.innerHTML = siblingNode.innerHTML; 938 | } 939 | catch(er) { 940 | dbg("Could not alter siblingNode to div, probably an IE restriction, reverting back to original."); 941 | nodeToAppend = siblingNode; 942 | s-=1; 943 | sl-=1; 944 | } 945 | } else { 946 | nodeToAppend = siblingNode; 947 | s-=1; 948 | sl-=1; 949 | } 950 | 951 | /* To ensure a node does not interfere with readability styles, remove its classnames */ 952 | nodeToAppend.className = ""; 953 | 954 | /* Append sibling and subtract from our list because it removes the node when you append to another node */ 955 | articleContent.appendChild(nodeToAppend); 956 | } 957 | } 958 | 959 | /** 960 | * So we have all of the content that we need. Now we clean it up for presentation. 961 | **/ 962 | readability.prepArticle(articleContent); 963 | 964 | if (readability.curPageNum === 1) { 965 | articleContent.innerHTML = '

' + articleContent.innerHTML + '
'; 966 | } 967 | 968 | /** 969 | * Now that we've gone through the full algorithm, check to see if we got any meaningful content. 970 | * If we didn't, we may need to re-run grabArticle with different flags set. This gives us a higher 971 | * likelihood of finding the content, and the sieve approach gives us a higher likelihood of 972 | * finding the -right- content. 973 | **/ 974 | if(readability.getInnerText(articleContent, false).length < 250) { 975 | page.innerHTML = pageCacheHtml; 976 | 977 | if (readability.flagIsActive(readability.FLAG_STRIP_UNLIKELYS)) { 978 | readability.removeFlag(readability.FLAG_STRIP_UNLIKELYS); 979 | return readability.grabArticle(page); 980 | } 981 | else if (readability.flagIsActive(readability.FLAG_WEIGHT_CLASSES)) { 982 | readability.removeFlag(readability.FLAG_WEIGHT_CLASSES); 983 | return readability.grabArticle(page); 984 | } 985 | else if (readability.flagIsActive(readability.FLAG_CLEAN_CONDITIONALLY)) { 986 | readability.removeFlag(readability.FLAG_CLEAN_CONDITIONALLY); 987 | return readability.grabArticle(page); 988 | } else { 989 | return null; 990 | } 991 | } 992 | 993 | return articleContent; 994 | }, 995 | 996 | /** 997 | * Removes script tags from the document. 998 | * 999 | * @param Element 1000 | **/ 1001 | removeScripts: function (doc) { 1002 | var scripts = doc.getElementsByTagName('script'); 1003 | for(var i = scripts.length-1; i >= 0; i-=1) 1004 | { 1005 | if(typeof(scripts[i].src) === "undefined" || (scripts[i].src.indexOf('readability') === -1 && scripts[i].src.indexOf('typekit') === -1)) 1006 | { 1007 | scripts[i].nodeValue=""; 1008 | scripts[i].removeAttribute('src'); 1009 | if (scripts[i].parentNode) { 1010 | scripts[i].parentNode.removeChild(scripts[i]); 1011 | } 1012 | } 1013 | } 1014 | }, 1015 | 1016 | /** 1017 | * Get the inner text of a node - cross browser compatibly. 1018 | * This also strips out any excess whitespace to be found. 1019 | * 1020 | * @param Element 1021 | * @return string 1022 | **/ 1023 | getInnerText: function (e, normalizeSpaces) { 1024 | var textContent = ""; 1025 | 1026 | if(typeof(e.textContent) === "undefined" && typeof(e.innerText) === "undefined") { 1027 | return ""; 1028 | } 1029 | 1030 | normalizeSpaces = (typeof normalizeSpaces === 'undefined') ? true : normalizeSpaces; 1031 | 1032 | if (navigator.appName === "Microsoft Internet Explorer") { 1033 | textContent = e.innerText.replace( readability.regexps.trim, "" ); } 1034 | else { 1035 | textContent = e.textContent.replace( readability.regexps.trim, "" ); } 1036 | 1037 | if(normalizeSpaces) { 1038 | return textContent.replace( readability.regexps.normalize, " "); } 1039 | else { 1040 | return textContent; } 1041 | }, 1042 | 1043 | /** 1044 | * Get the number of times a string s appears in the node e. 1045 | * 1046 | * @param Element 1047 | * @param string - what to split on. Default is "," 1048 | * @return number (integer) 1049 | **/ 1050 | getCharCount: function (e,s) { 1051 | s = s || ","; 1052 | return readability.getInnerText(e).split(s).length-1; 1053 | }, 1054 | 1055 | /** 1056 | * Remove the style attribute on every e and under. 1057 | * TODO: Test if getElementsByTagName(*) is faster. 1058 | * 1059 | * @param Element 1060 | * @return void 1061 | **/ 1062 | cleanStyles: function (e) { 1063 | e = e || document; 1064 | var cur = e.firstChild; 1065 | 1066 | if(!e) { 1067 | return; } 1068 | 1069 | // Remove any root styles, if we're able. 1070 | if(typeof e.removeAttribute === 'function' && e.className !== 'readability-styled') { 1071 | e.removeAttribute('style'); } 1072 | 1073 | // Go until there are no more child nodes 1074 | while ( cur !== null ) { 1075 | if ( cur.nodeType === 1 ) { 1076 | // Remove style attribute(s) : 1077 | if(cur.className !== "readability-styled") { 1078 | cur.removeAttribute("style"); 1079 | } 1080 | readability.cleanStyles( cur ); 1081 | } 1082 | cur = cur.nextSibling; 1083 | } 1084 | }, 1085 | 1086 | /** 1087 | * Get the density of links as a percentage of the content 1088 | * This is the amount of text that is inside a link divided by the total text in the node. 1089 | * 1090 | * @param Element 1091 | * @return number (float) 1092 | **/ 1093 | getLinkDensity: function (e) { 1094 | var links = e.getElementsByTagName("a"); 1095 | var textLength = readability.getInnerText(e).length; 1096 | var linkLength = 0; 1097 | for(var i=0, il=links.length; i 25) { 1209 | continue; 1210 | } 1211 | 1212 | /* If the leftovers of the URL after removing the base URL don't contain any digits, it's certainly not a next page link. */ 1213 | var linkHrefLeftover = linkHref.replace(articleBaseUrl, ''); 1214 | if(!linkHrefLeftover.match(/\d/)) { 1215 | continue; 1216 | } 1217 | 1218 | if(!(linkHref in possiblePages)) { 1219 | possiblePages[linkHref] = {"score": 0, "linkText": linkText, "href": linkHref}; 1220 | } else { 1221 | possiblePages[linkHref].linkText += ' | ' + linkText; 1222 | } 1223 | 1224 | var linkObj = possiblePages[linkHref]; 1225 | 1226 | /** 1227 | * If the articleBaseUrl isn't part of this URL, penalize this link. It could still be the link, but the odds are lower. 1228 | * Example: http://www.actionscript.org/resources/articles/745/1/JavaScript-and-VBScript-Injection-in-ActionScript-3/Page1.html 1229 | **/ 1230 | if(linkHref.indexOf(articleBaseUrl) !== 0) { 1231 | linkObj.score -= 25; 1232 | } 1233 | 1234 | var linkData = linkText + ' ' + link.className + ' ' + link.id; 1235 | if(linkData.match(readability.regexps.nextLink)) { 1236 | linkObj.score += 50; 1237 | } 1238 | if(linkData.match(/pag(e|ing|inat)/i)) { 1239 | linkObj.score += 25; 1240 | } 1241 | if(linkData.match(/(first|last)/i)) { // -65 is enough to negate any bonuses gotten from a > or » in the text, 1242 | /* If we already matched on "next", last is probably fine. If we didn't, then it's bad. Penalize. */ 1243 | if(!linkObj.linkText.match(readability.regexps.nextLink)) { 1244 | linkObj.score -= 65; 1245 | } 1246 | } 1247 | if(linkData.match(readability.regexps.negative) || linkData.match(readability.regexps.extraneous)) { 1248 | linkObj.score -= 50; 1249 | } 1250 | if(linkData.match(readability.regexps.prevLink)) { 1251 | linkObj.score -= 200; 1252 | } 1253 | 1254 | /* If a parentNode contains page or paging or paginat */ 1255 | var parentNode = link.parentNode, 1256 | positiveNodeMatch = false, 1257 | negativeNodeMatch = false; 1258 | while(parentNode) { 1259 | var parentNodeClassAndId = parentNode.className + ' ' + parentNode.id; 1260 | if(!positiveNodeMatch && parentNodeClassAndId && parentNodeClassAndId.match(/pag(e|ing|inat)/i)) { 1261 | positiveNodeMatch = true; 1262 | linkObj.score += 25; 1263 | } 1264 | if(!negativeNodeMatch && parentNodeClassAndId && parentNodeClassAndId.match(readability.regexps.negative)) { 1265 | /* If this is just something like "footer", give it a negative. If it's something like "body-and-footer", leave it be. */ 1266 | if(!parentNodeClassAndId.match(readability.regexps.positive)) { 1267 | linkObj.score -= 25; 1268 | negativeNodeMatch = true; 1269 | } 1270 | } 1271 | 1272 | parentNode = parentNode.parentNode; 1273 | } 1274 | 1275 | /** 1276 | * If the URL looks like it has paging in it, add to the score. 1277 | * Things like /page/2/, /pagenum/2, ?p=3, ?page=11, ?pagination=34 1278 | **/ 1279 | if (linkHref.match(/p(a|g|ag)?(e|ing|ination)?(=|\/)[0-9]{1,2}/i) || linkHref.match(/(page|paging)/i)) { 1280 | linkObj.score += 25; 1281 | } 1282 | 1283 | /* If the URL contains negative values, give a slight decrease. */ 1284 | if (linkHref.match(readability.regexps.extraneous)) { 1285 | linkObj.score -= 15; 1286 | } 1287 | 1288 | /** 1289 | * Minor punishment to anything that doesn't match our current URL. 1290 | * NOTE: I'm finding this to cause more harm than good where something is exactly 50 points. 1291 | * Dan, can you show me a counterexample where this is necessary? 1292 | * if (linkHref.indexOf(window.location.href) !== 0) { 1293 | * linkObj.score -= 1; 1294 | * } 1295 | **/ 1296 | 1297 | /** 1298 | * If the link text can be parsed as a number, give it a minor bonus, with a slight 1299 | * bias towards lower numbered pages. This is so that pages that might not have 'next' 1300 | * in their text can still get scored, and sorted properly by score. 1301 | **/ 1302 | var linkTextAsNumber = parseInt(linkText, 10); 1303 | if(linkTextAsNumber) { 1304 | // Punish 1 since we're either already there, or it's probably before what we want anyways. 1305 | if (linkTextAsNumber === 1) { 1306 | linkObj.score -= 10; 1307 | } 1308 | else { 1309 | // Todo: Describe this better 1310 | linkObj.score += Math.max(0, 10 - linkTextAsNumber); 1311 | } 1312 | } 1313 | } 1314 | 1315 | /** 1316 | * Loop thrugh all of our possible pages from above and find our top candidate for the next page URL. 1317 | * Require at least a score of 50, which is a relatively high confidence that this page is the next link. 1318 | **/ 1319 | var topPage = null; 1320 | for(var page in possiblePages) { 1321 | if(possiblePages.hasOwnProperty(page)) { 1322 | if(possiblePages[page].score >= 50 && (!topPage || topPage.score < possiblePages[page].score)) { 1323 | topPage = possiblePages[page]; 1324 | } 1325 | } 1326 | } 1327 | 1328 | if(topPage) { 1329 | var nextHref = topPage.href.replace(/\/$/,''); 1330 | 1331 | dbg('NEXT PAGE IS ' + nextHref); 1332 | readability.parsedPages[nextHref] = true; 1333 | return nextHref; 1334 | } 1335 | else { 1336 | return null; 1337 | } 1338 | }, 1339 | 1340 | /** 1341 | * Build a simple cross browser compatible XHR. 1342 | * 1343 | * TODO: This could likely be simplified beyond what we have here right now. There's still a bit of excess junk. 1344 | **/ 1345 | xhr: function () { 1346 | if (typeof XMLHttpRequest !== 'undefined' && (window.location.protocol !== 'file:' || !window.ActiveXObject)) { 1347 | return new XMLHttpRequest(); 1348 | } 1349 | else { 1350 | try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(sixerr) { } 1351 | try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(threrr) { } 1352 | try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(err) { } 1353 | } 1354 | 1355 | return false; 1356 | }, 1357 | 1358 | successfulRequest: function (request) { 1359 | return (request.status >= 200 && request.status < 300) || request.status === 304 || (request.status === 0 && request.responseText); 1360 | }, 1361 | 1362 | ajax: function (url, options) { 1363 | var request = readability.xhr(); 1364 | 1365 | function respondToReadyState(readyState) { 1366 | if (request.readyState === 4) { 1367 | if (readability.successfulRequest(request)) { 1368 | if (options.success) { options.success(request); } 1369 | } 1370 | else { 1371 | if (options.error) { options.error(request); } 1372 | } 1373 | } 1374 | } 1375 | 1376 | if (typeof options === 'undefined') { options = {}; } 1377 | 1378 | request.onreadystatechange = respondToReadyState; 1379 | 1380 | request.open('get', url, true); 1381 | request.setRequestHeader('Accept', 'text/html'); 1382 | 1383 | try { 1384 | request.send(options.postBody); 1385 | } 1386 | catch (e) { 1387 | if (options.error) { options.error(); } 1388 | } 1389 | 1390 | return request; 1391 | }, 1392 | 1393 | /** 1394 | * Make an AJAX request for each page and append it to the document. 1395 | **/ 1396 | curPageNum: 1, 1397 | 1398 | appendNextPage: function (nextPageLink) { 1399 | readability.curPageNum+=1; 1400 | 1401 | var articlePage = document.createElement("DIV"); 1402 | articlePage.id = 'readability-page-' + readability.curPageNum; 1403 | articlePage.className = 'page'; 1404 | articlePage.innerHTML = '

§

'; 1405 | 1406 | document.getElementById("readability-content").appendChild(articlePage); 1407 | 1408 | if(readability.curPageNum > readability.maxPages) { 1409 | var nextPageMarkup = "
View Next Page
"; 1410 | 1411 | articlePage.innerHTML = articlePage.innerHTML + nextPageMarkup; 1412 | return; 1413 | } 1414 | 1415 | /** 1416 | * Now that we've built the article page DOM element, get the page content 1417 | * asynchronously and load the cleaned content into the div we created for it. 1418 | **/ 1419 | (function(pageUrl, thisPage) { 1420 | readability.ajax(pageUrl, { 1421 | success: function(r) { 1422 | 1423 | /* First, check to see if we have a matching ETag in headers - if we do, this is a duplicate page. */ 1424 | var eTag = r.getResponseHeader('ETag'); 1425 | if(eTag) { 1426 | if(eTag in readability.pageETags) { 1427 | dbg("Exact duplicate page found via ETag. Aborting."); 1428 | articlePage.style.display = 'none'; 1429 | return; 1430 | } else { 1431 | readability.pageETags[eTag] = 1; 1432 | } 1433 | } 1434 | 1435 | // TODO: this ends up doubling up page numbers on NYTimes articles. Need to generically parse those away. 1436 | var page = document.createElement("DIV"); 1437 | 1438 | /** 1439 | * Do some preprocessing to our HTML to make it ready for appending. 1440 | * • Remove any script tags. Swap and reswap newlines with a unicode character because multiline regex doesn't work in javascript. 1441 | * • Turn any noscript tags into divs so that we can parse them. This allows us to find any next page links hidden via javascript. 1442 | * • Turn all double br's into p's - was handled by prepDocument in the original view. 1443 | * Maybe in the future abstract out prepDocument to work for both the original document and AJAX-added pages. 1444 | **/ 1445 | var responseHtml = r.responseText.replace(/\n/g,'\uffff').replace(/.*?<\/script>/gi, ''); 1446 | responseHtml = responseHtml.replace(/\n/g,'\uffff').replace(/.*?<\/script>/gi, ''); 1447 | responseHtml = responseHtml.replace(/\uffff/g,'\n').replace(/<(\/?)noscript/gi, '<$1div'); 1448 | responseHtml = responseHtml.replace(readability.regexps.replaceBrs, '

'); 1449 | responseHtml = responseHtml.replace(readability.regexps.replaceFonts, '<$1span>'); 1450 | 1451 | page.innerHTML = responseHtml; 1452 | 1453 | /** 1454 | * Reset all flags for the next page, as they will search through it and disable as necessary at the end of grabArticle. 1455 | **/ 1456 | readability.flags = 0x1 | 0x2 | 0x4; 1457 | 1458 | var nextPageLink = readability.findNextPageLink(page), 1459 | content = readability.grabArticle(page); 1460 | 1461 | if(!content) { 1462 | dbg("No content found in page to append. Aborting."); 1463 | return; 1464 | } 1465 | 1466 | /** 1467 | * Anti-duplicate mechanism. Essentially, get the first paragraph of our new page. 1468 | * Compare it against all of the the previous document's we've gotten. If the previous 1469 | * document contains exactly the innerHTML of this first paragraph, it's probably a duplicate. 1470 | **/ 1471 | var firstP = content.getElementsByTagName("P").length ? content.getElementsByTagName("P")[0] : null; 1472 | if(firstP && firstP.innerHTML.length > 100) { 1473 | for(var i=1; i <= readability.curPageNum; i+=1) { 1474 | var rPage = document.getElementById('readability-page-' + i); 1475 | if(rPage && rPage.innerHTML.indexOf(firstP.innerHTML) !== -1) { 1476 | dbg('Duplicate of page ' + i + ' - skipping.'); 1477 | articlePage.style.display = 'none'; 1478 | readability.parsedPages[pageUrl] = true; 1479 | return; 1480 | } 1481 | } 1482 | } 1483 | 1484 | readability.removeScripts(content); 1485 | 1486 | thisPage.innerHTML = thisPage.innerHTML + content.innerHTML; 1487 | 1488 | /** 1489 | * After the page has rendered, post process the content. This delay is necessary because, 1490 | * in webkit at least, offsetWidth is not set in time to determine image width. We have to 1491 | * wait a little bit for reflow to finish before we can fix floating images. 1492 | **/ 1493 | window.setTimeout( 1494 | function() { readability.postProcessContent(thisPage); }, 1495 | 500 1496 | ); 1497 | 1498 | if(nextPageLink) { 1499 | readability.appendNextPage(nextPageLink); 1500 | } 1501 | } 1502 | }); 1503 | }(nextPageLink, articlePage)); 1504 | }, 1505 | 1506 | /** 1507 | * Get an elements class/id weight. Uses regular expressions to tell if this 1508 | * element looks good or bad. 1509 | * 1510 | * @param Element 1511 | * @return number (Integer) 1512 | **/ 1513 | getClassWeight: function (e) { 1514 | if(!readability.flagIsActive(readability.FLAG_WEIGHT_CLASSES)) { 1515 | return 0; 1516 | } 1517 | 1518 | var weight = 0; 1519 | 1520 | /* Look for a special classname */ 1521 | if (typeof(e.className) === 'string' && e.className !== '') 1522 | { 1523 | if(e.className.search(readability.regexps.negative) !== -1) { 1524 | weight -= 25; } 1525 | 1526 | if(e.className.search(readability.regexps.positive) !== -1) { 1527 | weight += 25; } 1528 | } 1529 | 1530 | /* Look for a special ID */ 1531 | if (typeof(e.id) === 'string' && e.id !== '') 1532 | { 1533 | if(e.id.search(readability.regexps.negative) !== -1) { 1534 | weight -= 25; } 1535 | 1536 | if(e.id.search(readability.regexps.positive) !== -1) { 1537 | weight += 25; } 1538 | } 1539 | 1540 | return weight; 1541 | }, 1542 | 1543 | nodeIsVisible: function (node) { 1544 | return (node.offsetWidth !== 0 || node.offsetHeight !== 0) && node.style.display.toLowerCase() !== 'none'; 1545 | }, 1546 | 1547 | /** 1548 | * Remove extraneous break tags from a node. 1549 | * 1550 | * @param Element 1551 | * @return void 1552 | **/ 1553 | killBreaks: function (e) { 1554 | try { 1555 | e.innerHTML = e.innerHTML.replace(readability.regexps.killBreaks,'
'); 1556 | } 1557 | catch (eBreaks) { 1558 | dbg("KillBreaks failed - this is an IE bug. Ignoring.: " + eBreaks); 1559 | } 1560 | }, 1561 | 1562 | /** 1563 | * Clean a node of all elements of type "tag". 1564 | * (Unless it's a youtube/vimeo video. People love movies.) 1565 | * 1566 | * @param Element 1567 | * @param string tag to clean 1568 | * @return void 1569 | **/ 1570 | clean: function (e, tag) { 1571 | var targetList = e.getElementsByTagName( tag ); 1572 | var isEmbed = (tag === 'object' || tag === 'embed'); 1573 | 1574 | for (var y=targetList.length-1; y >= 0; y-=1) { 1575 | /* Allow youtube and vimeo videos through as people usually want to see those. */ 1576 | if(isEmbed) { 1577 | var attributeValues = ""; 1578 | for (var i=0, il=targetList[y].attributes.length; i < il; i+=1) { 1579 | attributeValues += targetList[y].attributes[i].value + '|'; 1580 | } 1581 | 1582 | /* First, check the elements attributes to see if any of them contain youtube or vimeo */ 1583 | if (attributeValues.search(readability.regexps.videos) !== -1) { 1584 | continue; 1585 | } 1586 | 1587 | /* Then check the elements inside this element for the same. */ 1588 | if (targetList[y].innerHTML.search(readability.regexps.videos) !== -1) { 1589 | continue; 1590 | } 1591 | 1592 | } 1593 | 1594 | targetList[y].parentNode.removeChild(targetList[y]); 1595 | } 1596 | }, 1597 | 1598 | /** 1599 | * Clean an element of all tags of type "tag" if they look fishy. 1600 | * "Fishy" is an algorithm based on content length, classnames, link density, number of images & embeds, etc. 1601 | * 1602 | * @return void 1603 | **/ 1604 | cleanConditionally: function (e, tag) { 1605 | 1606 | if(!readability.flagIsActive(readability.FLAG_CLEAN_CONDITIONALLY)) { 1607 | return; 1608 | } 1609 | 1610 | var tagsList = e.getElementsByTagName(tag); 1611 | var curTagsLength = tagsList.length; 1612 | 1613 | /** 1614 | * Gather counts for other typical elements embedded within. 1615 | * Traverse backwards so we can remove nodes at the same time without effecting the traversal. 1616 | * 1617 | * TODO: Consider taking into account original contentScore here. 1618 | **/ 1619 | for (var i=curTagsLength-1; i >= 0; i-=1) { 1620 | var weight = readability.getClassWeight(tagsList[i]); 1621 | var contentScore = (typeof tagsList[i].readability !== 'undefined') ? tagsList[i].readability.contentScore : 0; 1622 | 1623 | dbg("Cleaning Conditionally " + tagsList[i] + " (" + tagsList[i].className + ":" + tagsList[i].id + ")" + ((typeof tagsList[i].readability !== 'undefined') ? (" with score " + tagsList[i].readability.contentScore) : '')); 1624 | 1625 | if(weight+contentScore < 0) 1626 | { 1627 | tagsList[i].parentNode.removeChild(tagsList[i]); 1628 | } 1629 | else if ( readability.getCharCount(tagsList[i],',') < 10) { 1630 | /** 1631 | * If there are not very many commas, and the number of 1632 | * non-paragraph elements is more than paragraphs or other ominous signs, remove the element. 1633 | **/ 1634 | var p = tagsList[i].getElementsByTagName("p").length; 1635 | var img = tagsList[i].getElementsByTagName("img").length; 1636 | var li = tagsList[i].getElementsByTagName("li").length-100; 1637 | var input = tagsList[i].getElementsByTagName("input").length; 1638 | 1639 | var embedCount = 0; 1640 | var embeds = tagsList[i].getElementsByTagName("embed"); 1641 | for(var ei=0,il=embeds.length; ei < il; ei+=1) { 1642 | if (embeds[ei].src.search(readability.regexps.videos) === -1) { 1643 | embedCount+=1; 1644 | } 1645 | } 1646 | 1647 | var linkDensity = readability.getLinkDensity(tagsList[i]); 1648 | var contentLength = readability.getInnerText(tagsList[i]).length; 1649 | var toRemove = false; 1650 | 1651 | if ( img > p ) { 1652 | toRemove = true; 1653 | } else if(li > p && tag !== "ul" && tag !== "ol") { 1654 | toRemove = true; 1655 | } else if( input > Math.floor(p/3) ) { 1656 | toRemove = true; 1657 | } else if(contentLength < 25 && (img === 0 || img > 2) ) { 1658 | toRemove = true; 1659 | } else if(weight < 25 && linkDensity > 0.2) { 1660 | toRemove = true; 1661 | } else if(weight >= 25 && linkDensity > 0.5) { 1662 | toRemove = true; 1663 | } else if((embedCount === 1 && contentLength < 75) || embedCount > 1) { 1664 | toRemove = true; 1665 | } 1666 | 1667 | if(toRemove) { 1668 | tagsList[i].parentNode.removeChild(tagsList[i]); 1669 | } 1670 | } 1671 | } 1672 | }, 1673 | 1674 | /** 1675 | * Clean out spurious headers from an Element. Checks things like classnames and link density. 1676 | * 1677 | * @param Element 1678 | * @return void 1679 | **/ 1680 | cleanHeaders: function (e) { 1681 | for (var headerIndex = 1; headerIndex < 3; headerIndex+=1) { 1682 | var headers = e.getElementsByTagName('h' + headerIndex); 1683 | for (var i=headers.length-1; i >=0; i-=1) { 1684 | if (readability.getClassWeight(headers[i]) < 0 || readability.getLinkDensity(headers[i]) > 0.33) { 1685 | headers[i].parentNode.removeChild(headers[i]); 1686 | } 1687 | } 1688 | } 1689 | }, 1690 | 1691 | /*** Smooth scrolling logic ***/ 1692 | 1693 | /** 1694 | * easeInOut animation algorithm - returns an integer that says how far to move at this point in the animation. 1695 | * Borrowed from jQuery's easing library. 1696 | * @return integer 1697 | **/ 1698 | easeInOut: function(start,end,totalSteps,actualStep) { 1699 | var delta = end - start; 1700 | 1701 | if ((actualStep/=totalSteps/2) < 1) { 1702 | return delta/2*actualStep*actualStep + start; 1703 | } 1704 | actualStep -=1; 1705 | return -delta/2 * ((actualStep)*(actualStep-2) - 1) + start; 1706 | }, 1707 | 1708 | /** 1709 | * Helper function to, in a cross compatible way, get or set the current scroll offset of the document. 1710 | * @return mixed integer on get, the result of window.scrollTo on set 1711 | **/ 1712 | scrollTop: function(scroll){ 1713 | var setScroll = typeof scroll !== 'undefined'; 1714 | 1715 | if(setScroll) { 1716 | return window.scrollTo(0, scroll); 1717 | } 1718 | if(typeof window.pageYOffset !== 'undefined') { 1719 | return window.pageYOffset; 1720 | } 1721 | else if(document.documentElement.clientHeight) { 1722 | return document.documentElement.scrollTop; 1723 | } 1724 | else { 1725 | return document.body.scrollTop; 1726 | } 1727 | }, 1728 | 1729 | /** 1730 | * scrollTo - Smooth scroll to the point of scrollEnd in the document. 1731 | * @return void 1732 | **/ 1733 | curScrollStep: 0, 1734 | scrollTo: function (scrollStart, scrollEnd, steps, interval) { 1735 | if( 1736 | (scrollStart < scrollEnd && readability.scrollTop() < scrollEnd) || 1737 | (scrollStart > scrollEnd && readability.scrollTop() > scrollEnd) 1738 | ) { 1739 | readability.curScrollStep+=1; 1740 | if(readability.curScrollStep > steps) { 1741 | return; 1742 | } 1743 | 1744 | var oldScrollTop = readability.scrollTop(); 1745 | 1746 | readability.scrollTop(readability.easeInOut(scrollStart, scrollEnd, steps, readability.curScrollStep)); 1747 | 1748 | // We're at the end of the window. 1749 | if(oldScrollTop === readability.scrollTop()) { 1750 | return; 1751 | } 1752 | 1753 | window.setTimeout(function() { 1754 | readability.scrollTo(scrollStart, scrollEnd, steps, interval); 1755 | }, interval); 1756 | } 1757 | }, 1758 | 1759 | 1760 | /** 1761 | * Show the email popup. 1762 | * 1763 | * @return void 1764 | **/ 1765 | emailBox: function () { 1766 | var emailContainerExists = document.getElementById('email-container'); 1767 | if(null !== emailContainerExists) 1768 | { 1769 | return; 1770 | } 1771 | 1772 | var emailContainer = document.createElement("DIV"); 1773 | emailContainer.setAttribute('id', 'email-container'); 1774 | emailContainer.innerHTML = ''; 1775 | 1776 | document.body.appendChild(emailContainer); 1777 | }, 1778 | 1779 | /** 1780 | * Close the email popup. This is a hacktackular way to check if we're in a "close loop". 1781 | * Since we don't have crossdomain access to the frame, we can only know when it has 1782 | * loaded again. If it's loaded over 3 times, we know to close the frame. 1783 | * 1784 | * @return void 1785 | **/ 1786 | removeFrame: function () { 1787 | readability.iframeLoads+=1; 1788 | if (readability.iframeLoads > 3) 1789 | { 1790 | var emailContainer = document.getElementById('email-container'); 1791 | if (null !== emailContainer) { 1792 | emailContainer.parentNode.removeChild(emailContainer); 1793 | } 1794 | 1795 | readability.iframeLoads = 0; 1796 | } 1797 | }, 1798 | 1799 | htmlspecialchars: function (s) { 1800 | if (typeof(s) === "string") { 1801 | s = s.replace(/&/g, "&"); 1802 | s = s.replace(/"/g, """); 1803 | s = s.replace(/'/g, "'"); 1804 | s = s.replace(//g, ">"); 1806 | } 1807 | 1808 | return s; 1809 | }, 1810 | 1811 | flagIsActive: function(flag) { 1812 | return (readability.flags & flag) > 0; 1813 | }, 1814 | 1815 | addFlag: function(flag) { 1816 | readability.flags = readability.flags | flag; 1817 | }, 1818 | 1819 | removeFlag: function(flag) { 1820 | readability.flags = readability.flags & ~flag; 1821 | } 1822 | 1823 | }; 1824 | 1825 | readability.init(); 1826 | -------------------------------------------------------------------------------- /readability/readability-print.css: -------------------------------------------------------------------------------- 1 | body, #readOverlay { 2 | background-color: white !important; 3 | } 4 | 5 | embed, object { 6 | display: none !important; 7 | } 8 | 9 | /*#readInner { 10 | width: 100% !important; 11 | } 12 | */ 13 | #readInner.margin-x-narrow {width:100% !important;} 14 | #readInner.margin-narrow {width:91% !important;} 15 | #readInner.margin-medium {width:84% !important;} 16 | #readInner.margin-wide {width:77% !important;} 17 | #readInner.margin-x-wide {width:70% !important;} 18 | 19 | #readTools { 20 | display: none !important; 21 | } 22 | 23 | #readFooter { 24 | font-size: .85em; 25 | text-align: left !important; 26 | } 27 | 28 | #readFooter a { 29 | border-bottom-width: 0 !important; 30 | } 31 | 32 | #readability-url { 33 | display: inline !important; 34 | } 35 | 36 | #rdb-footer-print { 37 | display: block !important; 38 | font-size: .85em; 39 | text-align: right; 40 | margin-bottom: 1.5em; 41 | } 42 | 43 | #rdb-footer-print span { 44 | white-space: ; 45 | } 46 | 47 | #rdb-footer-left { 48 | width: auto !important; 49 | display: block !important; 50 | float: none !important; 51 | font-family: "Adobe Caslon Pro", "Hoefler Text", Georgia, Garamond, serif; 52 | } 53 | 54 | #rdb-footer-right { 55 | display: none !important; 56 | } 57 | 58 | #readFooter #arc90-logo, #readFooter #readability-logo { 59 | background-image: none !important; 60 | text-indent: 0 !important; 61 | width: auto !important; 62 | height: auto !important; 63 | line-height: auto !important; 64 | margin: 0 !important; 65 | text-align: left; 66 | } 67 | 68 | #readFooter #readability-logo { 69 | color: #333 !important; 70 | font-variant: small-caps; 71 | } 72 | 73 | #footer-twitterLink { 74 | display: none; 75 | } 76 | 77 | #readFooter span.version { 78 | display: none; 79 | } 80 | 81 | a { 82 | color: #333 !important; 83 | border-bottom: 1px solid #CCC !important; 84 | } 85 | 86 | div.footer-right { 87 | display: none; 88 | } 89 | -------------------------------------------------------------------------------- /readability/readability.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | /* Document */ 3 | body{font-size:10px;line-height:1;} 4 | #readability-logo,#arc90-logo,.footer-twitterLink,#readTools a,a.rdbTK-powered span{background-color:transparent!important;background-image:url(http://lab.arc90.com/experiments/readability/images/sprite-readability.png)!important;background-repeat:no-repeat!important;} 5 | #readOverlay{text-rendering:optimizeLegibility;display:block;position:absolute;top:0;left:0;width:100%;} 6 | #readInner{max-width:800px;margin:1em auto;} 7 | #readInner a{color:#039;text-decoration:none;} 8 | #readInner a:hover,#readInner a:focus{text-decoration:underline;} 9 | #readInner img{float:left;clear:both;margin:0 12px 12px 0;} 10 | #readInner img.blockImage{clear:both;float:none;display:block;margin-left:auto;margin-right:auto;} 11 | #readInner h1{display:block;width:100%;border-bottom:1px solid #333;font-size:1.2em;padding-bottom:.5em;margin-bottom:.75em;} 12 | #readInner sup{line-height:.8em;} 13 | #readInner .page-separator{clear:both;display:block;font-size:.85em;filter:alpha(opacity=20);opacity:.20;text-align:center;} 14 | .style-apertura #readInner h1{border-bottom-color:#ededed;} 15 | .style-terminal #readInner h1{border-bottom-color:#c6ffc6;} 16 | #readInner blockquote{margin-left:3em;margin-right:3em;} 17 | #readability-inner *{margin-bottom:16px;border:none;background:none;} 18 | #readability-footnotes{clear:both;} 19 | /* Footer */ 20 | #rdb-footer-wrapper{display:block;border-top:1px solid #333;clear:both;overflow:hidden;margin:2em 0;} 21 | .style-apertura #rdb-footer-wrapper{border-top-color:#ededed;} 22 | .style-terminal #rdb-footer-wrapper{border-top-color:#c6ffc6;} 23 | #rdb-footer-left{display:inline;float:left;margin-top:15px;width:285px;background-position:0 -36px;} 24 | .rdbTypekit #rdb-footer-left{width:475px;} 25 | #rdb-footer-left a,#rdb-footer-left a:link{float:left;} 26 | #readability-logo{display:inline;background-position:0 -36px;height:29px;width:189px;text-indent:-9000px;} 27 | #arc90-logo{display:inline;background-position:right -36px;height:29px;width:96px;text-indent:-9000px;} 28 | .style-apertura #readability-logo,.style-terminal #readability-logo{background-position:0 -67px;} 29 | .style-apertura #arc90-logo,.style-terminal #arc90-logo{background-position:right -67px;} 30 | #rdb-footer-right{display:inline;float:right;text-align:right;font-size:.75em;margin-top:18px;} 31 | #rdb-footer-right a{display:inline-block;float:left;overflow:visible;line-height:16px;vertical-align:baseline;} 32 | .footer-twitterLink{height:20px;margin-left:20px;background-position:0 -123px;font-size:12px;padding:4px 0 0 28px;} 33 | #rdb-footer-left .footer-twitterLink{display:none;margin-top:1px;padding-top:2px;} 34 | .rdbTypekit #rdb-footer-left .footer-twitterLink{display:inline-block!important;} 35 | a.rdbTK-powered,a.rdbTK-powered:link,a.rdbTK-powered:hover{font-size:16px;color:#858789!important;text-decoration:none!important;} 36 | a.rdbTK-powered span{display:inline-block;height:22px;margin-left:2px;background-position:0 -146px!important;padding:4px 0 0 26px;} 37 | .style-apertura #rdb-inverse,.style-athelas #rdb-athelas{display:block;} 38 | #rdb-footer-print,#readability-url,.rdbTypekit #rdb-footer-right .footer-twitterLink,span.version{display:none;} 39 | /* Tools */ 40 | #readTools{width:34px;height:150px;position:fixed;z-index:100;top:10px;left:10px;} 41 | #readTools a{overflow:hidden;margin-bottom:8px;display:block;opacity:.4;text-indent:-99999px;height:34px;width:34px;text-decoration:none;filter:alpha(opacity=40);} 42 | #reload-page{background-position:0 0;} 43 | #print-page{background-position:-36px 0;} 44 | #email-page{background-position:-72px 0;} 45 | #kindle-page{background-position:-108px 0;} 46 | #readTools a:hover,#readTools a:focus{opacity:1;filter:alpha(opacity=100);} 47 | /* @group User Styles */ 48 | /* Size */ 49 | .size-x-small{font-size:1.1em;line-height:1.5em;} 50 | .size-small{font-size:1.4em;line-height:1.5em;} 51 | .size-medium{font-size:1.7em;line-height:1.48em;} 52 | .size-large{font-size:2em;line-height:1.47em;} 53 | .size-x-large{font-size:2.5em;line-height:1.43em;} 54 | .size-x-small h1,.size-small h1,.size-medium h1,.size-large h1{font-size:1.6em;line-height:1.5em;} 55 | .size-x-large h1{font-size:1.6em;line-height:1.3em;} 56 | /* Style */ 57 | .style-newspaper {font-family:Georgia,"Times New Roman", Times, serif;background:#fbfbfb;color:#080000;} 58 | .style-newspaper h1 {text-transform:capitalize;font-family:Georgia, "Times New Roman", Times, serif;} 59 | .style-newspaper #readInner a {color:#0924e1;} 60 | .style-novel {font-family:"Palatino Linotype", "Book Antiqua", Palatino, serif;background:#f4eed9;color:#1d1916;} 61 | .style-novel #readInner a {color:#1856ba;} 62 | .style-ebook {font-family:Arial, Helvetica, sans-serif;background:#edebe8;color:#2c2d32;} 63 | .style-ebook #readInner a {color:#187dc9;} 64 | .style-ebook h1 {font-family:"Arial Black", Gadget, sans-serif;font-weight:400;} 65 | .style-terminal {font-family:"Lucida Console", Monaco, monospace;background:#1d4e2c;color:#c6ffc6;} 66 | .style-terminal #readInner a {color:#093;} 67 | /* Typekit */ 68 | .style-apertura{font-family:apertura-1,apertura-2,sans-serif;background-color:#2d2828;color:#eae8e9;} 69 | .style-apertura #readInner a{color:#58b0ff;} 70 | .style-athelas{font-family:athelas-1,athelas-2,"Palatino Linotype","Book Antiqua",Palatino,serif;background-color:#f7f7f7;color:#2b373d;} 71 | .style-athelas #readInner a{color:#1e83cb;} 72 | /* Margin */ 73 | .margin-x-narrow{width:95%;} 74 | .margin-narrow{width:85%;} 75 | .margin-medium{width:75%;} 76 | .margin-wide{width:55%;} 77 | .margin-x-wide{width:35%;} 78 | /* @end User Styles */ 79 | /* -- DEBUG -- */ 80 | .bug-green{background:#bbf9b0;border:4px solid green;} 81 | .bug-red{background:red;} 82 | .bug-yellow{background:#ffff8e;} 83 | .bug-blue{background:#bfdfff;} 84 | /* -- EMAIL / KINDLE POP UP -- */ 85 | #kindle-container,#email-container{position:fixed;top:60px;left:50%;width:500px;height:490px;border:solid 3px #666;background-color:#fff;z-index:100!important;overflow:hidden;margin:0 0 0 -240px;padding:0;} 86 | /* Override html styling attributes */ 87 | table,tr,td{background-color:transparent!important;} 88 | -------------------------------------------------------------------------------- /readability/readability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/readability.png -------------------------------------------------------------------------------- /readability/title-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/title-small.png -------------------------------------------------------------------------------- /readability/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/title.png -------------------------------------------------------------------------------- /readability/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/twitter.png -------------------------------------------------------------------------------- /readability/typekit-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/typekit-icon.png -------------------------------------------------------------------------------- /redux/background.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /redux/background.js: -------------------------------------------------------------------------------- 1 | 2 | function createJavascript(settings) 3 | { 4 | if(settings['remote']) 5 | { 6 | //console.log('Using remote Readability.'); 7 | 8 | js_url = "http://lab.arc90.com/experiments/readability/js/readability.js?x="+(Math.random()); 9 | css_url = "http://lab.arc90.com/experiments/readability/css/readability.css"; 10 | print_url = "http://lab.arc90.com/experiments/readability/css/readability-print.css"; 11 | } else 12 | { 13 | if(settings.enable_experimental) 14 | { 15 | // console.log('Using local, experimental Readability.'); 16 | var js_url = chrome.extension.getURL('readability/readability-x.js'); 17 | } else 18 | { 19 | //console.log('Using local Readability.'); 20 | var js_url = chrome.extension.getURL('readability/readability.js'); 21 | } 22 | 23 | var css_url = chrome.extension.getURL('readability/readability.css'); 24 | var print_url = chrome.extension.getURL('readability/readability-print.css'); 25 | } 26 | 27 | var code = "(function(){readConvertLinksToFootnotes=" + settings['enable_links'] + ";readStyle='" + settings['style'] + "';readSize='" + settings['size'] + "';readMargin='" + settings['margin'] + "';_readability_script=document.createElement('SCRIPT');_readability_script.type='text/javascript';_readability_script.src='" + js_url + "';document.getElementsByTagName('head')[0].appendChild(_readability_script);_readability_css=document.createElement('LINK');_readability_css.rel='stylesheet';_readability_css.href='" + css_url + "';_readability_css.type='text/css';_readability_css.media='screen';document.getElementsByTagName('head')[0].appendChild(_readability_css);_readability_print_css=document.createElement('LINK');_readability_print_css.rel='stylesheet';_readability_print_css.href='" + print_url + "';_readability_print_css.media='print';_readability_print_css.type='text/css';document.getElementsByTagName('head')[0].appendChild(_readability_print_css);})();"; 28 | 29 | return code; 30 | } 31 | 32 | function render(tab_id) 33 | { 34 | var settings = getSettings(); 35 | //console.log(settings); 36 | 37 | chrome.tabs.sendRequest(tab_id, {'type': 'render'}); 38 | } 39 | 40 | function getSettings() 41 | { 42 | function parse(x) 43 | { 44 | try 45 | { 46 | return JSON.parse(x); 47 | } catch(e) 48 | { 49 | return undefined; 50 | } 51 | } 52 | 53 | var settings = { 54 | style: localStorage['style'], 55 | size: localStorage['size'], 56 | margin: localStorage['margin'], 57 | enable_links: !!parse(localStorage['enable_links']), 58 | enable_experimental: !!parse(localStorage['enable_experimental']), 59 | enable_keys: !!parse(localStorage['enable_keys']), 60 | keys: parse(localStorage['keys']) 61 | }; 62 | 63 | if(!_.isArray(settings['keys'])) 64 | settings['keys'] = []; 65 | 66 | var defaults = { 67 | style: 'style-newspaper', 68 | size: 'size-large', 69 | margin: 'margin-wide', 70 | enable_links: false, 71 | enable_keys: false, 72 | enable_experimental: false, 73 | keys: [] 74 | }; 75 | 76 | return _.extend(defaults, settings); 77 | } 78 | 79 | function setSettings(settings) 80 | { 81 | var keys = _.keys(settings); 82 | 83 | if(_.include(keys, 'style')) 84 | settings['style'] = settings['style'] 85 | 86 | if(_.include(keys, 'size')) 87 | settings['size'] = settings['size'] 88 | 89 | if(_.include(keys, 'margin')) 90 | settings['margin'] = settings['margin'] 91 | 92 | if(_.include(_.keys(settings), 'enable_links')) 93 | settings['enable_links'] = JSON.stringify(!!settings['enable_links']); 94 | 95 | if(_.include(_.keys(settings), 'enable_experimental')) 96 | settings['enable_experimental'] = JSON.stringify(!!settings['enable_experimental']); 97 | 98 | if(_.include(_.keys(settings), 'enable_keys')) 99 | settings['enable_keys'] = JSON.stringify(!!settings['enable_keys']); 100 | 101 | if(_.include(_.keys(settings), 'keys')) 102 | settings['keys'] = JSON.stringify(settings['keys']); 103 | 104 | //console.log('setSettings', settings); 105 | 106 | _.extend(localStorage, settings); 107 | 108 | chrome.windows.getAll({'populate': true}, function(windows) 109 | { 110 | _.each(windows, function(window) 111 | { 112 | _.each(window.tabs, function(tab) 113 | { 114 | chrome.tabs.sendRequest(tab.id, {'type': 'newSettings', 'settings': getSettings()}); 115 | }); 116 | }); 117 | }); 118 | } 119 | 120 | function requestHandler(data, sender, callback) 121 | { 122 | if(data['type'] == 'javascript') 123 | { 124 | if(_.include(_.keys(data), 'settings')) 125 | callback(createJavascript(data['settings'])); 126 | else 127 | callback(createJavascript(getSettings())); 128 | } 129 | if(data['type'] == 'setSettings') 130 | { 131 | setSettings(data['settings']); 132 | callback(); 133 | } 134 | if(data['type'] == 'getSettings') 135 | { 136 | callback(getSettings()); 137 | } 138 | if(data['type'] == 'render') 139 | { 140 | render(data['tab_id']); 141 | callback(); 142 | } 143 | } 144 | 145 | chrome.extension.onRequest.addListener(requestHandler); 146 | chrome.extension.onRequestExternal.addListener(requestHandler); 147 | 148 | chrome.browserAction.onClicked.addListener(function(tab) 149 | { 150 | render(tab.id); 151 | }); 152 | 153 | var _gaq = _gaq || []; 154 | _gaq.push(['_setAccount', 'UA-27938065-1']); 155 | _gaq.push(['_trackPageview']); 156 | 157 | (function() { 158 | var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; 159 | ga.src = 'https://ssl.google-analytics.com/ga.js'; 160 | var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); 161 | })(); 162 | 163 | /*chrome.contextMenus.create({ 164 | 'title': 'Readability', 165 | 'contexts': ['page', 'selection'], 166 | 'onclick': function(selection, tab) 167 | { 168 | render(tab.id); 169 | } 170 | });*/ 171 | 172 | -------------------------------------------------------------------------------- /redux/contentscript.js: -------------------------------------------------------------------------------- 1 | 2 | function cmp_arrays(a, b) 3 | { 4 | if(a.length != b.length) 5 | return false; 6 | 7 | for(var i = 0; i < a.length; i++) 8 | { 9 | if(a[i] != b[i]) 10 | return false; 11 | } 12 | 13 | return true; 14 | } 15 | 16 | function remove(a, el) 17 | { 18 | for(var i = 0; i < a.length; i++) 19 | { 20 | if(a[i] == el) 21 | { 22 | a.splice(i, 1); 23 | return; 24 | } 25 | } 26 | } 27 | 28 | function contains(a, el) 29 | { 30 | for(var i = 0; i < a.length; i++) 31 | { 32 | if(a[i] == el) 33 | { 34 | return true; 35 | } 36 | } 37 | 38 | return false; 39 | } 40 | 41 | var listener = { 42 | enabled: false, 43 | goal: [17, 88], 44 | current_state: [], 45 | 46 | onkeydown: function(e) 47 | { 48 | if(!this.enabled) return false; 49 | 50 | if(!((e.which >= 65 && e.which <= 90) || e.which == 16 || e.which == 17 || e.which == 18)) 51 | return false; 52 | 53 | if(contains(this.current_state, e.which)) 54 | return false; 55 | 56 | this.current_state.push(e.which); 57 | this.current_state.sort(); 58 | 59 | if(cmp_arrays(this.goal, this.current_state)) 60 | { 61 | this.current_state = []; 62 | render(); 63 | } 64 | 65 | //console.log('keydown ' + e.which + ' => ' + this.current_state.toString()); 66 | 67 | return false; 68 | }, 69 | 70 | onkeyup: function(e) 71 | { 72 | if(!this.enabled) return false; 73 | 74 | if(!((e.which >= 65 && e.which <= 90) || e.which == 16 || e.which == 17 || e.which == 18)) 75 | return false; 76 | 77 | remove(this.current_state, e.which); 78 | //console.log('keyup ' + e.which + ' => ' + this.current_state.toString()); 79 | 80 | return false; 81 | }, 82 | 83 | setSettings: function(settings) 84 | { 85 | this.enabled = settings["enable_keys"]; 86 | this.goal = settings["keys"]; 87 | this.current_state = []; 88 | //console.log(settings); 89 | } 90 | 91 | }; 92 | 93 | function render() 94 | { 95 | chrome.extension.sendRequest({'type': 'javascript'}, function(response) 96 | { 97 | var script = document.createElement('script'); 98 | script.appendChild(document.createTextNode(response)); 99 | //console.log(document.getElementsByTagName('head')); 100 | document.getElementsByTagName('head')[0].appendChild(script); 101 | }); 102 | } 103 | 104 | chrome.extension.onRequest.addListener(function(data, sender, callback) 105 | { 106 | if(data['type'] === "render") 107 | { 108 | render(); 109 | } else 110 | if(data['type'] == 'newSettings') 111 | { 112 | listener.setSettings(data['settings']); 113 | } 114 | }); 115 | 116 | chrome.extension.sendRequest({'type': 'getSettings'}, function(r) { listener.setSettings(r); }); 117 | 118 | document.body.addEventListener('keydown', function(e) {listener.onkeydown(e);}, false); 119 | document.body.addEventListener('keyup', function(e) {listener.onkeyup(e);}, false); 120 | 121 | -------------------------------------------------------------------------------- /redux/example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The Evil Clergyman - Wikisource 5 | 6 | 7 | 8 | 9 | 10 | 11 |

12 |
13 |
14 | 15 |
16 | 17 |
18 |
19 | 20 |
21 |

The Evil Clergyman

22 |
23 |

From Wikisource

24 |
25 |
Jump to: navigation, search
26 | 27 | 28 | 31 | 33 |
The Evil Clergyman
30 | by H. P. Lovecraft
34 | 35 | 36 | 38 |
37 |
39 |


40 |
41 |

I was shown into the attic chamber by a grave, intelligent-looking man with quiet clothes and an iron-gray beard, who spoke to me in this fashion:

42 |

"Yes, he lived here – but I don’t advise your doing anything. Your curiosity makes you irresponsible. We never come here at night, and it’s only because of his will that we keep it this way. You know what he did. That abominable society took charge at last, and we don’t know where he is buried. There was no way the law or anything else could reach the society.

43 |

"I hope you won’t stay till after dark. And I beg of you to let that thing on the table – the thing that looks like a match-box – alone. We don’t know what it is, but we suspect it has something to do with what he did. We even avoid looking at it very steadily."

44 |

After a time the man left me alone in the attic room. It was very dingy and dusty, and only primitively furnished, but it had a neatness which showed it was not a slum-denizen’s quarters. There were shelves full of theological and classical books, and another bookcase containing treatises on magic — Paracelsus, Albertus Magnus, Trithemius, Hermes Trismegistus, Borellus, and others in a strange alphabet whose titles I could not decipher. The furniture was very plain. There was a door, but it led only into a closet. The only egress was the aperture in the floor up to which the crude, steep staircase led. The windows were of bull’s-eye pattern, and the black oak beams bespoke unbelievable antiquity. Plainly, this house was of the Old World. I seemed to know where I was, but cannot recall what I then knew. Certainly the town was not London. My impression is of a small seaport.

45 |

The small object on the table fascinated me intensely. I seemed to know what to do with it, for I drew a pocket electric light – or what looked like one – out of my pocket and nervously tested its flashes. The light was not white but violet, and seemed less like true light than like some radioactive bombardment. I recall that I did not regard it as a common flashlight – indeed, I had a common flashlight in another pocket.

46 |

It was getting dark, and the ancient roofs and chimney-pots outside looked very queer through the bull's-eye window-panes. Finally I summoned up courage and propped the small object up on the table against a book – then turned the rays of the peculiar violet light upon it. The light seemed now to be more like a rain of hail or small violet particles than like a continuous beam. As the particles struck the glassy surface at the center of the strange device, they seemed to produce a crackling noise like the sputtering of a vacuum tube through which sparks are passed. The dark glassy surface displayed a pinkish glow, and a vague white shape seemed to be taking form at its center. Then I noticed that I was not alone in the room – and put the ray-projector back in my pocket.

47 |

But the newcomer did not speak – nor did I hear any sound whatever during all the immediately following moments. Everything was shadowy pantomime, as if seen at a vast distance through some intervening haze – although on the other hand the newcomer and all subsequent comers loomed large and close, as if both near and distant, according to some abnormal geometry.

48 |

The newcomer was a thin, dark man of medium height attired in the clerical garb of the Anglican church. He was apparently about thirty years old, with a sallow, olive complexion and fairly good features, but an abnormally high forehead. His black hair was well cut and neatly brushed, and he was clean-shaven though blue-chinned with a heavy growth of beard. He wore rimless spectacles with steel bows. His build and lower facial features were like other clergymen I had seen, but he had a vastly higher forehead, and was darker and more intelligent-looking – also more subtly and concealedly evil-looking. At the present moment – having just lighted a faint oil lamp – he looked nervous, and before I knew it he was casting all his magical books into a fireplace on the window side of the room (where the wall slanted sharply) which I had not noticed before. The flames devoured the volumes greedily – leaping up in strange colors and emitting indescribably hideous odors as the strangely hieroglyphed leaves and wormy bindings succumbed to the devastating element. All at once I saw there were others in the room – grave-looking men in clerical costume, one of whom wore the bands and knee-breeches of a bishop. Though I could hear nothing, I could see that they were bringing a decision of vast import to the first-comer. They seemed to hate and fear him at the same time, and he seemed to return these sentiments. His face set itself into a grim expression, but I could see his right hand shaking as he tried to grip the back of a chair. The bishop pointed to the empty case and to the fireplace (where the flames had died down amidst a charred, non-committal mass), and seemed filled with a peculiar loathing. The first-comer then gave a wry smile and reached out with his left hand toward the small object on the table. Everyone then seemed frightened. The procession of clerics began filing down the steep stairs through the trapdoor in the floor, turning and making menacing gestures as they left. The bishop was last to go.

49 |

The first-comer now went to a cupboard on the inner side of the room and extracted a coil of rope. Mounting a chair, he attached one end of the rope to a hook in the great exposed central beam of black oak, and began making a noose with the other end. Realizing he was about to hang himself, I started forward to dissuade or save him. He saw me and ceased his preparations, looking at me with a kind of triumph which puzzled and disturbed me. He slowly stepped down from the chair and began gliding toward me with a positively wolfish grin on his dark, thin-lipped face.

50 |

I felt somehow in deadly peril, and drew out the peculiar ray-projector as a weapon of defense. Why I thought it could help me, I do not know. I turned it on – full in his face, and saw the sallow features glow first with violet and then with pinkish light. His expression of wolfish exultation began to be crowded aside by a look of profound fear – which did not, however, wholly displace the exultation. He stopped in his tracks – then, flailing his arms wildly in the air, began to stagger backwards. I saw he was edging toward the open stair-well in the floor, and tried to shout a warning, but he did not hear me. In another instant he had lurched backward through the opening and was lost to view.

51 |

I found difficulty in moving toward the stair-well, but when I did get there I found no crushed body on the floor below. Instead there was a clatter of people coming up with lanterns, for the spell of phantasmal silence had broken, and I once more heard sounds and saw figures as normally tri-dimensional. Something had evidently drawn a crowd to this place. Had there been a noise I had not heard?

52 |

Presently the two people (simple villagers, apparently) farthest in the lead saw me – and stood paralyzed. One of them shrieked loudly and reverberantly:

53 |

"Ahrrh! ... It be’ee, zur? Again?"

54 |

Then they all turned and fled frantically. All, that is, but one. When the crowd was gone I saw the grave-bearded man who had brought me to this place – standing alone with a lantern. He was gazing at me gaspingly and fascinatedly, but did not seem afraid. Then he began to ascend the stairs, and joined me in the attic. He spoke:

55 |

"So you didn’t let it alone! I’m sorry. I know what has happened. It happened once before, but the man got frightened and shot himself. You ought not to have made him come back. You know what he wants. But you mustn’t get frightened like the other man he got. Something very strange and terrible has happened to you, but it didn’t get far enough to hurt your mind and personality. If you’ll keep cool, and accept the need for making certain radical readjustments in your life, you can keep right on enjoying the world, and the fruits of your scholarship. But you can’t live here – and I don’t think you’ll wish to go back to London. I’d advise America.

56 |

"You mustn’t try anything more with that— thing. Nothing can be put back now. It would only make matters worse to do – or summon – anything. You are not as badly off as you might be – but you must get out of here at once and stay away. You’d better thank Heaven it didn’t go further...

57 |

"I’m going to prepare you as bluntly as I can. There’s been a certain change – in your personal appearance. He always causes that. But in a new country you can get used to it. There’s a mirror up at the other end of the room, and I’m going to take you to it. You’ll get a shock – though you will see nothing repulsive."

58 |

I was now shaking with a deadly fear, and the bearded man almost had to hold me up as he walked me across the room to the mirror, the faint lamp (i.e., that formerly on the table, not the still fainter lantern he had brought) in his free hand. This is what I saw in the glass:

59 |

A thin, dark man of medium stature attired in the clerical garb of the Anglican church, apparently about thirty, and with rimless, steel-bowed glasses glistening beneath a sallow, olive forehead of abnormal height.

60 |

It was the silent first-comer who had burned his books.

61 |

For all the rest of my life, in outward form, I was to be that man!

62 |
63 | 64 | 65 | 72 | 73 | 74 | 76 | 77 |
78 |
79 |
80 |
81 |
82 |
83 |
Views
84 |
85 | 92 |
93 |
94 |
95 |
Personal tools
96 |
97 | 101 |
102 |
103 | 106 | 107 | 118 |
119 |
Navigation
120 |
121 | 132 |
133 |
134 |
135 |
Toolbox
136 | 143 |
144 |
145 |
Print/export
146 | 148 |
149 |
150 |
151 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 178 | -------------------------------------------------------------------------------- /redux/jquery-1.4.2.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery JavaScript Library v1.4.2 3 | * http://jquery.com/ 4 | * 5 | * Copyright 2010, John Resig 6 | * Dual licensed under the MIT or GPL Version 2 licenses. 7 | * http://jquery.org/license 8 | * 9 | * Includes Sizzle.js 10 | * http://sizzlejs.com/ 11 | * Copyright 2010, The Dojo Foundation 12 | * Released under the MIT, BSD, and GPL Licenses. 13 | * 14 | * Date: Sat Feb 13 22:33:48 2010 -0500 15 | */ 16 | (function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, 21 | Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& 22 | (d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, 23 | a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== 24 | "find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, 25 | function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; 34 | var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, 35 | parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= 36 | false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= 37 | s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, 38 | applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; 39 | else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, 40 | a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== 41 | w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, 42 | cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= 47 | c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); 48 | a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, 49 | function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); 50 | k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), 51 | C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= 53 | e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& 54 | f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; 55 | if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", 63 | e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, 64 | "_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, 65 | d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, 71 | e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); 72 | t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| 73 | g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, 80 | CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, 81 | g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, 82 | text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, 83 | setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= 84 | h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== 86 | "="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, 87 | h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& 90 | q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; 91 | if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); 92 | (function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: 93 | function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= 96 | {},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== 97 | "string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", 98 | d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? 99 | a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== 100 | 1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= 102 | c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, 103 | wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, 104 | prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, 105 | this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); 106 | return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, 107 | ""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); 111 | return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", 112 | ""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= 113 | c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? 114 | c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= 115 | function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= 116 | Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, 117 | "border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= 118 | a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= 119 | a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== 120 | "string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, 121 | serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), 122 | function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, 123 | global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& 124 | e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? 125 | "&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== 126 | false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= 127 | false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", 128 | c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| 129 | d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); 130 | g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== 131 | 1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== 132 | "json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; 133 | if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== 139 | "number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| 140 | c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; 141 | this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= 142 | this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, 143 | e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; 149 | a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); 150 | c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, 151 | d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- 152 | f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": 153 | "pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in 154 | e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); 155 | -------------------------------------------------------------------------------- /redux/options.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | /* CSS for options page of Readability Redux. 3 | * HEAVILY inspired by original arc90 Readability homepage. 4 | * 5 | * Readability Redux by Michal Hordecki 6 | */ 7 | 8 | body { 9 | font-family:helvetica, arial, sans-serif; 10 | font-size:80%; 11 | margin:10px; 12 | margin-bottom: 100px; 13 | } 14 | 15 | #header { 16 | padding-bottom:1.5em; 17 | padding-top:1.5em; 18 | } 19 | 20 | #header h1 { 21 | font-size: 156%; 22 | display:inline; 23 | padding-bottom:43px; 24 | padding-left:75px; 25 | padding-top:40px; 26 | background:url(../icons/readability-128.png) no-repeat; 27 | background-size:67px; 28 | background-position:1px 18px; 29 | } 30 | 31 | .section-header { 32 | background:#ebeff9; 33 | border-top:1px solid #b5c7de; 34 | font-size:99%; 35 | padding:3px 0 2px 5px; 36 | font-weight:bold; 37 | margin-bottom:1em; 38 | margin-top:4em; 39 | } 40 | 41 | .section-header.first { 42 | margin-top:1em; 43 | } 44 | 45 | #custom-domain { 46 | width:300px; 47 | margin-left:2px; 48 | } 49 | 50 | #footer { 51 | margin-top:4em; 52 | } 53 | 54 | #keys 55 | { 56 | padding-top: 2px; 57 | padding-bottom: 2px; 58 | padding-left: 5px; 59 | padding-right: 5px; 60 | border: 1px solid gray; 61 | } 62 | 63 | #intro 64 | { 65 | margin: 1em auto; 66 | } 67 | 68 | #example { 69 | border: 1px solid gray; 70 | margin-top: 10px; 71 | margin-right:auto; 72 | margin-left:auto; 73 | width: 980px; 74 | padding: 10px; 75 | overflow: hidden; 76 | } 77 | 78 | a { 79 | color: blue; 80 | text-decoration: none; 81 | font-weight: bolder; 82 | margin-top: 10px; 83 | border-bottom: 1px solid #fff; 84 | } 85 | 86 | #example iframe { 87 | display: block; 88 | margin-left: 30px; 89 | margin-top: 24px; 90 | width: 888px; 91 | height: 458px; 92 | left: 30px; 93 | padding: 1em 2em; 94 | overflow: auto; 95 | border: 0; 96 | } 97 | 98 | .size-small { 99 | font-size: 12px; 100 | } 101 | .size-medium { 102 | font-size: 18px; 103 | } 104 | .size-large { 105 | font-size: 26px; 106 | } 107 | .size-x-large { 108 | font-size: 34px; 109 | } 110 | 111 | .style-novel { 112 | font-family:"Palatino Linotype", "Book Antiqua", Palatino, serif; 113 | background: #F4F3DB; 114 | color: #222; 115 | } 116 | 117 | .style-ebook { 118 | font-family:Arial, Helvetica, sans-serif; 119 | background: #eee; 120 | color: #333; 121 | } 122 | .style-ebook h1 { 123 | font-family: "Arial Black", Gadget, sans-serif; 124 | font-weight: normal; 125 | } 126 | 127 | .style-newspaper { 128 | font-family:"Times New Roman", Times, serif; 129 | background: #F7F7F7; 130 | color: #222; 131 | } 132 | .style-newspaper h1 { 133 | text-transform:capitalize; 134 | font-family: Georgia, "Times New Roman", Times, serif; 135 | } 136 | 137 | .style-terminal { 138 | font-family: "Lucida Console", Monaco, monospace; 139 | background: #1D4E2C; 140 | color: #C6FFC6; 141 | } 142 | 143 | .margin-x-wide { 144 | width: 35%; 145 | } 146 | .margin-wide { 147 | width: 55%; 148 | } 149 | .margin-medium { 150 | width: 75%; 151 | } 152 | .margin-narrow { 153 | width: 95%; 154 | } 155 | 156 | /* LOCK IN H1 SIZING */ 157 | #articleContent h1 { 158 | font-size: 1.2em !important; 159 | display: block; 160 | text-transform:capitalize; 161 | } 162 | #articleContent { 163 | line-height: 1.4em; 164 | } 165 | 166 | -------------------------------------------------------------------------------- /redux/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Readability Redux 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
Options
15 | 16 |

You can see the preview below.

17 |

18 | 19 | 20 | (Inverse and Athelas use online fonts)
27 | 28 | 29 |
36 | 37 | 38 | 45 |

46 | 47 |

48 | 49 | 50 |

51 | 52 |

53 | 54 | 55 | 56 |

57 | 58 |

59 | 60 | 61 |

62 | 63 |

64 | 65 | 66 |

67 | 68 |
Preview
69 |
70 | 71 |
72 | 73 |
Credits
74 | 75 |

76 | Readability created by
77 | Arc90 78 |

79 |

80 | Readability Redux created by Mike Hordecki. 81 |

82 |

Readability-experimental by IIsi 50Mhz.

83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /redux/options.js: -------------------------------------------------------------------------------- 1 | 2 | var settings = { 3 | 4 | init: function() 5 | { 6 | $('select').change(_.bind(function() { this.preview(); this.markDirty(); }, this)); 7 | $('input').change(_.bind(this.markDirty, this)); 8 | 9 | $('#cancel').click(_.bind(this.load, this)); 10 | $('#save').click(_.bind(this.save, this)); 11 | 12 | this.load(); 13 | }, 14 | 15 | getSelect: function(name) 16 | { 17 | return $('#' + name).val(); 18 | }, 19 | 20 | setSelect: function(name, value) 21 | { 22 | if($('#' + name + ' option[value=' + value + ']') 23 | .attr('selected', 'selected') 24 | .val() === undefined) 25 | $('#' + name + ' option:first-child').attr('selected', 'selected'); 26 | }, 27 | 28 | markDirty: function() 29 | { 30 | $('#save').attr('disabled', ''); 31 | }, 32 | 33 | markClean: function() 34 | { 35 | $('#save').attr('disabled', 'disabled'); 36 | }, 37 | 38 | save: function() 39 | { 40 | var settings = { 41 | style: this.getSelect('r_style'), 42 | size: this.getSelect('r_size'), 43 | margin: this.getSelect('r_margin'), 44 | enable_links: $('#enable_links').attr('checked'), 45 | enable_experimental: $('#enable_experimental').attr('checked'), 46 | enable_keys: $('#enable_keys').attr('checked'), 47 | keys: keybox.keys 48 | }; 49 | 50 | //console.log(settings); 51 | 52 | chrome.extension.sendRequest( 53 | {'type': 'setSettings', 'settings': settings}, 54 | _.bind(this.markClean, this)); 55 | }, 56 | 57 | load: function() 58 | { 59 | chrome.extension.sendRequest({'type': 'getSettings'}, _.bind(function(settings) 60 | { 61 | this.setSelect('r_style', settings['style']); 62 | this.setSelect('r_size', settings['size']); 63 | this.setSelect('r_margin', settings['margin']); 64 | $('#enable_links').attr('checked', settings['enable_links']); 65 | 66 | keybox.keys = settings['keys']; 67 | if(settings['enable_keys']) 68 | keybox.enable(); 69 | else 70 | keybox.disable(); 71 | 72 | $('#enable_experimental').attr('checked', settings['enable_experimental']); 73 | 74 | keybox.update(); 75 | this.preview() 76 | this.markClean(); 77 | }, this)); 78 | }, 79 | 80 | /* This is a bit wicked, but doing plain simple 81 | * location = 'javascript:...' resulted in blank iframe. 82 | */ 83 | hello_from_child: function(preview_window) 84 | { 85 | this.preview_window = preview_window; 86 | this.preview(); 87 | }, 88 | 89 | preview_window: null, 90 | 91 | preview: function() 92 | { 93 | var settings = { 94 | style: this.getSelect('r_style'), 95 | size: this.getSelect('r_size'), 96 | margin: this.getSelect('r_margin') 97 | }; 98 | 99 | chrome.extension.sendRequest({'type': 'javascript', 'settings': settings}, _.bind(function(js) 100 | { 101 | if(this.preview_window !== null) 102 | { 103 | this.preview_window.inject(js); 104 | } 105 | else console.log('ZOMG! Preview window IS NULL!'); 106 | }, this)); 107 | } 108 | }; 109 | 110 | 111 | var keybox = { 112 | pressed: 0, 113 | keys: [], 114 | enabled: false, 115 | 116 | init: function() 117 | { 118 | $('#keys').keydown(_.bind(this.keydown, this)); 119 | $('#keys').keyup(_.bind(this.keyup, this)); 120 | $('#keys').focus(_.bind(this.focus, this)); 121 | $('#keys').blur(_.bind(this.blur, this)); 122 | $('#enable_keys').change(_.bind(this.checkbox, this)); 123 | }, 124 | 125 | enable: function() 126 | { 127 | $('#enable_keys').attr('checked', 'checked'); 128 | $('#keys').css('background-color', ''); 129 | $('#keys').css('color', ''); 130 | this.enabled = 1; 131 | }, 132 | 133 | disable: function() 134 | { 135 | $('#enable_keys').attr('checked', ''); 136 | $('#keys').css('background-color', 'silver'); 137 | $('#keys').css('color', 'gray'); 138 | this.enabled = 0; 139 | }, 140 | 141 | checkbox: function() 142 | { 143 | if($('#enable_keys').attr('checked')) 144 | this.enable(); 145 | else 146 | this.disable(); 147 | }, 148 | 149 | // It sometimes fails, like when Ctrl+Shift+U, U has a strange key code 229. Dunno why. 150 | keydown: function(e) 151 | { 152 | if(!this.enabled) 153 | return; 154 | 155 | if(!((e.which >= 65 && e.which <= 90) || e.which == 16 || e.which == 17 || e.which == 18)) 156 | return false; 157 | 158 | if(this.pressed == 0) 159 | this.keys = []; 160 | 161 | if(_.include(this.keys, e.which)) // Degenerate situation 162 | { 163 | this.keys = []; 164 | this.pressed = 0; 165 | } 166 | 167 | this.keys.push(e.which); 168 | this.pressed++; 169 | 170 | settings.markDirty(); 171 | this.update(); 172 | }, 173 | 174 | keyup: function(e) 175 | { 176 | if(!this.enabled) 177 | return; 178 | 179 | if(!((e.which >= 65 && e.which <= 90) || e.which == 16 || e.which == 17 || e.which == 18)) 180 | return false; 181 | 182 | this.pressed--; 183 | 184 | this.update(); 185 | }, 186 | 187 | update: function() 188 | { 189 | var value = []; 190 | this.keys.sort(); 191 | 192 | for(var i = 0; i < this.keys.length; i++) 193 | { 194 | var key = this.keys[i]; 195 | if(key >= 65 && key <= 90) 196 | value.push(String.fromCharCode(key)); 197 | 198 | if(key == 16) 199 | value.push("Shift"); 200 | 201 | if(key == 17) 202 | value.push("Ctrl"); 203 | 204 | if(key == 18) 205 | value.push("Alt"); 206 | } 207 | 208 | $("#keys").attr('value', value.join(' + ')); 209 | }, 210 | 211 | focus: function() 212 | { 213 | if(!this.enabled) 214 | return; 215 | 216 | $('#keys').css('background-color', '#ebeff9'); 217 | }, 218 | 219 | blur: function() 220 | { 221 | if(!this.enabled) 222 | return; 223 | 224 | $('#keys').css('background-color', ''); 225 | $('#keys').css('color', ''); 226 | } 227 | }; 228 | 229 | $(document).ready(function() 230 | { 231 | $('#example iframe').ready(function() 232 | { 233 | settings.init(); 234 | keybox.init(); 235 | }); 236 | }); 237 | 238 | -------------------------------------------------------------------------------- /redux/underscore-0.6.js: -------------------------------------------------------------------------------- 1 | (function(){var n=this,A=n._,r=typeof StopIteration!=="undefined"?StopIteration:"__break__",B=function(a){return a.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")},j=Array.prototype,l=Object.prototype,o=j.slice,C=j.unshift,D=l.toString,p=l.hasOwnProperty,E=l.propertyIsEnumerable,s=j.forEach,t=j.map,u=j.reduce,v=j.reduceRight,w=j.filter,x=j.every,y=j.some,m=j.indexOf,z=j.lastIndexOf;l=Array.isArray;var F=Object.keys,b=function(a){return new k(a)};if(typeof exports!=="undefined")exports._=b;n._=b;b.VERSION= 2 | "0.6.0";var i=b.forEach=function(a,c,d){try{if(s&&a.forEach===s)a.forEach(c,d);else if(b.isNumber(a.length))for(var e=0,f=a.length;e=e.computed&&(e={value:f,computed:g})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};i(a,function(f,g,h){g=c?c.call(d,f,g,h):f;gf?1:0}),"value")};b.sortedIndex=function(a,c,d){d=d||b.identity;for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.zip=function(){for(var a=b.toArray(arguments),c=b.max(b.pluck(a,"length")),d=new Array(c),e=0;e0?f-c:c-f)>=0)return e;e[g++]=f}};b.bind=function(a,c){var d=b.rest(arguments,2);return function(){return a.apply(c||{},d.concat(b.toArray(arguments)))}};b.bindAll=function(a){var c=b.rest(arguments);if(c.length==0)c=b.functions(a);i(c,function(d){a[d]=b.bind(a[d], 10 | a)});return a};b.delay=function(a,c){var d=b.rest(arguments,2);return setTimeout(function(){return a.apply(a,d)},c)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(b.rest(arguments)))};b.wrap=function(a,c){return function(){var d=[a].concat(b.toArray(arguments));return c.apply(c,d)}};b.compose=function(){var a=b.toArray(arguments);return function(){for(var c=b.toArray(arguments),d=a.length-1;d>=0;d--)c=[a[d].apply(this,c)];return c[0]}};b.keys=F||function(a){if(b.isArray(a))return b.range(0, 11 | a.length);var c=[];for(var d in a)p.call(a,d)&&c.push(d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=function(a){return b.filter(b.keys(a),function(c){return b.isFunction(a[c])}).sort()};b.extend=function(a,c){for(var d in c)a[d]=c[d];return a};b.clone=function(a){if(b.isArray(a))return a.slice(0);return b.extend({},a)};b.tap=function(a,c){c(a);return a};b.isEqual=function(a,c){if(a===c)return true;var d=typeof a;if(d!=typeof c)return false;if(a==c)return true;if(!a&&c|| 12 | a&&!c)return false;if(a.isEqual)return a.isEqual(c);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return true;if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return false;if(a.length&&a.length!==c.length)return false;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!b.isEqual(a[f],c[f]))return false;return true};b.isEmpty= 13 | function(a){if(b.isArray(a))return a.length===0;for(var c in a)if(p.call(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=l||function(a){return!!(a&&a.concat&&a.unshift)};b.isArguments=function(a){return a&&b.isNumber(a.length)&&!a.concat&&!a.substr&&!a.apply&&!E.call(a,"length")};b.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};b.isNumber=function(a){return a===+a|| 14 | D.call(a)==="[object Number]"};b.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};b.isRegExp=function(a){return!!(a&&a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};b.isNaN=function(a){return b.isNumber(a)&&isNaN(a)};b.isNull=function(a){return a===null};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=function(){n._=A;return this};b.identity=function(a){return a};b.times=function(a,c,d){for(var e=0;e",interpolate:/<%=(.+?)%>/g};b.template=function(a,c){var d=b.templateSettings,e=new RegExp("'(?=[^"+d.end.substr(0,1)+"]*"+B(d.end)+")","g");a=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g," ").replace(e,"\t").split("'").join("\\'").split("\t").join("'").replace(d.interpolate, 16 | "',$1,'").split(d.start).join("');").split(d.end).join("p.push('")+"');}return p.join('');");return c?a(c):a};b.each=b.forEach;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.select=b.filter;b.all=b.every;b.any=b.some;b.head=b.first;b.tail=b.rest;b.methods=b.functions;var k=function(a){this._wrapped=a},q=function(a,c){return c?b(a).chain():a},G=function(a,c){k.prototype[a]=function(){var d=b.toArray(arguments);C.call(d,this._wrapped);return q(c.apply(b,d),this._chain)}};b.mixin(b);i(["pop","push", 17 | "reverse","shift","sort","splice","unshift"],function(a){var c=j[a];k.prototype[a]=function(){c.apply(this._wrapped,arguments);return q(this._wrapped,this._chain)}});i(["concat","join","slice"],function(a){var c=j[a];k.prototype[a]=function(){return q(c.apply(this._wrapped,arguments),this._chain)}});k.prototype.chain=function(){this._chain=true;return this};k.prototype.value=function(){return this._wrapped}})(); 18 | --------------------------------------------------------------------------------