├── .gitignore ├── static ├── bifocal │ ├── images │ │ ├── bg-body.jpg │ │ ├── footer.png │ │ ├── steps.png │ │ ├── title.png │ │ ├── twitter.png │ │ ├── badge-video.png │ │ ├── bg-settings.png │ │ ├── email-head.gif │ │ ├── email-head.png │ │ ├── footer-arc90.png │ │ ├── icon-typekit.png │ │ ├── read-email.png │ │ ├── read-kindle.png │ │ ├── read-print.png │ │ ├── read-refresh.png │ │ ├── readability.png │ │ ├── tab-example.png │ │ ├── title-small.png │ │ ├── typekit-icon.png │ │ ├── bg-settings-es.png │ │ ├── es │ │ │ └── readability.png │ │ ├── footer-thanks.png │ │ ├── icon-flourish.png │ │ ├── arc90-logo-large.png │ │ ├── arc90-logo-small.png │ │ ├── badge-readability.png │ │ ├── badge-whats_this.png │ │ ├── email-readability.gif │ │ ├── logo-arc90-large.png │ │ ├── logo-arc90-small.png │ │ ├── readability-drag.png │ │ ├── arc90lab-logo-small.png │ │ ├── fancybox │ │ │ ├── fancy_left.png │ │ │ ├── fancy_right.png │ │ │ ├── fancy_closebox.png │ │ │ ├── fancy_progress.png │ │ │ ├── fancy_shadow_e.png │ │ │ ├── fancy_shadow_n.png │ │ │ ├── fancy_shadow_ne.png │ │ │ ├── fancy_shadow_nw.png │ │ │ ├── fancy_shadow_s.png │ │ │ ├── fancy_shadow_se.png │ │ │ ├── fancy_shadow_sw.png │ │ │ ├── fancy_shadow_w.png │ │ │ ├── fancy_title_left.png │ │ │ ├── fancy_title_main.png │ │ │ └── fancy_title_right.png │ │ ├── footer-readability.png │ │ ├── kindling-logo-small.gif │ │ ├── logo-arc90lab-small.png │ │ ├── sprite-readability.png │ │ ├── logo-readability-large.png │ │ ├── logo-readability-small.png │ │ ├── readability-logo-small.png │ │ ├── icon-readability-favicon.png │ │ ├── kindling_250px_dark_trans.png │ │ └── logo-readability-es-large.png │ ├── js │ │ ├── bifocal-bookmarklet.js │ │ ├── es │ │ │ └── readability-start.js │ │ ├── readability-start.js │ │ ├── readability-0.1-debug.js │ │ ├── jquery.fancybox-1.2.6.pack.js │ │ ├── jquery-1.3.1.min.js │ │ └── bifocal.js │ ├── css │ │ ├── bifocal-print.css │ │ ├── readability-print.css │ │ ├── es │ │ │ └── readability-home.css │ │ ├── fancybox.css │ │ ├── bifocal.css │ │ ├── readability.css │ │ └── readability-home.css │ └── inject.js └── test.html ├── package.json ├── article-fetch.js ├── server.js └── bifocal.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /static/bifocal/images/bg-body.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/bg-body.jpg -------------------------------------------------------------------------------- /static/bifocal/images/footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/footer.png -------------------------------------------------------------------------------- /static/bifocal/images/steps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/steps.png -------------------------------------------------------------------------------- /static/bifocal/images/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/title.png -------------------------------------------------------------------------------- /static/bifocal/images/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/twitter.png -------------------------------------------------------------------------------- /static/bifocal/images/badge-video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/badge-video.png -------------------------------------------------------------------------------- /static/bifocal/images/bg-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/bg-settings.png -------------------------------------------------------------------------------- /static/bifocal/images/email-head.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/email-head.gif -------------------------------------------------------------------------------- /static/bifocal/images/email-head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/email-head.png -------------------------------------------------------------------------------- /static/bifocal/images/footer-arc90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/footer-arc90.png -------------------------------------------------------------------------------- /static/bifocal/images/icon-typekit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/icon-typekit.png -------------------------------------------------------------------------------- /static/bifocal/images/read-email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/read-email.png -------------------------------------------------------------------------------- /static/bifocal/images/read-kindle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/read-kindle.png -------------------------------------------------------------------------------- /static/bifocal/images/read-print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/read-print.png -------------------------------------------------------------------------------- /static/bifocal/images/read-refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/read-refresh.png -------------------------------------------------------------------------------- /static/bifocal/images/readability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/readability.png -------------------------------------------------------------------------------- /static/bifocal/images/tab-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/tab-example.png -------------------------------------------------------------------------------- /static/bifocal/images/title-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/title-small.png -------------------------------------------------------------------------------- /static/bifocal/images/typekit-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/typekit-icon.png -------------------------------------------------------------------------------- /static/bifocal/images/bg-settings-es.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/bg-settings-es.png -------------------------------------------------------------------------------- /static/bifocal/images/es/readability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/es/readability.png -------------------------------------------------------------------------------- /static/bifocal/images/footer-thanks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/footer-thanks.png -------------------------------------------------------------------------------- /static/bifocal/images/icon-flourish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/icon-flourish.png -------------------------------------------------------------------------------- /static/bifocal/images/arc90-logo-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/arc90-logo-large.png -------------------------------------------------------------------------------- /static/bifocal/images/arc90-logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/arc90-logo-small.png -------------------------------------------------------------------------------- /static/bifocal/images/badge-readability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/badge-readability.png -------------------------------------------------------------------------------- /static/bifocal/images/badge-whats_this.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/badge-whats_this.png -------------------------------------------------------------------------------- /static/bifocal/images/email-readability.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/email-readability.gif -------------------------------------------------------------------------------- /static/bifocal/images/logo-arc90-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/logo-arc90-large.png -------------------------------------------------------------------------------- /static/bifocal/images/logo-arc90-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/logo-arc90-small.png -------------------------------------------------------------------------------- /static/bifocal/images/readability-drag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/readability-drag.png -------------------------------------------------------------------------------- /static/bifocal/images/arc90lab-logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/arc90lab-logo-small.png -------------------------------------------------------------------------------- /static/bifocal/images/fancybox/fancy_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/fancybox/fancy_left.png -------------------------------------------------------------------------------- /static/bifocal/images/footer-readability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/footer-readability.png -------------------------------------------------------------------------------- /static/bifocal/images/kindling-logo-small.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/kindling-logo-small.gif -------------------------------------------------------------------------------- /static/bifocal/images/logo-arc90lab-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/logo-arc90lab-small.png -------------------------------------------------------------------------------- /static/bifocal/images/sprite-readability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/sprite-readability.png -------------------------------------------------------------------------------- /static/bifocal/images/fancybox/fancy_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/fancybox/fancy_right.png -------------------------------------------------------------------------------- /static/bifocal/images/logo-readability-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/logo-readability-large.png -------------------------------------------------------------------------------- /static/bifocal/images/logo-readability-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/logo-readability-small.png -------------------------------------------------------------------------------- /static/bifocal/images/readability-logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/readability-logo-small.png -------------------------------------------------------------------------------- /static/bifocal/images/fancybox/fancy_closebox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/fancybox/fancy_closebox.png -------------------------------------------------------------------------------- /static/bifocal/images/fancybox/fancy_progress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/fancybox/fancy_progress.png -------------------------------------------------------------------------------- /static/bifocal/images/fancybox/fancy_shadow_e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/fancybox/fancy_shadow_e.png -------------------------------------------------------------------------------- /static/bifocal/images/fancybox/fancy_shadow_n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/fancybox/fancy_shadow_n.png -------------------------------------------------------------------------------- /static/bifocal/images/fancybox/fancy_shadow_ne.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/fancybox/fancy_shadow_ne.png -------------------------------------------------------------------------------- /static/bifocal/images/fancybox/fancy_shadow_nw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/fancybox/fancy_shadow_nw.png -------------------------------------------------------------------------------- /static/bifocal/images/fancybox/fancy_shadow_s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/fancybox/fancy_shadow_s.png -------------------------------------------------------------------------------- /static/bifocal/images/fancybox/fancy_shadow_se.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/fancybox/fancy_shadow_se.png -------------------------------------------------------------------------------- /static/bifocal/images/fancybox/fancy_shadow_sw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/fancybox/fancy_shadow_sw.png -------------------------------------------------------------------------------- /static/bifocal/images/fancybox/fancy_shadow_w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/fancybox/fancy_shadow_w.png -------------------------------------------------------------------------------- /static/bifocal/images/icon-readability-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/icon-readability-favicon.png -------------------------------------------------------------------------------- /static/bifocal/images/fancybox/fancy_title_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/fancybox/fancy_title_left.png -------------------------------------------------------------------------------- /static/bifocal/images/fancybox/fancy_title_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/fancybox/fancy_title_main.png -------------------------------------------------------------------------------- /static/bifocal/images/fancybox/fancy_title_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/fancybox/fancy_title_right.png -------------------------------------------------------------------------------- /static/bifocal/images/kindling_250px_dark_trans.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/kindling_250px_dark_trans.png -------------------------------------------------------------------------------- /static/bifocal/images/logo-readability-es-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andris9/bfserv/master/static/bifocal/images/logo-readability-es-large.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bfserv", 3 | "version": "0.1.0", 4 | "author" : "Andris Reinman", 5 | "maintainers":[ 6 | { 7 | "name":"andris", 8 | "email":"andris@node.ee" 9 | } 10 | ], 11 | "dependencies": { 12 | "node-static": "*", 13 | "node-gearman":"*", 14 | "optimist":"*" 15 | } 16 | } -------------------------------------------------------------------------------- /static/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Test artikkel | MINUSAIT 6 | 7 | 8 |
9 |

Test artikkel

10 |
11 |

12 | Tegin oma statistikamootori mooduli source avalikuks, selle leiab GitHubist. Täpsemalt näiteks kodeeringute statistika skripti leiab näidete kataloogist 13 |

14 |

15 | Tegu on siis node.js skriptiga. Käivitamisel hakkab skript master protsessiks ning tellib vastava arvu forke kes hakkavad siis etteantud aadresse läbi vaatama. Kui feilib (ühendust ei saada, tundmatu nimi, fork lendab õhku vms.) siis saadetakse veateade Kui õnnestub, siis saadetakse lehe kohta metainfo. 16 |

17 |
18 | 19 | -------------------------------------------------------------------------------- /static/bifocal/js/bifocal-bookmarklet.js: -------------------------------------------------------------------------------- 1 | javascript: (function() { 2 | readConvertLinksToFootnotes = true; 3 | readStyle = 'style-newspaper'; 4 | readSize = 'size-medium'; 5 | readMargin = 'margin-medium'; 6 | 7 | bifocalScript = document.createElement('SCRIPT'); 8 | bifocalScript.type = 'text/javascript'; 9 | bifocalScript.src = 'http://tahvel.info/bifocal/js/bifocal.js?x='+ (Math.random()); 10 | document.getElementsByTagName('head')[0].appendChild(bifocalScript); 11 | 12 | bifocalCss = document.createElement('LINK'); 13 | bifocalCss.rel = 'stylesheet'; 14 | bifocalCss.href = 'http://tahvel.info/bifocal/css/bifocal.css'; 15 | bifocalCss.type = 'text/css'; 16 | bifocalCss.media = 'all'; 17 | document.getElementsByTagName('head')[0].appendChild(bifocalCss); 18 | 19 | bifocalPrintCss = document.createElement('LINK'); 20 | bifocalPrintCss.rel = 'stylesheet'; 21 | bifocalPrintCss.href = 'http://tahvel.info/bifocal/css/bifocal-print.css'; 22 | bifocalPrintCss.media = 'print'; 23 | bifocalPrintCss.type = 'text/css'; 24 | document.getElementsByTagName('head')[0].appendChild(bifocalPrintCss); 25 | })(); -------------------------------------------------------------------------------- /static/bifocal/css/bifocal-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 | -------------------------------------------------------------------------------- /static/bifocal/css/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 | -------------------------------------------------------------------------------- /article-fetch.js: -------------------------------------------------------------------------------- 1 | var pathlib = require("path"), 2 | spawn = require("child_process").spawn, 3 | fs = require("fs"); 4 | 5 | module.exports = articleFetch; 6 | 7 | var tempDir = "/mnt/ram", 8 | phscript = pathlib.join(__dirname, "bifocal.js"); 9 | 10 | function articleFetch(url, callback){ 11 | var fname = genFName(), 12 | fpath = pathlib.join(tempDir, fname); 13 | 14 | console.log("Cmd: "+"phantomjs "+phscript+" "+url+" "+fpath); 15 | 16 | var cmd = spawn("phantomjs", [phscript, url, fpath], {env: {'DISPLAY': ':0'}}); 17 | 18 | cmd.stdout.on('data', function (data) { 19 | console.log('stdout: ' + (data || "").toString().trim()); 20 | }); 21 | 22 | cmd.stderr.on('data', function (data) { 23 | console.log('stderr: ' + (data || "").toString().trim()); 24 | }); 25 | 26 | cmd.on('exit', function (code) { 27 | console.log("Child exited with "+code); 28 | if(code){ 29 | fs.unlink(fpath); 30 | return callback(new Error("Child exited with "+code)); 31 | } 32 | fs.readFile(fpath, function(err, data){ 33 | fs.unlink(fpath); 34 | var article = {}; 35 | try{ 36 | article = JSON.parse(decodeURIComponent(data.toString("utf-8").trim())); 37 | article.article = sanitizeHTML((article && article.article || "").toString().trim()); 38 | }catch(E){} 39 | 40 | callback(null, JSON.stringify(article)); 41 | }); 42 | }); 43 | 44 | } 45 | 46 | function genFName(){ 47 | return genFName.seed+"-"+(genFName.counter++); 48 | } 49 | genFName.seed = "S"+Date.now(); 50 | genFName.counter = 0; 51 | 52 | 53 | function sanitizeHTML(html){ 54 | html = html.trim(). 55 | replace(/\r?\n|\r/g, "\u0000"). 56 | replace(/<(div|p|ul|li|h1|h2|h3|h4|h5)>[\s\u0000]*(
[\s\u0000]*)*/g, "<$1>"). 57 | replace(/(?:[\s\u0000]*
)*[\s\u0000]*<\/(div|p|ul|li|h1|h2|h3|h4|h5)>/g, ""). 58 | replace(/<\!\-\-.*\-\->/g, ""). //comments 59 | replace(/

[\s\u0000]*(?=

)/g, ""). // empty P 60 | replace(/<([A-Za-z][^> ]*)[^>]*>[\s\u0000]*<\/([A-Za-z][^> ]*)[^>]*>/g,function(original, startTag, endTag){ 61 | startTag = (startTag || "").toLowerCase(); 62 | endTag = (endTag || "").toLowerCase(); 63 | if(startTag == endTag){ 64 | return ""; 65 | }else{ 66 | return original; 67 | } 68 | }). //empty nodes 69 | replace(/\u0000/g, "\n"). 70 | trim(); 71 | 72 | return html; 73 | } -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var staticServer = require("node-static"), 2 | pathlib = require("path"), 3 | Gearman = require("node-gearman"), 4 | articleFetch = require("./article-fetch"); 5 | 6 | // STATIC SERVER 7 | var file = new(staticServer.Server)(pathlib.join(__dirname, 'static')); 8 | 9 | require('http').createServer(function (request, response) { 10 | request.addListener('end', function () { 11 | file.serve(request, response); 12 | }); 13 | }).listen(8080); 14 | 15 | var counter = 0; 16 | 17 | // GEARMAN WORKER 18 | var gearman = new Gearman("localhost"); 19 | gearman.registerWorker("article", function(payload, worker){ 20 | console.log("Received JOB #"+(++counter)); 21 | if(!payload){ 22 | worker.error(); 23 | return; 24 | } 25 | var url = (payload || "").toString().trim(); 26 | console.log("URL: "+url); 27 | articleFetch(url, function(err, article){ 28 | if(err){ 29 | // try one more time in a 1s delay 30 | setTimeout(function(){ 31 | articleFetch(url, function(err, article){ 32 | if(err){ 33 | 34 | // try mode 35 | setTimeout(function(){ 36 | articleFetch(url, function(err, article){ 37 | if(err){ 38 | // try one more time in a 10s delay 39 | setTimeout(function(){ 40 | articleFetch(url, function(err, article){ 41 | if(err){ 42 | console.log("ERROR: "+err.message); 43 | worker.error(); 44 | }else{ 45 | console.log("SUCCESS"); 46 | worker.end(article); 47 | } 48 | }); 49 | }, 10000); 50 | console.log("ERROR: "+err.message); 51 | worker.error(); 52 | }else{ 53 | console.log("SUCCESS"); 54 | worker.end(article); 55 | } 56 | }); 57 | }, 5000); 58 | 59 | 60 | }else{ 61 | console.log("SUCCESS"); 62 | worker.end(article); 63 | } 64 | }); 65 | }, 1000); 66 | console.log("ERROR: "+err.message); 67 | worker.error(); 68 | }else{ 69 | console.log("SUCCESS"); 70 | worker.end(article); 71 | } 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /static/bifocal/js/es/readability-start.js: -------------------------------------------------------------------------------- 1 | var style = "style-newspaper"; 2 | var size = "size-medium"; 3 | var margin = "margin-wide"; 4 | 5 | var baseHref = window.location.toString().match(/.*\//); 6 | if (baseHref[0].match(/es\//i)) { 7 | baseHref = baseHref[0].replace(/es\//i, ''); 8 | } 9 | var linkStringStart = "javascript:(function(){"; 10 | var linkStringEnd = "';_readability_script=document.createElement('SCRIPT');_readability_script.type='text/javascript';_readability_script.src='" + baseHref + "js/readability.js?x='+(Math.random());document.getElementsByTagName('head')[0].appendChild(_readability_script);_readability_css=document.createElement('LINK');_readability_css.rel='stylesheet';_readability_css.href='" + baseHref + "css/readability.css';_readability_css.type='text/css';_readability_css.media='all';document.getElementsByTagName('head')[0].appendChild(_readability_css);_readability_print_css=document.createElement('LINK');_readability_print_css.rel='stylesheet';_readability_print_css.href='" + baseHref + "css/readability-print.css';_readability_print_css.media='print';_readability_print_css.type='text/css';document.getElementsByTagName('head')[0].appendChild(_readability_print_css);})();"; 11 | 12 | $(document).ready(function() { 13 | 14 | if($.browser.msie) { 15 | $("#browser-instruction-placer").hide(); 16 | $("#browser-instruction-ie").fadeIn('100'); 17 | $("#bookmarkletLink").css("cursor","pointer"); 18 | $("#video-instruction").attr("href","#video-ie"); 19 | } 20 | else { 21 | $("#browser-instruction-placer").hide(); 22 | $("#browser-instruction").fadeIn('100'); 23 | } 24 | 25 | $("#bookmarkletLink").attr("href", linkStringStart + "readStyle='" + style + "';readSize='" + size + "';readMargin='" + margin + linkStringEnd); 26 | 27 | function applyChange(s,y) { 28 | var example = document.getElementById("example"); 29 | var article = document.getElementById("articleContent"); 30 | 31 | switch(s){ 32 | case "style": 33 | style = y; 34 | break; 35 | case "size": 36 | size = y; 37 | break; 38 | case "margin": 39 | margin = y; 40 | break; 41 | } 42 | example.className = style; 43 | article.className = margin + " " + size; 44 | $("#bookmarkletLink").attr("href", linkStringStart + "readStyle='" + style + "';readSize='" + size + "';readMargin='" + margin + linkStringEnd); 45 | } 46 | 47 | $("#settings input").bind("click", function(){ 48 | applyChange(this.name, this.value); 49 | }); 50 | $("#settings input").bind("click", function(){ 51 | applyChange(this.name, this.value); 52 | }); 53 | $("#bookmarkletLink").bind("click", function(){ 54 | if($.browser.msie){ 55 | alert("Para empezar a usar Readability, click derecho y selecciona 'Agrega a favoritos...' para guardar este link en la barra de marcadores de tu navegador."); 56 | } 57 | else { 58 | alert("Para empezar a usar Readability, arrastra este link a la barra de marcadores de tu navegador."); 59 | } 60 | return false; 61 | }); 62 | 63 | $('.video').fancybox({ 64 | zoomSpeedIn: 0, 65 | zoomSpeedOut: 0, 66 | overlayShow: true, 67 | overlayOpacity: 0.85, 68 | overlayColor: "#091824", 69 | hideOnContentClick: false, 70 | frameWidth: 480, 71 | frameHeight: 360 72 | }); 73 | 74 | $('#footnote-details').fancybox({ 75 | zoomSpeedIn: 0, 76 | zoomSpeedOut: 0, 77 | overlayShow: true, 78 | overlayOpacity: 0.85, 79 | overlayColor: "#091824", 80 | hideOnContentClick: true, 81 | frameWidth: 480 82 | }); 83 | }); -------------------------------------------------------------------------------- /static/bifocal/css/es/readability-home.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | /* CSS Document */ 3 | 4 | body { 5 | background: #1E4E74; 6 | color: #ddd; 7 | } 8 | img { 9 | border: none; 10 | } 11 | #container { 12 | margin-top: 10px; 13 | margin-right:auto; 14 | margin-left:auto; 15 | width: 980px; 16 | height: 1125px; 17 | padding: 10px; 18 | background: url(../../images/es/readability.png) no-repeat; 19 | overflow: hidden; 20 | } 21 | #footer { 22 | margin-top: 40px; 23 | text-align: right; 24 | } 25 | div#arcLinks { 26 | float: right; 27 | } 28 | div#kindlingAd { 29 | width: 250px; 30 | float: right; 31 | margin-right: 150px; 32 | text-align: center; 33 | } 34 | div#kindlingAd p { 35 | color: #fff; 36 | font-size: .8em; 37 | line-height: 0px; 38 | } 39 | a.www-link { 40 | margin: 0 8px 0 30px; 41 | } 42 | #arc90 { 43 | display: block; 44 | text-align: right; 45 | margin-top: 60px; 46 | } 47 | #arc90 img { 48 | margin-right: 10px; 49 | } 50 | #arc90 a.twitter { 51 | color: #ddd; 52 | text-decoration: none; 53 | font-size: .8em; 54 | font-weight: bolder; 55 | margin-top: 10px; 56 | border-bottom: 1px solid #fff; 57 | } 58 | #settings { 59 | margin-top: 165px; 60 | padding: 0 1.5em; 61 | display: block; 62 | width: 900px; 63 | height: 160px; 64 | } 65 | div.settings-box, div#bookmarklet { 66 | float: left; 67 | } 68 | div#bookmarklet { 69 | width: 200px; 70 | margin-top: 16px; 71 | margin-left: 140px; 72 | text-align: center; 73 | } 74 | div#style { 75 | width: 175px; 76 | margin-left: 20px; 77 | } 78 | div#size { 79 | width: 165px; 80 | } 81 | div#margin { 82 | width: 160px; 83 | } 84 | .settings-box label { 85 | margin-left: .5em; 86 | cursor: pointer; 87 | } 88 | .settings-box p { 89 | margin: .1em 0; 90 | } 91 | #readHiddenContent { 92 | display: none; 93 | } 94 | #example { 95 | display: block; 96 | margin-left: 30px; 97 | margin-top: 24px; 98 | width: 888px; 99 | height: 454px; 100 | left: 30px; 101 | padding: 1em 2em; 102 | overflow: auto; 103 | } 104 | #articleContent { 105 | text-align: left; 106 | line-height: 1.4em; 107 | margin: 1em auto; 108 | } 109 | /* ---------------- USER-CONFIGURABLE STYLING --------------------- */ 110 | /* ---------------- USER-CONFIGURABLE STYLING --------------------- */ 111 | /* Size options */ 112 | .size-small { 113 | font-size: 12px; 114 | } 115 | .size-medium { 116 | font-size: 18px; 117 | } 118 | .size-large { 119 | font-size: 26px; 120 | } 121 | .size-x-large { 122 | font-size: 34px; 123 | } 124 | /* Style options */ 125 | .style-novel { 126 | font-family:"Palatino Linotype", "Book Antiqua", Palatino, serif; 127 | background: #F4F3DB; 128 | color: #222; 129 | } 130 | .style-ebook { 131 | font-family:Arial, Helvetica, sans-serif; 132 | background: #eee; 133 | color: #333; 134 | } 135 | .style-ebook h1 { 136 | font-family: "Arial Black", Gadget, sans-serif; 137 | font-weight: normal; 138 | } 139 | .style-newspaper { 140 | font-family:"Times New Roman", Times, serif; 141 | background: #F7F7F7; 142 | color: #222; 143 | } 144 | .style-newspaper h1 { 145 | text-transform:capitalize; 146 | font-family: Georgia, "Times New Roman", Times, serif; 147 | } 148 | .style-terminal { 149 | font-family: "Lucida Console", Monaco, monospace; 150 | background: #1D4E2C; 151 | color: #C6FFC6; 152 | } 153 | /* Margin Options */ 154 | /* Margin Options */ 155 | 156 | .margin-x-wide { 157 | width: 35%; 158 | } 159 | .margin-wide { 160 | width: 55%; 161 | } 162 | .margin-medium { 163 | width: 75%; 164 | } 165 | .margin-narrow { 166 | width: 95%; 167 | } 168 | /* ---------------- USER-CONFIGURABLE STYLING --------------------- */ 169 | /* ---------------- USER-CONFIGURABLE STYLING --------------------- */ 170 | 171 | 172 | 173 | /* LOCK IN H1 SIZING */ 174 | #articleContent h1 { 175 | font-size: 1.2em !important; 176 | display: block; 177 | text-transform:capitalize; 178 | } 179 | #articleContent { 180 | line-height: 1.4em; 181 | } 182 | -------------------------------------------------------------------------------- /static/bifocal/css/fancybox.css: -------------------------------------------------------------------------------- 1 | div#fancy_overlay{position:fixed;top:0;left:0;width:100%;height:100%;display:none;z-index:30;} 2 | div#fancy_loading{position:absolute;height:40px;width:40px;cursor:pointer;display:none;overflow:hidden;background:transparent;z-index:100;} 3 | div#fancy_loading div{position:absolute;top:0;left:0;width:40px;height:480px;background:transparent url("../images/fancybox/fancy_progress.png") no-repeat;} 4 | div#fancy_outer{position:absolute;top:0;left:0;z-index:90;background:transparent;display:none;margin:0;padding:20px 20px 40px;} 5 | div#fancy_inner{position:relative;width:100%;height:100%;background:#FFF;} 6 | div#fancy_content{z-index:100;position:absolute;margin:0;} 7 | div#fancy_div{color:#222;height:100%;width:100%;z-index:100;} 8 | div#fancy_div h2{text-align:center;font-variant:small-caps;margin:-15px 0 20px;padding:0 0 30px;background:#fff url("../images/icon-flourish.png") no-repeat center bottom;} 9 | img#fancy_img{position:absolute;top:0;left:0;border:0;z-index:100;width:100%;height:100%;margin:0;padding:0;} 10 | div#fancy_close{position:absolute;top:-12px;right:-15px;height:30px;width:30px;background:url("../images/fancybox/fancy_closebox.png") top left no-repeat;cursor:pointer;z-index:181;display:none;} 11 | #fancy_frame{position:relative;width:100%;height:100%;display:none;} 12 | #fancy_ajax{width:100%;height:100%;overflow:auto;} 13 | a#fancy_left,a#fancy_right{position:absolute;bottom:0;height:100%;width:35%;cursor:pointer;z-index:111;display:none;background-image:url("../images/fancybox/data:image/gif;base64,AAAA");outline:none;overflow:hidden;} 14 | a#fancy_left{left:0;} 15 | a#fancy_right{right:0;} 16 | span.fancy_ico{position:absolute;top:50%;margin-top:-15px;width:30px;height:30px;z-index:112;cursor:pointer;display:block;} 17 | span#fancy_left_ico{left:-9999px;background:transparent url("../images/fancybox/fancy_left.png") no-repeat;} 18 | span#fancy_right_ico{right:-9999px;background:transparent url("../images/fancybox/fancy_right.png") no-repeat;} 19 | a#fancy_left:hover,a#fancy_right:hover{visibility:visible;background-color:transparent;} 20 | a#fancy_left:hover span{left:20px;} 21 | a#fancy_right:hover span{right:20px;} 22 | #fancy_bigIframe{position:absolute;top:0;left:0;width:100%;height:100%;background:transparent;} 23 | div#fancy_bg{position:absolute;top:0;left:0;width:100%;height:100%;z-index:70;border:0;margin:0;padding:0;} 24 | div.fancy_bg{position:absolute;display:block;z-index:70;border:0;margin:0;padding:0;} 25 | div#fancy_bg_n{top:-20px;left:0;width:100%;height:20px;background:transparent url("../images/fancybox/fancy_shadow_n.png") repeat-x;} 26 | div#fancy_bg_ne{top:-20px;right:-20px;width:20px;height:20px;background:transparent url("../images/fancybox/fancy_shadow_ne.png") no-repeat;} 27 | div#fancy_bg_e{right:-20px;height:100%;width:20px;background:transparent url("../images/fancybox/fancy_shadow_e.png") repeat-y;} 28 | div#fancy_bg_se{bottom:-20px;right:-20px;width:20px;height:20px;background:transparent url("../images/fancybox/fancy_shadow_se.png") no-repeat;} 29 | div#fancy_bg_s{bottom:-20px;left:0;width:100%;height:20px;background:transparent url("../images/fancybox/fancy_shadow_s.png") repeat-x;} 30 | div#fancy_bg_sw{bottom:-20px;left:-20px;width:20px;height:20px;background:transparent url("../images/fancybox/fancy_shadow_sw.png") no-repeat;} 31 | div#fancy_bg_w{left:-20px;height:100%;width:20px;background:transparent url("../images/fancybox/fancy_shadow_w.png") repeat-y;} 32 | div#fancy_bg_nw{top:-20px;left:-20px;width:20px;height:20px;background:transparent url("../images/fancybox/fancy_shadow_nw.png") no-repeat;} 33 | div#fancy_title{position:absolute;z-index:100;display:none;} 34 | div#fancy_title div{color:#FFF;font:bold 12px Arial;padding-bottom:3px;white-space:nowrap;} 35 | div#fancy_title table{margin:0 auto;} 36 | div#fancy_title table td{vertical-align:middle;padding:0;} 37 | td#fancy_title_left{height:32px;width:15px;background:transparent url("../images/fancybox/fancy_title_left.png") repeat-x;} 38 | td#fancy_title_main{height:32px;background:transparent url("../images/fancybox/fancy_title_main.png") repeat-x;} 39 | td#fancy_title_right{height:32px;width:15px;background:transparent url("../images/fancybox/fancy_title_right.png") repeat-x;} -------------------------------------------------------------------------------- /static/bifocal/js/readability-start.js: -------------------------------------------------------------------------------- 1 | var style = "style-newspaper", 2 | size = "size-medium", 3 | margin = "margin-wide", 4 | footnotes = false, 5 | iOS = (navigator.userAgent.match(/safari/i) && navigator.userAgent.match(/mobile/i)) ? true : false; 6 | 7 | var baseHref = window.location.toString().match(/.*\//); 8 | var linkStringStart = "javascript:(function(){"; 9 | var linkStringEnd = "';_readability_script=document.createElement('script');_readability_script.type='text/javascript';_readability_script.src='" + baseHref + "js/readability.js?x='+(Math.random());document.documentElement.appendChild(_readability_script);_readability_css=document.createElement('link');_readability_css.rel='stylesheet';_readability_css.href='" + baseHref + "css/readability.css';_readability_css.type='text/css';_readability_css.media='all';document.documentElement.appendChild(_readability_css);_readability_print_css=document.createElement('link');_readability_print_css.rel='stylesheet';_readability_print_css.href='" + baseHref + "css/readability-print.css';_readability_print_css.media='print';_readability_print_css.type='text/css';document.getElementsByTagName('head')[0].appendChild(_readability_print_css);})();"; 10 | 11 | $(document).ready(function() { 12 | /* Prepare content instructions for specific browsers, */ 13 | if($.browser.msie) { 14 | $('#bookmarkletLink').html('Readability'); 15 | $("#browser-instruction-placer").hide(); 16 | $("#browser-instruction-ie").fadeIn('100'); 17 | $("#bookmarkletLink").css("cursor","pointer"); 18 | $("#video-instruction").attr("href","#video-ie"); 19 | } 20 | else if (iOS) { 21 | $("#browser-instruction-placer,#bookmarkletLink").hide(); 22 | $("#browser-instruction-ios").fadeIn('100'); 23 | $("#bookmarklet p:last-child").before('') 24 | } 25 | else { 26 | $("#browser-instruction-placer").hide(); 27 | $("#browser-instruction").fadeIn('100'); 28 | } 29 | 30 | $("#footer").after('

' + navigator.userAgent + '

'); 31 | 32 | $("#bookmarkletLink").attr("href", linkStringStart + "readConvertLinksToFootnotes=" + footnotes + ";readStyle='" + style + "';readSize='" + size + "';readMargin='" + margin + linkStringEnd); 33 | 34 | /* Apply the user's styles to the demonstration. */ 35 | function applyChange(s,y) { 36 | var example = $('#example'), 37 | article = $('#articleContent'), 38 | references = $('#references'); 39 | 40 | switch(s){ 41 | case "style": 42 | style = y; 43 | break; 44 | case "size": 45 | size = y; 46 | break; 47 | case "margin": 48 | margin = y; 49 | break; 50 | case "footnotes": 51 | footnotes = y; 52 | } 53 | example.attr('className', style); 54 | article.attr('className', margin + " " + size); 55 | example.toggleClass('showNotes', footnotes); 56 | 57 | if (iOS) { 58 | $("#bookmarklet textarea").val(linkStringStart + "readConvertLinksToFootnotes=" + (footnotes ? 'true' : 'false') + ";readStyle='" + style + "';readSize='" + size + "';readMargin='" + margin + linkStringEnd); 59 | } 60 | else { 61 | $("#bookmarkletLink").attr("href", linkStringStart + "readConvertLinksToFootnotes=" + (footnotes ? 'true' : 'false') + ";readStyle='" + style + "';readSize='" + size + "';readMargin='" + margin + linkStringEnd); 62 | } 63 | } 64 | 65 | $("#settings input[type='radio']").bind("click", function(){ 66 | applyChange(this.name, this.value); 67 | }); 68 | 69 | $("#settings input[type='checkbox']").bind("click", function() { 70 | applyChange(this.name, this.checked); 71 | }); 72 | 73 | $("#bookmarkletLink").bind("click", function(){ 74 | if($.browser.msie){ 75 | alert("To start using Readability, right-click and select 'Add To Favorites...' to save this link to your browser's bookmarks toolbar."); 76 | } 77 | else { 78 | alert("To start using Readability, drag this link to your browser's bookmarks toolbar."); 79 | } 80 | return false; 81 | }); 82 | 83 | /* Modal Windows */ 84 | $('.video').fancybox({ 85 | zoomSpeedIn: 0, 86 | zoomSpeedOut: 0, 87 | overlayShow: true, 88 | overlayOpacity: 0.85, 89 | overlayColor: "#091824", 90 | hideOnContentClick: false, 91 | frameWidth: 480, 92 | frameHeight: 360 93 | }); 94 | $('#footnote-details').fancybox({ 95 | zoomSpeedIn: 0, 96 | zoomSpeedOut: 0, 97 | overlayShow: true, 98 | overlayOpacity: 0.85, 99 | overlayColor: "#091824", 100 | padding: 40, 101 | hideOnContentClick: false, 102 | frameHeight: 240 103 | }); 104 | }); -------------------------------------------------------------------------------- /static/bifocal/css/bifocal.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | /* Document */ 3 | body{font-size:10px;line-height:1;} 4 | #bifocal-logo,#arc90-logo,.footer-twitterLink,#readTools a,a.rdbTK-powered span{background-color:transparent!important;background-image:url(http://tahvel.info/bifocal/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 | #bifocal-inner *{margin-bottom:16px;border:none;background:none;} 18 | #bifocal-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 | #bifocal-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 #bifocal-logo,.style-terminal #bifocal-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,#bifocal-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 | -------------------------------------------------------------------------------- /static/bifocal/js/readability-0.1-debug.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var objOverlay = document.createElement("div"); 3 | var objinnerDiv = document.createElement("div"); 4 | var debugControls = document.createElement("div"); 5 | var mainDiv; 6 | 7 | objOverlay.id = "readOverlay"; 8 | objinnerDiv.id = "readInner"; 9 | 10 | // Apply user-selected styling: 11 | document.body.className = style; 12 | objOverlay.className = style; 13 | objinnerDiv.className = margin + " " + size; 14 | 15 | debugControls.className = "debug-controls"; 16 | debugControls.innerHTML = " "; 17 | document.body.insertBefore(debugControls, document.body.firstChild); 18 | 19 | // objinnerDiv.appendChild(grabArticle()); // Get the article and place it inside the inner Div 20 | // objOverlay.appendChild(objinnerDiv); // Insert the inner div into the overlay 21 | 22 | // This removes everything else on the page. Requires a page refresh to undo it. 23 | // I tried the damn overlay on top - but had rendering issues: 24 | // document.body.innerHTML = ""; 25 | 26 | // Inserts the new content : 27 | // document.body.insertBefore(objOverlay, document.body.firstChild); 28 | })() 29 | 30 | 31 | function grabArticle() { 32 | var allParagraphs = document.getElementsByTagName("p"); 33 | var topDivCount = 0; 34 | var topDiv; 35 | var topDivParas; 36 | 37 | var articleContent = document.createElement("DIV"); 38 | var articleTitle = document.createElement("H1"); 39 | var articleFooter = document.createElement("DIV"); 40 | 41 | // Replace all doubled-up
tags with

tags : 42 | var pattern = new RegExp ("
[ \r\n\s]*
", "g"); 43 | document.body.innerHTML = document.body.innerHTML.replace(pattern, "

"); 44 | 45 | // Grab the title from the tag and inject it as the title. 46 | articleTitle.textContent = document.title; 47 | articleContent.appendChild(articleTitle); 48 | 49 | // Study all the paragraphs and find the chunk that has the most <p>'s and keep it: 50 | for (var j=0; j < allParagraphs.length; j++) { 51 | var tempParas = allParagraphs[j].parentNode.getElementsByTagName("p"); 52 | if ( tempParas.length > topDivCount && allParagraphs[j].parentNode.textContent.split(',').length >= tempParas.length ) { 53 | topDivCount = tempParas.length; 54 | topDiv = allParagraphs[j].parentNode; 55 | topDiv.className = "bug-yellow"; 56 | } 57 | } 58 | topDiv.className = "bug-green"; 59 | 60 | /* 61 | // REMOVES ALL STYLESHEETS ... 62 | for (var k=0;k < document.styleSheets.length; k++) { 63 | if (document.styleSheets[k].href != null && document.styleSheets[k].href.lastIndexOf("arc90.com") == -1) { 64 | document.styleSheets[k].disabled = true; 65 | } 66 | } 67 | */ 68 | 69 | // cleanStyles(topDiv); // Removes all style attributes 70 | // topDiv = killDivs(topDiv); // Goes in and removes DIV's that have more non <p> stuff than <p> stuff 71 | 72 | // Cleans out junk from the topDiv just in case: 73 | /* 74 | topDiv = clean(topDiv, "form"); 75 | topDiv = clean(topDiv, "object"); 76 | topDiv = clean(topDiv, "table"); 77 | topDiv = clean(topDiv, "h1"); 78 | topDiv = clean(topDiv, "h2"); 79 | topDiv = clean(topDiv, "iframe"); 80 | */ 81 | // Add the footer and contents: 82 | 83 | /* 84 | articleFooter.id = "readFooter"; 85 | articleFooter.innerHTML = "<a href='http://www.arc90.com'><img src='http://lab.arc90.com/experiments/readability/images/footer.png'></a>"; 86 | 87 | articleContent.appendChild(topDiv); 88 | articleContent.appendChild(articleFooter); 89 | 90 | return topDiv; 91 | */ 92 | mainDiv = topDiv; 93 | 94 | } 95 | 96 | function cleanAll() { 97 | mainDiv = clean(mainDiv, "form"); 98 | mainDiv = clean(mainDiv, "object"); 99 | mainDiv = clean(mainDiv, "table"); 100 | mainDiv = clean(mainDiv, "h1"); 101 | mainDiv = clean(mainDiv, "h2"); 102 | mainDiv = clean(mainDiv, "iframe"); 103 | 104 | } 105 | 106 | function cleanStyles( e ) { 107 | e = e || document; 108 | var cur = e.firstChild; 109 | 110 | // Go until there are no more child nodes 111 | while ( cur != null ) { 112 | if ( cur.nodeType == 1 ) { 113 | // Remove style attribute(s) : 114 | cur.removeAttribute("style"); 115 | cleanStyles( cur ); 116 | } 117 | cur = cur.nextSibling; 118 | } 119 | } 120 | 121 | function killDivs ( e ) { 122 | var divsList = e.getElementsByTagName( "div" ); 123 | var curDivLength = divsList.length; 124 | 125 | // Gather counts for other typical elements embedded within : 126 | for (var i=0; i < curDivLength; i ++) { 127 | var p = divsList[i].getElementsByTagName("p").length; 128 | var img = divsList[i].getElementsByTagName("img").length; 129 | var li = divsList[i].getElementsByTagName("li").length; 130 | var a = divsList[i].getElementsByTagName("a").length; 131 | var embed = divsList[i].getElementsByTagName("embed").length; 132 | 133 | // If the number of commas is less than 10 (bad sign) ... 134 | if (divsList[i].textContent.split(',').length < 10) { 135 | // And the number of non-paragraph elements is more than paragraphs 136 | // or other ominous signs : 137 | if ( img > p || li > p || a > p || p == 0 || embed > 0) { 138 | divsList[i].className = "bug-red"; 139 | divsList[i].color = "red"; 140 | // divsList[i].style.display = "none"; 141 | } 142 | } 143 | } 144 | 145 | return e; 146 | } 147 | 148 | function clean(e, tags, minWords) { 149 | var targetList = e.getElementsByTagName( tags ); 150 | minWords = minWords || 1000000; 151 | 152 | for (var y=0; y < targetList.length; y++) { 153 | // If the text content isn't laden with words, remove the child: 154 | if (targetList[y].textContent.split(' ').length < minWords) { 155 | targetList[y].className = "bug-red"; 156 | // targetList[y].parentNode.removeChild(targetList[y]); 157 | } 158 | } 159 | return e; 160 | } -------------------------------------------------------------------------------- /static/bifocal/css/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 | -------------------------------------------------------------------------------- /static/bifocal/inject.js: -------------------------------------------------------------------------------- 1 | console.log("Injected Main"); 2 | 3 | (function() { 4 | try{ 5 | console.log("FINAL URL: " + window.location.href); 6 | 7 | console.log("Run Main script"); 8 | 9 | readConvertLinksToFootnotes = false; 10 | readStyle = 'style-newspaper'; 11 | readSize = 'size-medium'; 12 | readMargin = 'margin-medium'; 13 | 14 | bifocalScript = document.createElement('script'); 15 | bifocalScript.type = 'text/javascript'; 16 | bifocalScript.src = 'http://127.0.0.1:8080/bifocal/js/bifocal.js?x='+ (Math.random()); 17 | document.getElementsByTagName('head')[0].appendChild(bifocalScript); 18 | 19 | bifocalCss = document.createElement('LINK'); 20 | bifocalCss.rel = 'stylesheet'; 21 | bifocalCss.href = 'http://127.0.0.1:8080/bifocal/css/bifocal.css'; 22 | bifocalCss.type = 'text/css'; 23 | bifocalCss.media = 'all'; 24 | document.getElementsByTagName('head')[0].appendChild(bifocalCss); 25 | 26 | bifocalPrintCss = document.createElement('LINK'); 27 | bifocalPrintCss.rel = 'stylesheet'; 28 | bifocalPrintCss.href = 'http://127.0.0.1:8080/bifocal/css/bifocal-print.css'; 29 | bifocalPrintCss.media = 'print'; 30 | bifocalPrintCss.type = 'text/css'; 31 | document.getElementsByTagName('head')[0].appendChild(bifocalPrintCss); 32 | }catch(E){ 33 | console.log("MAIN ERR: "+E.message); 34 | } 35 | })(); 36 | 37 | function __PHANTOM_RESPONSE(){ 38 | console.log("Response from Bifocal"); 39 | 40 | var article = document.querySelector('#bifocal-content .page'), 41 | title = document.querySelector('#readInner h1'), 42 | warning = document.querySelector('#bifocal-warning'), 43 | response = {bifocal:true, url: window.location.href}; 44 | 45 | if(!warning){ 46 | 47 | if(article){ 48 | sanitizeDOM(article); 49 | response.article = article.innerHTML.trim(); 50 | } 51 | 52 | if(title){ 53 | sanitizeDOM(title); 54 | response.title = title.innerHTML.trim(); 55 | } 56 | 57 | 58 | } 59 | console.log(JSON.stringify(response)); 60 | 61 | function sanitizeDOM(element){ 62 | 63 | /* 64 | // should replace bold spans with strongs.... but does not :S 65 | var elements = Array.prototype.slice.call(element.querySelectorAll("span")), 66 | attr, href, style, fontWeight, elm; 67 | 68 | for(var i = elements.length - 1; i>=0; i--){ 69 | if(elements[i].tagName == "SPAN"){ 70 | style = window.getComputedStyle(elements[i]); 71 | 72 | fontWeight = (style.getPropertyValue("font-weight")).toString().toLowerCase(); 73 | if(fontWeight == "bold" || fontWeight == "700"){ 74 | elm = document.createElement("strong"); 75 | elm.innerHTML = elements[i].innerHTML; 76 | try{ 77 | elements[i].parentNode.insertBefore(elm, elements[i]); 78 | elements[i].parentNode.removeChild(elements[i]); 79 | elements[i] = elm; 80 | }catch(E){} 81 | } 82 | } 83 | } 84 | */ 85 | 86 | //remove script tags 87 | var elements = element.getElementsByTagName("script"); 88 | for(var i=elements.length-1; i>=0; i--){ 89 | try{ 90 | elements[i].parentNode.removeChild(elements[i]); 91 | }catch(E){} 92 | } 93 | 94 | //remove style tags 95 | var elements = element.getElementsByTagName("style"); 96 | for(var i=elements.length-1; i>=0; i--){ 97 | try{ 98 | elements[i].parentNode.removeChild(elements[i]); 99 | }catch(E){} 100 | } 101 | 102 | //remove meta tags 103 | var elements = element.getElementsByTagName("meta"); 104 | for(var i=elements.length-1; i>=0; i--){ 105 | try{ 106 | elements[i].parentNode.removeChild(elements[i]); 107 | }catch(E){} 108 | } 109 | 110 | // sanitize nodes by removing all attributes except for href 111 | var elements = Array.prototype.slice.call(element.querySelectorAll("*")), 112 | attr, href, 113 | removeList = []; 114 | 115 | for(var i=0, len = elements.length; i<len; i++){ 116 | 117 | for(j = elements[i].attributes.length-1; j>=0; j--){ 118 | attr = (elements[i].attributes.item(j).nodeName || "").toString(); 119 | if(attr){ 120 | 121 | // lingid 122 | if(elements[i].tagName == "A" && attr.toLowerCase() == "href"){ 123 | href = (elements[i].href || "").toString().trim(); 124 | if(href.match(/^(javascript|about)\s*\:/)){ 125 | elements[i].href = "#"; 126 | }else if(href.match(/^https?\:\/\/[a-z\.\-]+\/teemalehed\//i)){ 127 | // delfi teemalehed 128 | elements[i].removeAttribute(attr); 129 | }else{ 130 | elements[i].href = href; 131 | } 132 | 133 | // pildid 134 | }else if(elements[i].tagName == "IMG"){ 135 | if(attr.toLowerCase() == "alt"){ 136 | // keep 137 | }else if(attr.toLowerCase() == "src"){ 138 | var src = (elements[i].src || "").toString().trim(); 139 | if(src.match(/^(javascript|about)\s*\:/)){ 140 | elements[i].removeAttribute(attr); 141 | }else{ 142 | elements[i].src = src; 143 | } 144 | }else{ 145 | elements[i].removeAttribute(attr); 146 | } 147 | 148 | // eemalda vaikimisi 149 | }else{ 150 | elements[i].removeAttribute(attr); 151 | } 152 | } 153 | } 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /static/bifocal/js/jquery.fancybox-1.2.6.pack.js: -------------------------------------------------------------------------------- 1 | /* 2 | * FancyBox - jQuery Plugin 3 | * simple and fancy lightbox alternative 4 | * 5 | * Copyright (c) 2009 Janis Skarnelis 6 | * Examples and documentation at: http://fancybox.net 7 | * 8 | * Version: 1.2.6 (16/11/2009) 9 | * Requires: jQuery v1.3+ 10 | * 11 | * Dual licensed under the MIT and GPL licenses: 12 | * http://www.opensource.org/licenses/mit-license.php 13 | * http://www.gnu.org/licenses/gpl.html 14 | */ 15 | 16 | ;eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}(';(p($){$.q.1Q=p(){J O.2n(p(){n b=$(O).u(\'2o\');8(b.1d(/^3i\\(["\']?(.*\\.2p)["\']?\\)$/i)){b=3j.$1;$(O).u({\'2o\':\'3k\',\'1e\':"3l:3m.3n.3o(3p=D, 3q="+($(O).u(\'3r\')==\'2q-3s\'?\'3t\':\'3u\')+", 13=\'"+b+"\')"}).2n(p(){n a=$(O).u(\'1u\');8(a!=\'2r\'&&a!=\'2s\')$(O).u(\'1u\',\'2s\')})}})};n l,4,1f=F,X=1v 1w,1x,1y=1,1z=/\\.(3v|3w|2p|3x|3y)(.*)?$/i;n m=1A,18=$.14.1g&&$.14.2t.1R(0,1)==6&&!19.3z,1S=18||($.14.1g&&$.14.2t.1R(0,1)==7);$.q.r=p(o){n j=$.2u({},$.q.r.2v,o);n k=O;p 2w(){l=O;4=$.2u({},j);2x();J F};p 2x(){8(1f)J;8($.1T(4.1U)){4.1U()}4.v=[];4.t=0;8(j.v.Y>0){4.v=j.v}C{n a={};8(!l.1B||l.1B==\'\'){n a={K:l.K,G:l.G};8($(l).1C("1l:1D").Y){a.S=$(l).1C("1l:1D")}C{a.S=$(l)}8(a.G==\'\'||1V a.G==\'1m\'){a.G=a.S.2y(\'1W\')}4.v.2z(a)}C{n b=$(k).1e("a[1B="+l.1B+"]");n a={};3A(n i=0;i<b.Y;i++){a={K:b[i].K,G:b[i].G};8($(b[i]).1C("1l:1D").Y){a.S=$(b[i]).1C("1l:1D")}C{a.S=$(b[i])}8(a.G==\'\'||1V a.G==\'1m\'){a.G=a.S.2y(\'1W\')}4.v.2z(a)}}}3B(4.v[4.t].K!=l.K){4.t++}8(4.1E){8(18){$(\'1X, 1Y, 1Z\').u(\'21\',\'3C\');$("#T").u(\'A\',$(U).A())}$("#T").u({\'3D-3E\':4.2A,\'22\':4.2B}).Z()}$(19).11("23.L 24.L",$.q.r.2C);1h()};p 1h(){$("#1n, #1o, #1i, #H").1a();n b=4.v[4.t].K;8(b.1d("1j")||l.3F.2D("1j")>=0){$.q.r.1F();1p(\'<1j s="2E" 3G="2F.q.r.2G()" 3H="3I\'+P.1b(P.3J()*3K)+\'" 2H="0" 3L="0" 13="\'+b+\'"></1j>\',4.1G,4.1H)}C 8(b.1d(/#/)){n c=19.3M.K.3N(\'#\')[0];c=b.3O(c,\'\');c=c.1R(c.2D(\'#\'));1p(\'<9 s="3P">\'+$(c).2I()+\'</9>\',4.1G,4.1H)}C 8(b.1d(1z)){X=1v 1w;X.13=b;8(X.3Q){25()}C{$.q.r.1F();$(X).Q().11(\'3R\',p(){$("#M").1a();25()})}}C{$.q.r.1F();$.3S(b,p(a){$("#M").1a();1p(\'<9 s="3T">\'+a+\'</9>\',4.1G,4.1H)})}};p 25(){n a=X.E;n b=X.A;n c=(4.N*2)+40;n d=(4.N*2)+26;n w=$.q.r.1q();8(4.2J&&(a>(w[0]-c)||b>(w[1]-d))){n e=P.28(P.28(w[0]-c,a)/a,P.28(w[1]-d,b)/b);a=P.1b(e*a);b=P.1b(e*b)}1p(\'<1l 1W="" s="3U" 13="\'+X.13+\'" />\',a,b)};p 2K(){8((4.v.Y-1)>4.t){n a=4.v[4.t+1].K||F;8(a&&a.1d(1z)){1I=1v 1w();1I.13=a}}8(4.t>0){n a=4.v[4.t-1].K||F;8(a&&a.1d(1z)){1I=1v 1w();1I.13=a}}};p 1p(a,b,c){1f=D;n d=4.N;8(1S||m){$("#y")[0].15.2L("A");$("#y")[0].15.2L("E")}8(d>0){b+=d*2;c+=d*2;$("#y").u({\'z\':d+\'R\',\'2M\':d+\'R\',\'2N\':d+\'R\',\'B\':d+\'R\',\'E\':\'2O\',\'A\':\'2O\'});8(1S||m){$("#y")[0].15.2P(\'A\',\'(O.2Q.3V - \'+d*2+\')\');$("#y")[0].15.2P(\'E\',\'(O.2Q.3W - \'+d*2+\')\')}}C{$("#y").u({\'z\':0,\'2M\':0,\'2N\':0,\'B\':0,\'E\':\'2R%\',\'A\':\'2R%\'})}8($("#x").16(":V")&&b==$("#x").E()&&c==$("#x").A()){$("#y").1J(\'29\',p(){$("#y").1r().1K($(a)).2a("1L",p(){1s()})});J}n w=$.q.r.1q();n e=(c+26)>w[1]?w[3]:(w[3]+P.1b((w[1]-c-26)*0.5));n f=(b+40)>w[0]?w[2]:(w[2]+P.1b((w[0]-b-40)*0.5));n g={\'B\':f,\'z\':e,\'E\':b+\'R\',\'A\':c+\'R\'};8($("#x").16(":V")){$("#y").1J("1L",p(){$("#y").1r();$("#x").2b(g,4.2S,4.2T,p(){$("#y").1K($(a)).2a("1L",p(){1s()})})})}C{8(4.2c>0&&4.v[4.t].S!==1m){$("#y").1r().1K($(a));n h=4.v[4.t].S;n i=$.q.r.2d(h);$("#x").u({\'B\':(i.B-20-4.N)+\'R\',\'z\':(i.z-20-4.N)+\'R\',\'E\':$(h).E()+(4.N*2),\'A\':$(h).A()+(4.N*2)});8(4.2e){g.22=\'Z\'}$("#x").2b(g,4.2c,4.2U,p(){1s()})}C{$("#y").1a().1r().1K($(a)).Z();$("#x").u(g).2a("1L",p(){1s()})}}};p 2V(){8(4.t!==0){$("#1o, #2W").Q().11("17",p(e){e.2X();4.t--;1h();J F});$("#1o").Z()}8(4.t!=(4.v.Y-1)){$("#1n, #2Y").Q().11("17",p(e){e.2X();4.t++;1h();J F});$("#1n").Z()}};p 1s(){8($.14.1g){$("#y")[0].15.1M(\'1e\');$("#x")[0].15.1M(\'1e\')}2V();2K();$(U).11("1N.L",p(e){8(e.2f==27&&4.2Z){$.q.r.1c()}C 8(e.2f==37&&4.t!==0){$(U).Q("1N.L");4.t--;1h()}C 8(e.2f==39&&4.t!=(4.v.Y-1)){$(U).Q("1N.L");4.t++;1h()}});8(4.30){$("#y").17($.q.r.1c)}8(4.1E&&4.31){$("#T").11("17",$.q.r.1c)}8(4.33){$("#1i").11("17",$.q.r.1c).Z()}8(1V 4.v[4.t].G!==\'1m\'&&4.v[4.t].G.Y>0){n a=$("#x").1u();$(\'#H 9\').3X(4.v[4.t].G).2I();$(\'#H\').u({\'z\':a.z+$("#x").34()-32,\'B\':a.B+(($("#x").35()*0.5)-($(\'#H\').E()*0.5))}).Z()}8(4.1E&&18){$(\'1X, 1Y, 1Z\',$(\'#y\')).u(\'21\',\'V\')}8($.1T(4.2g)){4.2g(4.v[4.t])}8($.14.1g){$("#x")[0].15.1M(\'1e\');$("#y")[0].15.1M(\'1e\')}1f=F};J O.Q(\'17.L\').11(\'17.L\',2w)};$.q.r.2C=p(){n w=$.q.r.1q();8(4.2h&&$("#x").16(\':V\')){n a=$("#x").35();n b=$("#x").34();n c={\'z\':(b>w[1]?w[3]:w[3]+P.1b((w[1]-b)*0.5)),\'B\':(a>w[0]?w[2]:w[2]+P.1b((w[0]-a)*0.5))};$("#x").u(c);$(\'#H\').u({\'z\':c.z+b-32,\'B\':c.B+((a*0.5)-($(\'#H\').E()*0.5))})}8(18&&$("#T").16(\':V\')){$("#T").u({\'A\':$(U).A()})}8($("#M").16(\':V\')){$("#M").u({\'B\':((w[0]-40)*0.5+w[2]),\'z\':((w[1]-40)*0.5+w[3])})}};$.q.r.1t=p(a,b){J 3Y($.3Z(a.41?a[0]:a,b,D))||0};$.q.r.2d=p(a){n b=a.42();b.z+=$.q.r.1t(a,\'43\');b.z+=$.q.r.1t(a,\'44\');b.B+=$.q.r.1t(a,\'45\');b.B+=$.q.r.1t(a,\'46\');J b};$.q.r.2G=p(){$("#M").1a();$("#2E").Z()};$.q.r.1q=p(){J[$(19).E(),$(19).A(),$(U).47(),$(U).48()]};$.q.r.36=p(){8(!$("#M").16(\':V\')){38(1x);J}$("#M > 9").u(\'z\',(1y*-40)+\'R\');1y=(1y+1)%12};$.q.r.1F=p(){38(1x);n w=$.q.r.1q();$("#M").u({\'B\':((w[0]-40)*0.5+w[2]),\'z\':((w[1]-40)*0.5+w[3])}).Z();$("#M").11(\'17\',$.q.r.1c);1x=49($.q.r.36,4a)};$.q.r.1c=p(){1f=D;$(X).Q();$(U).Q("1N.L");$(19).Q("23.L 24.L");$("#T, #y, #1i").Q();$("#1i, #M, #1o, #1n, #H").1a();1O=p(){8($("#T").16(\':V\')){$("#T").1J("29")}$("#y").1r();8(4.2h){$(19).Q("23.L 24.L")}8(18){$(\'1X, 1Y, 1Z\').u(\'21\',\'V\')}8($.1T(4.2i)){4.2i()}1f=F};8($("#x").16(":V")!==F){8(4.2j>0&&4.v[4.t].S!==1m){n a=4.v[4.t].S;n b=$.q.r.2d(a);n c={\'B\':(b.B-20-4.N)+\'R\',\'z\':(b.z-20-4.N)+\'R\',\'E\':$(a).E()+(4.N*2),\'A\':$(a).A()+(4.N*2)};8(4.2e){c.22=\'1a\'}$("#x").3a(F,D).2b(c,4.2j,4.3b,1O)}C{$("#x").3a(F,D).1J(\'29\',1O)}}C{1O()}J F};$.q.r.3c=p(){n a=\'\';a+=\'<9 s="T"></9>\';a+=\'<9 s="M"><9></9></9>\';a+=\'<9 s="x">\';a+=\'<9 s="3d">\';a+=\'<9 s="1i"></9>\';a+=\'<9 s="W"><9 I="W" s="4b"></9><9 I="W" s="4c"></9><9 I="W" s="4d"></9><9 I="W" s="4e"></9><9 I="W" s="4f"></9><9 I="W" s="4g"></9><9 I="W" s="4h"></9><9 I="W" s="4i"></9></9>\';a+=\'<a K="2k:;" s="1o"><1P I="2l" s="2W"></1P></a><a K="2k:;" s="1n"><1P I="2l" s="2Y"></1P></a>\';a+=\'<9 s="y"></9>\';a+=\'</9>\';a+=\'</9>\';a+=\'<9 s="H"></9>\';$(a).3e("4j");$(\'<3f 4k="0" 4l="0" 4m="0"><3g><1k I="H" s="4n"></1k><1k I="H" s="4o"><9></9></1k><1k I="H" s="4p"></1k></3g></3f>\').3e(\'#H\');8($.14.1g){$(".W").1Q()}8(18){$("9#T").u("1u","2r");$("#M 9, #1i, .H, .2l").1Q();$("#3d").4q(\'<1j s="3h" 13="2k:F;" 4r="2q" 2H="0"></1j>\');n b=$(\'#3h\')[0].4s.U;b.4t();b.1c()}};$.q.r.2v={N:10,2J:D,2e:D,2c:0,2j:0,2S:4u,2U:\'2m\',3b:\'2m\',2T:\'2m\',1G:4v,1H:4w,1E:D,2B:0.3,2A:\'#4x\',2Z:D,33:D,31:D,30:D,2h:D,v:[],1U:1A,2g:1A,2i:1A};$(U).4y(p(){m=$.14.1g&&!$.4z;8($("#x").Y<1){$.q.r.3c()}})})(2F);',62,284,'||||opts||||if|div||||||||||||||var||function|fn|fancybox|id|itemCurrent|css|itemArray||fancy_outer|fancy_content|top|height|left|else|true|width|false|title|fancy_title|class|return|href|fb|fancy_loading|padding|this|Math|unbind|px|orig|fancy_overlay|document|visible|fancy_bg|imagePreloader|length|show||bind||src|browser|style|is|click|IE6|window|hide|round|close|match|filter|busy|msie|_change_item|fancy_close|iframe|td|img|undefined|fancy_right|fancy_left|_set_content|getViewport|empty|_finish|getNumeric|position|new|Image|loadingTimer|loadingFrame|imageRegExp|null|rel|children|first|overlayShow|showLoading|frameWidth|frameHeight|objNext|fadeOut|append|normal|removeAttribute|keydown|__cleanup|span|fixPNG|substr|oldIE|isFunction|callbackOnStart|typeof|alt|embed|object|select||visibility|opacity|resize|scroll|_proceed_image|60||min|fast|fadeIn|animate|zoomSpeedIn|getPosition|zoomOpacity|keyCode|callbackOnShow|centerOnScroll|callbackOnClose|zoomSpeedOut|javascript|fancy_ico|swing|each|backgroundImage|png|no|absolute|relative|version|extend|defaults|_initialize|_start|attr|push|overlayColor|overlayOpacity|scrollBox|indexOf|fancy_frame|jQuery|showIframe|frameborder|html|imageScale|_preload_neighbor_images|removeExpression|right|bottom|auto|setExpression|parentNode|100|zoomSpeedChange|easingChange|easingIn|_set_navigation|fancy_left_ico|stopPropagation|fancy_right_ico|enableEscapeButton|hideOnContentClick|hideOnOverlayClick||showCloseButton|outerHeight|outerWidth|animateLoading||clearInterval||stop|easingOut|build|fancy_inner|appendTo|table|tr|fancy_bigIframe|url|RegExp|none|progid|DXImageTransform|Microsoft|AlphaImageLoader|enabled|sizingMethod|backgroundRepeat|repeat|crop|scale|jpg|gif|bmp|jpeg|XMLHttpRequest|for|while|hidden|background|color|className|onload|name|fancy_iframe|random|1000|hspace|location|split|replace|fancy_div|complete|load|get|fancy_ajax|fancy_img|clientHeight|clientWidth|text|parseInt|curCSS||jquery|offset|paddingTop|borderTopWidth|paddingLeft|borderLeftWidth|scrollLeft|scrollTop|setInterval|66|fancy_bg_n|fancy_bg_ne|fancy_bg_e|fancy_bg_se|fancy_bg_s|fancy_bg_sw|fancy_bg_w|fancy_bg_nw|body|cellspacing|cellpadding|border|fancy_title_left|fancy_title_main|fancy_title_right|prepend|scrolling|contentWindow|open|300|560|340|666|ready|boxModel'.split('|'),0,{})); -------------------------------------------------------------------------------- /static/bifocal/css/readability-home.css: -------------------------------------------------------------------------------- 1 | /* @group Body and Layout */ 2 | body { 3 | background: #3574a6 url("../images/bg-body.jpg") repeat-x 0 0; 4 | color: #ededed; 5 | font-family: "Palatino Linotype", "Book Antiqua", Palatino, "Times New Roman", Times, Georgia, serif; 6 | } 7 | 8 | #container, #header, #instructions, #article, #example, #footer { 9 | clear: both; 10 | display: block; 11 | padding: 0 0 10px; 12 | position: relative; 13 | overflow: hidden; 14 | } 15 | 16 | #container { 17 | margin: 10px auto 0; 18 | padding: 10px; 19 | width: 961px; 20 | } 21 | 22 | #example { 23 | height: 458px; 24 | padding: 1em 2em; 25 | overflow: auto; 26 | } 27 | /* @end Body and Layout */ 28 | 29 | /* @group General Typography */ 30 | #header p, #instructions p, #footer p, 31 | #header li, #instructions li, #footer li { 32 | margin: 0; 33 | padding: 0; 34 | line-height: 1.6em; 35 | font-weight: 300; 36 | } 37 | 38 | ol,ul { list-style-type: none; padding: 0; margin: 0; } 39 | 40 | #readInner ol, #readInner ul { 41 | margin: 1em 0px 1em 0px; 42 | } 43 | #readInner sup{line-height:.8em;} 44 | 45 | img { border: 0; outline: 0; } 46 | 47 | a, a:link, a:visited { color: #ddd; text-decoration: none; } 48 | 49 | a:hover { color: #fff; } 50 | 51 | a:active { color: #aaa; } 52 | 53 | em { 54 | font-size: 1.1em; 55 | line-height: 1.4em; 56 | font-style: normal; 57 | font-variant: small-caps; 58 | } 59 | /* @end General Typography */ 60 | 61 | /* @group Header */ 62 | #header h1 { 63 | display: inline; 64 | height: 133px; 65 | float: left; 66 | margin: 20px 0 10px; 67 | width: 315px; 68 | background: transparent url("../images/logo-readability-large.png") no-repeat 0 0; 69 | text-indent: -9000px; 70 | } 71 | 72 | #es #header h1 { background-image: url("../images/logo-readability-es-large.png"); } 73 | 74 | #introduction { 75 | display: inline; 76 | float: left; 77 | margin: 25px 0 0; 78 | width: 350px; 79 | } 80 | 81 | #watch-video { 82 | display: inline; 83 | float: left; 84 | margin: 30px 0 0 30px; 85 | width: 110px; 86 | } 87 | 88 | #header .meta { 89 | display: inline; 90 | float: left; 91 | width: 130px; 92 | margin: 50px 0 0 25px; 93 | font-size: .75em; 94 | text-align: center; 95 | } 96 | 97 | #header .meta p a, #header .meta p a:link, #header .meta p a:visited { line-height: 2em; border-bottom: 1px solid #ddd; } 98 | 99 | #header .meta p a:hover { border-bottom-color: #fff; } 100 | 101 | #header .meta p a:active { border-bottom-color: #aaa; } 102 | /* @end Header */ 103 | 104 | /* @group instructions */ 105 | #settings { 106 | display: inline; 107 | float: left; 108 | width: 560px; 109 | background: transparent url("../images/bg-settings.png") no-repeat 0 65px; 110 | } 111 | 112 | #es #settings { background-image: url("../images/bg-settings-es.png"); } 113 | 114 | #settings h2, #bookmarklet h2 { 115 | margin: 0 0 15px; 116 | padding: 16px 0 0 45px; 117 | background: transparent url("../images/steps.png") no-repeat -45px 0; 118 | font-size: 24px; 119 | font-weight: 300; 120 | line-height: 1; 121 | text-transform: uppercase; 122 | } 123 | 124 | #settings .settings-box { 125 | display: inline; 126 | float: left; 127 | margin: 55px 0 0 25px; 128 | padding: 0 0 35px; 129 | width: 135px; 130 | } 131 | 132 | #settings dt { display: none; } 133 | 134 | #settings dd { margin: 0; padding: 0; } 135 | 136 | #settings input { margin: 0 10px 0 0; } 137 | 138 | #settings dd a, #settings dd a:link { 139 | display: inline-block; 140 | height: 14px; 141 | margin: 0 0 0 6px; 142 | position: relative; 143 | width: 14px; 144 | top: 5px; 145 | background: transparent url("../images/icon-typekit.png") no-repeat 0 0; 146 | text-indent: -9000px; 147 | } 148 | 149 | #settings p { 150 | clear: both; 151 | display: block; 152 | margin: 0 0 10px 0; 153 | width: 500px; 154 | text-align: center; 155 | } 156 | 157 | #settings p label { font-style: italic; } 158 | 159 | #footnote-details { 160 | margin: 0 0 0 5px; 161 | padding: 0 0 0 14px; 162 | background: transparent url("../images/bg-settings.png") no-repeat -63px -28px; 163 | font-size: .8em; 164 | font-weight: 600; 165 | text-decoration: underline; 166 | } 167 | 168 | #footnote-details span { 169 | margin: 0; 170 | padding: 3px 0; 171 | background: #ccc; 172 | border-right: 1px solid #ccc; 173 | border-left: 1px solid #ccc; 174 | } 175 | 176 | #footnote-details span span { 177 | padding: 3px .4em; 178 | position: relative; 179 | border-top: 1px solid #ccc; 180 | border-bottom: 1px solid #ccc; 181 | border-width: 1px 1px; 182 | } 183 | 184 | #bookmarklet { 185 | display: inline; 186 | float: left; 187 | width: 380px; 188 | font-size: .9em; 189 | } 190 | #bookmarklet h2 { 191 | margin-bottom: 45px; 192 | background-position: 0 -45px; 193 | } 194 | #bookmarklet p { 195 | margin: 0 0 0 45px; 196 | width: 330px; 197 | } 198 | #browser-instruction-placer { display: block; height: 46px; } 199 | #bookmarkletLink { 200 | display: block; 201 | height: 40px; 202 | margin: 20px 0 20px 115px; 203 | width: 174px; 204 | cursor: move; 205 | } 206 | #bookmarkletText { 207 | margin: 0 0 0 45px; 208 | height: 3.6em; 209 | width: 330px; 210 | } 211 | #readabilityBadge { 212 | -moz-border-radius: 8px; 213 | -webkit-border-radius: 8px; 214 | border-radius: 8px; 215 | -moz-box-shadow:3px 2px 2px 0 rgba(0, 0, 0, 0.35); 216 | -webkit-box-shadow: 3px 2px 2px 0 rgba(0,0,0, 0.35); 217 | box-shadow: 3px 2px 2px 0 rgba(0,0,0, 0.35); 218 | *border: 1px solid #888; /* IE hax */ 219 | background-color: #ddd; 220 | background: -moz-linear-gradient(90deg, #bbb, #eee) repeat scroll 0 0 transparent; 221 | background: -webkit-gradient(linear, left top, left bottom, from(#bbb), to(#eee)); 222 | color: #222; 223 | letter-spacing: 0.02em; 224 | font-size: 22px; 225 | font-variant: small-caps; 226 | height: 35px; 227 | line-height: 35px; 228 | text-align: center; 229 | width: 167px; 230 | cursor: move; 231 | } 232 | /* @end instructions */ 233 | 234 | /* @group footer */ 235 | #footer { background: transparent url("../images/logo-readability-small.png") no-repeat 0 30px; } 236 | 237 | #footer hr { 238 | height: 0; 239 | margin-bottom: 20px; 240 | outline: 0; 241 | border: 1px solid #8ea6b9; 242 | } 243 | 244 | #arcLinks li { display: inline; float: right; } 245 | 246 | #arcLinks img { vertical-align: -8px; } 247 | 248 | #arcLinks .www-link { margin-left: 25px; padding-left: 25px; border-left: 1px solid #ededed; } 249 | 250 | #kindlingAd { 251 | margin: 0 auto; 252 | width: 250px; 253 | text-align: center; 254 | font-size: .8em; 255 | margin-top: -10px; 256 | } 257 | 258 | #kindlingAd span { 259 | font-size: 11px; 260 | } 261 | /* @end footer */ 262 | 263 | /* @group overlay */ 264 | #fancy_outer a { 265 | color: #036; 266 | text-decoration: underline; 267 | } 268 | /* @end overlay */ 269 | 270 | /* @group Readability Examples */ 271 | #article {font-size:10px;line-height:1;} 272 | 273 | #article h2 { 274 | display: block; 275 | margin: 0; 276 | padding: 5px 0; 277 | position: absolute; 278 | right: 35px; 279 | width: 136px; 280 | z-index: 10; 281 | background: transparent url("../images/tab-example.png") no-repeat 0 bottom; 282 | font-weight: 300; 283 | text-align: center; 284 | } 285 | 286 | #articleContent { 287 | text-align: left; 288 | line-height: 1.4em; 289 | margin: 1em auto; 290 | } 291 | 292 | #articleContent h1 { 293 | display: block; 294 | padding-bottom: .5em; 295 | margin-bottom: .75em; 296 | border-bottom:1px solid #333; 297 | font-size: 1.2em; 298 | text-transform: capitalize; 299 | } 300 | 301 | #articleContent a:hover { 302 | text-decoration: underline; 303 | } 304 | 305 | #articleContent ol { 306 | list-style-type: decimal; 307 | list-style-position: outside; 308 | margin-left: 2em; 309 | } 310 | 311 | #example #references { 312 | display: none; 313 | } 314 | 315 | #example a.footnote { 316 | display: none; 317 | } 318 | 319 | #example.showNotes #articleBody a { 320 | color: inherit; 321 | } 322 | 323 | #example.showNotes #references { 324 | display: block; 325 | } 326 | 327 | #example.showNotes a.footnote { 328 | display: inline; 329 | } 330 | 331 | /* Size options */ 332 | .size-x-small { font-size: 12px; } 333 | .size-small { font-size: 15px; } 334 | .size-medium { font-size: 18px; } 335 | .size-large { font-size: 22px; } 336 | .size-x-large { font-size: 28px; } 337 | /* Style options */ 338 | .style-newspaper { font-family:Georgia,"Times New Roman", Times, serif; background:#fbfbfb; color:#080000; } 339 | .style-newspaper h1 { text-transform:capitalize; font-family:Georgia, "Times New Roman", Times, serif; } 340 | .style-newspaper #readInner a { color:#0924e1; } 341 | .style-novel { font-family:"Palatino Linotype", "Book Antiqua", Palatino, serif; background:#f4eed9; color:#1d1916; } 342 | .style-novel #readInner a { color:#1856ba; } 343 | .style-ebook { font-family:Arial, Helvetica, sans-serif; background:#edebe8; color:#2c2d32; } 344 | .style-ebook #readInner a { color:#187dc9; } 345 | .style-ebook h1 { font-family:"Arial Black", Gadget, sans-serif; font-weight:400; } 346 | .style-terminal { font-family:"Lucida Console", Monaco, monospace; background:#1d4e2c; color:#c6ffc6; } 347 | .style-terminal #readInner a { color:#093; } 348 | /* Begin Typekit Styles */ 349 | .style-apertura { font-family:"apertura-1", "apertura-2", sans-serif; background:#2d2828; color:#eae8e9; } 350 | .style-apertura #articleContent h1 { border-bottom-color: #ededed; } 351 | .style-apertura #readInner a { color:#58b0ff; } 352 | .style-athelas { font-family:"athelas-1", "athelas-2", sans-serif; background:#f7f7f7; color:#2b373d; } 353 | .style-athelas #readInner a { color:#1e83cb; } 354 | /* Margin Options */ 355 | .margin-x-narrow { width: 95%; } 356 | .margin-narrow { width: 85%; } 357 | .margin-medium { width: 75%; } 358 | .margin-wide { width: 55%; } 359 | .margin-x-wide { width: 35%; } 360 | /* @end Readability Examples */ 361 | -------------------------------------------------------------------------------- /bifocal.js: -------------------------------------------------------------------------------- 1 | var page = new WebPage(); 2 | 3 | var fs = require("fs"); 4 | 5 | var log = []; 6 | 7 | if (phantom.args.length === 0) { 8 | phantom.exit(1); 9 | } 10 | 11 | // USAGE: bifocal.js URL OUTPUT.TXT 12 | 13 | page.settings.userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:8.0.1) Gecko/20100101 Firefox/8.0.1'; 14 | //page.settings.javascriptEnabled = false; 15 | page.settings.loadImages = false; 16 | //page.settings.loadPlugins = false; 17 | 18 | page.onConsoleMessage = function(msg) { 19 | try{ 20 | var data = JSON.parse(msg); 21 | if(data.bifocal){ 22 | Log("Saving output to: " + (phantom.args[1] || "out.txt")); 23 | data.log = log; 24 | try{ 25 | fs.write(phantom.args[1] || "out.txt", encodeURIComponent(JSON.stringify(data)), "w"); 26 | Log("Success"); 27 | }catch(E){Log(E.message)}; 28 | phantom.exit(); 29 | } 30 | }catch(E){} 31 | Log(msg); 32 | }; 33 | 34 | page.onInitialized = function(status){ 35 | //Log("initialized") 36 | } 37 | 38 | page.onLoadFinished = function(status){ 39 | //Log("Load status: "+status) 40 | } 41 | 42 | page.onLoadFinished = function(){ 43 | //Log("Load started") 44 | } 45 | 46 | page.onResourceRequested = function(r){ 47 | //Log(JSON.stringify(r)); 48 | } 49 | 50 | page.onResourceReceived = function(r){ 51 | //Log(JSON.stringify(r)); 52 | } 53 | 54 | var filters = []; 55 | 56 | Log("Opening "+phantom.args[0]+" ..."); 57 | page.open(phantom.args[0], function (status) { 58 | if (status !== "success") { 59 | Log("ERROR: Network"); 60 | phantom.exit(2); 61 | } else { 62 | 63 | Log("Page opened"); 64 | 65 | for(var i=0, len=filters.length; i<len; i++){ 66 | Log("Applying filter #"+(i+1)); 67 | page.evaluate(filters[i]); 68 | } 69 | 70 | Log("Injecting main script"); 71 | page.includeJs("http://127.0.0.1:8080/bifocal/inject.js", function() { 72 | window.setTimeout(function () { 73 | phantom.exit(3); 74 | }, 10000); 75 | }); 76 | 77 | } 78 | 79 | }); 80 | 81 | // delfi 82 | filters.push(function(){ 83 | try{ 84 | console.log("Filter 1"); 85 | 86 | var list = document.querySelectorAll("font.articleBody"); 87 | if(list && list.length > 1){ 88 | list[1].innerHTML = "<p><strong>"+list[0].innerHTML+"</strong></p>"+list[1].innerHTML 89 | } 90 | try{ 91 | list[0].parentNode.removeChild(list[0]); 92 | }catch(e){} 93 | 94 | var block = document.querySelector(".articlebody span.articlelead"); 95 | if(block){ 96 | try{ 97 | var elm = document.createElement("p"); 98 | elm.innerHTML = "<strong>"+(block.innerHTML || "").trim()+"</strong>"; 99 | 100 | block.parentNode.insertBefore(elm, block); 101 | block.parentNode.removeChild(block); 102 | }catch(E){} 103 | } 104 | 105 | var block = document.querySelector(".AB_banner"); 106 | if(block){ 107 | try{ 108 | block.parentNode.removeChild(block); 109 | }catch(E){} 110 | } 111 | 112 | var block = document.querySelector(".articlebody .paidcontent"); 113 | if(block){ 114 | try{ 115 | block.parentNode.removeChild(block); 116 | }catch(E){} 117 | } 118 | 119 | var block = document.querySelector(".content .art-authors"); 120 | if(block){ 121 | try{ 122 | block.parentNode.removeChild(block); 123 | }catch(E){} 124 | } 125 | 126 | var block = document.querySelector(".content .artImage"); 127 | if(block){ 128 | try{ 129 | block.parentNode.removeChild(block); 130 | }catch(E){} 131 | } 132 | 133 | var block = document.querySelector(".content .articleSource"); 134 | if(block){ 135 | try{ 136 | block.parentNode.removeChild(block); 137 | }catch(E){} 138 | } 139 | 140 | var block = document.querySelector(".articlebody_holder .articleimage"); 141 | if(block){ 142 | try{ 143 | block.parentNode.removeChild(block); 144 | }catch(E){} 145 | } 146 | 147 | var block = document.querySelectorAll(".articlebody p, .articlebody div"); 148 | for(var i = block.length-1; i>=0; i--){ 149 | try{ 150 | if(!block[i].innerHTML.replace(/\ |[\s\n\r\t]/gi, " ").trim() || (block[i].id || "").toString().match(/adocean/)){ 151 | block[i].parentNode.removeChild(block[i]); 152 | } 153 | }catch(E){} 154 | } 155 | 156 | var block = document.querySelector(".articlebody #ss_buttons"); 157 | if(block){ 158 | try{ 159 | block.parentNode.removeChild(block); 160 | }catch(E){} 161 | } 162 | 163 | // remove comments 164 | var block = document.querySelector(".articlebody"); 165 | if(block){ 166 | block.innerHTML = block.innerHTML.replace(/\r?\n|\r/g, "\u0000").replace(/<\!--.*?-->/g, "").replace(/\u0000/g,"\n").trim(); 167 | } 168 | 169 | }catch(E){console.log("ERR1: "+E.message)} 170 | }); 171 | 172 | // postimees 173 | filters.push(function(){ 174 | try{ 175 | console.log("Filter 2"); 176 | 177 | var block = document.querySelector("#lisade_peidetud_andmed"); 178 | try{ 179 | block.parentNode.removeChild(block); 180 | }catch(e){ 181 | return; 182 | } 183 | 184 | var sissejuhatus = document.querySelector("#artikli_sissejuhatus"), 185 | tykid, text; 186 | 187 | if(sissejuhatus){ 188 | 189 | var p = sissejuhatus.querySelectorAll("p"); 190 | for(var i=0, len = p.length; i<len; i++){ 191 | p[i].innerHTML = "<strong>"+p[i].innerHTML+"</strong>"; 192 | } 193 | 194 | text = sissejuhatus.innerHTML || ""; 195 | 196 | try{ 197 | sissejuhatus.parentNode.removeChild(sissejuhatus); 198 | }catch(e){ 199 | return; 200 | } 201 | 202 | if((tykid = document.querySelector(".artikkel_tykid"))){ 203 | tykid.innerHTML = text + tykid.innerHTML; 204 | } 205 | } 206 | 207 | }catch(E){console.log("ERR2: "+E.message)} 208 | }); 209 | 210 | // err 211 | filters.push(function(){ 212 | try{ 213 | console.log("Filter 3"); 214 | 215 | var block = document.querySelector(".space .biggerfont"), 216 | fs = block && block.firstChild; 217 | 218 | if(fs && fs.nodeName == "#text"){ 219 | if((fs.nodeValue || "").toString().trim().match(/^[0-9\. :]+$/)){ 220 | try{ 221 | fs.parentNode.removeChild(fs); 222 | }catch(E){} 223 | } 224 | } 225 | 226 | var block = document.querySelector(".box .content .time"); 227 | 228 | if(block){ 229 | try{ 230 | block.parentNode.removeChild(block); 231 | }catch(E){} 232 | } 233 | 234 | }catch(E){console.log("ERR3: "+E.message)} 235 | }); 236 | 237 | // ap3 238 | filters.push(function(){ 239 | try{ 240 | console.log("Filter 4"); 241 | 242 | var block = document.querySelector(".publicationpublished"); 243 | 244 | if(block){ 245 | try{ 246 | block.parentNode.removeChild(block); 247 | }catch(E){} 248 | } 249 | 250 | }catch(E){console.log("ERR4: "+E.message)} 251 | }); 252 | 253 | // õhtuleht 254 | filters.push(function(){ 255 | try{ 256 | console.log("Filter 5"); 257 | 258 | var block; 259 | 260 | if((block = document.querySelector("#article-info.cfx"))){ 261 | try{ 262 | block.parentNode.removeChild(block); 263 | }catch(E){} 264 | } 265 | 266 | if((block = document.querySelector("#article-content #gallery"))){ 267 | try{ 268 | block.parentNode.removeChild(block); 269 | }catch(E){} 270 | } 271 | 272 | if((block = document.querySelectorAll("#article-content .banner"))){ 273 | for(var i=block.length-1; i>=0; i--){ 274 | try{ 275 | block[i].parentNode.removeChild(block[i]); 276 | }catch(E){} 277 | } 278 | } 279 | 280 | }catch(E){console.log("ERR5: "+E.message)} 281 | }); 282 | 283 | // memokraat 284 | filters.push(function(){ 285 | try{ 286 | console.log("Filter 6"); 287 | 288 | var block = document.querySelector("#content #content-main .post h5"); 289 | 290 | if(block){ 291 | try{ 292 | block.parentNode.removeChild(block); 293 | }catch(E){} 294 | } 295 | 296 | var block = document.querySelector(".sharedaddy"); 297 | 298 | if(block){ 299 | try{ 300 | block.parentNode.removeChild(block); 301 | }catch(E){} 302 | } 303 | 304 | }catch(E){console.log("ERR6: "+E.message)} 305 | }); 306 | 307 | // kes-kus 308 | filters.push(function(){ 309 | try{ 310 | console.log("Filter 7"); 311 | 312 | var sissejuhatus = document.querySelector("td.koht h5"), 313 | tykid, text; 314 | 315 | if(sissejuhatus){ 316 | 317 | text = "<p>"+(sissejuhatus.innerHTML || "")+"</p>"; 318 | 319 | try{ 320 | sissejuhatus.parentNode.removeChild(sissejuhatus); 321 | }catch(e){ 322 | return; 323 | } 324 | 325 | if((tykid = document.querySelector("td.tekst"))){ 326 | tykid.innerHTML = text + tykid.innerHTML; 327 | } 328 | } 329 | 330 | }catch(E){console.log("ERR7: "+E.message)} 331 | }); 332 | 333 | // õpetajate leht 334 | filters.push(function(){ 335 | try{ 336 | console.log("Filter 8"); 337 | 338 | var block = document.querySelector(".full_artikel .h1_link_a"); 339 | 340 | if(block){ 341 | try{ 342 | block.parentNode.removeChild(block); 343 | }catch(E){} 344 | } 345 | 346 | var block = document.querySelector(".full_artikel .komment_link_a"); 347 | 348 | if(block){ 349 | try{ 350 | block.parentNode.removeChild(block); 351 | }catch(E){} 352 | } 353 | 354 | }catch(E){console.log("ERR8: "+E.message)} 355 | }); 356 | 357 | // remove media 358 | filters.push(function(){ 359 | try{ 360 | console.log("Filter 9"); 361 | 362 | var block = document.querySelectorAll("video, embed, audio, object, script"); 363 | 364 | for(var i = block.length-1; i>=0; i--){ 365 | try{ 366 | block[i].parentNode.removeChild(block[i]); 367 | }catch(E){} 368 | } 369 | 370 | }catch(E){console.log("ERR9: "+E.message)} 371 | 372 | //console.log(document.body.innerHTML); 373 | }); 374 | 375 | function Log(msg){ 376 | log.push(msg); 377 | console.log(msg); 378 | } 379 | -------------------------------------------------------------------------------- /static/bifocal/js/jquery-1.3.1.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery JavaScript Library v1.3.1 3 | * http://jquery.com/ 4 | * 5 | * Copyright (c) 2009 John Resig 6 | * Dual licensed under the MIT and GPL licenses. 7 | * http://docs.jquery.com/License 8 | * 9 | * Date: 2009-01-21 20:42:16 -0500 (Wed, 21 Jan 2009) 10 | * Revision: 6158 11 | */ 12 | (function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.makeArray(E))},selector:"",jquery:"1.3.1",size:function(){return this.length},get:function(E){return E===g?o.makeArray(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,find:function(E){if(this.length===1&&!/,/.test(E)){var G=this.pushStack([],"find",E);G.length=0;o.find(E,this[0],G);return G}else{var F=o.map(this,function(H){return o.find(E,H)});return this.pushStack(/[^+>] [^+>]/.test(E)?o.unique(F):F,"find",E)}},clone:function(F){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.cloneNode(true),H=document.createElement("div");H.appendChild(I);return o.clean([H.innerHTML])[0]}else{return this.cloneNode(true)}});var G=E.find("*").andSelf().each(function(){if(this[h]!==g){this[h]=null}});if(F===true){this.find("*").andSelf().each(function(I){if(this.nodeType==3){return}var H=o.data(this,"events");for(var K in H){for(var J in H[K]){o.event.add(G[I],K,H[K][J],H[K][J].data)}}})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var F=o.expr.match.POS.test(E)?o(E):null;return this.map(function(){var G=this;while(G&&G.ownerDocument){if(F?F.index(G)>-1:o(G).is(E)){return G}G=G.parentNode}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F<J;F++){var G=M[F];if(G.selected){K=o(G).val();if(H){return K}L.push(K)}}return L}return(E.value||"").replace(/\r/g,"")}return g}if(typeof K==="number"){K+=""}return this.each(function(){if(this.nodeType!=1){return}if(o.isArray(K)&&/radio|checkbox/.test(this.type)){this.checked=(o.inArray(this.value,K)>=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML:null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(K,N,M){if(this[0]){var J=(this[0].ownerDocument||this[0]).createDocumentFragment(),G=o.clean(K,(this[0].ownerDocument||this[0]),J),I=J.firstChild,E=this.length>1?J.cloneNode(true):J;if(I){for(var H=0,F=this.length;H<F;H++){M.call(L(this[H],I),H>0?E.cloneNode(true):J)}}if(G){o.each(G,z)}}return this;function L(O,P){return N&&o.nodeName(O,"table")&&o.nodeName(P,"tr")?(O.getElementsByTagName("tbody")[0]||O.appendChild(O.ownerDocument.createElement("tbody"))):O}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H<I;H++){if((G=arguments[H])!=null){for(var F in G){var K=J[F],L=G[F];if(J===L){continue}if(E&&L&&typeof L==="object"&&!L.nodeType){J[F]=o.extend(E,K||(L.length!=null?[]:{}),L)}else{if(L!==g){J[F]=L}}}}}return J};var b=/z-?index|font-?weight|opacity|zoom|line-?height/i,q=document.defaultView||{},s=Object.prototype.toString;o.extend({noConflict:function(E){l.$=p;if(E){l.jQuery=y}return o},isFunction:function(E){return s.call(E)==="[object Function]"},isArray:function(E){return s.call(E)==="[object Array]"},isXMLDoc:function(E){return E.nodeType===9&&E.documentElement.nodeName!=="HTML"||!!E.ownerDocument&&o.isXMLDoc(E.ownerDocument)},globalEval:function(G){G=o.trim(G);if(G){var F=document.getElementsByTagName("head")[0]||document.documentElement,E=document.createElement("script");E.type="text/javascript";if(o.support.scriptEval){E.appendChild(document.createTextNode(G))}else{E.text=G}F.insertBefore(E,F.firstChild);F.removeChild(E)}},nodeName:function(F,E){return F.nodeName&&F.nodeName.toUpperCase()==E.toUpperCase()},each:function(G,K,F){var E,H=0,I=G.length;if(F){if(I===g){for(E in G){if(K.apply(G[E],F)===false){break}}}else{for(;H<I;){if(K.apply(G[H++],F)===false){break}}}}else{if(I===g){for(E in G){if(K.call(G[E],E,G[E])===false){break}}}else{for(var J=G[0];H<I&&K.call(J,H,J)!==false;J=G[++H]){}}}return G},prop:function(H,I,G,F,E){if(o.isFunction(I)){I=I.call(H,F)}return typeof I==="number"&&G=="curCSS"&&!b.test(E)?I+"px":I},className:{add:function(E,F){o.each((F||"").split(/\s+/),function(G,H){if(E.nodeType==1&&!o.className.has(E.className,H)){E.className+=(E.className?" ":"")+H}})},remove:function(E,F){if(E.nodeType==1){E.className=F!==g?o.grep(E.className.split(/\s+/),function(G){return !o.className.has(F,G)}).join(" "):""}},has:function(F,E){return F&&o.inArray(E,(F.className||F).toString().split(/\s+/))>-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(G,E,I){if(E=="width"||E=="height"){var K,F={position:"absolute",visibility:"hidden",display:"block"},J=E=="width"?["Left","Right"]:["Top","Bottom"];function H(){K=E=="width"?G.offsetWidth:G.offsetHeight;var M=0,L=0;o.each(J,function(){M+=parseFloat(o.curCSS(G,"padding"+this,true))||0;L+=parseFloat(o.curCSS(G,"border"+this+"Width",true))||0});K-=Math.round(M+L)}if(o(G).is(":visible")){H()}else{o.swap(G,F,H)}return Math.max(0,K)}return o.curCSS(G,E,I)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,R){if(typeof R==="number"){R+=""}if(!R){return}if(typeof R==="string"){R=R.replace(/(<(\w+)[^>]*?)\/>/g,function(T,U,S){return S.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?T:U+"></"+S+">"});var O=o.trim(R).toLowerCase();var Q=!O.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!O.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!O.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!O.indexOf("<td")||!O.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!O.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!o.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];L.innerHTML=Q[1]+R+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var N=!O.indexOf("<table")&&O.indexOf("<tbody")<0?L.firstChild&&L.firstChild.childNodes:Q[1]=="<table>"&&O.indexOf("<tbody")<0?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(R)){L.insertBefore(K.createTextNode(R.match(/^\s*/)[0]),L.firstChild)}R=o.makeArray(L.childNodes)}if(R.nodeType){G.push(R)}else{G=o.merge(G,R)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E<F;E++){if(H[E]===G){return E}}return -1},merge:function(H,E){var F=0,G,I=H.length;if(!o.support.getAll){while((G=E[F++])!=null){if(G.nodeType!=8){H[I++]=G}}}else{while((G=E[F++])!=null){H[I++]=G}}return H},unique:function(K){var F=[],E={};try{for(var G=0,H=K.length;G<H;G++){var J=o.data(K[G]);if(!E[J]){E[J]=true;F.push(K[G])}}}catch(I){F=K}return F},grep:function(F,J,E){var G=[];for(var H=0,I=F.length;H<I;H++){if(!E!=!J(F[H],H)){G.push(F[H])}}return G},map:function(E,J){var F=[];for(var G=0,H=E.length;G<H;G++){var I=J(E[G],G);if(I!=null){F[F.length]=I}}return F.concat.apply([],F)}});var C=navigator.userAgent.toLowerCase();o.browser={version:(C.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(C),opera:/opera/.test(C),msie:/msie/.test(C)&&!/opera/.test(C),mozilla:/mozilla/.test(C)&&!/(compatible|webkit)/.test(C)};o.each({parent:function(E){return E.parentNode},parents:function(E){return o.dir(E,"parentNode")},next:function(E){return o.nth(E,2,"nextSibling")},prev:function(E){return o.nth(E,2,"previousSibling")},nextAll:function(E){return o.dir(E,"nextSibling")},prevAll:function(E){return o.dir(E,"previousSibling")},siblings:function(E){return o.sibling(E.parentNode.firstChild,E)},children:function(E){return o.sibling(E.firstChild)},contents:function(E){return o.nodeName(E,"iframe")?E.contentDocument||E.contentWindow.document:o.makeArray(E.childNodes)}},function(E,F){o.fn[E]=function(G){var H=o.map(this,F);if(G&&typeof G=="string"){H=o.multiFilter(G,H)}return this.pushStack(o.unique(H),E,G)}});o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(E,F){o.fn[E]=function(){var G=arguments;return this.each(function(){for(var H=0,I=G.length;H<I;H++){o(G[H])[F](this)}})}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(">*",this).remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}}); 13 | /* 14 | * Sizzle CSS Selector Engine - v0.9.3 15 | * Copyright 2009, The Dojo Foundation 16 | * Released under the MIT, BSD, and GPL Licenses. 17 | * More information: http://sizzlejs.com/ 18 | */ 19 | (function(){var Q=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]+['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[]+)+|[>+~])(\s*,\s*)?/g,K=0,G=Object.prototype.toString;var F=function(X,T,aa,ab){aa=aa||[];T=T||document;if(T.nodeType!==1&&T.nodeType!==9){return[]}if(!X||typeof X!=="string"){return aa}var Y=[],V,ae,ah,S,ac,U,W=true;Q.lastIndex=0;while((V=Q.exec(X))!==null){Y.push(V[1]);if(V[2]){U=RegExp.rightContext;break}}if(Y.length>1&&L.exec(X)){if(Y.length===2&&H.relative[Y[0]]){ae=I(Y[0]+Y[1],T)}else{ae=H.relative[Y[0]]?[T]:F(Y.shift(),T);while(Y.length){X=Y.shift();if(H.relative[X]){X+=Y.shift()}ae=I(X,ae)}}}else{var ad=ab?{expr:Y.pop(),set:E(ab)}:F.find(Y.pop(),Y.length===1&&T.parentNode?T.parentNode:T,P(T));ae=F.filter(ad.expr,ad.set);if(Y.length>0){ah=E(ae)}else{W=false}while(Y.length){var ag=Y.pop(),af=ag;if(!H.relative[ag]){ag=""}else{af=Y.pop()}if(af==null){af=T}H.relative[ag](ah,af,P(T))}}if(!ah){ah=ae}if(!ah){throw"Syntax error, unrecognized expression: "+(ag||X)}if(G.call(ah)==="[object Array]"){if(!W){aa.push.apply(aa,ah)}else{if(T.nodeType===1){for(var Z=0;ah[Z]!=null;Z++){if(ah[Z]&&(ah[Z]===true||ah[Z].nodeType===1&&J(T,ah[Z]))){aa.push(ae[Z])}}}else{for(var Z=0;ah[Z]!=null;Z++){if(ah[Z]&&ah[Z].nodeType===1){aa.push(ae[Z])}}}}}else{E(ah,aa)}if(U){F(U,T,aa,ab)}return aa};F.matches=function(S,T){return F(S,null,null,T)};F.find=function(Z,S,aa){var Y,W;if(!Z){return[]}for(var V=0,U=H.order.length;V<U;V++){var X=H.order[V],W;if((W=H.match[X].exec(Z))){var T=RegExp.leftContext;if(T.substr(T.length-1)!=="\\"){W[1]=(W[1]||"").replace(/\\/g,"");Y=H.find[X](W,S,aa);if(Y!=null){Z=Z.replace(H.match[X],"");break}}}}if(!Y){Y=S.getElementsByTagName("*")}return{set:Y,expr:Z}};F.filter=function(ab,aa,ae,V){var U=ab,ag=[],Y=aa,X,S;while(ab&&aa.length){for(var Z in H.filter){if((X=H.match[Z].exec(ab))!=null){var T=H.filter[Z],af,ad;S=false;if(Y==ag){ag=[]}if(H.preFilter[Z]){X=H.preFilter[Z](X,Y,ae,ag,V);if(!X){S=af=true}else{if(X===true){continue}}}if(X){for(var W=0;(ad=Y[W])!=null;W++){if(ad){af=T(ad,X,W,Y);var ac=V^!!af;if(ae&&af!=null){if(ac){S=true}else{Y[W]=false}}else{if(ac){ag.push(ad);S=true}}}}}if(af!==g){if(!ae){Y=ag}ab=ab.replace(H.match[Z],"");if(!S){return[]}break}}}ab=ab.replace(/\s*,\s*/,"");if(ab==U){if(S==null){throw"Syntax error, unrecognized expression: "+ab}else{break}}U=ab}return Y};var H=F.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(S){return S.getAttribute("href")}},relative:{"+":function(W,T){for(var U=0,S=W.length;U<S;U++){var V=W[U];if(V){var X=V.previousSibling;while(X&&X.nodeType!==1){X=X.previousSibling}W[U]=typeof T==="string"?X||false:X===T}}if(typeof T==="string"){F.filter(T,W,true)}},">":function(X,T,Y){if(typeof T==="string"&&!/\W/.test(T)){T=Y?T:T.toUpperCase();for(var U=0,S=X.length;U<S;U++){var W=X[U];if(W){var V=W.parentNode;X[U]=V.nodeName===T?V:false}}}else{for(var U=0,S=X.length;U<S;U++){var W=X[U];if(W){X[U]=typeof T==="string"?W.parentNode:W.parentNode===T}}if(typeof T==="string"){F.filter(T,X,true)}}},"":function(V,T,X){var U="done"+(K++),S=R;if(!T.match(/\W/)){var W=T=X?T:T.toUpperCase();S=O}S("parentNode",T,U,V,W,X)},"~":function(V,T,X){var U="done"+(K++),S=R;if(typeof T==="string"&&!T.match(/\W/)){var W=T=X?T:T.toUpperCase();S=O}S("previousSibling",T,U,V,W,X)}},find:{ID:function(T,U,V){if(typeof U.getElementById!=="undefined"&&!V){var S=U.getElementById(T[1]);return S?[S]:[]}},NAME:function(S,T,U){if(typeof T.getElementsByName!=="undefined"&&!U){return T.getElementsByName(S[1])}},TAG:function(S,T){return T.getElementsByTagName(S[1])}},preFilter:{CLASS:function(V,T,U,S,Y){V=" "+V[1].replace(/\\/g,"")+" ";var X;for(var W=0;(X=T[W])!=null;W++){if(X){if(Y^(" "+X.className+" ").indexOf(V)>=0){if(!U){S.push(X)}}else{if(U){T[W]=false}}}}return false},ID:function(S){return S[1].replace(/\\/g,"")},TAG:function(T,S){for(var U=0;S[U]===false;U++){}return S[U]&&P(S[U])?T[1]:T[1].toUpperCase()},CHILD:function(S){if(S[1]=="nth"){var T=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(S[2]=="even"&&"2n"||S[2]=="odd"&&"2n+1"||!/\D/.test(S[2])&&"0n+"+S[2]||S[2]);S[2]=(T[1]+(T[2]||1))-0;S[3]=T[3]-0}S[0]="done"+(K++);return S},ATTR:function(T){var S=T[1].replace(/\\/g,"");if(H.attrMap[S]){T[1]=H.attrMap[S]}if(T[2]==="~="){T[4]=" "+T[4]+" "}return T},PSEUDO:function(W,T,U,S,X){if(W[1]==="not"){if(W[3].match(Q).length>1){W[3]=F(W[3],null,null,T)}else{var V=F.filter(W[3],T,U,true^X);if(!U){S.push.apply(S,V)}return false}}else{if(H.match.POS.test(W[0])){return true}}return W},POS:function(S){S.unshift(true);return S}},filters:{enabled:function(S){return S.disabled===false&&S.type!=="hidden"},disabled:function(S){return S.disabled===true},checked:function(S){return S.checked===true},selected:function(S){S.parentNode.selectedIndex;return S.selected===true},parent:function(S){return !!S.firstChild},empty:function(S){return !S.firstChild},has:function(U,T,S){return !!F(S[3],U).length},header:function(S){return/h\d/i.test(S.nodeName)},text:function(S){return"text"===S.type},radio:function(S){return"radio"===S.type},checkbox:function(S){return"checkbox"===S.type},file:function(S){return"file"===S.type},password:function(S){return"password"===S.type},submit:function(S){return"submit"===S.type},image:function(S){return"image"===S.type},reset:function(S){return"reset"===S.type},button:function(S){return"button"===S.type||S.nodeName.toUpperCase()==="BUTTON"},input:function(S){return/input|select|textarea|button/i.test(S.nodeName)}},setFilters:{first:function(T,S){return S===0},last:function(U,T,S,V){return T===V.length-1},even:function(T,S){return S%2===0},odd:function(T,S){return S%2===1},lt:function(U,T,S){return T<S[3]-0},gt:function(U,T,S){return T>S[3]-0},nth:function(U,T,S){return S[3]-0==T},eq:function(U,T,S){return S[3]-0==T}},filter:{CHILD:function(S,V){var Y=V[1],Z=S.parentNode;var X=V[0];if(Z&&(!Z[X]||!S.nodeIndex)){var W=1;for(var T=Z.firstChild;T;T=T.nextSibling){if(T.nodeType==1){T.nodeIndex=W++}}Z[X]=W-1}if(Y=="first"){return S.nodeIndex==1}else{if(Y=="last"){return S.nodeIndex==Z[X]}else{if(Y=="only"){return Z[X]==1}else{if(Y=="nth"){var ab=false,U=V[2],aa=V[3];if(U==1&&aa==0){return true}if(U==0){if(S.nodeIndex==aa){ab=true}}else{if((S.nodeIndex-aa)%U==0&&(S.nodeIndex-aa)/U>=0){ab=true}}return ab}}}}},PSEUDO:function(Y,U,V,Z){var T=U[1],W=H.filters[T];if(W){return W(Y,V,U,Z)}else{if(T==="contains"){return(Y.textContent||Y.innerText||"").indexOf(U[3])>=0}else{if(T==="not"){var X=U[3];for(var V=0,S=X.length;V<S;V++){if(X[V]===Y){return false}}return true}}}},ID:function(T,S){return T.nodeType===1&&T.getAttribute("id")===S},TAG:function(T,S){return(S==="*"&&T.nodeType===1)||T.nodeName===S},CLASS:function(T,S){return S.test(T.className)},ATTR:function(W,U){var S=H.attrHandle[U[1]]?H.attrHandle[U[1]](W):W[U[1]]||W.getAttribute(U[1]),X=S+"",V=U[2],T=U[4];return S==null?V==="!=":V==="="?X===T:V==="*="?X.indexOf(T)>=0:V==="~="?(" "+X+" ").indexOf(T)>=0:!U[4]?S:V==="!="?X!=T:V==="^="?X.indexOf(T)===0:V==="$="?X.substr(X.length-T.length)===T:V==="|="?X===T||X.substr(0,T.length+1)===T+"-":false},POS:function(W,T,U,X){var S=T[2],V=H.setFilters[S];if(V){return V(W,U,T,X)}}}};var L=H.match.POS;for(var N in H.match){H.match[N]=RegExp(H.match[N].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(T,S){T=Array.prototype.slice.call(T);if(S){S.push.apply(S,T);return S}return T};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(M){E=function(W,V){var T=V||[];if(G.call(W)==="[object Array]"){Array.prototype.push.apply(T,W)}else{if(typeof W.length==="number"){for(var U=0,S=W.length;U<S;U++){T.push(W[U])}}else{for(var U=0;W[U];U++){T.push(W[U])}}}return T}}(function(){var T=document.createElement("form"),U="script"+(new Date).getTime();T.innerHTML="<input name='"+U+"'/>";var S=document.documentElement;S.insertBefore(T,S.firstChild);if(!!document.getElementById(U)){H.find.ID=function(W,X,Y){if(typeof X.getElementById!=="undefined"&&!Y){var V=X.getElementById(W[1]);return V?V.id===W[1]||typeof V.getAttributeNode!=="undefined"&&V.getAttributeNode("id").nodeValue===W[1]?[V]:g:[]}};H.filter.ID=function(X,V){var W=typeof X.getAttributeNode!=="undefined"&&X.getAttributeNode("id");return X.nodeType===1&&W&&W.nodeValue===V}}S.removeChild(T)})();(function(){var S=document.createElement("div");S.appendChild(document.createComment(""));if(S.getElementsByTagName("*").length>0){H.find.TAG=function(T,X){var W=X.getElementsByTagName(T[1]);if(T[1]==="*"){var V=[];for(var U=0;W[U];U++){if(W[U].nodeType===1){V.push(W[U])}}W=V}return W}}S.innerHTML="<a href='#'></a>";if(S.firstChild&&S.firstChild.getAttribute("href")!=="#"){H.attrHandle.href=function(T){return T.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var S=F,T=document.createElement("div");T.innerHTML="<p class='TEST'></p>";if(T.querySelectorAll&&T.querySelectorAll(".TEST").length===0){return}F=function(X,W,U,V){W=W||document;if(!V&&W.nodeType===9&&!P(W)){try{return E(W.querySelectorAll(X),U)}catch(Y){}}return S(X,W,U,V)};F.find=S.find;F.filter=S.filter;F.selectors=S.selectors;F.matches=S.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){H.order.splice(1,0,"CLASS");H.find.CLASS=function(S,T){return T.getElementsByClassName(S[1])}}function O(T,Z,Y,ac,aa,ab){for(var W=0,U=ac.length;W<U;W++){var S=ac[W];if(S){S=S[T];var X=false;while(S&&S.nodeType){var V=S[Y];if(V){X=ac[V];break}if(S.nodeType===1&&!ab){S[Y]=W}if(S.nodeName===Z){X=S;break}S=S[T]}ac[W]=X}}}function R(T,Y,X,ab,Z,aa){for(var V=0,U=ab.length;V<U;V++){var S=ab[V];if(S){S=S[T];var W=false;while(S&&S.nodeType){if(S[X]){W=ab[S[X]];break}if(S.nodeType===1){if(!aa){S[X]=V}if(typeof Y!=="string"){if(S===Y){W=true;break}}else{if(F.filter(Y,[S]).length>0){W=S;break}}}S=S[T]}ab[V]=W}}}var J=document.compareDocumentPosition?function(T,S){return T.compareDocumentPosition(S)&16}:function(T,S){return T!==S&&(T.contains?T.contains(S):true)};var P=function(S){return S.nodeType===9&&S.documentElement.nodeName!=="HTML"||!!S.ownerDocument&&P(S.ownerDocument)};var I=function(S,Z){var V=[],W="",X,U=Z.nodeType?[Z]:Z;while((X=H.match.PSEUDO.exec(S))){W+=X[0];S=S.replace(H.match.PSEUDO,"")}S=H.relative[S]?S+"*":S;for(var Y=0,T=U.length;Y<T;Y++){F(S,U[Y],V)}return F.filter(W,V)};o.find=F;o.filter=F.filter;o.expr=F.selectors;o.expr[":"]=o.expr.filters;F.selectors.filters.hidden=function(S){return"hidden"===S.type||o.css(S,"display")==="none"||o.css(S,"visibility")==="hidden"};F.selectors.filters.visible=function(S){return"hidden"!==S.type&&o.css(S,"display")!=="none"&&o.css(S,"visibility")!=="hidden"};F.selectors.filters.animated=function(S){return o.grep(o.timers,function(T){return S===T.elem}).length};o.multiFilter=function(U,S,T){if(T){U=":not("+U+")"}return F.matches(U,S)};o.dir=function(U,T){var S=[],V=U[T];while(V&&V!=document){if(V.nodeType==1){S.push(V)}V=V[T]}return S};o.nth=function(W,S,U,V){S=S||1;var T=0;for(;W;W=W[U]){if(W.nodeType==1&&++T==S){break}}return W};o.sibling=function(U,T){var S=[];for(;U;U=U.nextSibling){if(U.nodeType==1&&U!=T){S.push(U)}}return S};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F<E.length){o.event.proxy(G,E[F++])}return this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;H.preventDefault();return E[this.lastToggle++].apply(this,arguments)||false}))},hover:function(E,F){return this.mouseenter(E).mouseleave(F)},ready:function(E){B();if(o.isReady){E.call(document,o)}else{o.readyList.push(E)}return this},live:function(G,F){var E=o.event.proxy(F);E.guid+=this.selector+G;o(document).bind(i(G,this.selector),this.selector,E);return this},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);return this}});function c(H){var E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var K=o(H.target).closest(J.data)[0];if(K){F.push({elem:K,fn:J})}}});o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){G=false}});return G}function i(F,E){return["live",F,E.replace(/\./g,"`").replace(/ /g,"|")].join(".")}o.extend({isReady:false,readyList:[],ready:function(){if(!o.isReady){o.isReady=true;if(o.readyList){o.each(o.readyList,function(){this.call(document,o)});o.readyList=null}o(document).triggerHandler("ready")}}});var x=false;function B(){if(x){return}x=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);o.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);o.ready()}});if(document.documentElement.doScroll&&typeof l.frameElement==="undefined"){(function(){if(o.isReady){return}try{document.documentElement.doScroll("left")}catch(E){setTimeout(arguments.callee,0);return}o.ready()})()}}}o.event.add(l,"load",o.ready)}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(F,E){o.fn[E]=function(G){return G?this.bind(E,G):this.trigger(E)}});o(l).bind("unload",function(){for(var E in o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem)}}});(function(){o.support={};var F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new Date).getTime();K.style.display="none";K.innerHTML=' <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var L=document.createElement("div");L.style.width="1px";L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L)})})();var w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G)}var I=G.indexOf(" ");if(I>=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H<F;H++){var E=o.data(this[H],"olddisplay");this[H].style.display=E||"";if(o.css(this[H],"display")==="none"){var G=this[H].tagName,K;if(m[G]){K=m[G]}else{var I=o("<"+G+" />").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}this[H].style.display=o.data(this[H],"olddisplay",K)}}return this}},hide:function(H,I){if(H){return this.animate(t("hide",3),H,I)}else{for(var G=0,F=this.length;G<F;G++){var E=o.data(this[G],"olddisplay");if(!E&&E!=="none"){o.data(this[G],"olddisplay",o.css(this[G],"display"))}this[G].style.display="none"}return this}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof G==="boolean";return o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var H=E?G:o(this).is(":hidden");o(this)[H?"show":"hide"]()}):this.animate(t("toggle",3),G,F)},fadeTo:function(E,G,F){return this.animate({opacity:G},E,F)},animate:function(I,F,H,G){var E=o.speed(F,H,G);return this[E.queue===false?"each":"queue"](function(){var K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;for(M in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return K.complete.call(this)}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");K.overflow=this.style.overflow}}if(K.overflow!=null){this.style.overflow="hidden"}K.curAnim=o.extend({},I);o.each(I,function(O,S){var R=new o.fx(J,K,O);if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I)}else{var Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cur(true)||0;if(Q){var N=parseFloat(Q[2]),P=Q[3]||"px";if(P!="px"){J.style[O]=(N||1)+P;T=((N||1)/R.cur(true))*T;J.style[O]=T+P}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T}R.custom(T,N,P)}else{R.custom(T,S,"")}}});return true})},stop:function(F,E){var G=o.timers;if(F){this.queue([])}this.each(function(){for(var H=G.length-1;H>=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)==1){n=setInterval(function(){var K=o.timers;for(var J=0;J<K.length;J++){if(!K[J]()){K.splice(J--,1)}}if(!K.length){clearInterval(n)}},13)}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());o(this.elem).show()},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(H){var G=e();if(H||G>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(H,F){var E=H?"Left":"Top",G=H?"Right":"Bottom";o.fn["inner"+F]=function(){return this[F.toLowerCase()]()+j(this,"padding"+E)+j(this,"padding"+G)};o.fn["outer"+F]=function(J){return this["inner"+F]()+j(this,"border"+E+"Width")+j(this,"border"+G+"Width")+(J?j(this,"margin"+E)+j(this,"margin"+G):0)};var I=F.toLowerCase();o.fn[I]=function(J){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+F]||document.body["client"+F]:this[0]==document?Math.max(document.documentElement["client"+F],document.body["scroll"+F],document.documentElement["scroll"+F],document.body["offset"+F],document.documentElement["offset"+F]):J===g?(this.length?o.css(this[0],I):null):this.css(I,typeof J==="string"?J:J+"px")}})})(); -------------------------------------------------------------------------------- /static/bifocal/js/bifocal.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("bifocal: " + s); 6 | } : function() {}; 7 | 8 | 9 | var bifocal = { 10 | version: '1.7.1', 11 | emailSrc: '', 12 | iframeLoads: 0, 13 | convertLinksToFootnotes: false, 14 | reversePageScroll: false, /* If they hold shift and hit space, scroll up */ 15 | frameHack: false, 16 | /** 17 | * The frame hack is to workaround a firefox bug where if you pull content out of a frame and stick it into the parent element, the scrollbar won't appear. 18 | * So we fake a scrollbar in the wrapping div. 19 | */ 20 | biggestFrame: false, 21 | bodyCache: null, /* Cache the body HTML in case we need to re-use it later */ 22 | flags: 0x1 | 0x2 | 0x4, /* Start with all flags set. */ 23 | 24 | /* constants */ 25 | FLAG_STRIP_UNLIKELYS: 0x1, 26 | FLAG_WEIGHT_CLASSES: 0x2, 27 | FLAG_CLEAN_CONDITIONALLY: 0x4, 28 | 29 | maxPages: 30, /* The maximum number of pages to loop through before we call it quits and just show a link. */ 30 | parsedPages: {}, /* The list of pages we've parsed in this call of bifocal, for autopaging. As a key store for easier searching. */ 31 | 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. */ 32 | 33 | /** 34 | * All of the regular expressions in use within bifocal. Defined up here so we don't instantiate them repeatedly in loops. 35 | */ 36 | regexps: { 37 | unlikelyCandidates: /combx|comment|community|disqus|extra|foot|header|menu|remark|rss|shoutbox|sidebar|sponsor|ad-break|agegate|pagination|pager|popup|tweet|twitter/i, 38 | okMaybeItsACandidate: /and|article|body|column|main|shadow/i, 39 | positive: /article|body|content|entry|hentry|main|page|pagination|post|text|blog|story/i, 40 | negative: /combx|comment|com-|contact|foot|footer|footnote|masthead|media|meta|outbrain|promo|related|scroll|shoutbox|sidebar|sponsor|shopping|tags|tool|widget/i, 41 | extraneous: /print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single/i, 42 | divToPElements: /<(a|blockquote|dl|div|img|ol|p|pre|table|ul)/i, 43 | replaceBrs: /(<br[^>]*>[ \n\r\t]*){2,}/gi, 44 | replaceFonts: /<(\/?)font[^>]*>/gi, 45 | trim: /^\s+|\s+$/g, 46 | normalize: /\s{2,}/g, 47 | killBreaks: /(<br\s*\/?>(\s| ?)*){1,}/g, 48 | videos: /http:\/\/(www\.)?(youtube|vimeo)\.com/i, 49 | skipFootnoteLink: /^\s*(\[?[a-z0-9]{1,2}\]?|^|edit|citation needed)\s*$/i, 50 | nextLink: /(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i, // Match: next, continue, >, >>, » but not >|, »| as those usually mean last. 51 | prevLink: /(prev|earl|old|new|<|«)/i 52 | }, 53 | 54 | /** 55 | * Runs bifocal. 56 | * 57 | * Workflow: 1. Prep the document by removing script tags, css, etc. 2. Build bifocal's DOM tree. 3. Grab the article content from the current dom tree. 4. 58 | * Replace the current DOM tree with the new one. 5. Read peacefully. 59 | * 60 | * @return void 61 | */ 62 | init: function() { 63 | /* Before we do anything, remove all scripts that are not bifocal. */ 64 | window.onload = window.onunload = function() {}; 65 | 66 | bifocal.removeScripts(document); 67 | 68 | if(document.body && !bifocal.bodyCache) { 69 | bifocal.bodyCache = document.body.innerHTML; 70 | 71 | } 72 | /* Make sure this document is added to the list of parsed pages first, so we don't double up on the first page */ 73 | bifocal.parsedPages[window.location.href.replace(/\/$/, '')] = true; 74 | 75 | /* Pull out any possible next page link first */ 76 | var nextPageLink = bifocal.findNextPageLink(document.body); 77 | 78 | bifocal.prepDocument(); 79 | 80 | /* Build bifocal's DOM tree */ 81 | var overlay = document.createElement("DIV"); 82 | var innerDiv = document.createElement("DIV"); 83 | var articleTools = bifocal.getArticleTools(); 84 | var articleTitle = bifocal.getArticleTitle(); 85 | var articleContent = bifocal.grabArticle(); 86 | var articleFooter = bifocal.getArticleFooter(); 87 | 88 | if(!articleContent) { 89 | articleContent = document.createElement("DIV"); 90 | articleContent.id = "bifocal-content"; 91 | articleContent.innerHTML = [ 92 | "<p>Sorry, bifocal was unable to parse this page for content. If you feel like it should have been able to, please <a href='http://code.google.com/p/bifocal/issues/entry'>let us know by submitting an issue.</a></p>", 93 | (bifocal.frameHack ? "<p><strong>It appears this page uses frames.</strong> Unfortunately, browser security properties often cause bifocal to fail on pages that include frames. You may want to try running bifocal itself on this source page: <a href='" 94 | + bifocal.biggestFrame.src + "'>" + bifocal.biggestFrame.src + "</a></p>" 95 | : ""), 96 | "<p>Also, please note that bifocal does not play very nicely with front pages. bifocal is intended to work on articles with a sizable chunk of text that you'd like to read comfortably. If you're using bifocal on a landing page (like nytimes.com for example), please click into an article first before using bifocal.</p>"] 97 | .join(''); 98 | 99 | nextPageLink = null; 100 | } 101 | 102 | overlay.id = "readOverlay"; 103 | innerDiv.id = "readInner"; 104 | 105 | /* Apply user-selected styling */ 106 | document.body.className = readStyle; 107 | document.dir = bifocal.getSuggestedDirection(articleTitle.innerHTML); 108 | 109 | if(readStyle === "style-athelas" || readStyle === "style-apertura") { 110 | overlay.className = readStyle + " rdbTypekit"; 111 | } else { 112 | overlay.className = readStyle; 113 | } 114 | innerDiv.className = readMargin + " " + readSize; 115 | 116 | if(typeof (readConvertLinksToFootnotes) !== 'undefined' && readConvertLinksToFootnotes === true) { 117 | bifocal.convertLinksToFootnotes = true; 118 | } 119 | 120 | /* Glue the structure of our document together. */ 121 | innerDiv.appendChild(articleTitle); 122 | innerDiv.appendChild(articleContent); 123 | innerDiv.appendChild(articleFooter); 124 | overlay.appendChild(articleTools); 125 | overlay.appendChild(innerDiv); 126 | 127 | /* Clear the old HTML, insert the new content. */ 128 | //document.body.innerHTML = ""; 129 | document.body.insertBefore(overlay, document.body.firstChild); 130 | document.body.removeAttribute('style'); 131 | 132 | if(bifocal.frameHack) { 133 | var readOverlay = document.getElementById('readOverlay'); 134 | readOverlay.style.height = '100%'; 135 | readOverlay.style.overflow = 'auto'; 136 | } 137 | 138 | /** 139 | * If someone tries to use bifocal on a site's root page, give them a warning about usage. 140 | */ 141 | if((window.location.protocol + "//" + window.location.host + "/") === window.location.href) { 142 | articleContent.style.display = "none"; 143 | var rootWarning = document.createElement('p'); 144 | rootWarning.id = "bifocal-warning"; 145 | rootWarning.innerHTML = "<em>bifocal</em> was intended for use on individual articles and not home pages. " 146 | + "If you'd like to try rendering this page anyway, <a onClick='javascript:document.getElementById(\"bifocal-warning\").style.display=\"none\";document.getElementById(\"bifocal-content\").style.display=\"block\";'>click here</a> to continue."; 147 | 148 | innerDiv.insertBefore(rootWarning, articleContent); 149 | } 150 | 151 | bifocal.postProcessContent(articleContent); 152 | 153 | __PHANTOM_RESPONSE(); 154 | 155 | window.scrollTo(0, 0); 156 | 157 | /* If we're using the Typekit library, select the font */ 158 | if(readStyle === "style-athelas" || readStyle === "style-apertura") { 159 | bifocal.useRdbTypekit(); 160 | } 161 | 162 | if(nextPageLink) { 163 | /** 164 | * Append any additional pages after a small timeout so that people can start reading without having to wait for this to finish processing. 165 | */ 166 | window.setTimeout(function() { 167 | bifocal.appendNextPage(nextPageLink); 168 | }, 500); 169 | } 170 | 171 | /** Smooth scrolling * */ 172 | document.onkeydown = function(e) { 173 | var code = (window.event) ? event.keyCode : e.keyCode; 174 | if(code === 16) { 175 | bifocal.reversePageScroll = true; 176 | return; 177 | } 178 | 179 | if(code === 32) { 180 | bifocal.curScrollStep = 0; 181 | var windowHeight = window.innerHeight ? window.innerHeight : (document.documentElement.clientHeight ? document.documentElement.clientHeight 182 | : document.body.clientHeight); 183 | 184 | if(bifocal.reversePageScroll) { 185 | bifocal.scrollTo(bifocal.scrollTop(), bifocal.scrollTop() - (windowHeight - 50), 20, 10); 186 | } else { 187 | bifocal.scrollTo(bifocal.scrollTop(), bifocal.scrollTop() + (windowHeight - 50), 20, 10); 188 | } 189 | 190 | return false; 191 | } 192 | }; 193 | 194 | document.onkeyup = function(e) { 195 | var code = (window.event) ? event.keyCode : e.keyCode; 196 | if(code === 16) { 197 | bifocal.reversePageScroll = false; 198 | return; 199 | } 200 | }; 201 | }, 202 | 203 | /** 204 | * Run any post-process modifications to article content as necessary. 205 | * 206 | * @param Element 207 | * @return void 208 | */ 209 | postProcessContent: function(articleContent) { 210 | if(bifocal.convertLinksToFootnotes && !window.location.href.match(/wikipedia\.org/g)) { 211 | bifocal.addFootnotes(articleContent); 212 | } 213 | 214 | bifocal.fixImageFloats(articleContent); 215 | }, 216 | 217 | /** 218 | * Some content ends up looking ugly if the image is too large to be floated. If the image is wider than a threshold (currently 55%), no longer float it, 219 | * center it instead. 220 | * 221 | * @param Element 222 | * @return void 223 | */ 224 | fixImageFloats: function(articleContent) { 225 | var imageWidthThreshold = Math.min(articleContent.offsetWidth, 800) * 0.55, images = articleContent.getElementsByTagName('img'); 226 | 227 | for( var i = 0, il = images.length; i < il; i += 1) { 228 | var image = images[i]; 229 | 230 | if(image.offsetWidth > imageWidthThreshold) { 231 | image.className += " blockImage"; 232 | } 233 | } 234 | }, 235 | 236 | /** 237 | * Get the article tools Element that has buttons like reload, print, email. 238 | * 239 | * @return void 240 | */ 241 | getArticleTools: function() { 242 | var articleTools = document.createElement("DIV"); 243 | 244 | articleTools.id = "readTools"; 245 | articleTools.innerHTML = "<a href='#' onclick='return window.location.reload()' title='Reload original page' id='reload-page'>Reload Original Page</a>" 246 | + "<a href='#' onclick='javascript:window.print();' title='Print page' id='print-page'>Print Page</a>" 247 | + "<a href='#' onclick='bifocal.emailBox(); return false;' title='Email page' id='email-page'>Email Page</a>"; 248 | 249 | return articleTools; 250 | }, 251 | 252 | /** 253 | * retuns the suggested direction of the string 254 | * 255 | * @return "rtl" || "ltr" 256 | */ 257 | getSuggestedDirection: function(text) { 258 | function sanitizeText() { 259 | return text.replace(/@\w+/, ""); 260 | } 261 | 262 | function countMatches(match) { 263 | var matches = text.match(new RegExp(match, "g")); 264 | return matches !== null ? matches.length : 0; 265 | } 266 | 267 | function isRTL() { 268 | var count_heb = countMatches("[\\u05B0-\\u05F4\\uFB1D-\\uFBF4]"); 269 | var count_arb = countMatches("[\\u060C-\\u06FE\\uFB50-\\uFEFC]"); 270 | 271 | // if 20% of chars are Hebrew or Arbic then direction is rtl 272 | return (count_heb + count_arb) * 100 / text.length > 20; 273 | } 274 | 275 | text = sanitizeText(text); 276 | return isRTL() ? "rtl" : "ltr"; 277 | }, 278 | 279 | /** 280 | * Get the article title as an H1. 281 | * 282 | * @return void 283 | */ 284 | getArticleTitle: function() { 285 | var curTitle = "", origTitle = ""; 286 | 287 | try { 288 | curTitle = origTitle = document.title; 289 | 290 | if(typeof curTitle !== "string") { /* If they had an element with id "title" in their HTML */ 291 | curTitle = origTitle = bifocal.getInnerText(document.getElementsByTagName('title')[0]); 292 | } 293 | } catch (e) { 294 | } 295 | 296 | if(curTitle.match(/ [\|\-] /)) { 297 | curTitle = origTitle.replace(/(.*)[\|\-] .*/gi, '$1'); 298 | 299 | if(curTitle.split(' ').length < 3) { 300 | curTitle = origTitle.replace(/[^\|\-]*[\|\-](.*)/gi, '$1'); 301 | } 302 | } else if(curTitle.indexOf(': ') !== -1) { 303 | curTitle = origTitle.replace(/.*:(.*)/gi, '$1'); 304 | 305 | if(curTitle.split(' ').length < 3) { 306 | curTitle = origTitle.replace(/[^:]*[:](.*)/gi, '$1'); 307 | } 308 | } else if(curTitle.length > 150 || curTitle.length < 15) { 309 | var hOnes = document.getElementsByTagName('h1'); 310 | if(hOnes.length === 1) { 311 | curTitle = bifocal.getInnerText(hOnes[0]); 312 | } 313 | } 314 | 315 | curTitle = curTitle.replace(bifocal.regexps.trim, ""); 316 | 317 | if(curTitle.split(' ').length <= 4) { 318 | curTitle = origTitle; 319 | } 320 | 321 | var articleTitle = document.createElement("H1"); 322 | articleTitle.innerHTML = curTitle; 323 | 324 | return articleTitle; 325 | }, 326 | 327 | /** 328 | * Get the footer with the bifocal mark etc. 329 | * 330 | * @return void 331 | */ 332 | getArticleFooter: function() { 333 | var articleFooter = document.createElement("DIV"); 334 | 335 | /** 336 | * For research purposes, generate an img src that contains the chosen readstyle etc, so we can generate aggregate stats and change styles based on them 337 | * in the future 338 | */ 339 | // var statsQueryParams = "?readStyle=" + encodeURIComponent(readStyle) + "&readMargin=" + encodeURIComponent(readMargin) + "&readSize=" + 340 | // encodeURIComponent(readSize); 341 | /* TODO: attach this to an image */ 342 | 343 | articleFooter.id = "readFooter"; 344 | articleFooter.innerHTML = ["<div id='rdb-footer-print'>Excerpted from <cite>" + document.title + "</cite><br />" + window.location.href + "</div>", 345 | "<div id='rdb-footer-wrapper'>", 346 | "<div id='rdb-footer-right'>", 347 | "<span class='version'>bifocal version " + bifocal.version + "</span>", "</div>", "</div>"].join(''); 348 | 349 | return articleFooter; 350 | }, 351 | 352 | /** 353 | * Prepare the HTML document for bifocal to scrape it. This includes things like stripping javascript, CSS, and handling terrible markup. 354 | * 355 | * @return void 356 | */ 357 | prepDocument: function() { 358 | /** 359 | * In some cases a body element can't be found (if the HTML is totally hosed for example) so we create a new body node and append it to the document. 360 | */ 361 | if(document.body === null) { 362 | var body = document.createElement("body"); 363 | try { 364 | document.body = body; 365 | } catch (e) { 366 | document.documentElement.appendChild(body); 367 | dbg(e); 368 | } 369 | } 370 | 371 | document.body.id = "bifocalBody"; 372 | 373 | var frames = document.getElementsByTagName('frame'); 374 | if(frames.length > 0) { 375 | var bestFrame = null; 376 | var bestFrameSize = 0; /* The frame to try to run bifocal upon. Must be on same domain. */ 377 | var biggestFrameSize = 0; /* Used for the error message. Can be on any domain. */ 378 | for( var frameIndex = 0; frameIndex < frames.length; frameIndex += 1) { 379 | var frameSize = frames[frameIndex].offsetWidth + frames[frameIndex].offsetHeight; 380 | var canAccessFrame = false; 381 | try { 382 | var frameBody = frames[frameIndex].contentWindow.document.body; 383 | canAccessFrame = true; 384 | } catch (eFrames) { 385 | dbg(eFrames); 386 | } 387 | 388 | if(frameSize > biggestFrameSize) { 389 | biggestFrameSize = frameSize; 390 | bifocal.biggestFrame = frames[frameIndex]; 391 | } 392 | 393 | if(canAccessFrame && frameSize > bestFrameSize) { 394 | bifocal.frameHack = true; 395 | 396 | bestFrame = frames[frameIndex]; 397 | bestFrameSize = frameSize; 398 | } 399 | } 400 | 401 | if(bestFrame) { 402 | var newBody = document.createElement('body'); 403 | newBody.innerHTML = bestFrame.contentWindow.document.body.innerHTML; 404 | newBody.style.overflow = 'scroll'; 405 | document.body = newBody; 406 | 407 | var frameset = document.getElementsByTagName('frameset')[0]; 408 | if(frameset) { 409 | frameset.parentNode.removeChild(frameset); 410 | } 411 | } 412 | } 413 | 414 | /* Remove all stylesheets */ 415 | for( var k = 0; k < document.styleSheets.length; k += 1) { 416 | if(document.styleSheets[k].href !== null && document.styleSheets[k].href.lastIndexOf("bifocal") === -1) { 417 | document.styleSheets[k].disabled = true; 418 | } 419 | } 420 | 421 | /* Remove all style tags in head (not doing this on IE) - TODO: Why not? */ 422 | var styleTags = document.getElementsByTagName("style"); 423 | for( var st = 0; st < styleTags.length; st += 1) { 424 | styleTags[st].textContent = ""; 425 | } 426 | 427 | /* Turn all double br's into p's */ 428 | /* Note, this is pretty costly as far as processing goes. Maybe optimize later. */ 429 | document.body.innerHTML = document.body.innerHTML.replace(bifocal.regexps.replaceBrs, '</p><p>').replace(bifocal.regexps.replaceFonts, '<$1span>'); 430 | }, 431 | 432 | /** 433 | * For easier reading, convert this document to have footnotes at the bottom rather than inline links. 434 | * 435 | * @see http://www.roughtype.com/archives/2010/05/experiments_in.php 436 | * 437 | * @return void 438 | */ 439 | addFootnotes: function(articleContent) { 440 | var footnotesWrapper = document.getElementById('bifocal-footnotes'), articleFootnotes = document.getElementById('bifocal-footnotes-list'); 441 | 442 | if(!footnotesWrapper) { 443 | footnotesWrapper = document.createElement("DIV"); 444 | footnotesWrapper.id = 'bifocal-footnotes'; 445 | footnotesWrapper.innerHTML = '<h3>References</h3>'; 446 | footnotesWrapper.style.display = 'none'; /* Until we know we have footnotes, don't show the references block. */ 447 | 448 | articleFootnotes = document.createElement('ol'); 449 | articleFootnotes.id = 'bifocal-footnotes-list'; 450 | 451 | footnotesWrapper.appendChild(articleFootnotes); 452 | 453 | var readFooter = document.getElementById('readFooter'); 454 | 455 | if(readFooter) { 456 | readFooter.parentNode.insertBefore(footnotesWrapper, readFooter); 457 | } 458 | } 459 | 460 | var articleLinks = articleContent.getElementsByTagName('a'); 461 | var linkCount = articleFootnotes.getElementsByTagName('li').length; 462 | for( var i = 0; i < articleLinks.length; i += 1) { 463 | var articleLink = articleLinks[i], footnoteLink = articleLink.cloneNode(true), refLink = document.createElement('a'), footnote = document 464 | .createElement('li'), linkDomain = footnoteLink.host ? footnoteLink.host : document.location.host, linkText = bifocal 465 | .getInnerText(articleLink); 466 | 467 | if(articleLink.className && articleLink.className.indexOf('bifocal-DoNotFootnote') !== -1 || linkText.match(bifocal.regexps.skipFootnoteLink)) { 468 | continue; 469 | } 470 | 471 | linkCount += 1; 472 | 473 | /** Add a superscript reference after the article link */ 474 | refLink.href = '#bifocalFootnoteLink-' + linkCount; 475 | refLink.innerHTML = '<small><sup>[' + linkCount + ']</sup></small>'; 476 | refLink.className = 'bifocal-DoNotFootnote'; 477 | try { 478 | refLink.style.color = 'inherit'; 479 | } catch (e) { 480 | } /* IE7 doesn't like inherit. */ 481 | 482 | if(articleLink.parentNode.lastChild === articleLink) { 483 | articleLink.parentNode.appendChild(refLink); 484 | } else { 485 | articleLink.parentNode.insertBefore(refLink, articleLink.nextSibling); 486 | } 487 | 488 | articleLink.name = 'bifocalLink-' + linkCount; 489 | try { 490 | articleLink.style.color = 'inherit'; 491 | } catch (err) { 492 | } /* IE7 doesn't like inherit. */ 493 | 494 | footnote.innerHTML = "<small><sup><a href='#bifocalLink-" + linkCount + "' title='Jump to Link in Article'>^</a></sup></small> "; 495 | 496 | footnoteLink.innerHTML = (footnoteLink.title ? footnoteLink.title : linkText); 497 | footnoteLink.name = 'bifocalFootnoteLink-' + linkCount; 498 | 499 | footnote.appendChild(footnoteLink); 500 | footnote.innerHTML = footnote.innerHTML + "<small> (" + linkDomain + ")</small>"; 501 | 502 | articleFootnotes.appendChild(footnote); 503 | } 504 | 505 | if(linkCount > 0) { 506 | footnotesWrapper.style.display = 'block'; 507 | } 508 | }, 509 | 510 | useRdbTypekit: function() { 511 | var rdbHead = document.getElementsByTagName('head')[0]; 512 | var rdbTKScript = document.createElement('script'); 513 | var rdbTKCode = null; 514 | 515 | var rdbTKLink = document.createElement('a'); 516 | rdbTKLink.setAttribute('class', 'rdbTK-powered'); 517 | rdbTKLink.setAttribute('title', 'Fonts by Typekit'); 518 | rdbTKLink.innerHTML = "Fonts by <span class='rdbTK'>Typekit</span>"; 519 | 520 | if(readStyle === "style-athelas") { 521 | rdbTKCode = "sxt6vzy"; 522 | dbg("Using Athelas Theme"); 523 | 524 | rdbTKLink.setAttribute('href', 'http://typekit.com/?utm_source=bifocal&utm_medium=affiliate&utm_campaign=athelas'); 525 | rdbTKLink.setAttribute('id', 'rdb-athelas'); 526 | document.getElementById("rdb-footer-right").appendChild(rdbTKLink); 527 | } 528 | if(readStyle === "style-apertura") { 529 | rdbTKCode = "bae8ybu"; 530 | dbg("Using Inverse Theme"); 531 | 532 | rdbTKLink.setAttribute('href', 'http://typekit.com/?utm_source=bifocal&utm_medium=affiliate&utm_campaign=inverse'); 533 | rdbTKLink.setAttribute('id', 'rdb-inverse'); 534 | document.getElementById("rdb-footer-right").appendChild(rdbTKLink); 535 | } 536 | 537 | /** 538 | * Setting new script tag attributes to pull Typekits libraries 539 | */ 540 | rdbTKScript.setAttribute('type', 'text/javascript'); 541 | rdbTKScript.setAttribute('src', "http://use.typekit.com/" + rdbTKCode + ".js"); 542 | rdbTKScript.setAttribute('charset', 'UTF-8'); 543 | rdbHead.appendChild(rdbTKScript); 544 | 545 | /** 546 | * In the future, maybe try using the following experimental Callback function?: http://gist.github.com/192350 & 547 | * http://getsatisfaction.com/typekit/topics/support_a_pre_and_post_load_callback_function 548 | */ 549 | var typekitLoader = function() { 550 | dbg("Looking for Typekit."); 551 | if(typeof Typekit !== "undefined") { 552 | try { 553 | dbg("Caught typekit"); 554 | Typekit.load(); 555 | clearInterval(window.typekitInterval); 556 | } catch (e) { 557 | dbg("Typekit error: " + e); 558 | } 559 | } 560 | }; 561 | 562 | window.typekitInterval = window.setInterval(typekitLoader, 100); 563 | }, 564 | 565 | /** 566 | * Prepare the article node for display. Clean out any inline styles, iframes, forms, strip extraneous 567 | * <p> 568 | * tags, etc. 569 | * 570 | * @param Element 571 | * @return void 572 | */ 573 | prepArticle: function(articleContent) { 574 | bifocal.cleanStyles(articleContent); 575 | bifocal.killBreaks(articleContent); 576 | 577 | /* Clean out junk from the article content */ 578 | bifocal.cleanConditionally(articleContent, "form"); 579 | bifocal.clean(articleContent, "object"); 580 | bifocal.clean(articleContent, "h1"); 581 | 582 | /******************************************************************************************************************************************************* 583 | * If there is only one h2, they are probably using it as a header and not a subheader, so remove it since we already have a header. 584 | ******************************************************************************************************************************************************/ 585 | if(articleContent.getElementsByTagName('h2').length === 1) { 586 | bifocal.clean(articleContent, "h2"); 587 | } 588 | bifocal.clean(articleContent, "iframe"); 589 | 590 | bifocal.cleanHeaders(articleContent); 591 | 592 | /* Do these last as the previous stuff may have removed junk that will affect these */ 593 | bifocal.cleanConditionally(articleContent, "table"); 594 | bifocal.cleanConditionally(articleContent, "ul"); 595 | bifocal.cleanConditionally(articleContent, "div"); 596 | 597 | /* Remove extra paragraphs */ 598 | var articleParagraphs = articleContent.getElementsByTagName('p'); 599 | for( var i = articleParagraphs.length - 1; i >= 0; i -= 1) { 600 | var imgCount = articleParagraphs[i].getElementsByTagName('img').length; 601 | var embedCount = articleParagraphs[i].getElementsByTagName('embed').length; 602 | var objectCount = articleParagraphs[i].getElementsByTagName('object').length; 603 | 604 | if(imgCount === 0 && embedCount === 0 && objectCount === 0 && bifocal.getInnerText(articleParagraphs[i], false) === '') { 605 | articleParagraphs[i].parentNode.removeChild(articleParagraphs[i]); 606 | } 607 | } 608 | 609 | try { 610 | articleContent.innerHTML = articleContent.innerHTML.replace(/<br[^>]*>\s*<p/gi, '<p'); 611 | } catch (e) { 612 | dbg("Cleaning innerHTML of breaks failed. This is an IE strict-block-elements bug. Ignoring.: " + e); 613 | } 614 | }, 615 | 616 | /** 617 | * Initialize a node with the bifocal object. Also checks the className/id for special names to add to its score. 618 | * 619 | * @param Element 620 | * @return void 621 | */ 622 | initializeNode: function(node) { 623 | node.bifocal = { 624 | "contentScore": 0 625 | }; 626 | 627 | switch(node.tagName) { 628 | case 'DIV': 629 | node.bifocal.contentScore += 5; 630 | break; 631 | 632 | case 'PRE': 633 | case 'TD': 634 | case 'BLOCKQUOTE': 635 | node.bifocal.contentScore += 3; 636 | break; 637 | 638 | case 'ADDRESS': 639 | case 'OL': 640 | case 'UL': 641 | case 'DL': 642 | case 'DD': 643 | case 'DT': 644 | case 'LI': 645 | case 'FORM': 646 | node.bifocal.contentScore -= 3; 647 | break; 648 | 649 | case 'H1': 650 | case 'H2': 651 | case 'H3': 652 | case 'H4': 653 | case 'H5': 654 | case 'H6': 655 | case 'TH': 656 | node.bifocal.contentScore -= 5; 657 | break; 658 | } 659 | 660 | node.bifocal.contentScore += bifocal.getClassWeight(node); 661 | }, 662 | 663 | /*********************************************************************************************************************************************************** 664 | * grabArticle - Using a variety of metrics (content score, classname, element types), find the content that is most likely to be the stuff a user wants to 665 | * read. Then return it wrapped up in a div. 666 | * 667 | * @param page 668 | * a document to run upon. Needs to be a full document, complete with body. 669 | * @return Element 670 | */ 671 | grabArticle: function(page) { 672 | var stripUnlikelyCandidates = bifocal.flagIsActive(bifocal.FLAG_STRIP_UNLIKELYS), isPaging = (page !== null) ? true : false; 673 | 674 | page = page ? page : document.body; 675 | 676 | var pageCacheHtml = page.innerHTML; 677 | 678 | var allElements = page.getElementsByTagName('*'); 679 | 680 | /** 681 | * First, node prepping. Trash nodes that look cruddy (like ones with the class name "comment", etc), and turn divs into P tags where they have been 682 | * used inappropriately (as in, where they contain no other block level elements.) 683 | * 684 | * Note: Assignment from index for performance. See http://www.peachpit.com/articles/article.aspx?p=31567&seqNum=5 TODO: Shouldn't this be a reverse 685 | * traversal? 686 | */ 687 | var node = null; 688 | var nodesToScore = []; 689 | for( var nodeIndex = 0; (node = allElements[nodeIndex]); nodeIndex += 1) { 690 | /* Remove unlikely candidates */ 691 | if(stripUnlikelyCandidates) { 692 | var unlikelyMatchString = node.className + node.id; 693 | if((unlikelyMatchString.search(bifocal.regexps.unlikelyCandidates) !== -1 694 | && unlikelyMatchString.search(bifocal.regexps.okMaybeItsACandidate) === -1 && node.tagName !== "BODY")) { 695 | dbg("Removing unlikely candidate - " + unlikelyMatchString); 696 | node.parentNode.removeChild(node); 697 | nodeIndex -= 1; 698 | continue; 699 | } 700 | } 701 | 702 | if(node.tagName === "P" || node.tagName === "TD" || node.tagName === "PRE") { 703 | nodesToScore[nodesToScore.length] = node; 704 | } 705 | 706 | /* Turn all divs that don't have children block level elements into p's */ 707 | if(node.tagName === "DIV") { 708 | if(node.innerHTML.search(bifocal.regexps.divToPElements) === -1) { 709 | var newNode = document.createElement('p'); 710 | try { 711 | newNode.innerHTML = node.innerHTML; 712 | node.parentNode.replaceChild(newNode, node); 713 | nodeIndex -= 1; 714 | 715 | nodesToScore[nodesToScore.length] = node; 716 | } catch (e) { 717 | dbg("Could not alter div to p, probably an IE restriction, reverting back to div.: " + e); 718 | } 719 | } else { 720 | /* EXPERIMENTAL */ 721 | for( var i = 0, il = node.childNodes.length; i < il; i += 1) { 722 | var childNode = node.childNodes[i]; 723 | if(childNode.nodeType === 3) { // Node.TEXT_NODE 724 | var p = document.createElement('p'); 725 | p.innerHTML = childNode.nodeValue; 726 | p.style.display = 'inline'; 727 | p.className = 'bifocal-styled'; 728 | childNode.parentNode.replaceChild(p, childNode); 729 | } 730 | } 731 | } 732 | } 733 | } 734 | 735 | /** 736 | * Loop through all paragraphs, and assign a score to them based on how content-y they look. Then add their score to their parent node. 737 | * 738 | * A score is determined by things like number of commas, class names, etc. Maybe eventually link density. 739 | */ 740 | var candidates = []; 741 | for( var pt = 0; pt < nodesToScore.length; pt += 1) { 742 | var parentNode = nodesToScore[pt].parentNode; 743 | var grandParentNode = parentNode ? parentNode.parentNode : null; 744 | var innerText = bifocal.getInnerText(nodesToScore[pt]); 745 | 746 | if(!parentNode || typeof (parentNode.tagName) === 'undefined') { 747 | continue; 748 | } 749 | 750 | /* If this paragraph is less than 25 characters, don't even count it. */ 751 | if(innerText.length < 25) { 752 | continue; 753 | } 754 | 755 | /* Initialize bifocal data for the parent. */ 756 | if(typeof parentNode.bifocal === 'undefined') { 757 | bifocal.initializeNode(parentNode); 758 | candidates.push(parentNode); 759 | } 760 | 761 | /* Initialize bifocal data for the grandparent. */ 762 | if(grandParentNode && typeof (grandParentNode.bifocal) === 'undefined' && typeof (grandParentNode.tagName) !== 'undefined') { 763 | bifocal.initializeNode(grandParentNode); 764 | candidates.push(grandParentNode); 765 | } 766 | 767 | var contentScore = 0; 768 | 769 | /* Add a point for the paragraph itself as a base. */ 770 | contentScore += 1; 771 | 772 | /* Add points for any commas within this paragraph */ 773 | contentScore += innerText.split(',').length; 774 | 775 | /* For every 100 characters in this paragraph, add another point. Up to 3 points. */ 776 | contentScore += Math.min(Math.floor(innerText.length / 100), 3); 777 | 778 | /* Add the score to the parent. The grandparent gets half. */ 779 | parentNode.bifocal.contentScore += contentScore; 780 | 781 | if(grandParentNode) { 782 | grandParentNode.bifocal.contentScore += contentScore / 2; 783 | } 784 | } 785 | 786 | /** 787 | * After we've calculated scores, loop through all of the possible candidate nodes we found and find the one with the highest score. 788 | */ 789 | var topCandidate = null; 790 | for( var c = 0, cl = candidates.length; c < cl; c += 1) { 791 | /** 792 | * Scale the final candidates score based on link density. Good content should have a relatively small link density (5% or less) and be mostly 793 | * unaffected by this operation. 794 | */ 795 | candidates[c].bifocal.contentScore = candidates[c].bifocal.contentScore * (1 - bifocal.getLinkDensity(candidates[c])); 796 | 797 | dbg('Candidate: ' + candidates[c] + " (" + candidates[c].className + ":" + candidates[c].id + ") with score " + candidates[c].bifocal.contentScore); 798 | 799 | if(!topCandidate || candidates[c].bifocal.contentScore > topCandidate.bifocal.contentScore) { 800 | topCandidate = candidates[c]; 801 | } 802 | } 803 | 804 | /** 805 | * If we still have no top candidate, just use the body as a last resort. We also have to copy the body node so it is something we can modify. 806 | */ 807 | if(topCandidate === null || topCandidate.tagName === "BODY") { 808 | topCandidate = document.createElement("DIV"); 809 | topCandidate.innerHTML = page.innerHTML; 810 | page.innerHTML = ""; 811 | page.appendChild(topCandidate); 812 | bifocal.initializeNode(topCandidate); 813 | } 814 | 815 | /** 816 | * Now that we have the top candidate, look through its siblings for content that might also be related. Things like preambles, content split by ads 817 | * that we removed, etc. 818 | */ 819 | var articleContent = document.createElement("DIV"); 820 | if(isPaging) { 821 | articleContent.id = "bifocal-content"; 822 | } 823 | var siblingScoreThreshold = Math.max(10, topCandidate.bifocal.contentScore * 0.2); 824 | var siblingNodes = topCandidate.parentNode.childNodes; 825 | 826 | for( var s = 0, sl = siblingNodes.length; s < sl; s += 1) { 827 | var siblingNode = siblingNodes[s]; 828 | var append = false; 829 | 830 | /** 831 | * Fix for odd IE7 Crash where siblingNode does not exist even though this should be a live nodeList. Example of error visible here: 832 | * http://www.esquire.com/features/honesty0707 833 | */ 834 | if(!siblingNode) { 835 | continue; 836 | } 837 | 838 | dbg("Looking at sibling node: " + siblingNode + " (" + siblingNode.className + ":" + siblingNode.id + ")" 839 | + ((typeof siblingNode.bifocal !== 'undefined') ? (" with score " + siblingNode.bifocal.contentScore) : '')); 840 | dbg("Sibling has score " + (siblingNode.bifocal ? siblingNode.bifocal.contentScore : 'Unknown')); 841 | 842 | if(siblingNode === topCandidate) { 843 | append = true; 844 | } 845 | 846 | var contentBonus = 0; 847 | /* Give a bonus if sibling nodes and top candidates have the example same classname */ 848 | if(siblingNode.className === topCandidate.className && topCandidate.className !== "") { 849 | contentBonus += topCandidate.bifocal.contentScore * 0.2; 850 | } 851 | 852 | if(typeof siblingNode.bifocal !== 'undefined' && (siblingNode.bifocal.contentScore + contentBonus) >= siblingScoreThreshold) { 853 | append = true; 854 | } 855 | 856 | if(siblingNode.nodeName === "P") { 857 | var linkDensity = bifocal.getLinkDensity(siblingNode); 858 | var nodeContent = bifocal.getInnerText(siblingNode); 859 | var nodeLength = nodeContent.length; 860 | 861 | if(nodeLength > 80 && linkDensity < 0.25) { 862 | append = true; 863 | } else if(nodeLength < 80 && linkDensity === 0 && nodeContent.search(/\.( |$)/) !== -1) { 864 | append = true; 865 | } 866 | } 867 | 868 | if(append) { 869 | dbg("Appending node: " + siblingNode); 870 | 871 | var nodeToAppend = null; 872 | if(siblingNode.nodeName !== "DIV" && siblingNode.nodeName !== "P") { 873 | /* 874 | * 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 875 | * accident. 876 | */ 877 | 878 | dbg("Altering siblingNode of " + siblingNode.nodeName + ' to div.'); 879 | nodeToAppend = document.createElement("DIV"); 880 | try { 881 | nodeToAppend.id = siblingNode.id; 882 | nodeToAppend.innerHTML = siblingNode.innerHTML; 883 | } catch (er) { 884 | dbg("Could not alter siblingNode to div, probably an IE restriction, reverting back to original."); 885 | nodeToAppend = siblingNode; 886 | s -= 1; 887 | sl -= 1; 888 | } 889 | } else { 890 | nodeToAppend = siblingNode; 891 | s -= 1; 892 | sl -= 1; 893 | } 894 | 895 | /* To ensure a node does not interfere with bifocal styles, remove its classnames */ 896 | nodeToAppend.className = ""; 897 | 898 | /* Append sibling and subtract from our list because it removes the node when you append to another node */ 899 | articleContent.appendChild(nodeToAppend); 900 | } 901 | } 902 | 903 | /** 904 | * So we have all of the content that we need. Now we clean it up for presentation. 905 | */ 906 | bifocal.prepArticle(articleContent); 907 | 908 | if(bifocal.curPageNum === 1) { 909 | articleContent.innerHTML = '<div id="bifocal-page-1" class="page">' + articleContent.innerHTML + '</div>'; 910 | } 911 | 912 | /** 913 | * Now that we've gone through the full algorithm, check to see if we got any meaningful content. If we didn't, we may need to re-run grabArticle with 914 | * different flags set. This gives us a higher likelihood of finding the content, and the sieve approach gives us a higher likelihood of finding the 915 | * -right- content. 916 | */ 917 | if(bifocal.getInnerText(articleContent, false).length < 250) { 918 | page.innerHTML = pageCacheHtml; 919 | 920 | if(bifocal.flagIsActive(bifocal.FLAG_STRIP_UNLIKELYS)) { 921 | bifocal.removeFlag(bifocal.FLAG_STRIP_UNLIKELYS); 922 | return bifocal.grabArticle(page); 923 | } else if(bifocal.flagIsActive(bifocal.FLAG_WEIGHT_CLASSES)) { 924 | bifocal.removeFlag(bifocal.FLAG_WEIGHT_CLASSES); 925 | return bifocal.grabArticle(page); 926 | } else if(bifocal.flagIsActive(bifocal.FLAG_CLEAN_CONDITIONALLY)) { 927 | bifocal.removeFlag(bifocal.FLAG_CLEAN_CONDITIONALLY); 928 | return bifocal.grabArticle(page); 929 | } else { 930 | return null; 931 | } 932 | } 933 | 934 | return articleContent; 935 | }, 936 | 937 | /** 938 | * Removes script tags from the document. 939 | * 940 | * @param Element 941 | */ 942 | removeScripts: function(doc) { 943 | var scripts = doc.getElementsByTagName('script'); 944 | for( var i = scripts.length - 1; i >= 0; i -= 1) { 945 | if(typeof (scripts[i].src) === "undefined" || (scripts[i].src.indexOf('bifocal') === -1 && scripts[i].src.indexOf('typekit') === -1)) { 946 | scripts[i].nodeValue = ""; 947 | scripts[i].removeAttribute('src'); 948 | if(scripts[i].parentNode) { 949 | scripts[i].parentNode.removeChild(scripts[i]); 950 | } 951 | } 952 | } 953 | }, 954 | 955 | /** 956 | * Get the inner text of a node - cross browser compatibly. This also strips out any excess whitespace to be found. 957 | * 958 | * @param Element 959 | * @return string 960 | */ 961 | getInnerText: function(e, normalizeSpaces) { 962 | var textContent = ""; 963 | 964 | if(typeof (e.textContent) === "undefined" && typeof (e.innerText) === "undefined") { 965 | return ""; 966 | } 967 | 968 | normalizeSpaces = (typeof normalizeSpaces === 'undefined') ? true : normalizeSpaces; 969 | 970 | if(navigator.appName === "Microsoft Internet Explorer") { 971 | textContent = e.innerText.replace(bifocal.regexps.trim, ""); 972 | } else { 973 | textContent = e.textContent.replace(bifocal.regexps.trim, ""); 974 | } 975 | 976 | if(normalizeSpaces) { 977 | return textContent.replace(bifocal.regexps.normalize, " "); 978 | } else { 979 | return textContent; 980 | } 981 | }, 982 | 983 | /** 984 | * Get the number of times a string s appears in the node e. 985 | * 986 | * @param Element 987 | * @param string - 988 | * what to split on. Default is "," 989 | * @return number (integer) 990 | */ 991 | getCharCount: function(e, s) { 992 | s = s || ","; 993 | return bifocal.getInnerText(e).split(s).length - 1; 994 | }, 995 | 996 | /** 997 | * Remove the style attribute on every e and under. TODO: Test if getElementsByTagName(*) is faster. 998 | * 999 | * @param Element 1000 | * @return void 1001 | */ 1002 | cleanStyles: function(e) { 1003 | e = e || document; 1004 | var cur = e.firstChild; 1005 | 1006 | if(!e) { 1007 | return; 1008 | } 1009 | 1010 | // Remove any root styles, if we're able. 1011 | if(typeof e.removeAttribute === 'function' && e.className !== 'bifocal-styled') { 1012 | e.removeAttribute('style'); 1013 | } 1014 | 1015 | // Go until there are no more child nodes 1016 | while(cur !== null) { 1017 | if(cur.nodeType === 1) { 1018 | // Remove style attribute(s) : 1019 | if(cur.className !== "bifocal-styled") { 1020 | cur.removeAttribute("style"); 1021 | } 1022 | bifocal.cleanStyles(cur); 1023 | } 1024 | cur = cur.nextSibling; 1025 | } 1026 | }, 1027 | 1028 | /** 1029 | * Get the density of links as a percentage of the content This is the amount of text that is inside a link divided by the total text in the node. 1030 | * 1031 | * @param Element 1032 | * @return number (float) 1033 | */ 1034 | getLinkDensity: function(e) { 1035 | var links = e.getElementsByTagName("a"); 1036 | var textLength = bifocal.getInnerText(e).length; 1037 | var linkLength = 0; 1038 | for( var i = 0, il = links.length; i < il; i += 1) { 1039 | linkLength += bifocal.getInnerText(links[i]).length; 1040 | } 1041 | 1042 | return linkLength / textLength; 1043 | }, 1044 | 1045 | /** 1046 | * Find a cleaned up version of the current URL, to use for comparing links for possible next-pageyness. 1047 | * 1048 | * @author Dan Lacy 1049 | * @return string the base url 1050 | */ 1051 | findBaseUrl: function() { 1052 | var noUrlParams = window.location.pathname.split("?")[0], urlSlashes = noUrlParams.split("/").reverse(), cleanedSegments = [], possibleType = ""; 1053 | 1054 | for( var i = 0, slashLen = urlSlashes.length; i < slashLen; i += 1) { 1055 | var segment = urlSlashes[i]; 1056 | 1057 | // Split off and save anything that looks like a file type. 1058 | if(segment.indexOf(".") !== -1) { 1059 | possibleType = segment.split(".")[1]; 1060 | 1061 | /* If the type isn't alpha-only, it's probably not actually a file extension. */ 1062 | if(!possibleType.match(/[^a-zA-Z]/)) { 1063 | segment = segment.split(".")[0]; 1064 | } 1065 | } 1066 | 1067 | /** 1068 | * EW-CMS specific segment replacement. Ugly. Example: http://www.ew.com/ew/article/0,,20313460_20369436,00.html 1069 | */ 1070 | if(segment.indexOf(',00') !== -1) { 1071 | segment = segment.replace(',00', ''); 1072 | } 1073 | 1074 | // If our first or second segment has anything looking like a page number, remove it. 1075 | if(segment.match(/((_|-)?p[a-z]*|(_|-))[0-9]{1,2}$/i) && ((i === 1) || (i === 0))) { 1076 | segment = segment.replace(/((_|-)?p[a-z]*|(_|-))[0-9]{1,2}$/i, ""); 1077 | } 1078 | 1079 | var del = false; 1080 | 1081 | /* If this is purely a number, and it's the first or second segment, it's probably a page number. Remove it. */ 1082 | if(i < 2 && segment.match(/^\d{1,2}$/)) { 1083 | del = true; 1084 | } 1085 | 1086 | /* If this is the first segment and it's just "index", remove it. */ 1087 | if(i === 0 && segment.toLowerCase() === "index") { 1088 | del = true; 1089 | } 1090 | 1091 | /* If our first or second segment is smaller than 3 characters, and the first segment was purely alphas, remove it. */ 1092 | if(i < 2 && segment.length < 3 && !urlSlashes[0].match(/[a-z]/i)) { 1093 | del = true; 1094 | } 1095 | 1096 | /* If it's not marked for deletion, push it to cleanedSegments. */ 1097 | if(!del) { 1098 | cleanedSegments.push(segment); 1099 | } 1100 | } 1101 | 1102 | // This is our final, cleaned, base article URL. 1103 | return window.location.protocol + "//" + window.location.host + cleanedSegments.reverse().join("/"); 1104 | }, 1105 | 1106 | /** 1107 | * Look for any paging links that may occur within the document. 1108 | * 1109 | * @param body 1110 | * @return object (array) 1111 | */ 1112 | findNextPageLink: function(elem) { 1113 | var possiblePages = {}, allLinks = elem.getElementsByTagName('a'), articleBaseUrl = bifocal.findBaseUrl(); 1114 | 1115 | /** 1116 | * Loop through all links, looking for hints that they may be next-page links. Things like having "page" in their textContent, className or id, or being 1117 | * a child of a node with a page-y className or id. 1118 | * 1119 | * Also possible: levenshtein distance? longest common subsequence? 1120 | * 1121 | * After we do that, assign each page a score, and 1122 | */ 1123 | for( var i = 0, il = allLinks.length; i < il; i += 1) { 1124 | var link = allLinks[i], linkHref = allLinks[i].href.replace(/#.*$/, '').replace(/\/$/, ''); 1125 | 1126 | /* If we've already seen this page, ignore it */ 1127 | if(linkHref === "" || linkHref === articleBaseUrl || linkHref === window.location.href || linkHref in bifocal.parsedPages) { 1128 | continue; 1129 | } 1130 | 1131 | /* If it's on a different domain, skip it. */ 1132 | if(window.location.host !== linkHref.split(/\/+/g)[1]) { 1133 | continue; 1134 | } 1135 | 1136 | var linkText = bifocal.getInnerText(link); 1137 | 1138 | /* If the linkText looks like it's not the next page, skip it. */ 1139 | if(linkText.match(bifocal.regexps.extraneous) || linkText.length > 25) { 1140 | continue; 1141 | } 1142 | 1143 | /* If the leftovers of the URL after removing the base URL don't contain any digits, it's certainly not a next page link. */ 1144 | var linkHrefLeftover = linkHref.replace(articleBaseUrl, ''); 1145 | if(!linkHrefLeftover.match(/\d/)) { 1146 | continue; 1147 | } 1148 | 1149 | if(!(linkHref in possiblePages)) { 1150 | possiblePages[linkHref] = { 1151 | "score": 0, 1152 | "linkText": linkText, 1153 | "href": linkHref 1154 | }; 1155 | } else { 1156 | possiblePages[linkHref].linkText += ' | ' + linkText; 1157 | } 1158 | 1159 | var linkObj = possiblePages[linkHref]; 1160 | 1161 | /** 1162 | * If the articleBaseUrl isn't part of this URL, penalize this link. It could still be the link, but the odds are lower. Example: 1163 | * http://www.actionscript.org/resources/articles/745/1/JavaScript-and-VBScript-Injection-in-ActionScript-3/Page1.html 1164 | */ 1165 | if(linkHref.indexOf(articleBaseUrl) !== 0) { 1166 | linkObj.score -= 25; 1167 | } 1168 | 1169 | var linkData = linkText + ' ' + link.className + ' ' + link.id; 1170 | if(linkData.match(bifocal.regexps.nextLink)) { 1171 | linkObj.score += 50; 1172 | } 1173 | if(linkData.match(/pag(e|ing|inat)/i)) { 1174 | linkObj.score += 25; 1175 | } 1176 | if(linkData.match(/(first|last)/i)) { // -65 is enough to negate any bonuses gotten from a > or » in the text, 1177 | /* If we already matched on "next", last is probably fine. If we didn't, then it's bad. Penalize. */ 1178 | if(!linkObj.linkText.match(bifocal.regexps.nextLink)) { 1179 | linkObj.score -= 65; 1180 | } 1181 | } 1182 | if(linkData.match(bifocal.regexps.negative) || linkData.match(bifocal.regexps.extraneous)) { 1183 | linkObj.score -= 50; 1184 | } 1185 | if(linkData.match(bifocal.regexps.prevLink)) { 1186 | linkObj.score -= 200; 1187 | } 1188 | 1189 | /* If a parentNode contains page or paging or paginat */ 1190 | var parentNode = link.parentNode, positiveNodeMatch = false, negativeNodeMatch = false; 1191 | while(parentNode) { 1192 | var parentNodeClassAndId = parentNode.className + ' ' + parentNode.id; 1193 | if(!positiveNodeMatch && parentNodeClassAndId && parentNodeClassAndId.match(/pag(e|ing|inat)/i)) { 1194 | positiveNodeMatch = true; 1195 | linkObj.score += 25; 1196 | } 1197 | if(!negativeNodeMatch && parentNodeClassAndId && parentNodeClassAndId.match(bifocal.regexps.negative)) { 1198 | /* If this is just something like "footer", give it a negative. If it's something like "body-and-footer", leave it be. */ 1199 | if(!parentNodeClassAndId.match(bifocal.regexps.positive)) { 1200 | linkObj.score -= 25; 1201 | negativeNodeMatch = true; 1202 | } 1203 | } 1204 | 1205 | parentNode = parentNode.parentNode; 1206 | } 1207 | 1208 | /** 1209 | * If the URL looks like it has paging in it, add to the score. Things like /page/2/, /pagenum/2, ?p=3, ?page=11, ?pagination=34 1210 | */ 1211 | if(linkHref.match(/p(a|g|ag)?(e|ing|ination)?(=|\/)[0-9]{1,2}/i) || linkHref.match(/(page|paging)/i)) { 1212 | linkObj.score += 25; 1213 | } 1214 | 1215 | /* If the URL contains negative values, give a slight decrease. */ 1216 | if(linkHref.match(bifocal.regexps.extraneous)) { 1217 | linkObj.score -= 15; 1218 | } 1219 | 1220 | /** 1221 | * Minor punishment to anything that doesn't match our current URL. NOTE: I'm finding this to cause more harm than good where something is exactly 1222 | * 50 points. Dan, can you show me a counterexample where this is necessary? if (linkHref.indexOf(window.location.href) !== 0) { linkObj.score -= 1; } 1223 | */ 1224 | 1225 | /** 1226 | * If the link text can be parsed as a number, give it a minor bonus, with a slight bias towards lower numbered pages. This is so that pages that 1227 | * might not have 'next' in their text can still get scored, and sorted properly by score. 1228 | */ 1229 | var linkTextAsNumber = parseInt(linkText, 10); 1230 | if(linkTextAsNumber) { 1231 | // Punish 1 since we're either already there, or it's probably before what we want anyways. 1232 | if(linkTextAsNumber === 1) { 1233 | linkObj.score -= 10; 1234 | } else { 1235 | // Todo: Describe this better 1236 | linkObj.score += Math.max(0, 10 - linkTextAsNumber); 1237 | } 1238 | } 1239 | } 1240 | 1241 | /** 1242 | * Loop thrugh all of our possible pages from above and find our top candidate for the next page URL. Require at least a score of 50, which is a 1243 | * relatively high confidence that this page is the next link. 1244 | */ 1245 | var topPage = null; 1246 | for( var page in possiblePages) { 1247 | if(possiblePages.hasOwnProperty(page)) { 1248 | if(possiblePages[page].score >= 50 && (!topPage || topPage.score < possiblePages[page].score)) { 1249 | topPage = possiblePages[page]; 1250 | } 1251 | } 1252 | } 1253 | 1254 | if(topPage) { 1255 | var nextHref = topPage.href.replace(/\/$/, ''); 1256 | 1257 | dbg('NEXT PAGE IS ' + nextHref); 1258 | bifocal.parsedPages[nextHref] = true; 1259 | return nextHref; 1260 | } else { 1261 | return null; 1262 | } 1263 | }, 1264 | 1265 | /** 1266 | * Build a simple cross browser compatible XHR. 1267 | * 1268 | * TODO: This could likely be simplified beyond what we have here right now. There's still a bit of excess junk. 1269 | */ 1270 | xhr: function() { 1271 | if(typeof XMLHttpRequest !== 'undefined' && (window.location.protocol !== 'file:' || !window.ActiveXObject)) { 1272 | return new XMLHttpRequest(); 1273 | } else { 1274 | try { 1275 | return new ActiveXObject('Msxml2.XMLHTTP.6.0'); 1276 | } catch (sixerr) { 1277 | } 1278 | try { 1279 | return new ActiveXObject('Msxml2.XMLHTTP.3.0'); 1280 | } catch (threrr) { 1281 | } 1282 | try { 1283 | return new ActiveXObject('Msxml2.XMLHTTP'); 1284 | } catch (err) { 1285 | } 1286 | } 1287 | 1288 | return false; 1289 | }, 1290 | 1291 | successfulRequest: function(request) { 1292 | return (request.status >= 200 && request.status < 300) || request.status === 304 || (request.status === 0 && request.responseText); 1293 | }, 1294 | 1295 | ajax: function(url, options) { 1296 | var request = bifocal.xhr(); 1297 | 1298 | function respondToReadyState(readyState) { 1299 | if(request.readyState === 4) { 1300 | if(bifocal.successfulRequest(request)) { 1301 | if(options.success) { 1302 | options.success(request); 1303 | } 1304 | } else { 1305 | if(options.error) { 1306 | options.error(request); 1307 | } 1308 | } 1309 | } 1310 | } 1311 | 1312 | if(typeof options === 'undefined') { 1313 | options = {}; 1314 | } 1315 | 1316 | request.onreadystatechange = respondToReadyState; 1317 | 1318 | request.open('get', url, true); 1319 | request.setRequestHeader('Accept', 'text/html'); 1320 | 1321 | try { 1322 | request.send(options.postBody); 1323 | } catch (e) { 1324 | if(options.error) { 1325 | options.error(); 1326 | } 1327 | } 1328 | 1329 | return request; 1330 | }, 1331 | 1332 | /** 1333 | * Make an AJAX request for each page and append it to the document. 1334 | */ 1335 | curPageNum: 1, 1336 | 1337 | appendNextPage: function(nextPageLink) { 1338 | bifocal.curPageNum += 1; 1339 | 1340 | var articlePage = document.createElement("DIV"); 1341 | articlePage.id = 'bifocal-page-' + bifocal.curPageNum; 1342 | articlePage.className = 'page'; 1343 | articlePage.innerHTML = '<p class="page-separator" title="Page ' + bifocal.curPageNum + '">§</p>'; 1344 | 1345 | document.getElementById("bifocal-content").appendChild(articlePage); 1346 | 1347 | if(bifocal.curPageNum > bifocal.maxPages) { 1348 | var nextPageMarkup = "<div style='text-align: center'><a href='" + nextPageLink + "'>View Next Page</a></div>"; 1349 | 1350 | articlePage.innerHTML = articlePage.innerHTML + nextPageMarkup; 1351 | return; 1352 | } 1353 | 1354 | /** 1355 | * Now that we've built the article page DOM element, get the page content asynchronously and load the cleaned content into the div we created for it. 1356 | */ 1357 | (function(pageUrl, thisPage) { 1358 | bifocal.ajax(pageUrl, { 1359 | success: function(r) { 1360 | 1361 | /* First, check to see if we have a matching ETag in headers - if we do, this is a duplicate page. */ 1362 | var eTag = r.getResponseHeader('ETag'); 1363 | if(eTag) { 1364 | if(eTag in bifocal.pageETags) { 1365 | dbg("Exact duplicate page found via ETag. Aborting."); 1366 | articlePage.style.display = 'none'; 1367 | return; 1368 | } else { 1369 | bifocal.pageETags[eTag] = 1; 1370 | } 1371 | } 1372 | 1373 | // TODO: this ends up doubling up page numbers on NYTimes articles. Need to generically parse those away. 1374 | var page = document.createElement("DIV"); 1375 | 1376 | /** 1377 | * Do some preprocessing to our HTML to make it ready for appending. • Remove any script tags. Swap and reswap newlines with a unicode 1378 | * character because multiline regex doesn't work in javascript. • Turn any noscript tags into divs so that we can parse them. This allows 1379 | * us to find any next page links hidden via javascript. • Turn all double br's into p's - was handled by prepDocument in the original 1380 | * view. Maybe in the future abstract out prepDocument to work for both the original document and AJAX-added pages. 1381 | */ 1382 | var responseHtml = r.responseText.replace(/\n/g, '\uffff').replace(/<script.*?>.*?<\/script>/gi, ''); 1383 | responseHtml = responseHtml.replace(/\n/g, '\uffff').replace(/<script.*?>.*?<\/script>/gi, ''); 1384 | responseHtml = responseHtml.replace(/\uffff/g, '\n').replace(/<(\/?)noscript/gi, '<$1div'); 1385 | responseHtml = responseHtml.replace(bifocal.regexps.replaceBrs, '</p><p>'); 1386 | responseHtml = responseHtml.replace(bifocal.regexps.replaceFonts, '<$1span>'); 1387 | 1388 | page.innerHTML = responseHtml; 1389 | 1390 | /** 1391 | * Reset all flags for the next page, as they will search through it and disable as necessary at the end of grabArticle. 1392 | */ 1393 | bifocal.flags = 0x1 | 0x2 | 0x4; 1394 | 1395 | var nextPageLink = bifocal.findNextPageLink(page), content = bifocal.grabArticle(page); 1396 | 1397 | if(!content) { 1398 | dbg("No content found in page to append. Aborting."); 1399 | return; 1400 | } 1401 | 1402 | /** 1403 | * Anti-duplicate mechanism. Essentially, get the first paragraph of our new page. Compare it against all of the the previous document's 1404 | * we've gotten. If the previous document contains exactly the innerHTML of this first paragraph, it's probably a duplicate. 1405 | */ 1406 | var firstP = content.getElementsByTagName("P").length ? content.getElementsByTagName("P")[0] : null; 1407 | if(firstP && firstP.innerHTML.length > 100) { 1408 | for( var i = 1; i <= bifocal.curPageNum; i += 1) { 1409 | var rPage = document.getElementById('bifocal-page-' + i); 1410 | if(rPage && rPage.innerHTML.indexOf(firstP.innerHTML) !== -1) { 1411 | dbg('Duplicate of page ' + i + ' - skipping.'); 1412 | articlePage.style.display = 'none'; 1413 | bifocal.parsedPages[pageUrl] = true; 1414 | return; 1415 | } 1416 | } 1417 | } 1418 | 1419 | bifocal.removeScripts(content); 1420 | 1421 | thisPage.innerHTML = thisPage.innerHTML + content.innerHTML; 1422 | 1423 | /** 1424 | * After the page has rendered, post process the content. This delay is necessary because, in webkit at least, offsetWidth is not set in 1425 | * time to determine image width. We have to wait a little bit for reflow to finish before we can fix floating images. 1426 | */ 1427 | window.setTimeout(function() { 1428 | bifocal.postProcessContent(thisPage); 1429 | }, 500); 1430 | 1431 | if(nextPageLink) { 1432 | bifocal.appendNextPage(nextPageLink); 1433 | } 1434 | } 1435 | }); 1436 | }(nextPageLink, articlePage)); 1437 | }, 1438 | 1439 | /** 1440 | * Get an elements class/id weight. Uses regular expressions to tell if this element looks good or bad. 1441 | * 1442 | * @param Element 1443 | * @return number (Integer) 1444 | */ 1445 | getClassWeight: function(e) { 1446 | if(!bifocal.flagIsActive(bifocal.FLAG_WEIGHT_CLASSES)) { 1447 | return 0; 1448 | } 1449 | 1450 | var weight = 0; 1451 | 1452 | /* Look for a special classname */ 1453 | if(typeof (e.className) === 'string' && e.className !== '') { 1454 | if(e.className.search(bifocal.regexps.negative) !== -1) { 1455 | weight -= 25; 1456 | } 1457 | 1458 | if(e.className.search(bifocal.regexps.positive) !== -1) { 1459 | weight += 25; 1460 | } 1461 | } 1462 | 1463 | /* Look for a special ID */ 1464 | if(typeof (e.id) === 'string' && e.id !== '') { 1465 | if(e.id.search(bifocal.regexps.negative) !== -1) { 1466 | weight -= 25; 1467 | } 1468 | 1469 | if(e.id.search(bifocal.regexps.positive) !== -1) { 1470 | weight += 25; 1471 | } 1472 | } 1473 | 1474 | return weight; 1475 | }, 1476 | 1477 | nodeIsVisible: function(node) { 1478 | return (node.offsetWidth !== 0 || node.offsetHeight !== 0) && node.style.display.toLowerCase() !== 'none'; 1479 | }, 1480 | 1481 | /** 1482 | * Remove extraneous break tags from a node. 1483 | * 1484 | * @param Element 1485 | * @return void 1486 | */ 1487 | killBreaks: function(e) { 1488 | try { 1489 | e.innerHTML = e.innerHTML.replace(bifocal.regexps.killBreaks, '<br />'); 1490 | } catch (eBreaks) { 1491 | dbg("KillBreaks failed - this is an IE bug. Ignoring.: " + eBreaks); 1492 | } 1493 | }, 1494 | 1495 | /** 1496 | * Clean a node of all elements of type "tag". (Unless it's a youtube/vimeo video. People love movies.) 1497 | * 1498 | * @param Element 1499 | * @param string 1500 | * tag to clean 1501 | * @return void 1502 | */ 1503 | clean: function(e, tag) { 1504 | var targetList = e.getElementsByTagName(tag); 1505 | var isEmbed = (tag === 'object' || tag === 'embed'); 1506 | 1507 | for( var y = targetList.length - 1; y >= 0; y -= 1) { 1508 | /* Allow youtube and vimeo videos through as people usually want to see those. */ 1509 | if(isEmbed) { 1510 | var attributeValues = ""; 1511 | for( var i = 0, il = targetList[y].attributes.length; i < il; i += 1) { 1512 | attributeValues += targetList[y].attributes[i].value + '|'; 1513 | } 1514 | 1515 | /* First, check the elements attributes to see if any of them contain youtube or vimeo */ 1516 | if(attributeValues.search(bifocal.regexps.videos) !== -1) { 1517 | continue; 1518 | } 1519 | 1520 | /* Then check the elements inside this element for the same. */ 1521 | if(targetList[y].innerHTML.search(bifocal.regexps.videos) !== -1) { 1522 | continue; 1523 | } 1524 | 1525 | } 1526 | 1527 | targetList[y].parentNode.removeChild(targetList[y]); 1528 | } 1529 | }, 1530 | 1531 | /** 1532 | * Clean an element of all tags of type "tag" if they look fishy. "Fishy" is an algorithm based on content length, classnames, link density, number of 1533 | * images & embeds, etc. 1534 | * 1535 | * @return void 1536 | */ 1537 | cleanConditionally: function(e, tag) { 1538 | 1539 | if(!bifocal.flagIsActive(bifocal.FLAG_CLEAN_CONDITIONALLY)) { 1540 | return; 1541 | } 1542 | 1543 | var tagsList = e.getElementsByTagName(tag); 1544 | var curTagsLength = tagsList.length; 1545 | 1546 | /** 1547 | * Gather counts for other typical elements embedded within. Traverse backwards so we can remove nodes at the same time without effecting the traversal. 1548 | * 1549 | * TODO: Consider taking into account original contentScore here. 1550 | */ 1551 | for( var i = curTagsLength - 1; i >= 0; i -= 1) { 1552 | var weight = bifocal.getClassWeight(tagsList[i]); 1553 | var contentScore = (typeof tagsList[i].bifocal !== 'undefined') ? tagsList[i].bifocal.contentScore : 0; 1554 | 1555 | dbg("Cleaning Conditionally " + tagsList[i] + " (" + tagsList[i].className + ":" + tagsList[i].id + ")" 1556 | + ((typeof tagsList[i].bifocal !== 'undefined') ? (" with score " + tagsList[i].bifocal.contentScore) : '')); 1557 | 1558 | if(weight + contentScore < 0) { 1559 | tagsList[i].parentNode.removeChild(tagsList[i]); 1560 | } else if(bifocal.getCharCount(tagsList[i], ',') < 10) { 1561 | /** 1562 | * If there are not very many commas, and the number of non-paragraph elements is more than paragraphs or other ominous signs, remove the 1563 | * element. 1564 | */ 1565 | var p = tagsList[i].getElementsByTagName("p").length; 1566 | var img = tagsList[i].getElementsByTagName("img").length; 1567 | var li = tagsList[i].getElementsByTagName("li").length - 100; 1568 | var input = tagsList[i].getElementsByTagName("input").length; 1569 | 1570 | var embedCount = 0; 1571 | var embeds = tagsList[i].getElementsByTagName("embed"); 1572 | for( var ei = 0, il = embeds.length; ei < il; ei += 1) { 1573 | if(embeds[ei].src.search(bifocal.regexps.videos) === -1) { 1574 | embedCount += 1; 1575 | } 1576 | } 1577 | 1578 | var linkDensity = bifocal.getLinkDensity(tagsList[i]); 1579 | var contentLength = bifocal.getInnerText(tagsList[i]).length; 1580 | var toRemove = false; 1581 | 1582 | if(img > p) { 1583 | toRemove = true; 1584 | } else if(li > p && tag !== "ul" && tag !== "ol") { 1585 | toRemove = true; 1586 | } else if(input > Math.floor(p / 3)) { 1587 | toRemove = true; 1588 | } else if(contentLength < 25 && (img === 0 || img > 2)) { 1589 | toRemove = true; 1590 | } else if(weight < 25 && linkDensity > 0.2) { 1591 | toRemove = true; 1592 | } else if(weight >= 25 && linkDensity > 0.5) { 1593 | toRemove = true; 1594 | } else if((embedCount === 1 && contentLength < 75) || embedCount > 1) { 1595 | toRemove = true; 1596 | } 1597 | 1598 | if(toRemove) { 1599 | tagsList[i].parentNode.removeChild(tagsList[i]); 1600 | } 1601 | } 1602 | } 1603 | }, 1604 | 1605 | /** 1606 | * Clean out spurious headers from an Element. Checks things like classnames and link density. 1607 | * 1608 | * @param Element 1609 | * @return void 1610 | */ 1611 | cleanHeaders: function(e) { 1612 | for( var headerIndex = 1; headerIndex < 3; headerIndex += 1) { 1613 | var headers = e.getElementsByTagName('h' + headerIndex); 1614 | for( var i = headers.length - 1; i >= 0; i -= 1) { 1615 | if(bifocal.getClassWeight(headers[i]) < 0 || bifocal.getLinkDensity(headers[i]) > 0.33) { 1616 | headers[i].parentNode.removeChild(headers[i]); 1617 | } 1618 | } 1619 | } 1620 | }, 1621 | 1622 | /** * Smooth scrolling logic ** */ 1623 | 1624 | /** 1625 | * easeInOut animation algorithm - returns an integer that says how far to move at this point in the animation. Borrowed from jQuery's easing library. 1626 | * 1627 | * @return integer 1628 | */ 1629 | easeInOut: function(start, end, totalSteps, actualStep) { 1630 | var delta = end - start; 1631 | 1632 | if((actualStep /= totalSteps / 2) < 1) { 1633 | return delta / 2 * actualStep * actualStep + start; 1634 | } 1635 | actualStep -= 1; 1636 | return -delta / 2 * ((actualStep) * (actualStep - 2) - 1) + start; 1637 | }, 1638 | 1639 | /** 1640 | * Helper function to, in a cross compatible way, get or set the current scroll offset of the document. 1641 | * 1642 | * @return mixed integer on get, the result of window.scrollTo on set 1643 | */ 1644 | scrollTop: function(scroll) { 1645 | var setScroll = typeof scroll !== 'undefined'; 1646 | 1647 | if(setScroll) { 1648 | return window.scrollTo(0, scroll); 1649 | } 1650 | if(typeof window.pageYOffset !== 'undefined') { 1651 | return window.pageYOffset; 1652 | } else if(document.documentElement.clientHeight) { 1653 | return document.documentElement.scrollTop; 1654 | } else { 1655 | return document.body.scrollTop; 1656 | } 1657 | }, 1658 | 1659 | /** 1660 | * scrollTo - Smooth scroll to the point of scrollEnd in the document. 1661 | * 1662 | * @return void 1663 | */ 1664 | curScrollStep: 0, 1665 | scrollTo: function(scrollStart, scrollEnd, steps, interval) { 1666 | if((scrollStart < scrollEnd && bifocal.scrollTop() < scrollEnd) || (scrollStart > scrollEnd && bifocal.scrollTop() > scrollEnd)) { 1667 | bifocal.curScrollStep += 1; 1668 | if(bifocal.curScrollStep > steps) { 1669 | return; 1670 | } 1671 | 1672 | var oldScrollTop = bifocal.scrollTop(); 1673 | 1674 | bifocal.scrollTop(bifocal.easeInOut(scrollStart, scrollEnd, steps, bifocal.curScrollStep)); 1675 | 1676 | // We're at the end of the window. 1677 | if(oldScrollTop === bifocal.scrollTop()) { 1678 | return; 1679 | } 1680 | 1681 | window.setTimeout(function() { 1682 | bifocal.scrollTo(scrollStart, scrollEnd, steps, interval); 1683 | }, interval); 1684 | } 1685 | }, 1686 | 1687 | /** 1688 | * Show the email popup. 1689 | * 1690 | * @return void 1691 | */ 1692 | emailBox: function() { 1693 | var emailContainerExists = document.getElementById('email-container'); 1694 | if(null !== emailContainerExists) { 1695 | return; 1696 | } 1697 | 1698 | var emailContainer = document.createElement("DIV"); 1699 | emailContainer.setAttribute('id', 'email-container'); 1700 | emailContainer.innerHTML = '<iframe src="' + bifocal.emailSrc + '?pageUrl=' + encodeURIComponent(window.location) + '&pageTitle=' 1701 | + encodeURIComponent(document.title) 1702 | + '" scrolling="no" onload="bifocal.removeFrame()" style="width:500px; height: 490px; border: 0;"></iframe>'; 1703 | 1704 | document.body.appendChild(emailContainer); 1705 | }, 1706 | 1707 | /** 1708 | * Close the email popup. This is a hacktackular way to check if we're in a "close loop". Since we don't have crossdomain access to the frame, we can only 1709 | * know when it has loaded again. If it's loaded over 3 times, we know to close the frame. 1710 | * 1711 | * @return void 1712 | */ 1713 | removeFrame: function() { 1714 | bifocal.iframeLoads += 1; 1715 | if(bifocal.iframeLoads > 3) { 1716 | var emailContainer = document.getElementById('email-container'); 1717 | if(null !== emailContainer) { 1718 | emailContainer.parentNode.removeChild(emailContainer); 1719 | } 1720 | 1721 | bifocal.iframeLoads = 0; 1722 | } 1723 | }, 1724 | 1725 | htmlspecialchars: function(s) { 1726 | if(typeof (s) === "string") { 1727 | s = s.replace(/&/g, "&"); 1728 | s = s.replace(/"/g, """); 1729 | s = s.replace(/'/g, "'"); 1730 | s = s.replace(/</g, "<"); 1731 | s = s.replace(/>/g, ">"); 1732 | } 1733 | 1734 | return s; 1735 | }, 1736 | 1737 | flagIsActive: function(flag) { 1738 | return (bifocal.flags & flag) > 0; 1739 | }, 1740 | 1741 | addFlag: function(flag) { 1742 | bifocal.flags = bifocal.flags | flag; 1743 | }, 1744 | 1745 | removeFlag: function(flag) { 1746 | bifocal.flags = bifocal.flags & ~flag; 1747 | } 1748 | 1749 | }; 1750 | 1751 | bifocal.init(); 1752 | --------------------------------------------------------------------------------